Skip to content

Refund a held payment and block the customer

The risk.reviews.reject operation: POST /api/v1/risk/reviews/{id}/reject in the REST API and the risk_reviews_reject tool in the MCP server.

POST/api/v1/risk/reviews/{id}/reject

Rejects a payment the risk rules held, in one transaction:

  • Refund, exactly as refunds.create with type full makes 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: false skips it (for a payment already refunded).
  • Block: the customer's email and the card's fingerprint go on the brand's blocklist (block chooses; ipNetwork: true adds 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.

At a glance

  • REST: POST /api/v1/risk/reviews/{id}/reject
  • MCP tool: risk_reviews_reject
  • Operation ID: risk.reviews.reject
  • Scope: Brand
  • Permission: refunds:write
  • Risk tier: financial
  • Dry run: Supported (send Ownrecord-Dry-Run: true)
  • Idempotency: Idempotency-Key required
  • Modes: Test and live
  • Authentication: API key with the refunds:write scope
  • Since: M9

Request

Path parameters

FieldTypeDescription
idrsk_… ID

Body

A JSON object (Content-Type: application/json):

FieldTypeRequiredDescription
reasonstringYes
refundbooleanNo
blockobjectNo
block.emailbooleanNo
block.cardFingerprintbooleanNo
block.ipNetworkbooleanNo
expectedVersioninteger (at least 1)No

Response

200 OK with a JSON object:

FieldTypeDescription
idrsk_… ID
object"risk_evaluation"
livemodeboolean
brandIdbrd_… ID
subjectobject
subject.typeone of checkout_session, auto_reload
subject.checkoutSessionIdcs_… ID or null
subject.walletIdwal_… ID or null
customerIdcus_… ID or null
paymentIdpay_… ID or null
stageone of intent, payment_method, confirm, off_session
decisionone of allow, require_3ds, review, block
scoreinteger
reasonsarray of object
reasons[].codeone of 21 values, e.g. customer_blocked, customer_elevated, blocklist_email (all in the OpenAPI document)
reasons[].actionone of block, review, require_3ds, score
reasons[].pointsinteger or null
reasons[].detailstring
signalsobject
signals.emailDomainstring or null
signals.ipNetworkstring or null
signals.ipCountrystring or null
signals.billingCountrystring or null
signals.cardCountrystring or null
signals.cardFingerprintstring or null
signals.amountmoney or null
signals.topupboolean
signals.newCustomerboolean
signals.firstPaymentboolean
signals.disposableEmailboolean
historyarray of object
history[].atdate-time
history[].stageone of intent, payment_method, confirm, off_session
history[].decisionone of allow, require_3ds, review, block
history[].scoreinteger
reviewobject or null
createdAtdate-time
updatedAtdate-time

Examples

Refund and block a stolen card

HTTP
POST /api/v1/risk/reviews/rsk_01m4ttwd3veh9apbewxheq5xr1/reject
Authorization: Bearer or_test_…
Idempotency-Key: 3f1c9a52-7d0e-4b8f-9a61-0c2d5e8b7f14
Content-Type: application/json

{
  "reason": "The cardholder doesn't know the customer."
}

Response (200):

JSON
{
  "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"
}

Errors

CodeHTTP statusWhenWhat to do
resource_not_found404No risk evaluation with this ID in this brand and mode.Check the ID and that your credentials are scoped to the right organization, entity, brand and mode.
risk_evaluation_not_held400The evaluation held no payment for review.Only payments the risk rules held are in the review queue (risk.reviews.list). Refund other payments with refunds.create.
risk_review_not_pending409The review was already approved or rejected.Reload the review: it was approved or rejected (details.status). A decision is final; refund the payment or unfreeze the wallet by hand if something must change.
refund_payment_not_refundable409The payment can't be refunded (disputed, or refunded already): reject with refund: false.Refund a succeeded card payment that has an invoice (details.status says what the payment is now). A disputed payment is settled through the dispute; an invoice paid by bank transfer or only from the credit balance has no payment to refund.
refund_nothing_to_refund409Nothing is left to refund (the credits were used): reject with refund: false.The invoice is fully credited, its credits are used, or its period is over. Check the invoice's credit notes and the wallet before trying another type.
refund_limit_exceeded403The refund is above your role's limit: ask finance.Ask a member with the finance role (or an API key with refunds:admin) to make it, or refund at most details.limit. The limit is the brand's (brands.policies.supportRefundLimits).
refund_outside_policy403Support can't refund these credits under the brand's policy.Credits are refundable by support within the brand's refund window when none were used; anything else is the finance role's decision (refunds:admin).
version_conflict409The review changed since expectedVersion, or at the same moment.Fetch the object again and retry the change.
permission_denied403You can't refund this brand's payments.Ask an organization owner or admin for a role or scope that allows this action.

It can also return these common errors: validation_failed, api_version_unsupported, invalid_json, unsupported_media_type, authentication_required, api_key_invalid, scope_required, idempotency_key_required, idempotency_key_reused, idempotency_in_progress, approval_required, approval_rejected, approval_expired, stale_approval, approval_policy_denied, rate_limited, internal_error.