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.

YouCoris
  1. You → Coris
    1POST /merchant_profiler/
  2. Coris → You
    2201 request_id
  3. You → Coris
    3GET /merchant_profiler/?request_id=...
  4. Coris → You
    4425 or 206 while running
  5. You → Coris
    5GET /merchant_profiler/?request_id=...
  6. Coris → You
    6200 establishment + legal_entity
  7. You → Coris
    7GET /establishment/{establishment_id}/
  8. Coris → You
    8200 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" | jq
response = 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"
}
FieldMeaningWhat to do
establishment.idThe ID of this business.Store it against your merchant record.
legal_entity.statusACTIVE, INACTIVE or UNKNOWN.Review anything other than ACTIVE. A new sandbox record shows UNKNOWN or null.
establishment_ratingsBusiness and website ratings.Lower is better: 1 is best and 5 is worst. See How to read Coris scores.
portal_linkThe 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

ResultNext step
You want this business monitoredCreate an account from establishment.id. See Monitor your portfolio.
You need KYB checksRun Verify a business at onboarding.
You need a credit-style reviewRun Underwrite a merchant.
You prefer not to pollSend 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?

Responses do not include it. Use establishment.id, and legal_entity.id for Legal Entity endpoints.

Next: Core concepts


Did this page help you?