Skip to main content
POST /api/ingestion/customers/{customerId}/kyb-runs starts a KYB run for a business Customer that your ingestion source already created. Use it when the Customer and its documents are already in Karsa and you want a fresh evaluation, for example after uploading a replacement document. To submit a complete snapshot with related parties and provider evidence, use KYB dossiers instead.

Address the customer

Every KYB run route accepts either form of customer reference. Both resolve only Customers owned by the calling ingestion source.

Start a run

An Idempotency-Key header is required. The body is optional.
With an empty body, the run uses the Customer’s current version and the current AVAILABLE version of every ingested document linked to it or cited by its latest KYB dossier. Related parties and provider evidence carry forward from that latest dossier. To choose the documents yourself, list them with a KYB document role:
Karsa reads each document by its subtype (for example CERTIFICATE_OF_INCORPORATION_OR_FORMATION, UTILITY_BILL, or SHAREHOLDER_OR_MEMBER_REGISTER, as in a KYB dossier) and language (a BCP 47 tag such as en or pt-BR; und is not accepted). A document cited by the Customer’s latest KYB dossier in the same role reuses that dossier’s subtype and languages. Karsa does not guess: on a first run, or for a document no dossier has cited, supply subtype and language in documents, otherwise the request is refused with 422 KYB_DOCUMENT_METADATA_REQUIRED. Each entry in its issues has the documentVersionId as path and names what is missing. Karsa answers 202 Accepted with a Location header for the run:
Replaying the same key and body returns the same 202 without starting another run. Reusing the key with a different body, or for a different customer reference, returns 409 IDEMPOTENCY_CONFLICT. A Customer can have one active run at a time.

Poll the run

List a Customer’s runs, newest first, with GET on the same customer path. Pass limit (1–100, default 20) and the returned nextCursor as cursor to read the next page.

Status lifecycle

status is derived from the run and its Case. A finished run has result.outcome, result.openIssueCount, and result.caseId. Karsa evaluations report ATTENTION_REQUIRED or NO_ATTENTION; prepared cases report APPROVED or REVIEW_REQUIRED; runs from the earlier KYB investigation keep RFI_REQUIRED, RESEARCH_REQUIRED, or HUMAN_REVIEW_REQUIRED. A failed run has failure.code, for example KYB_EXECUTION_FAILED. New statuses and outcomes may be added; treat an unknown value as not yet terminal and keep polling or wait for a webhook.

Errors

Errors use application/problem+json with a stable code. A trigger checks the Customer first, so CUSTOMER_NOT_FOUND and CUSTOMER_NOT_BUSINESS are returned even while KYB evaluation is unavailable.

Webhooks

Subscribe an endpoint to kyb.evaluation.queued, kyb.evaluation.completed, and kyb.evaluation.failed as described in Set up outbound webhooks. Each KYB event’s data.kybRun is the run exactly as GET /api/ingestion/kyb-runs/{id} returned it when the event was recorded, so you can act on the webhook without polling. Events are delivered only to endpoints that are active when they occur; to catch up after downtime or before an endpoint was verified, list them with GET /api/ingestion/webhook-events.
A kyb.evaluation.queued event carries kybRun.status pending. A kyb.evaluation.failed event carries kybRun.status failed and the same code in failureCode and kybRun.failure.code. Deliveries are retried with the same event ID, timestamp, and signature, so deduplicate on the signed body’s id. The Karsa-Webhook-Id header is not signed: after verifying, reject a delivery whose header ID or type differs from the body’s id or type.

Verify the signature

Karsa signs the UTF-8 bytes timestamp + "." + rawBody with Ed25519. Verify with the public key for the delivery’s Karsa-Webhook-Key-Version before parsing the JSON: