# Invoice API

- 服务地址（示例，真实 Host 由接入团队提供）：`https://invoice-api.psp.example.com`
- 认证：Ed25519 签名
- 版本：1.0.0
- OpenAPI 规范：https://docs.potabank.com/openapi/invoice.openapi.yaml

Invoice service surface for merchant invoice write flows. This service
only accepts invoice account secrets and rejects transfer/query/webhook/proof
traffic.
A missing X-API-ID header returns 400 INVALID_REQUEST. A missing X-API-Key
header or invalid credentials return 401 UNAUTHORIZED. A credential store
failure returns 500 INTERNAL_ERROR before the request handler runs.

## Invoice Payment Intents

### Create a invoice payment intent

**POST** `/api/v1/payments/intents`

Requires a invoice account secret and `invoices:write` scope.

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

Unlike other write operations, this one is not deduplicated by the
idempotency key: the gateway keeps no response cache for it, and the
key does not decide retries. The invoice service identifies a retry by
`merchant_order_id` within the merchant account; reusing a
`merchant_order_id` with a different request is rejected with
409 CONFLICT.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `payment_method` | `enum` | 必填 | 可选值：`pix`、`spei`、`upi`、`credit_card`、`apple_pay`、`google_pay`、`cash_app`、`paypal`、`zelle`、`chime`、`venmo`、`emt`、`boleto` |
| `rail_variant` | `string` | 必填 | Canonical rail variant paired with payment_method; cash_app accepts standard/ecashapp, paypal accepts standard/epaypal, and zelle/chime/venmo/emt use standard. |
| `amount` | `integer<int64>` | 必填 | ≥ 1 |
| `currency` | `string` | 必填 | 最短 3 · 最长 3 |
| `instruction` | `object` | 可选 | — |
| `items` | `object[]` | 可选 | — |
| `items[].name` | `string` | 必填 | 最长 160 |
| `items[].description` | `string` | 可选 | 最长 500 |
| `items[].sku` | `string` | 可选 | 最长 80 |
| `items[].quantity` | `integer` | 必填 | ≥ 1 · ≤ 999999 |
| `items[].unit_amount` | `integer<int64>` | 必填 | ≥ 0 |
| `items[].currency` | `string` | 可选 | 最短 3 · 最长 3 |
| `items[].image_url` | `string<uri>` | 可选 | 最长 2048 |
| `payer_info` | `object` | 可选 | — |
| `payer_info.name` | `string` | 可选 | 最长 200 |
| `payer_info.tax_id` | `string` | 可选 | 付款人证件号。账户 payin_payer_validation_mode 为 optional 或 required 且提交了本字段时，须符合账户市场格式：巴西 CPF（11 位数字含校验位）或 CNPJ （14 位，数字或字母数字，含官方校验位，例如 00.000.000/E08G-12）；墨西哥 RFC （12 或 13 位，日期段月份 01–12、日期 01–31）。格式错误返回 INVALID_REQUEST。 required 档未提交亦返回 INVALID_REQUEST。 · 最长 50 |
| `payer_info.email` | `string<email>` | 可选 | 最长 200 |
| `payer_info.phone` | `string` | 可选 | 最长 50 |
| `payer_info.account` | `string` | 可选 | 最长 200 |
| `description` | `string` | 可选 | 最长 500 |
| `merchant_order_id` | `string` | 必填 | 最长 100 |
| `return_url` | `string<uri>` | 可选 | HTTPS return URL for provider-hosted checkout or 3DS completion. · 最长 500 |
| `webhook_url` | `string<uri>` | 可选 | 最长 500 |
| `expires_in_minutes` | `integer` | 可选 | ≥ 1 · ≤ 1440 |
| `allow_different_amount` | `boolean` | 可选 | — |
| `allow_multiple_payments` | `boolean` | 可选 | — |
| `metadata` | `object` | 可选 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/payments/intents' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "payment_method": "pix",
    "rail_variant": "standard",
    "amount": 1,
    "currency": "string",
    "instruction": {},
    "items": [
      {
        "name": "string",
        "description": "string",
        "sku": "string",
        "quantity": 1,
        "unit_amount": 0,
        "currency": "string",
        "image_url": "https://example.com"
      }
    ],
    "payer_info": {
      "name": "string",
      "tax_id": "string",
      "email": "user@example.com",
      "phone": "string",
      "account": "string"
    },
    "description": "string",
    "merchant_order_id": "string",
    "return_url": "https://example.com",
    "webhook_url": "https://example.com",
    "expires_in_minutes": 1,
    "allow_different_amount": false,
    "allow_multiple_payments": false,
    "metadata": {}
  }'
