Developers API v1

Authentication and connecting

One key, one header, no token exchange. Everything harder than that is on our side of the boundary.

What you receive at onboarding#

ItemUsed for
API keyEvery request, in the X-Api-Key header
HostThe base URL. Environment-specific, which is why it is not published here
Signing secretVerifying the callbacks we send you. Different from the API key
Policy version identifiersThe strings you send as policy_version
Source addressesWhere our callbacks originate, if you allowlist inbound traffic

You supply one thing in return: the HTTPS endpoint that will receive callbacks. It can be changed later without reissuing anything.

Configuring your policy#

You supply your rules: thresholds, band boundaries, evidence floors, and which conditions are mandatory. They are configured as a named policy version, one per lending product. The identifiers come back to you in the table above, and those are the strings you send as policy_version.

A change is requested through your account contact and comes back as a new version identifier. Versions are never edited in place, which is what lets an assessment from months ago still resolve to the exact rules that produced it.

Registering or changing the callback URL#

Also through your account contact. Send us the HTTPS endpoint at onboarding and tell us when you want it changed. A change takes effect for events generated after it lands; events already queued for delivery finish against the old endpoint, so keep the old one answering until you stop seeing traffic on it.

One endpoint receives every event type. Branch on type.

Using your key#

Send it as X-Api-Key on every request, including the ones that touch no upstream source. There is no bearer token, no OAuth exchange and no session. A key that works keeps working until it is revoked.

The key identifies your tenant. Everything the API returns is scoped to it: your assessments, your policy versions, your coverage. There is no cross-tenant read of any kind, and the error codes are chosen to keep it that way.

Making your first call#

Start with GET /v1/countries. It consults no upstream source, so it confirms three things at once, without consuming anything chargeable: that your key is valid, that your host is right, and that your network path works.

A 200 with a list of markets means you are connected. A 401 means the key or the header name is wrong. A connection error means the host is wrong.

Test environment#

There is none in v1. Every key is live, and every assessment consumes real sources, some of which are chargeable.

Build against mode: screening

It runs the first stage and stops, so you can exercise the whole request, callback and result path, including signature verification and your error handling, without running the rest of the policy.

livemode is on every response and is always true, so adding a test environment later changes nothing about the shape of anything you have already built.

Storing the key#

Tell us immediately if a key appears in a log aggregator, a screenshot, a ticket or a repository, and we will replace it.

Verifying callbacks#

The one piece of cryptography in this integration, and the one place a shortcut costs you something real. Full detail and the common failure modes are on the webhooks page; the samples are in the right-hand column here.

Three rules: sign the raw bytes, compare in constant time, reject a stale timestamp.

Tenant scoping#

A request for another tenant's assessment returns 404, not 403.

A 403 would confirm the resource exists, which discloses something about another tenant. 404 tells you the only thing you are entitled to know: it is not yours.

Rate limits#

Per-tenant limits apply to request volume and to how many assessments you may have running at once. Your values are issued at onboarding.

LimitValueScope
RequestsSet at onboardingPer tenant, all endpoints
Assessments createdSet at onboardingPer tenant
Assessments in flightSet at onboardingPer tenant
Callback delivery7 attempts over 24 hoursPer event
What “in flight” counts

An assessment we are actively working on: screening or processing. An assessment sitting in awaiting_bank_data is waiting on you, holds none of our capacity, and does not count. Terminal states never count.

A borrower who starts an application and never finishes the bank-data step therefore cannot consume your concurrency. An abandoned case holds no slot, and expires_at is the point after which it will never produce a result.

Build for 429 from the first day

Exceeding a limit returns 429 with Retry-After. Treat it as an expected response with a documented remedy, not as an error to escalate. Retry after the interval, with jitter if you are running several workers.

You attest and Credit Atlas records. The consents object states what the borrower agreed to and when. It is stored with the assessment, so any later question about the basis for processing has an answer attached to the case rather than to a policy document.

ConsentNeeded for
data_processingAlways required
bureau_enquiryAny bureau lookup, where one is in scope
account_informationSubmitting bank data

A missing consent returns 402 with consent_error, separately from a validation error, because the remedy is different: you need something from the borrower, not a corrected field.

The account-information relationship stays with you. You initiate the borrower's journey under your own agreement and submit the result. Credit Atlas does not stand between you and that relationship, which keeps the regulated party where it already sits.

On the decision itself: policy_outcome reports the result of applying the configured policy to the evidence. It is not a creditworthiness decision made by Credit Atlas, and your analyst retains decision authority. analyst_questions arrives as structured data so each question can be routed, tracked and closed against the driver that raised it.

Versioning policy#

The version is in the path: /v1. It changes only for a breaking change. Inside v1, the following holds.

Current contract: version 1.0, released 6 July 2026.

May changeWill not change
Add a new optional request fieldAdd a required request field
Add a new response fieldRemove or rename a response field
Add a new enum valueRemove an enum value or change its meaning
Add a new endpoint or event typeChange an endpoint's semantics
Add a new success status code to an existing operationChange which status code an existing outcome returns
Relax a validation ruleTighten one
Raise a rate limitLower one without notice
Two consequences for your code

Tolerate unknown enum values. New markets, new reason codes and new check keys will appear. A consumer that throws on an unrecognised enum value will break on an additive change. One that routes unknown values to a review queue will not.

Tolerate unknown response fields. Fields get added, so do not validate responses with a strict closed schema. Unknown fields are rejected on the way in, and that asymmetry is deliberate.