Rules and Thresholds
Compliance rules decide what happens to a transfer once it is screened: flag it, hold it for review, or block it. Regulatory thresholds decide, per jurisdiction, when the Travel Rule applies and when a suspicion report is due. Both are also managed in the dashboard, under Rules.
Endpoints
Section titled “Endpoints”| Method | Endpoint | Scope | Description |
|---|---|---|---|
| GET | /api/v2/rules |
rules:read |
List rules |
| POST | /api/v2/rules |
rules:write |
Create a rule |
| GET | /api/v2/rules/:id |
rules:read |
Get a rule, with its conditions |
| PATCH | /api/v2/rules/:id |
rules:write |
Change a rule |
| DELETE | /api/v2/rules/:id |
rules:write |
Deactivate a rule |
| GET | /api/v2/thresholds |
thresholds:read |
List thresholds |
| POST | /api/v2/thresholds |
thresholds:write |
Create a threshold (live key) |
| GET | /api/v2/thresholds/:id |
thresholds:read |
Get a threshold |
| PATCH | /api/v2/thresholds/:id |
thresholds:write |
Change a threshold (live key) |
Rules belong to the key's environment. The key's owner's role needs rules:view to read, rules:create to create, and rules:update to change or delete. Promoting test rules to live is a dashboard action: the API has no route for it.
List Rules
Section titled “List Rules”curl "$COVALENT_URL/api/v2/rules?category=aml&isActive=true" \ -H "x-api-key: $COVALENT_API_KEY"| Parameter | Description |
|---|---|
category |
aml or sanctions. |
isActive |
true or false. |
severity |
low, medium or high. |
stage |
precheck, postcheck or both. |
search |
Part of the rule's name or description, any case, at most 200 characters. |
limit |
Items per page, 1 to 100, default 50. |
cursor |
meta.cursor of the previous page. |
For a choice filter, an empty value or all means no filter. A value the list cannot read is 400 INVALID_QUERY, whose details.issues lists each problem as { "path", "message" }. Rules are listed newest first:
{ "id": "rule_id", "name": "Large transfers", "description": null, "category": "aml", "stage": "both", "action": "require_review", "severity": "high", "isActive": true, "threshold": 10000, "thresholdCurrency": "USD", "jurisdictions": ["GB", "EU"], "asset": null, "network": null, "thresholdOperator": "gt", "conditionCount": 1, "environment": "live", "createdAt": "2026-10-09T12:00:00.000Z", "updatedAt": "2026-10-09T12:00:00.000Z"}GET /api/v2/rules/:id adds createdBy, conditions (each branch, with the integration's name) and hasLegacyConditions. A rule of the other environment is 404 RULE_NOT_FOUND.
Create a Rule
Section titled “Create a Rule”curl -X POST "$COVALENT_URL/api/v2/rules" \ -H "x-api-key: $COVALENT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Large transfers", "category": "aml", "action": "require_review", "severity": "high", "jurisdictions": ["GB", "EU"], "condition": { "rules": [ { "type": "if", "field": "amountUSD", "operator": "gte", "value": "10000", "action": "require_review" } ] } }'| Field | Required | Description |
|---|---|---|
name |
Yes | 1 to 200 characters. |
category |
Yes | aml or sanctions. |
stage |
No | precheck, postcheck or both (the default). |
action |
No | flag (the default: record and continue), require_review (hold for review) or block. |
severity |
No | low, medium (the default) or high. |
isActive |
No | true (the default) or false. |
description |
No | At most 500 characters, or null. |
jurisdictions |
No | Up to 50 ISO 3166-1 codes, EU, or GLOBAL alone (the rule applies everywhere). |
threshold |
No | A number from 0, or null. |
thresholdCurrency |
No | A fiat currency code, or null. |
metadata |
No | thresholdOperator (lt, eq or gt), asset and network (a code, or all), and nothing else; or null. |
condition |
No | The rule's branches, or null. See below. |
No other field is accepted. The answer is 201 with the rule and its conditions.
Conditions
Section titled “Conditions”condition.rules holds up to 20 branches, in order: one if first, then any elseIf, then at most one else, last. Every branch has an action (flag, require_review or block). A branch other than else compares either:
- a
field: a transfer attribute (amount,amountUSD,amountLocal,asset,network,jurisdiction,direction,walletType,originatorName,beneficiaryName,originatorAddress,beneficiaryAddress), or, with anintegrationId, a dotted path into that integration's response; or - a
query: a JSON response query into the response of the integration named byintegrationId. Aquerybranch needsintegrationId,operatorandvalue.
operator is eq, neq, contains, gt, gte, lt or lte, and value is text of at most 100 characters. integrationId is the ID of one of your company's enabled integrations: any other is refused, on the path condition.rules.<n>.integrationId. A branch names its integration with integrationId only; a providerId is not read, so a query branch with providerId and no integrationId is refused.
Change or Delete a Rule
Section titled “Change or Delete a Rule”PATCH /api/v2/rules/:id takes any of the create fields, isActive included, and at least one. The answer is the rule.
DELETE /api/v2/rules/:id deactivates the rule and keeps it, for its cases and its audit trail. The answer is the rule, with isActive: false.
A body that fails validation is 422 VALIDATION_ERROR. Its details.issues lists each problem as { "path", "message" }:
{ "error": "Invalid request body", "code": "VALIDATION_ERROR", "details": { "issues": [ { "path": "condition.rules.0", "message": "JSON response conditions require an integration, operator, and value" } ] }, "meta": { "apiVersion": 2, "timestamp": "2026-10-09T12:00:00.000Z" }}Thresholds
Section titled “Thresholds”Thresholds belong to your company, not to an environment: one set applies to test and live alike. Any key with thresholds:read reads them, but only a live key changes them (403 LIVE_KEY_REQUIRED), and every change is recorded in the live audit log. The key's owner's role needs thresholds:view, thresholds:create or thresholds:update; switching an active threshold off also needs thresholds:disable.
While your company has no active threshold, built-in FATF fallbacks apply. Its first active threshold ends them.
List Thresholds
Section titled “List Thresholds”curl "$COVALENT_URL/api/v2/thresholds?type=tr" \ -H "x-api-key: $COVALENT_API_KEY"| Parameter | Description |
|---|---|
type |
tr (Travel Rule) or str (suspicious transaction reporting). |
status |
active or inactive. |
search |
Part of the jurisdiction code, name, regulation or regulatory body, any case. At most 100 characters. |
limit |
Items per page, 1 to 100, default 50. |
cursor |
meta.cursor of the previous page: a threshold's ID. |
Thresholds are listed by jurisdiction, then type. meta adds activeCount: how many thresholds are active in all, whatever the filters (0 means the fallbacks apply).
{ "id": "threshold_id", "countryCode": "GB", "type": "tr", "name": "UK Travel Rule", "thresholdAmount": "1000", "thresholdCurrency": "GBP", "regulation": "UK MLRs 2017", "regulatoryBody": "FCA", "effectiveDate": null, "filingDeadlineDays": null, "isEUMember": false, "requiresOriginatorAccount": true, "isActive": true, "notes": null, "createdAt": "2026-10-09T12:00:00.000Z", "updatedAt": "2026-10-09T12:00:00.000Z", "createdBy": "user_id", "updatedBy": "user_id"}Create a Threshold
Section titled “Create a Threshold”| Field | Required | Description |
|---|---|---|
countryCode |
Yes | An ISO 3166-1 alpha-2 code, EU, or DEFAULT (the fallback for any other jurisdiction). |
type |
Yes | tr or str. |
name |
Yes | 1 to 200 characters. |
thresholdAmount |
Yes | A decimal of at least 0, as a number or a string, with at most 8 decimals. |
thresholdCurrency |
No | An ISO 4217 code, default USD. |
regulation |
Yes | 1 to 200 characters. |
regulatoryBody |
No | At most 200 characters. |
effectiveDate |
No | A day or an ISO 8601 instant; null means in effect already. |
filingDeadlineDays |
No | str thresholds only: the days a report must be filed within, 1 to 365. |
isEUMember |
No | Default false. |
requiresOriginatorAccount |
No | Default true. |
isActive |
No | Default true. |
notes |
No | At most 2,000 characters. |
No other field is accepted. The answer is 201 with the threshold. A jurisdiction has at most one threshold of each type: another is 409 THRESHOLD_EXISTS.
Change a Threshold
Section titled “Change a Threshold”PATCH /api/v2/thresholds/:id takes any field but the jurisdiction and type, which are fixed: sending another countryCode or type is 422 IMMUTABLE_FIELD. Setting isActive: false on an active threshold needs the role's thresholds:disable. The answer is the threshold.