CorebanqCorebanq Developer Docs
KYCv1KYC Screening

Get a screening

Returns one stored screening, rendered as UniversalKYCResponse rather than as the stored row. The two query parameters below are accepted and parsed but DISCARDED before they can change the body: matches are always included, and the provider's raw response is never included, whatever is sent.

GET
/v1/kyc/screening/{id}

Authorization

bearerAuth
AuthorizationBearer <token>

JWT token from the authentication endpoint.

In: header

Path Parameters

id*string

The screening row id.

Query Parameters

include_matches?string

Include the matches array on each screening result.

IT HAS NO EFFECT. The handler parses this flag and the service passes it on, but convertToUniversalResponse declares both flags as blank parameters — func (s *UniversalScreeningService) convertToUniversalResponse(screening *models.KYCScreening, _, _ bool) — so neither is read. The matches array is ALWAYS rendered, from the stored response column, whether or not the flag is sent. Kept in the spec because the parameter is still accepted and still parsed; do not build a client that depends on it.

include_response?string

Include the provider's raw response.

IT HAS NO EFFECT. The handler parses this flag and the service passes it on, but convertToUniversalResponse declares both flags as blank parameters — func (s *UniversalScreeningService) convertToUniversalResponse(screening *models.KYCScreening, _, _ bool) — so neither is read. There is no raw-provider-response field on UniversalKYCResponse at all, so sending the flag cannot add one. Kept in the spec because the parameter is still accepted and still parsed; do not build a client that depends on it.

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/kyc/screening/497f6eca-6276-4993-bfeb-53cbbbba6f08"
{
  "request_id": "string",
  "reference_id": "string",
  "entity_type": "customers",
  "entity_id": "8161163a-f227-466f-bc01-090a01e80165",
  "overall_risk_level": "low",
  "overall_score": 0.1,
  "screening_results": [
    {
      "screening_type": "sanctions",
      "risk_level": "low",
      "score": 0.1,
      "status": "string",
      "matches": [
        {
          "match_id": "string",
          "match_type": "string",
          "confidence": 0.1,
          "risk_level": "low",
          "matched_entity": {
            "id": "string",
            "name": "string",
            "schema": "string",
            "properties": {},
            "datasets": [
              "string"
            ],
            "country": "string",
            "birth_date": "string",
            "address": "string",
            "aliases": [
              "string"
            ]
          },
          "match_reason": "string",
          "match_details": {},
          "source": "string",
          "source_id": "string",
          "last_updated": "2019-08-24T14:15:22Z",
          "sanctions_list": "string",
          "pep_status": "string",
          "adverse_media": [
            {
              "title": "string",
              "summary": "string",
              "url": "string",
              "source": "string",
              "published_at": "2019-08-24T14:15:22Z",
              "relevance": 0.1,
              "sentiment": "string"
            }
          ]
        }
      ],
      "summary": "string",
      "details": {},
      "last_updated": "2019-08-24T14:15:22Z"
    }
  ],
  "total_matches": 0,
  "has_matches": true,
  "requires_review": true,
  "screened_at": "2019-08-24T14:15:22Z",
  "expires_at": "2019-08-24T14:15:22Z",
  "recommendations": [
    "string"
  ],
  "metadata": {},
  "case_id": "c74269e5-1f97-4e20-9164-ffbe3494d8d6",
  "assigned_to": "b9f52997-ff03-4166-bbff-22fd35e12939",
  "assigned_at": "2019-08-24T14:15:22Z"
}
{
  "status": 400,
  "message": "KYC screening record not found",
  "code": "kyc_m.not_found",
  "class": "validation"
}
{
  "status": 401,
  "message": "Unauthorized",
  "code": "common.unauthorized",
  "class": "business"
}
{
  "status": 403,
  "message": "No access to the record",
  "code": "common.rbac_no_rec_access",
  "class": "business"
}
{
  "status": 404,
  "message": "KYC screening record not found",
  "code": "kyc_m.not_found",
  "class": "business"
}
{
  "status": 429,
  "message": "Rate limit for 203.0.113.7 to POST:/v1/kyc/screening exceeded.",
  "code": "rate_limits_m.exceeded",
  "class": "temporary",
  "retryable": true
}
{
  "status": 500,
  "message": "Failed to retrieve KYC screening record",
  "code": "kyc_m.failed_to_get",
  "class": "business"
}

{
  "overall_status": "unhealthy",
  "message": "Service is shutting down",
  "timestamp": "2026-08-27T15:04:05Z"
}

POSTStart identity verification

Opens a provider verification session for one signatory and returns the URL to send them to. Answers 201 Created. Takes NO request body. Only one session may be open per signatory: a second call while one is in progress is 409. THE RESPONSE SET BELOW IS NOT CLOSED. The Ondato driver forwards the provider's own HTTP status verbatim from three sites, TWO of which this route reaches: CreateIDVSession, and requestAccessToken — its OAuth token endpoint, called through getAccessToken on this same path and identifiable by reason=token_endpoint_error. The third, GetIDVSession, is reached only from refreshFromProvider, i.e. from the IDV GET (where the error is swallowed) and from the background poller, so its verbatim status reaches no client at all. Whatever Ondato answers >= 400 becomes the status here, so a caller can receive a status this operation does not declare at all: an upstream 422 is rendered as 422, and any status apireply's switch does not know — 402 and 405 aside, it covers 200, 400, 401, 402, 403, 404, 405, 408, 409, 422, 429, 502, 503 and 504 — falls to 500. Treat kyc_m.idv_provider_error as the signal and the status as advisory.

GETScreening statistics

Aggregate counts over EVERY screening row in the tenant, not the caller's permitted subset. The handler resolves a user id and passes it down, but GetScreeningStats hands the repository only the date range — the id reaches no query and no RbacRecordType is set — so any caller with the endpoint grant sees the whole table's totals. GET /v1/kyc/screening is no better: it asks for CUSTOMER-record scoping through GetAllTotalInput and then applies the permitted customer ids to kyc.screening.id, so it answers with an empty page or an unscoped one. Neither route is a tenant boundary. THE DATE RANGE DOES NOT WORK. The handler runs the full shared query parser and hands the result to the service, which then looks for the keys date_from and date_to. The shared parser never emits those keys — its switch recognises limit, offset, sort, stack, distinct, filter, search, search_text and fill_gaps, plus any search.<field> key, and everything else hits default: return nil. So both are always nil and the statistics are ALWAYS COMPUTED OVER ALL TIME, whatever the caller sends. Every other query parameter is parsed and then discarded too: only the two date keys are read, and neither can arrive. DATE RANGE: THERE IS NO WAY TO ASK FOR ONE. GetScreeningStatsWithQuery reads queryMap["date_from"] and queryMap["date_to"] and passes the parsed pair to GetScreeningStats, so the service is built for a range — but the keys never arrive. parseStandardQueryParameter has cases for limit/offset, sort/stack/distinct/fill_gaps, search/search_text and filter, and everything else falls to default: return nil. ?date_from=2026-01-01 is therefore handled IDENTICALLY to ?banana=1: both are dropped, and both answer 200 with all-time totals. The two are deliberately NOT declared as parameters for that reason — declaring one would be a contract statement the code does not make, and a generated client would emit a dateFrom argument whose caller receives all-time figures rendered as a filtered range. Contrast offset, which IS declared here and on the list route: parseLimitOffset really parses it and ?offset=abc really is a 400 common.invalid_input, so it exists in the request contract even though FetchKYCScreenings never applies it. date_from has no such foothold.