Monichek API API v1
Integration guide

Monichek API

AML/CFT screening, transaction monitoring, registry lookups and hosted verification for Paysorta's internal products. This site is the contract and the runbook for teams wiring a service into the engine.

Internal tooling

There is no public signup, pricing, wallet or billing anywhere in this API. Usage pages are diagnostic telemetry only.

Overview

The API is a company-scoped REST surface. A credential belongs to exactly one company; every request made with it reads and writes that company's rows. Staff sessions can be assigned to several companies and bind one at a time from the console.

Screen a person or business

Sanctions, PEP and watchlist checks with a deterministic, explainable decision.

Run the first call →

Monitor transactions

Evaluate payments against rules and risk context, then hold, release or reject.

Browse endpoints →

Receive events

Signed webhooks for screenings, decisions, alerts, cases and verifications.

Set up webhooks →

Verify a customer

Create a single-use session and hand the customer a hosted verification link.

Verification sessions →

Quickstart

Issue a sandbox key in the console under Platform → Developer tools → API keys. Keys are shown once. Store the secret in the integrating service's secret store, never in source control.

Shell
export MONICHEK_API_KEY="wk_test_..."
export MONICHEK_API="https://sandbox-api-monichek.paysorta.com/v1"

curl -s "$MONICHEK_API/me" \
  -H "Authorization: Bearer $MONICHEK_API_KEY"

A successful identity call returns the company the credential is pinned to. If it returns 401, the key is revoked, mistyped or from a different environment.

First screening
curl -s -X POST "$MONICHEK_API/screenings" \
  -H "Authorization: Bearer $MONICHEK_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: onboarding-ada-0001" \
  -d '{
    "profile": "onboarding_individual",
    "subject": {
      "type": "person",
      "names": [{"full": "Ada Okafor"}],
      "date_of_birth": "1990-04-12",
      "nationalities": ["NG"]
    }
  }'

The response carries the decision, score, hits, snapshot and profile version. Treat the decision as the engine's output and the hits as the evidence behind it — both are audited.

Start in sandbox

Sandbox and live are separate consoles, APIs and keys. A sandbox key cannot call the live host.

Authentication

Send the key as a bearer token. The API resolves the key to a company and applies that company's row-level scope before the controller runs.

Authorization: Bearer wk_live_...
Content-Type: application/json

The API is versioned in the URL path (/v1); there is no version header to send. Responses include a Monichek-Version header for traceability, which you can log but do not need to echo back.

Access model

Every key has company-wide data-plane access: screenings, transactions, customers, cases, reports and verification. That is the default and there are no per-service scopes to configure.

A key may additionally carry the Management access flag. That lets it create, rotate and revoke other keys and manage team access. Use it only for an operator or a tightly controlled admin service.

Keys are powerful

A data-plane key can reach every data-plane endpoint for its company. Rotate on suspected exposure; rotation issues a new secret and leaves the old key valid until you revoke it.

Company header

API-key traffic ignores X-Monichek-Company; the key's company is fixed. Staff sessions use that header to bind one company at a time. A forged value fails closed rather than widening scope.

Ed25519 credentials

Services can register an Ed25519 public key instead of a shared secret and sign requests per the RFC 9421 profile. The private key never leaves the service. See docs/security/http-signatures.md before choosing this scheme.

Environments

EnvironmentConsoleAPI base
Sandboxsandbox-monichek.paysorta.comhttps://sandbox-api-monichek.paysorta.com/v1
Livemonichek.paysorta.comhttps://api-monichek.paysorta.com/v1
Local—http://localhost:28080/v1

The live and sandbox consoles share one image; only configuration differs. The badge in the sidebar tells you which one you are in.

Errors

Failures use application/problem+json with a stable machine code, a human detail string and the HTTP status. Branch on code, not on prose.

{
  "type": "https://docs-monichek.paysorta.com/errors/auth.forbidden",
  "title": "auth.forbidden",
  "status": 403,
  "code": "auth.forbidden",
  "detail": "requires super_admin role"
}
CodeStatusWhat to do
auth.unauthenticated401Missing, expired or revoked credential. Re-issue the key or refresh the session.
auth.forbidden403The credential or member role is not allowed to perform this operation.
company.forbidden403The requested company is outside the staff member's assignments.
request.validation_failed422A field is missing or invalid. The detail names the field where possible.
webhook.url_denied422The endpoint is not a permitted public destination (private, loopback or blocked egress).
webhook.secret_missing409The endpoint has no signing secret. Rotate it before testing or redelivering.
request.upstream_unreachable502The console cannot reach the API. Check the service, not the request payload.
Retries

Retry 429, 502, 503 and 504 with bounded exponential backoff and jitter. Do not retry a 422 unchanged; fix the request first.

Idempotency

Creation endpoints that support it accept an Idempotency-Key header. Use a stable value derived from your own work item, not a random value on every retry — the point is to make a repeated delivery safe.

Idempotency-Key: onboarding-ada-0001

