Quickstart
Make your first Coris API call. Profile a business in the sandbox, then use its ID to fetch it directly.
Profile a fictional business in the sandbox and fetch it by its establishment ID. You need a sandbox API key, plus curl with jq, Python 3 with requests, or Node 18 or later.
- You → Coris1POST
/ merchant_profiler/ - Coris → You2201
request_id - You → Coris3GET
/ merchant_profiler/ ? request_id=... - Coris → You4425
or 206 while running - You → Coris5GET
/ merchant_profiler/ ? request_id=... - Coris → You6200
establishment + legal_entity - You → Coris7GET
/ establishment/ {establishment_id}/ - Coris → You8200
establishment
Step 1: Set up your key
Create a key at sandbox.coris.ai under Profile → Account Settings → Partner API Keys. Replace YOUR_API_KEY below, and run every step in the same session.
export CORIS_BASE_URL="https://sandbox-api.coris.ai/api/v0_2"
export CORIS_API_KEY="YOUR_API_KEY"import requests
BASE_URL = "https://sandbox-api.coris.ai/api/v0_2"
HEADERS = {"Authorization": "Token YOUR_API_KEY"}const BASE_URL = "https://sandbox-api.coris.ai/api/v0_2";
const HEADERS = {
Authorization: "Token YOUR_API_KEY",
"Content-Type": "application/json",
};The samples below wait with the polling helper. Expand it, and run it too.
Polling helper
# Polls an async endpoint and prints the body once it returns 200.
# 206, 425, 429 and 500 all mean wait and poll again. A 500 re-queues the job.
poll() {
delay=5
for _ in $(seq 1 30); do
http_status=$(curl -s -o /tmp/coris_body -w '%{http_code}' \
-H "Authorization: Token $CORIS_API_KEY" \
"$CORIS_BASE_URL$1?request_id=$2")
if [ "$http_status" = "200" ]; then cat /tmp/coris_body; return 0; fi
case "$http_status" in
206|425|429|500) ;;
*) echo "HTTP $http_status: $(cat /tmp/coris_body)" >&2; return 1 ;;
esac
sleep "$delay"
delay=$((delay * 3 / 2)); [ "$delay" -gt 30 ] && delay=30
done
echo "Timed out" >&2; return 1
}import time
# 206, 425, 429 and 500 all mean wait and poll again. A 500 re-queues the job.
RETRYABLE = (206, 425, 429, 500)
def poll(path, request_id, attempts=30):
"""Polls an async endpoint and returns the JSON body once it returns 200."""
delay = 5
for _ in range(attempts):
response = requests.get(
f"{BASE_URL}{path}", params={"request_id": request_id}, headers=HEADERS
)
if response.status_code == 200:
return response.json()
if response.status_code not in RETRYABLE:
response.raise_for_status()
time.sleep(delay)
delay = min(delay * 1.5, 30)
raise TimeoutError(f"{path} did not finish")// 206, 425, 429 and 500 all mean wait and poll again. A 500 re-queues the job.
const RETRYABLE = [206, 425, 429, 500];
// Polls an async endpoint and returns the JSON body once it returns 200.
async function poll(path, requestId, attempts = 30) {
let delay = 5000;
for (let i = 0; i < attempts; i++) {
const url = `${BASE_URL}${path}?request_id=${requestId}`;
const response = await fetch(url, { headers: HEADERS });
if (response.status === 200) return response.json();
if (!RETRYABLE.includes(response.status)) {
throw new Error(`HTTP ${response.status}: ${await response.text()}`);
}
await new Promise((resolve) => setTimeout(resolve, delay));
delay = Math.min(delay * 1.5, 30000);
}
throw new Error(`${path} did not finish`);
}Step 2: Start a Merchant Profiler request
Send a business name and a registration address. Coris returns a request_id right away and keeps working.
REQUEST_ID=$(curl -s -X POST "$CORIS_BASE_URL/merchant_profiler/" \
-H "Authorization: Token $CORIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"business_name": "Acme Plumbing Co.",
"address": {
"address_type": "Registration",
"city": "San Jose",
"state": "CA",
"country": "US"
},
"phone_number": "408-555-0142",
"website": "https://www.acmeplumbing.example"
}' | jq -r '.request_id')
echo "$REQUEST_ID"response = requests.post(
f"{BASE_URL}/merchant_profiler/",
headers=HEADERS,
json={
"business_name": "Acme Plumbing Co.",
"address": {
"address_type": "Registration",
"city": "San Jose",
"state": "CA",
"country": "US",
},
"phone_number": "408-555-0142",
"website": "https://www.acmeplumbing.example",
},
)
response.raise_for_status()
request_id = response.json()["request_id"]
print(request_id)const created = await fetch(`${BASE_URL}/merchant_profiler/`, {
method: "POST",
headers: HEADERS,
body: JSON.stringify({
business_name: "Acme Plumbing Co.",
address: {
address_type: "Registration",
city: "San Jose",
state: "CA",
country: "US",
},
phone_number: "408-555-0142",
website: "https://www.acmeplumbing.example",
}),
});
if (!created.ok) throw new Error(await created.text());
const { request_id: requestId } = await created.json();
console.log(requestId);Try POST /merchant_profiler/ in the API explorer.
Step 3: Poll for the result
Poll Get a Merchant Profiler result with request_id. It returns 425 before any data exists, 206 with partial data, and 200 when every part is done.
PROFILE=$(poll /merchant_profiler/ "$REQUEST_ID")
ESTABLISHMENT_ID=$(printf '%s' "$PROFILE" | jq -r '.establishment.id')
printf '%s' "$PROFILE" | jq '{establishment, legal_entity, portal_link}'profile = poll("/merchant_profiler/", request_id)
establishment_id = profile["establishment"]["id"]
print(profile["establishment"], profile["legal_entity"], profile.get("portal_link"))const profile = await poll("/merchant_profiler/", requestId);
const establishmentId = profile.establishment.id;
console.log(profile.establishment, profile.legal_entity, profile.portal_link);Step 4: Fetch the business with its establishment ID
Use establishment.id instead of sending the name and address again. Get an establishment returns the object from step 3.
curl -s "$CORIS_BASE_URL/establishment/$ESTABLISHMENT_ID/" \
-H "Authorization: Token $CORIS_API_KEY" | jqresponse = requests.get(f"{BASE_URL}/establishment/{establishment_id}/", headers=HEADERS)
response.raise_for_status()
print(response.json())const establishment = await fetch(`${BASE_URL}/establishment/${establishmentId}/`, {
headers: HEADERS,
});
console.log(await establishment.json());Try GET /establishment/{establishment_id}/ in the API explorer.
Read the response
This 200 from step 3 is shortened, and sandbox values vary between runs.
{
"establishment": {
"id": "3f6c1a52-8e47-4b1d-9a60-5c2e7d1f0b34",
"name": "Acme Plumbing Co.",
"addresses": [],
"is_online_business": false,
"legal_entity_id": "a81d2c07-4f3e-4e6b-b1d9-90e6c3f27a15"
},
"legal_entity": {
"id": "a81d2c07-4f3e-4e6b-b1d9-90e6c3f27a15",
"name": "Acme Plumbing Co.",
"ein": null,
"country": "US",
"entity_type": "OTHER",
"status": "UNKNOWN",
"raw_status": "Unknown",
"addresses": [
{
"city": "San Jose",
"state": "CA",
"country": "US",
"address_sub_type": "registration_address",
"address_type": "Registration",
"source": "Other"
}
]
},
"establishment_ratings": { "biz_rating": 3, "website_rating": 3 },
"establishment_phones": [
{ "phone_number": "4085550142", "phone_type": "Landline", "metadata": {} }
],
"personnel": [],
"legal_entity_licenses": [],
"portal_link": "https://sandbox.coris.ai/search-result/1f0c9a7e"
}| Field | Meaning | What to do |
|---|---|---|
establishment.id | The ID of this business. | Store it against your merchant record. |
legal_entity.status | ACTIVE, INACTIVE or UNKNOWN. | Review anything other than ACTIVE. A new sandbox record shows UNKNOWN or null. |
establishment_ratings | Business and website ratings. | Lower is better: 1 is best and 5 is worst. See How to read Coris scores. |
portal_link | The same result in the Coris portal. | Share it with your review team. |
A new sandbox record leaves the website, phone and address you sent off establishment. See Test in the sandbox.
What to do next
| Result | Next step |
|---|---|
| You want this business monitored | Create an account from establishment.id. See Monitor your portfolio. |
| You need KYB checks | Run Verify a business at onboarding. |
| You need a credit-style review | Run Underwrite a merchant. |
| You prefer not to poll | Send a callback_url. See Async requests. |
FAQ
Why did my request return 422?
The address does not match the name you sent. business_name needs address_type Registration, and dba_name needs Establishment. The address also needs city and state, or zip_code.
Why do my results change between runs?
Most sandbox data is mocked, and some values are random. See Test in the sandbox for fixed test scenarios.
Where is business_id?
business_id?Responses do not include it. Use establishment.id, and legal_entity.id for Legal Entity endpoints.
Next: Core concepts
Updated about 23 hours ago