```

**响应**

#### 响应 201 Created

Payment intent created

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | `string<uuid>` | 必填 | — |
| `invoice_number` | `string` | 必填 | — |
| `payment_method` | `string` | 必填 | — |
| `classification` | `object` | 可选 | — |
| `amount` | `integer<int64>` | 必填 | — |
| `currency` | `string` | 必填 | — |
| `paid_amount` | `integer<int64>` | 可选 | — |
| `refunded_amount` | `integer<int64>` | 可选 | — |
| `status` | `string` | 必填 | — |
| `state` | `string` | 可选 | — |
| `merchant_order_id` | `string` | 可选 | — |
| `payment_url` | `string` | 可选 | — |
| `psp_checkout_url` | `string` | 可选 | — |
| `provider_checkout_url` | `string` | 可选 | — |
| `payment_url_source` | `string` | 可选 | — |
| `instruction` | `object` | 可选 | — |
| `expected_payer_info` | `object` | 可选 | — |
| `expected_payer_info.name` | `string` | 可选 | 最长 200 |
| `expected_payer_info.tax_id` | `string` | 可选 | 付款人证件号。账户 payin_payer_validation_mode 为 optional 或 required 且提交了本字段时，须符合账户市场格式：巴西 CPF（11 位数字含校验位）或 CNPJ （14 位，数字或字母数字，含官方校验位，例如 00.000.000/E08G-12）；墨西哥 RFC （12 或 13 位，日期段月份 01–12、日期 01–31）。格式错误返回 INVALID_REQUEST。 required 档未提交亦返回 INVALID_REQUEST。 · 最长 50 |
| `expected_payer_info.email` | `string<email>` | 可选 | 最长 200 |
| `expected_payer_info.phone` | `string` | 可选 | 最长 50 |
| `expected_payer_info.account` | `string` | 可选 | 最长 200 |
| `payer_info` | `object` | 可选 | — |
| `payer_info.name` | `string` | 可选 | 最长 200 |
| `payer_info.tax_id` | `string` | 可选 | 付款人证件号。账户 payin_payer_validation_mode 为 optional 或 required 且提交了本字段时，须符合账户市场格式：巴西 CPF（11 位数字含校验位）或 CNPJ （14 位，数字或字母数字，含官方校验位，例如 00.000.000/E08G-12）；墨西哥 RFC （12 或 13 位，日期段月份 01–12、日期 01–31）。格式错误返回 INVALID_REQUEST。 required 档未提交亦返回 INVALID_REQUEST。 · 最长 50 |
| `payer_info.email` | `string<email>` | 可选 | 最长 200 |
| `payer_info.phone` | `string` | 可选 | 最长 50 |
| `payer_info.account` | `string` | 可选 | 最长 200 |
| `items` | `object[]` | 可选 | — |
| `items[].name` | `string` | 必填 | 最长 160 |
| `items[].description` | `string` | 可选 | 最长 500 |
| `items[].sku` | `string` | 可选 | 最长 80 |
| `items[].quantity` | `integer` | 必填 | ≥ 1 · ≤ 999999 |
| `items[].unit_amount` | `integer<int64>` | 必填 | ≥ 0 |
| `items[].currency` | `string` | 可选 | 最短 3 · 最长 3 |
| `items[].image_url` | `string<uri>` | 可选 | 最长 2048 |
| `allow_different_amount` | `boolean` | 可选 | — |
| `allow_multiple_payments` | `boolean` | 可选 | — |
| `expires_at` | `string<date-time>` | 可选 | — |
| `created_at` | `string<date-time>` | 必填 | — |
| `updated_at` | `string<date-time>` | 必填 | — |
| `metadata` | `object` | 可选 | — |


```json
{
  "id": "00000000-0000-7000-8000-000000000000",
  "invoice_number": "string",
  "payment_method": "string",
  "classification": {},
  "amount": 0,
  "currency": "string",
  "paid_amount": 0,
  "refunded_amount": 0,
  "status": "string",
  "state": "string",
  "merchant_order_id": "string",
  "payment_url": "string",
  "psp_checkout_url": "string",
  "provider_checkout_url": "string",
  "payment_url_source": "string",
  "instruction": {},
  "expected_payer_info": {
    "name": "string",
    "tax_id": "string",
    "email": "user@example.com",
    "phone": "string",
    "account": "string"
  },
  "payer_info": {
    "name": "string",
    "tax_id": "string",
    "email": "user@example.com",
    "phone": "string",
    "account": "string"
  },
  "items": [
    {
      "name": "string",
      "description": "string",
      "sku": "string",
      "quantity": 1,
      "unit_amount": 0,
      "currency": "string",
      "image_url": "https://example.com"
    }
  ],
  "allow_different_amount": false,
  "allow_multiple_payments": false,
  "expires_at": "2026-01-01T00:00:00Z",
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": "2026-01-01T00:00:00Z",
  "metadata": {}
}
```

#### 响应 400 Bad Request

Invalid request. When payin_payer_validation_mode is optional or required and payer_info.tax_id is present but not a valid market document, or when required mode is missing payer name/tax_id, the gateway returns INVALID_REQUEST.

#### 响应 401 Unauthorized

The credential kind or host does not match the invoice service.

#### 响应 403 Forbidden

The account secret lacks the required invoice scope.

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

#### 响应 503 Unavailable

Risk evaluation unavailable; no invoice or provider order is created. Retry the same merchant order and idempotency key after the prerequisite is restored.

### Cancel a invoice payment intent

**POST** `/api/v1/payments/intents/{invoice_number}/cancel`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_number` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `reason` | `string` | 可选 | 最长 500 |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/payments/intents/{invoice_number}/cancel' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "reason": "string"
  }'
