Risk tools
MCP tools for Risk: risk_blocklist_create, risk_blocklist_delete, risk_blocklist_list, risk_evaluations_get, risk_evaluations_list, risk_reviews_approve, risk_reviews_get, risk_reviews_list, risk_reviews_reject, risk_settings_get, risk_settings_update.
risk_blocklist_create: Block an email, card, IP range or countryrisk_blocklist_delete: Remove a blocklist entryrisk_blocklist_list: List blocklist entriesrisk_evaluations_get: Get a risk evaluationrisk_evaluations_list: List risk evaluationsrisk_reviews_approve: Approve a held paymentrisk_reviews_get: Get a risk reviewrisk_reviews_list: List risk reviewsrisk_reviews_reject: Refund a held payment and block the customerrisk_settings_get: Get the risk settingsrisk_settings_update: Update the risk settings
risk_blocklist_create
Block an email, card, IP range or country. Operation risk.blocklist.create · Brand level · permission customers:write · risk tier write · since M9
Adds a value to the brand's blocklist in the mode of the request. From the next attempt on, checkout and
auto-reload refuse payments that match it (risk_payment_declined for the buyer, without saying why):
email: the customer's address (any case);card_fingerprint: the processor's fingerprint of a card number (Stripecard.fingerprint; a risk evaluation shows it), so the same card is refused whatever its expiry or the customer;ip_range: CIDR such as203.0.113.0/24or2001:db8::/32, at most /24 (IPv4) or /48 (IPv6) narrow, since Ownrecord keeps only the truncated network of an address; a bare address blocks its /24;country: an ISO country code, matched against the IP country, the billing country and the card's country.
Values are stored normalised (the answer shows how). A value already listed is risk_blocklist_entry_exists.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
kind | one of email, card_fingerprint, ip_range, country | yes | – |
value | string | yes | (1–320 characters) |
reason | string | no | (1–500 characters) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: The value isn't one of its kind, or the IP range is narrower than /24 (/48).risk_blocklist_entry_exists: The value is already on the blocklist (details.entryId).permission_denied: You can't change this brand's customers.
Examples
Block a card tester's email
Arguments:
{
"kind": "email",
"value": "Card.Tester@Example.com",
"reason": "Tried six cards in ten minutes",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr2",
"object": "risk_blocklist_entry",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"kind": "email",
"value": "card.tester@example.com",
"reason": "Tried six cards in ten minutes",
"source": "operator",
"evaluationId": null,
"createdBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"createdAt": "2026-10-20T09:00:00.000Z"
}
Block an IP network
Arguments:
{
"kind": "ip_range",
"value": "203.0.113.77",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr9",
"object": "risk_blocklist_entry",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"kind": "ip_range",
"value": "203.0.113.0/24",
"reason": null,
"source": "operator",
"evaluationId": null,
"createdBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"createdAt": "2026-10-20T09:00:00.000Z"
}
risk_blocklist_delete
Remove a blocklist entry. Operation risk.blocklist.delete · Brand level · permission customers:write · risk tier write · since M9
Removes a value from the brand's blocklist: payments that match it are no longer refused for it (other rules
still apply). Returns the removed entry. The audit log keeps what was removed and by whom. A customer whose risk
a rejected review set to blocked stays blocked: change that on the customer.
Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (rbl_…) | yes | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
resource_not_found: No blocklist entry with this ID in this brand and mode.version_conflict: The entry changed at the same moment; retry.permission_denied: You can't change this brand's customers.
Example
Unblock an email
Arguments:
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr2",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr2",
"object": "risk_blocklist_entry",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"kind": "email",
"value": "card.tester@example.com",
"reason": "Tried six cards in ten minutes",
"source": "operator",
"evaluationId": null,
"createdBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"createdAt": "2026-10-20T09:00:00.000Z"
}
risk_blocklist_list
List blocklist entries. Operation risk.blocklist.list · Brand level · permission customers:read · risk tier read · since M9
Lists the brand's blocklist in the mode of the request, newest first: emails, card fingerprints (the
processor's), IP ranges and countries whose payments the risk rules refuse. Filter by kind, and by value
with it (an email in any case, a bare IP address for its /24). Paginate with limit (1–100, default 10) and
starting_after. Entries a rejected risk review added say so (source: review, evaluationId).
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
kind | one of email, card_fingerprint, ip_range, country | no | Entries of one kind. |
value | string | no | The entry for one value (with kind; written as you like). (1–320 characters) |
limit | integer | no | (1–100) |
starting_after | ID (rbl_…) | no | The next_cursor of the previous page. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or pagination value is invalid.permission_denied: You can't see this brand's customers.
Examples
The blocked emails
Arguments:
{
"kind": "email",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr2",
"object": "risk_blocklist_entry",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"kind": "email",
"value": "card.tester@example.com",
"reason": "Tried six cards in ten minutes",
"source": "operator",
"evaluationId": null,
"createdBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"createdAt": "2026-10-20T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
Is this card blocked?
Arguments:
{
"kind": "card_fingerprint",
"value": "Xo1abC9dEf2GhI3j",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "rbl_01m4ttwd3veh9apbewxheq5xr3",
"object": "risk_blocklist_entry",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"kind": "card_fingerprint",
"value": "Xo1abC9dEf2GhI3j",
"reason": "Risk review rsk_01m4ttwd3veh9apbewxheq5xr1 rejected: The cardholder doesn't know the customer.",
"source": "review",
"evaluationId": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"createdBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"createdAt": "2026-10-20T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
risk_evaluations_get
Get a risk evaluation. Operation risk.evaluations.get · Brand level · permission payments:read · risk tier read · since M9
One payment attempt's risk evaluation: the decision and score, every reason (which rule, what it asked for, its
points, in plain words), the signals the rules used (the email's domain, the truncated IP network, the IP,
billing and card countries, the card's fingerprint, the amount, whether the customer was new) and every run of
the rules. When the payment was held, review says how the review went.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (rsk_…) | yes | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
resource_not_found: No risk evaluation with this ID in this brand and mode.permission_denied: You can't see this brand's payments.
Example
A held first top-up
Arguments:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "pending",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": null,
"decidedBy": null,
"note": null,
"refundId": null,
"blocklistEntryIds": [],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T09:02:00.000Z"
}
risk_evaluations_list
List risk evaluations. Operation risk.evaluations.list · Brand level · permission payments:read · risk tier read · since M9
Lists what the brand's risk rules decided for payment attempts in the mode of the request, newest first: one
evaluation per checkout session or auto-reload, with every run (history: before the payment intent, once the
card was known, at confirmation), the decision (allow, require_3ds, review, block), the score and each
reason. Filter by paymentId (why a payment was held), checkoutSessionId (why a checkout was refused; the
buyer only saw risk_payment_declined), customerId or decision. Paginate with limit (1–100, default 10)
and starting_after.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
paymentId | ID (pay_…) | no | The evaluation of one payment (pay_…). |
checkoutSessionId | ID (cs_…) | no | The evaluation of one checkout (cs_…). |
customerId | ID (cus_…) | no | A customer's evaluations (cus_…). |
decision | one of allow, require_3ds, review, block | no | Only this decision (e.g. block). |
limit | integer | no | (1–100) |
starting_after | ID (rsk_…) | no | The next_cursor of the previous page. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or pagination value is invalid.permission_denied: You can't see this brand's payments.
Example
Why was this payment held?
Arguments:
{
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "pending",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": null,
"decidedBy": null,
"note": null,
"refundId": null,
"blocklistEntryIds": [],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T09:02:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
risk_reviews_approve
Approve a held payment. Operation risk.reviews.approve · Brand level · permission customers:write · risk tier write · since M9
Releases a payment the risk rules held: the customer's wallets the hold froze are unfrozen (unless another
review of the customer is still pending, or someone changed the wallet since), the hold's reason leaves the
customer's risk (back to normal when nothing else elevated it), and risk.review.approved goes to your
webhook endpoints, so your integration can deliver what it held back. A review is decided once.
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: false · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (rsk_…) | yes | – |
note | string | no | (1–1000 characters) |
expectedVersion | integer | no | (1–9007199254740991) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
resource_not_found: No risk evaluation with this ID in this brand and mode.risk_evaluation_not_held: The evaluation held no payment for review.risk_review_not_pending: The review was already approved or rejected.version_conflict: The review changed sinceexpectedVersion, or at the same moment.permission_denied: You can't change this brand's customers.
Example
Approve after calling the customer
Arguments:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"note": "Called the customer; the card is a company card.",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "approved",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": "2026-10-20T11:30:00.000Z",
"decidedBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"note": "Called the customer; the card is a company card.",
"refundId": null,
"blocklistEntryIds": [],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T11:30:00.000Z"
}
risk_reviews_get
Get a risk review. Operation risk.reviews.get · Brand level · permission customers:read · risk tier read · since M9
One held payment of the review queue: its risk evaluation (the decision, the score, every reason and the
signals the rules used: the email's domain, the truncated IP network, the IP, billing and card countries, the
card's fingerprint), the payment and customer, and the review (pending, approved or rejected, by whom, the
refund and blocklist entries of a rejection, the wallets the hold froze). An evaluation that held nothing is
risk_evaluation_not_held: read it with risk.evaluations.get.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (rsk_…) | yes | – |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
resource_not_found: No risk evaluation with this ID in this brand and mode.risk_evaluation_not_held: The evaluation held no payment for review.permission_denied: You can't see this brand's customers.
Example
A held first top-up
Arguments:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "pending",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": null,
"decidedBy": null,
"note": null,
"refundId": null,
"blocklistEntryIds": [],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T09:02:00.000Z"
}
risk_reviews_list
List risk reviews. Operation risk.reviews.list · Brand level · permission customers:read · risk tier read · since M9
The brand's risk review queue in the mode of the request, newest first: payments the risk rules held. A held
payment went through and is invoiced; the customer's wallet that took its credits is frozen until someone
approves it (risk.reviews.approve) or refunds it and blocks the customer (risk.reviews.reject). Each review
is the payment's risk evaluation: the decision, the score and every reason.
status is pending by default; approved and rejected list the decided ones. Paginate with limit (1–100,
default 10) and starting_after.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
status | one of pending, approved, rejected | no | Default pending: the queue. |
customerId | ID (cus_…) | no | Reviews of one customer (cus_…). |
limit | integer | no | (1–100) |
starting_after | ID (rsk_…) | no | The next_cursor of the previous page. |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
validation_failed: A filter or pagination value is invalid.permission_denied: You can't see this brand's customers.
Example
The queue
Arguments:
{
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "list",
"data": [
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "pending",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": null,
"decidedBy": null,
"note": null,
"refundId": null,
"blocklistEntryIds": [],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T09:02:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}
risk_reviews_reject
Refund a held payment and block the customer. Operation risk.reviews.reject · Brand level · permission refunds:write · risk tier financial · since M9
Rejects a payment the risk rules held, in one transaction:
- Refund, exactly as
refunds.createwith typefullmakes it: a credit note at the original rates, the ledger reversal and the processor refund (a credit pack only for its unused credits; the hold kept the wallet frozen, so normally all of them). Support refunds up to the brand's limit, finance without one.refund: falseskips it (for a payment already refunded). - Block: the customer's email and the card's fingerprint go on the brand's blocklist (
blockchooses;ipNetwork: trueadds the IP network, which can block neighbours). An entry already listed is reused. - The customer's risk becomes
blocked; their frozen wallets stay frozen.
risk.review.rejected goes to your webhook endpoints. Financial tier: approval policies apply to agents and
apps; dry-run it first to see the refund.
Annotations: readOnlyHint: false · destructiveHint: true · idempotentHint: false · openWorldHint: true
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
id | ID (rsk_…) | yes | – |
reason | string | yes | (1–1000 characters) |
refund | boolean | no | – |
block | object | no | – |
expectedVersion | integer | no | (1–9007199254740991) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
resource_not_found: No risk evaluation with this ID in this brand and mode.risk_evaluation_not_held: The evaluation held no payment for review.risk_review_not_pending: The review was already approved or rejected.refund_payment_not_refundable: The payment can't be refunded (disputed, or refunded already): reject withrefund: false.refund_nothing_to_refund: Nothing is left to refund (the credits were used): reject withrefund: false.refund_limit_exceeded: The refund is above your role's limit: ask finance.refund_outside_policy: Support can't refund these credits under the brand's policy.version_conflict: The review changed sinceexpectedVersion, or at the same moment.permission_denied: You can't refund this brand's payments.
Example
Refund and block a stolen card
Arguments:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"reason": "The cardholder doesn't know the customer.",
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"id": "rsk_01m4ttwd3veh9apbewxheq5xr1",
"object": "risk_evaluation",
"livemode": true,
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"subject": {
"type": "checkout_session",
"checkoutSessionId": "cs_01m4ttwd3veh9apbewxheq5xr4",
"walletId": null
},
"customerId": "cus_01m4ttwd3veh9apbewxheq5xr5",
"paymentId": "pay_01m4ttwd3veh9apbewxheq5xr6",
"stage": "confirm",
"decision": "review",
"score": 70,
"reasons": [
{
"code": "first_payment",
"action": "require_3ds",
"points": null,
"detail": "The customer's first payment."
},
{
"code": "new_customer",
"action": "score",
"points": 10,
"detail": "A new customer."
},
{
"code": "country_mismatch_ip_billing",
"action": "score",
"points": 20,
"detail": "IP country DE isn't the billing country HR."
},
{
"code": "country_mismatch_card_billing",
"action": "score",
"points": 25,
"detail": "Card country US isn't the billing country HR."
},
{
"code": "country_mismatch_ip_card",
"action": "score",
"points": 15,
"detail": "IP country DE isn't the card country US."
},
{
"code": "score_review",
"action": "review",
"points": null,
"detail": "Score 70 ≥ 70."
}
],
"signals": {
"emailDomain": "corp.example",
"ipNetwork": "203.0.113.0",
"ipCountry": "DE",
"billingCountry": "HR",
"cardCountry": "US",
"cardFingerprint": "Xo1abC9dEf2GhI3j",
"amount": {
"amount": "90000000",
"currency": "EUR"
},
"topup": true,
"newCustomer": true,
"firstPayment": true,
"disposableEmail": false
},
"history": [
{
"at": "2026-10-20T09:00:00.000Z",
"stage": "intent",
"decision": "require_3ds",
"score": 30
},
{
"at": "2026-10-20T09:01:00.000Z",
"stage": "payment_method",
"decision": "review",
"score": 70
},
{
"at": "2026-10-20T09:01:30.000Z",
"stage": "confirm",
"decision": "review",
"score": 70
}
],
"review": {
"status": "rejected",
"openedAt": "2026-10-20T09:02:00.000Z",
"decidedAt": "2026-10-20T11:30:00.000Z",
"decidedBy": "usr_01m4ttwd3veh9apbewxheq5xh6",
"note": "The cardholder doesn't know the customer.",
"refundId": "re_01m4ttwd3veh9apbewxheq5xr8",
"blocklistEntryIds": ["rbl_01m4ttwd3veh9apbewxheq5xr2", "rbl_01m4ttwd3veh9apbewxheq5xr3"],
"frozenWalletIds": ["wal_01m4ttwd3veh9apbewxheq5xr7"]
},
"createdAt": "2026-10-20T09:00:00.000Z",
"updatedAt": "2026-10-20T11:30:00.000Z"
}
risk_settings_get
Get the risk settings. Operation risk.settings.get · Brand level · permission brands:read · risk tier read · since M9
Returns the brand's risk rules in the mode of the request (spec §20). Until someone changes them the documented
defaults apply (isDefault: true, version: 0), suited to prepaid credits:
- New customers (no payment older than
newCustomer.ageHours, 168): at most 2 top-ups in 24 hours, a first top-up of at most 100 EUR, USD, GBP or CHF, and 3-D Secure on the first payment. - Velocity: per IP network (/24 or /48; 10 attempts and 3 cards an hour), per card (5 attempts in 24 hours) and per email domain of new customers (10 an hour; large mail providers exempt).
- Score: country mismatches between the IP, the billing address and the card add points (20, 25, 15), so do a new customer (10) and an elevated one (40); 20 points ask for 3-D Secure, 75 hold the payment for review.
- Disposable email addresses are blocked; blocklists always apply.
- Fresh balances: no usage cap until set (
wallet.usageCapUntilAgeHours).
The counting rules (velocity and the new-customer top-up limits) are on in live mode and off in test mode, where everyone pays with the same test cards from the same machine; turn them on to try them. Amounts are integer micros as strings, per currency; a currency without an amount has no limit.
Annotations: readOnlyHint: true · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Read-only: changes nothing;
idempotency_keyis ignored.
Errors
permission_denied: You can't read this brand's settings.
Example
The live-mode defaults
Arguments:
{
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz"
}
Result output:
{
"object": "risk_settings",
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"livemode": true,
"isDefault": true,
"version": 0,
"updatedAt": null,
"newCustomer": {
"ageHours": 168,
"topups": {
"enabled": true,
"limit": 2,
"windowHours": 24,
"action": "block"
},
"firstTopupMax": {
"enabled": true,
"amounts": {
"CHF": "100000000",
"EUR": "100000000",
"GBP": "100000000",
"USD": "100000000"
},
"action": "block"
},
"threeDSecureFirstPayment": true
},
"velocity": {
"ipNetwork": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"cardLimit": 3
},
"cardFingerprint": {
"enabled": true,
"limit": 5,
"windowHours": 24,
"action": "block"
},
"emailDomain": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"exemptDomains": [
"aol.com",
"gmail.com",
"gmx.at",
"gmx.de",
"gmx.net",
"googlemail.com",
"hotmail.com",
"icloud.com",
"live.com",
"mail.com",
"me.com",
"msn.com",
"outlook.com",
"proton.me",
"protonmail.com",
"t-online.de",
"web.de",
"yahoo.com",
"yandex.com"
]
}
},
"points": {
"ipBillingMismatch": 20,
"cardBillingMismatch": 25,
"ipCardMismatch": 15,
"elevatedCustomer": 40,
"newCustomer": 10
},
"thresholds": {
"threeDSecure": 20,
"review": 75,
"block": null
},
"disposableEmail": {
"enabled": true,
"action": "block"
},
"wallet": {
"usageCapUntilAgeHours": null,
"usageCap": {}
}
}
risk_settings_update
Update the risk settings. Operation risk.settings.update · Brand level · permission brands:write · risk tier write · since M9
Changes the brand's risk rules in the mode of the request. Give only what changes: any group
(newCustomer, velocity, points, thresholds, disposableEmail, wallet) and, within it, any field;
the rest keeps its value (the defaults until the first change). Per-currency amounts (firstTopupMax.amounts,
wallet.usageCap, integer micros as strings) and velocity.emailDomain.exemptDomains are replaced as a whole.
Each rule's action is block (the payment is refused before it reaches the card), review (it goes through,
and waits in the review queue with the customer's wallet frozen) or require_3ds (the bank authenticates the
customer). Thresholds must rise: threeDSecure ≤ review ≤ block (null: no score blocks). Windows are 1–168
hours. A usage cap for fresh balances (wallet.usageCapUntilAgeHours, 1–720, with wallet.usageCap) limits
how much of the credits bought in that time can be reserved or spent; null turns it off.
Pass expectedVersion to refuse the change if someone else changed the settings meanwhile. Test and live mode
have their own settings. Needs brands:write (owners and admins).
Annotations: readOnlyHint: false · destructiveHint: false · idempotentHint: true · openWorldHint: false
Arguments
| Argument | Type | Required | Description |
|---|---|---|---|
newCustomer | object | no | – |
velocity | object | no | – |
points | object | no | – |
thresholds | object | no | – |
disposableEmail | object | no | – |
wallet | object | no | – |
expectedVersion | integer | no | (0–9007199254740991) |
entity_id | ID (ent_…) | no | Optional: the brand's legal entity (ent_…); brand_id alone is enough. |
brand_id | ID (brd_…) | no | The brand to act on (brd_…), inside your API key's reach. Needed with an organization or entity key; a brand key acts on its own brand. |
idempotency_key | string | no | A unique string for this change. Retrying with the same key and arguments never acts twice. When left out, the server generates one and returns it in the result's idempotency_key. (1–255 characters) |
dry_run | boolean | no | true: check permissions and rules and compute the result, then roll everything back. Nothing is saved. (default false) |
- Brand: pass
brand_idwith an organization or entity key; a brand key acts on its own brand. - Idempotency: the result returns the
idempotency_keyused, yours or one the server generated. Retry with it: a call with the same key and arguments never acts twice (keys are kept for 24 hours). - Dry run: supported.
dry_run: truechecks permissions and rules and computes the result, then rolls everything back.
Errors
validation_failed: A value is out of range, a currency is unknown, or the thresholds don't rise.version_conflict: The settings changed sinceexpectedVersion, or at the same moment.permission_denied: You can't change this brand's settings.
Examples
Hold riskier payments sooner and cap fresh balances
Arguments:
{
"thresholds": {
"review": 60
},
"wallet": {
"usageCapUntilAgeHours": 24,
"usageCap": {
"EUR": "20000000"
}
},
"expectedVersion": 0,
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"object": "risk_settings",
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"livemode": true,
"isDefault": false,
"version": 1,
"updatedAt": "2026-10-20T09:00:00.000Z",
"newCustomer": {
"ageHours": 168,
"topups": {
"enabled": true,
"limit": 2,
"windowHours": 24,
"action": "block"
},
"firstTopupMax": {
"enabled": true,
"amounts": {
"CHF": "100000000",
"EUR": "100000000",
"GBP": "100000000",
"USD": "100000000"
},
"action": "block"
},
"threeDSecureFirstPayment": true
},
"velocity": {
"ipNetwork": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"cardLimit": 3
},
"cardFingerprint": {
"enabled": true,
"limit": 5,
"windowHours": 24,
"action": "block"
},
"emailDomain": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"exemptDomains": [
"aol.com",
"gmail.com",
"gmx.at",
"gmx.de",
"gmx.net",
"googlemail.com",
"hotmail.com",
"icloud.com",
"live.com",
"mail.com",
"me.com",
"msn.com",
"outlook.com",
"proton.me",
"protonmail.com",
"t-online.de",
"web.de",
"yahoo.com",
"yandex.com"
]
}
},
"points": {
"ipBillingMismatch": 20,
"cardBillingMismatch": 25,
"ipCardMismatch": 15,
"elevatedCustomer": 40,
"newCustomer": 10
},
"thresholds": {
"threeDSecure": 20,
"review": 60,
"block": null
},
"disposableEmail": {
"enabled": true,
"action": "block"
},
"wallet": {
"usageCapUntilAgeHours": 24,
"usageCap": {
"EUR": "20000000"
}
}
}
Try the velocity rules in test mode
Arguments:
{
"velocity": {
"ipNetwork": {
"enabled": true
},
"cardFingerprint": {
"enabled": true
},
"emailDomain": {
"enabled": true
}
},
"brand_id": "brd_01jbx4m3v8e9t0s6k2c5n7q1wz",
"idempotency_key": "8d0c5f8e-4b7a-4e43-9b0f-2f6a0c1d9e21"
}
Result output:
{
"object": "risk_settings",
"brandId": "brd_01m4ttwd3veh9apbewxheq5xh5",
"livemode": false,
"isDefault": false,
"version": 1,
"updatedAt": "2026-10-20T09:00:00.000Z",
"newCustomer": {
"ageHours": 168,
"topups": {
"enabled": false,
"limit": 2,
"windowHours": 24,
"action": "block"
},
"firstTopupMax": {
"enabled": false,
"amounts": {
"CHF": "100000000",
"EUR": "100000000",
"GBP": "100000000",
"USD": "100000000"
},
"action": "block"
},
"threeDSecureFirstPayment": true
},
"velocity": {
"ipNetwork": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"cardLimit": 3
},
"cardFingerprint": {
"enabled": true,
"limit": 5,
"windowHours": 24,
"action": "block"
},
"emailDomain": {
"enabled": true,
"limit": 10,
"windowHours": 1,
"action": "block",
"exemptDomains": [
"aol.com",
"gmail.com",
"gmx.at",
"gmx.de",
"gmx.net",
"googlemail.com",
"hotmail.com",
"icloud.com",
"live.com",
"mail.com",
"me.com",
"msn.com",
"outlook.com",
"proton.me",
"protonmail.com",
"t-online.de",
"web.de",
"yahoo.com",
"yandex.com"
]
}
},
"points": {
"ipBillingMismatch": 20,
"cardBillingMismatch": 25,
"ipCardMismatch": 15,
"elevatedCustomer": 40,
"newCustomer": 10
},
"thresholds": {
"threeDSecure": 20,
"review": 75,
"block": null
},
"disposableEmail": {
"enabled": true,
"action": "block"
},
"wallet": {
"usageCapUntilAgeHours": null,
"usageCap": {}
}
}