Headless (API only) integration with Payment Screening
Last updated: August 14, 2026
Last updated [CMS-generated]
Headless Payment Screening lets a customer submit a payment, retrieve the risks it produced, and record a decision on each one entirely over the API, from their own case management tooling. Use it when analysts already work in an existing system and the team wants screening results delivered into that system rather than reviewed in Mesh UI.
What headless integration is
In a standard Payment Screening integration, a payment is submitted over the API, and any risks it produces are reviewed by analysts in the Mesh Case Manager through the web browser. Risks are reached through a parent case and alert, and risks, alerts and cases should be resolved before a transaction is decisioned on.
Headless integration removes that dependency. Risks are addressed directly by their own identifier, retrieved with a single call against the payment reference the customer already holds, and updated without any alert lookup. Three things change:
Standard integration | Headless integration | |
Where analysts work | Mesh Case Manager | The customer's own tooling |
How risks are reached | Through a parent case and alert | Directly, by transaction identifier, or by specific risk identifier |
What the team needs | Access to the Comply web app | API credentials only |
Everything else remains unchanged. Payments go through the same screening engine, the same configurations apply, the same risks are produced, and every status change is written to the audit trail exactly as it is when an analyst works in Mesh through the web browser. Cases and alerts are still created inside Mesh, so a customer can run headless integration and the Case Manager side by side, or move between them.
Why it matters
Headless integration suits a customer who has already invested in a case management workflow and does not want payment screening to sit outside it. In practice it addresses four things:
One queue for analysts. Screening hits arrive in the system analysts already use, rather than requiring them to switch tools to triage a payment.
Fewer calls to reach a risk. A risk is retrieved and updated directly. There is no need to resolve a case, then an alert, then the risks beneath it.
No additional user accounts. The integration needs API credentials and one account permission. Analysts do not need Comply web app logins or customer screening entitlements.
Audit parity. Decisions recorded over the API carry the same audit fields as decisions made in Mesh, so evidencing a decision to an auditor works the same way either route.
Before you begin
You will need:
The relevant account permission that covers every endpoint in this guide.
A realm, provided by ComplyAdvantage at onboarding. Realms are case sensitive.
Your base URL. This is https://api.mesh.complyadvantage.com, or a regional equivalent such as https://api.eu.mesh.complyadvantage.com.
A dedicated API user is recommended rather than a shared human account, so that decisions recorded over the API are attributable in the audit trail.
The end-to-end flow
The integration has six stages. Stages one and two are setup and run once, then again whenever screening policy changes. Stages three to six run per payment. There are also two optional stages that may be used, depending on your specific needs.
Step | Stage | What happens |
1 | Authenticate | Exchange credentials for a bearer token |
2 | Configure | Define what payments are screened against |
3 | Custom Lists (optional) | Upload and manage custom lists owned by you |
4 | Submit | Send a payment for screening |
5 | Retrieve | Read the risks the payment produced |
6 | Resolve | Record a decision on each risk |
7 | Manage muted profiles (optional) | Create or delete a whitelisted profile to stop generating future alerts on a known false positive |
8 | Decide | Release or reject a held payment |
Stage one: authenticate
Request a token, supplying your username, password, and realm.
POST /v2/token
{
"username": "[email protected]",
"password": "your-password",
"realm": "your-realm"
}
Pass the returned token on every subsequent call.
Authorization: Bearer {access_token}
Tokens are valid for 24 hours and are refreshed with the same call. There is no separate refresh token grant. Cache the token and refresh it on a schedule or on the first 401 response, rather than requesting a new one for every payment.
Stage two: configure screening
Create a payment screening configuration. A configuration defines which lists a payment is screened against and how closely a value must match to produce a risk. Each configuration contains one or more source collections, and each source collection carries the lists to screen against, a global fuzziness score, name search options, reference text search options, and BIC search strictness.
POST /v2/payment-screening/configurations
Retain the configuration_identifier returned. You supply it on every payment you submit, and it is returned on every risk as detail.configuration_identifier, which is what lets an analyst trace a hit back to the policy that produced it.
If you screen against your own lists, create and populate them before referencing them from a configuration.
POST /v2/custom-lists
Optionally, register a webhook so that your system is notified when a held payment is reviewed.
POST /v2/notifications/configurations/webhook
The event type for Payment Screening is TRANSACTION_REVIEWED, which is triggered when a held payment is released or rejected:
{
"api_version": "v3",
"account_identifier": "…",
"webhook_type": "TRANSACTION_REVIEWED",
"transaction_identifier": "…",
"transaction_external_identifier": "…",
"evaluation_outcome": "HOLD",
"review_decision": "RELEASE"
}
Configurations can also be listed, versioned, and retrieved over the API. See Setting up your Payment Screening Configuration for the full configuration model.
Stage three: submit a payment
Submit the payment for screening, supplying the configuration identifier from stage two.
POST /v3/transactions/process
Set transaction.external_identifier to your own payment reference. This is the value you will most often use to retrieve risks in the next stage, so it should be one your system already holds.
Read the evaluation outcome from the response. The outcome is one of PROCESS, ALLOW, HOLD, REJECT, UNKNOWN, ERROR, or PENDING.
If the outcome is HOLD, the payment has been stopped pending review, and the risks that caused it are available in the next stage. A held payment also requires a decision in stage six before it can move.
If the outcome is ALLOW, the payment has been processed, however there are risks associated with this payment that will need to be reviewed. This status is also sometimes referred to as soft stop.
Stage four: retrieve the risks
Retrieve the risks for the payment, addressed by either your own reference or the ComplyAdvantage identifier.
GET /v2/payment-screening/risks?transaction_external_identifier=your-payment-ref
GET /v2/payment-screening/risks?transaction_identifier=9f2a7c10-3e44-4b21-bc55-1d0a9e6f2b88
Supply exactly one of the two parameters. Supplying both, or neither, is not allowed and returns a 400 response.
Page through the results if needed, using page_number (default one) and page_size (default 25, maximum 100). The response carries total_count and self, first, prev, and next links.
Read the risks from the response. Each risk carries its identifier, its type, its current status, and a detail block describing the match:
RiskResponse
├── total_count, self, first, prev, next
└── risks[]
├── identifier, type, status, created_at, updated_at, updated_by
└── detail
├── configuration_identifier, source_type, relevance
├── screened_entity_info which payment field was screened
├── screening_context the value screened and the lists used
└── provider_detail
├── match why the profile matched
└── profile the matched entity and its attributes
Distinguish two responses that look similar but mean different things:
200 with an empty risks array. The payment was screened and produced no risks. This is a clean pass, not an error.
404. The payment reference could not be resolved within your account.
Allow for risks to settle. Risks are computed as the payment is screened, but they become available to retrieve shortly afterward rather than instantly. A call made immediately after screening may briefly return an empty array, and an update attempted in the same window may return a 404. This settles on its own within a short period.
Build for this. Retry with a short backoff rather than treating an immediate empty result as final. An integration that calls the retrieve endpoint synchronously off the back of the screening response, and reads an empty array as "no risk," will under-report hits.
Stage five: resolve the risks
Update one risk by its identifier.
PATCH /v2/payment-screening/risks/{risk_identifier}
{ "status": "FALSE_POSITIVE" }
The response confirms the change:
{
"risk_id": "8d2f7b6e-1c44-4a90-9b2e-2f3c1a0b7d11",
"status": "FALSE_POSITIVE",
"last_updated_at": "2026-06-16T10:42:03.120Z"
}
Set the status to one of NOT_REVIEWED, IN_REVIEW, FALSE_POSITIVE, or TRUE_POSITIVE. Any other value is rejected with a 400. Muting is a separate capability with its own endpoints and is not a risk status.
To triage several risks at once, update them in a single call.
PATCH /v2/payment-screening/risks/bulk
{
"risk_identifiers": ["019e1c18-…", "019e1b9d-…"],
"status": "FALSE_POSITIVE"
}
Read the per-risk outcome from the results array. This endpoint returns HTTP 207 for any well-formed request, whether all, some, or none of the risks were updated, so the status code alone does not tell you whether your updates landed.
{
"results": [
{ "identifier": "019e1c18-…", "success": true, "errors": null },
{ "identifier": "019e1b9d-…", "success": false,
"errors": [ { "code": "NOT_FOUND", "message": "No risk found for the supplied risk_identifier within the account scope." } ] }
]
}
One unrecognized identifier does not affect the rest of the batch. The remaining risks are updated normally, and only the identifier that could not be resolved is returned with success: false. When retrying, send only the identifiers that failed rather than the whole batch.
Stage six: decide the payment
Resolving the risks records the analyst's assessment of each hit. It does not release the payment. A payment held at stage three needs a separate decision.
Release or reject the held payment.
POST /v3/transactions/{identifier}/review
The decision is recorded in review_decision and, if you registered a webhook at stage two, delivered as a TRANSACTION_REVIEWED event. This endpoint cannot be used on a payment that is not held.
Retrieve a payment at any point, by your own reference or the ComplyAdvantage identifier.
GET /v3/transactions/external/{external_identifier}
GET /v3/transactions/{identifier}
Retrieve the audit trail for a payment where a record of the decision is needed.
GET /v2/audit/transactions/{identifier}
The audit trail records what was decided, by whom, and when, for decisions made over the API and in Mesh alike.
What you need to know
Permissions: every endpoint in this guide is gated behind the PAYMENT_SCREENING_BASE account permission. No additional permission or scope is required for headless integration.
Scope: this applies to Payment Screening on Mesh only. It is not available for Customer Screening and Ongoing Monitoring.
Account scoping: every call is scoped to your own account. A payment or risk belonging to another account is reported as not found, so there is no way to detect another account's data.
Risks settle shortly after screening: risks are not retrievable at the instant screening completes. Allow for a short delay and retry rather than treating an immediate empty result or 404 as final.
Muted risks: risks suppressed by a mute rule are excluded from the retrieve endpoint before paging is applied, so a muted risk does not occupy a page slot or count toward total_count. At this release, mutes scoped to a customer are applied. Mutes scoped to a counterparty or an agent are not yet applied to this endpoint, so a risk suppressed by one of those rules may still be returned. Mutes are managed at /v3/alerts/mutes.
Cases still exist: a headless integration does not need to interact with cases or alerts, but they are still created in Mesh. Statuses set over the API are written to the same records, so the two views stay consistent.
What the response does not include: entity images, adverse media articles, and change history are not returned. The response is a point-in-time read with no record of what changed since a previous screening.
Attribute values are unmodified: dates of birth, places of birth, nationalities, genders, and addresses are returned as they appear in the source data. Sanctions sources often record these as free text, so a date of birth may read "circa 1975," a year alone, or a range. Values are sorted into the correct attribute but are not converted into a standard format.
API access
Full request and response schemas for every endpoint in this guide are published in the API reference. The endpoints used here are:
Stage | Endpoint |
Authenticate | |
Configure | |
Custom lists (optional) | |
Submit | |
Retrieve | |
Resolve | PATCH /v2/payment-screening/risks/{risk_identifier} |
Mutes (optional) | |
Decide | GET /v3/transactions/external/{identifier} |