```

**响应**

#### 响应 200 OK

Payment intent canceled

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `status` | `enum` | 必填 | 可选值：`canceled` |


```json
{
  "status": "canceled"
}
```

#### 响应 401 Unauthorized

The credential kind or host does not match the invoice service.

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Create a invoice refund

**POST** `/api/v1/payments/intents/{invoice_number}/refund`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

The same header key is also the refund's business idempotency key
within the merchant: a retry with the same key returns the existing
refund, and reusing the key for a different refund is rejected with
409 CONFLICT.

New requests evaluate the original account's published refund rules
before creating the refund or freezing funds. A block returns
403 RISK_REJECTED; risk dependency failure returns 503 SERVICE_UNAVAILABLE.
The refund amount is evaluated against the original frozen method/rail;
no new invoice or transfer limit reservation is created.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_number` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `amount` | `integer<int64>` | 必填 | ≥ 1 |
| `reason` | `string` | 可选 | 最长 500 |
| `metadata` | `object` | 可选 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/payments/intents/{invoice_number}/refund' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "amount": 1,
    "reason": "string",
    "metadata": {}
  }'
```

**响应**

#### 响应 201 Created

Invoice refund created

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `id` | `string<uuid>` | 必填 | — |
| `invoice_number` | `string` | 必填 | — |
| `refund_number` | `string` | 必填 | — |
| `original_intent_id` | `string<uuid>` | 可选 | — |
| `amount` | `integer<int64>` | 必填 | — |
| `currency` | `string` | 必填 | — |
| `status` | `string` | 必填 | — |
| `reason` | `string` | 可选 | — |
| `created_at` | `string<date-time>` | 可选 | — |
| `updated_at` | `string<date-time>` | 可选 | — |


```json
{
  "id": "00000000-0000-7000-8000-000000000000",
  "invoice_number": "string",
  "refund_number": "string",
  "original_intent_id": "00000000-0000-7000-8000-000000000000",
  "amount": 0,
  "currency": "string",
  "status": "string",
  "reason": "string",
  "created_at": "2026-01-01T00:00:00Z",
  "updated_at": "2026-01-01T00:00:00Z"
}
```

#### 响应 401 Unauthorized

The credential kind or host does not match the invoice service.

#### 响应 403 Forbidden

RISK_REJECTED or RISK_REVIEW; no refund created

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

#### 响应 503 Unavailable

SERVICE_UNAVAILABLE; refund risk evaluation failed closed

## Invoice Credit Cards

### Create a credit card authorization

**POST** `/api/v1/cards/authorizations`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

This operation has two idempotency layers. The header key is covered
by the signature and deduplicates the request at the gateway. The
required JSON field `idempotency_key` in the request body is the
business idempotency key: the card service uses it to recognize a
retried authorization within the merchant account. The gateway does
not check that the two values are equal. Send the same value in both
places and keep it unchanged when retrying.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_number` | `string` | 必填 | — |
| `idempotency_key` | `string` | 必填 | — |
| `channel_id` | `string<uuid>` | 必填 | — |
| `amount` | `integer<int64>` | 必填 | ≥ 1 |
| `currency` | `string` | 必填 | 最短 3 · 最长 3 |
| `card_token` | `string` | 可选 | — |
| `card_cvv` | `string` | 可选 | — |
| `card_info` | `object` | 可选 | — |
| `card_info.card_number` | `string` | 必填 | — |
| `card_info.cvv` | `string` | 必填 | — |
| `card_info.expiry_month` | `integer` | 必填 | ≥ 1 · ≤ 12 |
| `card_info.expiry_year` | `integer` | 必填 | — |
| `card_info.cardholder_name` | `string` | 必填 | — |
| `payer_info` | `object` | 必填 | — |
| `payer_info.name` | `string` | 必填 | — |
| `payer_info.email` | `string<email>` | 必填 | — |
| `payer_info.phone` | `string` | 可选 | — |
| `description` | `string` | 可选 | — |
| `merchant_order_id` | `string` | 可选 | — |
| `require_3ds` | `boolean` | 可选 | — |
| `pre_auth` | `boolean` | 可选 | — |
| `metadata` | `object` | 可选 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/cards/authorizations' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoice_number": "string",
    "idempotency_key": "string",
    "channel_id": "00000000-0000-7000-8000-000000000000",
    "amount": 1,
    "currency": "string",
    "card_token": "string",
    "card_cvv": "string",
    "card_info": {
      "card_number": "string",
      "cvv": "string",
      "expiry_month": 1,
      "expiry_year": 0,
      "cardholder_name": "string"
    },
    "payer_info": {
      "name": "string",
      "email": "user@example.com",
      "phone": "string"
    },
    "description": "string",
    "merchant_order_id": "string",
    "require_3ds": false,
    "pre_auth": false,
    "metadata": {}
  }'
