# 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.

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

| Field | Type       | Description |
| ----- | ---------- | ----------- |
| `id`  | `rsk_…` ID |             |

### Body

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

| Field                   | Type                 | Required | Description |
| ----------------------- | -------------------- | -------- | ----------- |
| `reason`                | string               | Yes      |             |
| `refund`                | boolean              | No       |             |
| `block`                 | object               | No       |             |
| `block.email`           | boolean              | No       |             |
| `block.cardFingerprint` | boolean              | No       |             |
| `block.ipNetwork`       | boolean              | No       |             |
| `expectedVersion`       | integer (at least 1) | No       |             |

## Response

`200 OK` with a JSON object:

| Field                       | Type                                                                                                            | Description |
| --------------------------- | --------------------------------------------------------------------------------------------------------------- | ----------- |
| `id`                        | `rsk_…` ID                                                                                                      |             |
| `object`                    | `"risk_evaluation"`                                                                                             |             |
| `livemode`                  | boolean                                                                                                         |             |
| `brandId`                   | `brd_…` ID                                                                                                      |             |
| `subject`                   | object                                                                                                          |             |
| `subject.type`              | one of `checkout_session`, `auto_reload`                                                                        |             |
| `subject.checkoutSessionId` | `cs_…` ID or null                                                                                               |             |
| `subject.walletId`          | `wal_…` ID or null                                                                                              |             |
| `customerId`                | `cus_…` ID or null                                                                                              |             |
| `paymentId`                 | `pay_…` ID or null                                                                                              |             |
| `stage`                     | one of `intent`, `payment_method`, `confirm`, `off_session`                                                     |             |
| `decision`                  | one of `allow`, `require_3ds`, `review`, `block`                                                                |             |
| `score`                     | integer                                                                                                         |             |
| `reasons`                   | array of object                                                                                                 |             |
| `reasons[].code`            | one of 21 values, e.g. `customer_blocked`, `customer_elevated`, `blocklist_email` (all in the OpenAPI document) |             |
| `reasons[].action`          | one of `block`, `review`, `require_3ds`, `score`                                                                |             |
| `reasons[].points`          | integer or null                                                                                                 |             |
| `reasons[].detail`          | string                                                                                                          |             |
| `signals`                   | object                                                                                                          |             |
| `signals.emailDomain`       | string or null                                                                                                  |             |
| `signals.ipNetwork`         | string or null                                                                                                  |             |
| `signals.ipCountry`         | string or null                                                                                                  |             |
| `signals.billingCountry`    | string or null                                                                                                  |             |
| `signals.cardCountry`       | string or null                                                                                                  |             |
| `signals.cardFingerprint`   | string or null                                                                                                  |             |
| `signals.amount`            | money or null                                                                                                   |             |
| `signals.topup`             | boolean                                                                                                         |             |
| `signals.newCustomer`       | boolean                                                                                                         |             |
| `signals.firstPayment`      | boolean                                                                                                         |             |
| `signals.disposableEmail`   | boolean                                                                                                         |             |
| `history`                   | array of object                                                                                                 |             |
| `history[].at`              | date-time                                                                                                       |             |
| `history[].stage`           | one of `intent`, `payment_method`, `confirm`, `off_session`                                                     |             |
| `history[].decision`        | one of `allow`, `require_3ds`, `review`, `block`                                                                |             |
| `history[].score`           | integer                                                                                                         |             |
| `review`                    | object or null                                                                                                  |             |
| `createdAt`                 | date-time                                                                                                       |             |
| `updatedAt`                 | date-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

| Code                                                                                                           | HTTP status | When                                                                                        | What to do                                                                                                                                                                                                                                         |
| -------------------------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`resource_not_found`](https://ownrecord.io/docs/reference/errors.md#resource_not_found)                       | 404         | No 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_held`](https://ownrecord.io/docs/reference/errors.md#risk_evaluation_not_held)           | 400         | The 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_pending`](https://ownrecord.io/docs/reference/errors.md#risk_review_not_pending)             | 409         | The 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_refundable`](https://ownrecord.io/docs/reference/errors.md#refund_payment_not_refundable) | 409         | The 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_refund`](https://ownrecord.io/docs/reference/errors.md#refund_nothing_to_refund)           | 409         | Nothing 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_exceeded`](https://ownrecord.io/docs/reference/errors.md#refund_limit_exceeded)                 | 403         | The 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_policy`](https://ownrecord.io/docs/reference/errors.md#refund_outside_policy)                 | 403         | Support 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_conflict`](https://ownrecord.io/docs/reference/errors.md#version_conflict)                           | 409         | The review changed since `expectedVersion`, or at the same moment.                          | Fetch the object again and retry the change.                                                                                                                                                                                                       |
| [`permission_denied`](https://ownrecord.io/docs/reference/errors.md#permission_denied)                         | 403         | You 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](https://ownrecord.io/docs/reference.md#common-errors): [`validation_failed`](https://ownrecord.io/docs/reference/errors.md#validation_failed), [`api_version_unsupported`](https://ownrecord.io/docs/reference/errors.md#api_version_unsupported), [`invalid_json`](https://ownrecord.io/docs/reference/errors.md#invalid_json), [`unsupported_media_type`](https://ownrecord.io/docs/reference/errors.md#unsupported_media_type), [`authentication_required`](https://ownrecord.io/docs/reference/errors.md#authentication_required), [`api_key_invalid`](https://ownrecord.io/docs/reference/errors.md#api_key_invalid), [`scope_required`](https://ownrecord.io/docs/reference/errors.md#scope_required), [`idempotency_key_required`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_required), [`idempotency_key_reused`](https://ownrecord.io/docs/reference/errors.md#idempotency_key_reused), [`idempotency_in_progress`](https://ownrecord.io/docs/reference/errors.md#idempotency_in_progress), [`approval_required`](https://ownrecord.io/docs/reference/errors.md#approval_required), [`approval_rejected`](https://ownrecord.io/docs/reference/errors.md#approval_rejected), [`approval_expired`](https://ownrecord.io/docs/reference/errors.md#approval_expired), [`stale_approval`](https://ownrecord.io/docs/reference/errors.md#stale_approval), [`approval_policy_denied`](https://ownrecord.io/docs/reference/errors.md#approval_policy_denied), [`rate_limited`](https://ownrecord.io/docs/reference/errors.md#rate_limited), [`internal_error`](https://ownrecord.io/docs/reference/errors.md#internal_error).