Supported today on screening creation, transaction decisions and hosted verification session creation. A replay returns the original response instead of creating a second record. If you do not have a stable key, treat the network error as unknown and query the resource before retrying.

Webhooks

Add a publicly resolvable endpoint in Platform → Developer tools → Webhooks. The signing secret is shown once. An endpoint with an empty event filter receives every event, including events added after the endpoint was created.

POST /v1/webhook-endpoints
{
  "url": "https://service.example/monichek/webhook",
  "events": ["screening.completed", "transaction.evaluated", "verify.completed"]
}

Events

EventRaised when
screening.completedA screening finishes, with its decision.
screening.match_foundA screening returns at least one match.
screening.batch.completedA batch screening run finishes.
transaction.evaluatedA payment is evaluated by the rules engine.
transaction.held / transaction.released / transaction.rejectedA payment changes hold state or is decided.
decision.takenA decision is recorded for an item.
alert.created / case.createdAn alert or case is opened.
risk.changedA customer risk rating changes.
kyb.completedA business check finishes.
verify.completedA hosted verification session reaches a terminal state.
watch.hitA watch subscription finds a new list hit.
monitoring.sweep_completedA monitoring sweep finishes.
security.anomalyA security control records a burst or denial pattern.

Envelope and signature

Every delivery is a JSON envelope with a stable event id, type and data object.

{
  "id": "evt_01M3R...",
  "type": "screening.completed",
  "tenant_id": "ten_...",
  "data": { "screening_id": "scr_...", "decision": "clear" }
}

Headers include:

Monichek-Event: screening.completed
Monichek-Delivery: whd_01M3R...
Monichek-Signature: t=1760000000,v1=<hex hmac-sha256>

The signed bytes are the Unix timestamp, a literal dot, then the raw request body: t + "." + rawBody. Verify with the endpoint's current signing secret and compare in constant time.

Node.js verification
import crypto from "node:crypto";

function verifyMonichek(rawBody, header, secret) {
  const parts = Object.fromEntries(
    header.split(",").map((part) => part.trim().split("="))
  );
  const timestamp = Number(parts.t);
  if (!Number.isFinite(timestamp) || Math.abs(Date.now() / 1000 - timestamp) > 300) {
    return false;
  }
  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${parts.t}.${rawBody}`)
    .digest("hex");
  return crypto.timingSafeEqual(
    Buffer.from(expected, "utf8"),
    Buffer.from(parts.v1 ?? "", "utf8")
  );
}

Retries and replay

  • Delivery is asynchronous; the API returns before the receiver is called.
  • Transient failures retry with bounded exponential backoff (default up to 8 attempts).
  • Permanent 3xx/4xx responses stop early, except 408 and 429.
  • Failed deliveries stay visible in the console and can be requeued by hand.
  • Rotating the secret re-signs queued deliveries; the old secret stops immediately.
Receiver contract

Accept the event quickly, persist it, return 2xx, then process asynchronously. Do not do slow downstream work inside the webhook request.

Verification sessions

Create a single-use session and send the customer the returned hosted_url. The session tracks identity, liveness and optional address steps; configuration can brand the hosted page and choose which steps are required.

POST /v1/verify/sessions
Idempotency-Key: onboarding-ada-0001
{
  "customer_id": "cus_01M3R...",
  "config": {
    "brand_name": "Paysorta",
    "liveness_required": true,
    "address_required": false
  },
  "redirect_url": "https://app.example/onboarding/return",
  "webhook_url": "https://service.example/monichek/verify"
}

The response contains session_id, a short-lived token and hosted_url. The token is for the hosted flow; keep it out of logs. Read the session with an API key or the scoped X-Verify-Token header.

Internal operators can review sessions, copy links and inspect outcomes under Monitoring → Verifications.

Console, logs and health

The console is the operational surface for in-house engineers. Everything developer-facing lives under Platform.

PageUse it for
Platform → OverviewIntegration readiness: active keys, webhook endpoint, recent traffic and failing deliveries.
Developer tools → API keysIssue, rotate and revoke company-bound keys; grant management access only when needed.
Developer tools → WebhooksEndpoints, event filters, signing secrets, tests, delivery attempts and redelivery.
Developer tools → API logsRaw request tail: method, path, status, latency, key and remote address.
Developer tools → Usage & healthAggregates over the request tail: volume, error classes, p95 and traffic by key.
Telemetry, not billing

Request logs are retained for 7 days. Usage is for debugging and adoption, not invoicing or quota enforcement.

Changelog

2026-10-23

  • Published this documentation site at docs-monichek.paysorta.com.
  • Added Platform overview, webhook management and usage & health screens.
  • Clarified API-key access: company-wide data plane; admin is the only enforced scope flag.
  • Versioning is in the URL path (/v1); removed the optional Monichek-Version request header from the examples and SDKs. Responses still report the served version.
  • API reference is now a static, searchable site generated from the OpenAPI contract.

2026-09-24

  • API v1 released.