```

**响应**

#### 响应 201 Created

Authorization created

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Complete 3DS for an authorization

**POST** `/api/v1/cards/authorizations/{authorization_id}/complete-3ds`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

The header key only signs and deduplicates the request; the request
body has no `idempotency_key`. A replayed completion is rejected by the
one-time `cres_nonce` with 409 CONFLICT.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `authorization_id` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_id` | `string<uuid>` | 必填 | — |
| `transaction_id` | `string` | 必填 | — |
| `auth_value` | `string` | 必填 | — |
| `eci` | `string` | 必填 | — |
| `cres_nonce` | `string` | 必填 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/cards/authorizations/{authorization_id}/complete-3ds' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoice_id": "00000000-0000-7000-8000-000000000000",
    "transaction_id": "string",
    "auth_value": "string",
    "eci": "string",
    "cres_nonce": "string"
  }'
```

**响应**

#### 响应 200 OK

Authorization updated

#### 响应 410 Gone

Authorization has expired (INVOICE_EXPIRED).

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Capture a credit card authorization

**POST** `/api/v1/cards/captures`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

This operation has two idempotency layers. The header key is covered
by the signature and deduplicates the request at the gateway. The
required JSON field `idempotency_key` in the request body is the
business idempotency key: the card service uses it to recognize a
retried capture. The gateway does not check that the two values are
equal. Send the same value in both places and keep it unchanged when
retrying.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_id` | `string<uuid>` | 必填 | — |
| `capture_amount` | `integer<int64>` | 必填 | ≥ 1 |
| `idempotency_key` | `string` | 必填 | — |
| `reason` | `string` | 可选 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/cards/captures' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoice_id": "00000000-0000-7000-8000-000000000000",
    "capture_amount": 1,
    "idempotency_key": "string",
    "reason": "string"
  }'
