📘 Public beta · Endpoints are stable; OpenAPI specs and SDKs ship monthly. See changelog →
Products
AML Platform
Quickstart

AML Platform · Quickstart

End-to-end: screen a new customer, evaluate a transaction, work the alert, file the SAR.

Time: ~25 minutes against sandbox.

Prerequisites

Sandbox API key with scopes: read, write, screen.run, case.write, sar.write.

1. Create a customer

POST/api/customers
Auth · API keyScope · write
curl -X POST https://sandbox.quantumelixir.tech/aml/api/customers \
  -H "Authorization: Bearer $QE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fullName": "Umar Patek",
    "nik": "3201234567890099",
    "customerType": "individual",
    "nationality": "ID",
    "dateOfBirth": "1970-07-20",
    "occupation": "Trader",
    "reportedIncomeIdr": 800000000,
    "kycLevel": 2
  }'

We use "Umar Patek" because the sandbox watchlist is seeded with the real UN-SC QDi.007 entry — you'll get a guaranteed sanctions hit on the name. (For a NIK-driven PEP hit, use Bambang Setiawan Hartono with NIK 3171010101710001, which matches PPATK PEP entry PEP-DOM-001.) In production this customer would be a real person.

Response:

{
  "ok": true,
  "data": {
    "id": "cus_01HXY...",
    "fullName": "Umar Patek",
    "nik": "3201234567890099",
    "riskRating": "medium",
    "isPep": false,
    "isSanctioned": false,
    "createdAt": "..."
  }
}

2. Run onboarding screening

POST/api/screenings
Auth · API keyScope · screen.runRate limit · 60/min
curl -X POST https://sandbox.quantumelixir.tech/aml/api/screenings \
  -H "Authorization: Bearer $QE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lane": "onboarding",
    "customerId": "cus_01HXY...",
    "subjectType": "individual",
    "fullName": "Umar Patek",
    "nik": "3201234567890099",
    "dateOfBirth": "1970-07-20",
    "nationality": "ID"
  }'

Response:

{
  "ok": true,
  "data": {
    "screeningId": "scr_01HXY...",
    "customerId": "cus_01HXY...",
    "status": "confirmed",
    "topMatchScore": 0.95,
    "startedAt": "...",
    "completedAt": "...",
    "matches": [
      {
        "id": "mat_01HXY...",
        "score": 0.95,
        "watchlistEntry": {
          "fullName": "Umar Patek",
          "category": "sanctions",
          "watchlistId": "wl_un_sc",
          "sourceListSlug": "QDi.007",
          "remarks": "JI — Bali bombing 2002"
        }
      }
    ]
  }
}

Confirmed hit → an alert was auto-created. Look for the alert.created webhook arriving on your endpoint, or poll:

curl "https://sandbox.quantumelixir.tech/aml/api/alerts?customerId=cus_01HXY..." \
  -H "Authorization: Bearer $QE_API_KEY"

3. Evaluate a transaction

POST/api/transactions/evaluate
Auth · API keyScope · writeRate limit · 600/min

This is the high-volume, real-time endpoint. Use it inline on every transaction:

curl -X POST https://sandbox.quantumelixir.tech/aml/api/transactions/evaluate \
  -H "Authorization: Bearer $QE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customerId": "cus_01HXY...",
    "direction": "credit",
    "amountIdr": 550000000,
    "currency": "IDR",
    "channel": "transfer",
    "counterpartyName": "PT Foo",
    "isCrossBorder": false,
    "city": "Jakarta",
    "country": "ID"
  }'

Response (this one trips the IDR 500M cash threshold rule):

{
  "ok": true,
  "data": {
    "decision": "review",
    "riskScore": 65,
    "alertId": "alt_01HXY...",
    "hits": [
      {
        "ruleId": "rul_01HXY...",
        "ruleName": "High Transaction Amount",
        "severity": "medium",
        "scoreContribution": 35
      }
    ]
  }
}

Use data.decision to gate the transaction in your core banking system.

4. Work the case

The screening hit + transaction hit are both alerts on the same customer. Promote the screening alert to a case:

curl -X POST .../api/alerts/alt_01HXY.../escalate \
  -H "Authorization: Bearer $QE_API_KEY"

Response includes the new (or existing) case ID. Add notes, assign it:

curl -X PATCH .../api/cases/cas_01HXY... \
  -H "Authorization: Bearer $QE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "in_review",
    "priority": "high",
    "assignedToId": "usr_01HXY..."
  }'
 
curl -X POST .../api/cases/cas_01HXY.../notes \
  -H "Authorization: Bearer $QE_API_KEY" \
  -d '{ "body": "Counterparty PT Foo also under separate watchlist hit." }'

5. File the SAR (four-eyes)

Drafting a SAR happens in the dashboard (it's a form-heavy step that doesn't fit raw API ergonomics). When the maker has drafted, the MLRO submits:

POST/api/sar-filings/{id}/submit
Auth · API keyScope · sar.write
curl -X POST .../api/sar-filings/sar_01HXY.../submit \
  -H "Authorization: Bearer $QE_API_KEY"

Response:

{
  "ok": true,
  "data": {
    "filing": {
      "id": "sar_01HXY...",
      "caseId": "cas_01HXY...",
      "status": "submitted",
      "filedById": "usr_drafter...",
      "submittedById": "usr_mlro...",
      "submittedAt": "..."
    },
    "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<goAML>...</goAML>",
    "next": "Forward XML to PPATK goAML gateway via the configured connector."
  }
}

The xml field is your PPATK-ready goAML envelope. Forward it through your existing PPATK channel.

Four-eyes rule

submittedById must differ from filedById. Same user attempting both → HTTP 409 four-eyes violation: drafter cannot submit. No exceptions, configurable per-org policy.

Next steps