```

**响应**

#### 响应 200 OK

Capture completed

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_id` | `string<uuid>` | 可选 | — |
| `captured_amount` | `integer<int64>` | 可选 | — |
| `total_captured` | `integer<int64>` | 可选 | — |
| `status` | `string` | 可选 | — |
| `captured_at` | `string<date-time>` | 可选 | — |


```json
{
  "invoice_id": "00000000-0000-7000-8000-000000000000",
  "captured_amount": 0,
  "total_captured": 0,
  "status": "string",
  "captured_at": "2026-01-01T00:00:00Z"
}
```

#### 响应 410 Gone

Authorization has expired (INVOICE_EXPIRED).

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Create a credit card refund

**POST** `/api/v1/cards/refunds`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

This operation has two idempotency layers. The header key is covered
by the signature and deduplicates the request at the gateway. The
required JSON field `idempotency_key` in the request body is the
business idempotency key: within the merchant account, a retry with
the same `idempotency_key` and the same refund returns the first
refund, and reusing it for a different refund is rejected with
409 DUPLICATE_IDEMPOTENCY_KEY. The gateway does not check that the two
values are equal. Send the same value in both places and keep it
unchanged when retrying.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `invoice_id` | `string<uuid>` | 必填 | — |
| `idempotency_key` | `string` | 必填 | — |
| `merchant_refund_id` | `string` | 可选 | — |
| `refund_amount` | `integer<int64>` | 必填 | ≥ 1 |
| `reason` | `string` | 可选 | — |
| `notes` | `string` | 可选 | — |
| `metadata` | `object` | 可选 | — |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/cards/refunds' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "invoice_id": "00000000-0000-7000-8000-000000000000",
    "idempotency_key": "string",
    "merchant_refund_id": "string",
    "refund_amount": 1,
    "reason": "string",
    "notes": "string",
    "metadata": {}
  }'
```

**响应**

#### 响应 201 Created

Card refund created

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

## Invoice Tokenization

### Tokenize a card

**POST** `/api/v1/tokenization/cards`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `customer_id` | `string` | 必填 | — |
| `card_number` | `string` | 必填 | 最短 16 · 最长 16 |
| `expiry_month` | `string` | 必填 | 最短 2 · 最长 2 |
| `expiry_year` | `string` | 必填 | 最短 4 · 最长 4 |
| `cardholder_name` | `string` | 必填 | — |
| `cvv` | `string` | 可选 | 最短 3 · 最长 4 |
| `scope` | `enum` | 可选 | 可选值：`single_use`、`multi_use`、`permanent` |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/tokenization/cards' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "customer_id": "string",
    "card_number": "string",
    "expiry_month": "string",
    "expiry_year": "string",
    "cardholder_name": "string",
    "cvv": "string",
    "scope": "single_use"
  }'
```

**响应**

#### 响应 201 Created

Token created

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token_id` | `string` | 必填 | — |
| `customer_id` | `string` | 必填 | — |
| `token_type` | `enum` | 必填 | 可选值：`card`、`bank_account` |
| `scope` | `string` | 可选 | — |
| `created_at` | `string<date-time>` | 必填 | — |
| `expires_at` | `string<date-time>` | 可选 | — |
| `masked_info` | `object` | 必填 | — |


```json
{
  "token_id": "string",
  "customer_id": "string",
  "token_type": "card",
  "scope": "string",
  "created_at": "2026-01-01T00:00:00Z",
  "expires_at": "2026-01-01T00:00:00Z",
  "masked_info": {}
}
```

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Tokenize a bank account

**POST** `/api/v1/tokenization/bank-accounts`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json · 必填)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `customer_id` | `string` | 必填 | — |
| `account_number` | `string` | 必填 | — |
| `bank_code` | `string` | 必填 | — |
| `account_type` | `enum` | 可选 | 可选值：`checking`、`savings` |
| `account_holder_name` | `string` | 必填 | — |
| `branch_code` | `string` | 可选 | — |
| `scope` | `enum` | 可选 | 可选值：`single_use`、`multi_use`、`permanent` |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/tokenization/bank-accounts' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "customer_id": "string",
    "account_number": "string",
    "bank_code": "string",
    "account_type": "checking",
    "account_holder_name": "string",
    "branch_code": "string",
    "scope": "single_use"
  }'
```

**响应**

#### 响应 201 Created

Token created

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token_id` | `string` | 必填 | — |
| `customer_id` | `string` | 必填 | — |
| `token_type` | `enum` | 必填 | 可选值：`card`、`bank_account` |
| `scope` | `string` | 可选 | — |
| `created_at` | `string<date-time>` | 必填 | — |
| `expires_at` | `string<date-time>` | 可选 | — |
| `masked_info` | `object` | 必填 | — |


```json
{
  "token_id": "string",
  "customer_id": "string",
  "token_type": "card",
  "scope": "string",
  "created_at": "2026-01-01T00:00:00Z",
  "expires_at": "2026-01-01T00:00:00Z",
  "masked_info": {}
}
```

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Detokenize a token

**POST** `/api/v1/tokenization/tokens/{token_id}/detokenize`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token_id` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/tokenization/tokens/{token_id}/detokenize' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>'
```

**响应**

#### 响应 200 OK

Sensitive token data returned

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Extend a token

**POST** `/api/v1/tokenization/tokens/{token_id}/extend`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token_id` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求体** (application/json)

| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `extension_days` | `integer` | 可选 | ≥ 1 · ≤ 365 · 默认 `365` |

**请求示例**

```bash
curl -X POST 'https://invoice-api.psp.example.com/api/v1/tokenization/tokens/{token_id}/extend' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>' \
  -H 'Content-Type: application/json' \
  -d '{
    "extension_days": 365
  }'
```

**响应**

#### 响应 200 OK

Token extended

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.

### Revoke a token

**DELETE** `/api/v1/tokenization/tokens/{token_id}`

Send the idempotency key in `X-Idempotency-Key` or `Idempotency-Key`;
at least one is required. When both are sent they must be equal,
otherwise the request is rejected with 400 INVALID_REQUEST. The Ed25519
signature covers `X-Idempotency-Key` when it is sent, otherwise
`Idempotency-Key`.

**路径参数**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `token_id` | `string` | 必填 | — |

**请求头**

| 名称 | 类型 | 必填 | 说明 |
|---|---|---|---|
| `X-Idempotency-Key` | `string` | 可选 | Idempotency key. Send it in this header or in Idempotency-Key; at least one of the two is required. When this header is sent, the Ed25519 signature covers its value. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |
| `Idempotency-Key` | `string` | 可选 | Idempotency key, alternative to X-Idempotency-Key; at least one of the two is required. The Ed25519 signature covers this header only when X-Idempotency-Key is not sent. If both headers are sent they must be equal, otherwise the request is rejected with 400 INVALID_REQUEST. · 最短 1 |

**请求示例**

```bash
curl -X DELETE 'https://invoice-api.psp.example.com/api/v1/tokenization/tokens/{token_id}' \
  -H 'X-API-ID: <api-id>' \
  -H 'X-API-Key: <api-key>' \
  -H 'X-Timestamp: <timestamp>' \
  -H 'X-Signature: <signature>'
```

**响应**

#### 响应 204 No Content

Token revoked

#### 响应 500 Server Error

Credential lookup failed (INTERNAL_ERROR). The request handler was not executed.
