> For the complete documentation index, see [llms.txt](https://docs.coda.co/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.coda.co/https-coda-payments.gitbook.io-zhong-wen-coda-private-technical-documentation/codapay/xun-huan-fu-kuan-ji-jiang-tui-chu/shi-yong-token-hua-zhi-fu-fang-shi-fa-qi-kou-kuan.md).

# 使用 Token 化支付方式发起扣款

顾客不在场的情况下，使用已保存的支付方式进行扣款。请仅从**后端服务器**，且使用已列入白名单的 IP 地址调用此端点。

### Headers 标头

| 标头                | 是否必须 | 介绍                                           |
| ----------------- | ---- | -------------------------------------------- |
| `Content-Type`    | yes  | `application/json; charset=UTF-8`            |
| `X-API-Key`       | yes  | 与 Init v2 的值相同`apiKey`。仅标识符，不包含 JWT HMAC 密钥。 |
| `Authorization`   | yes  | `Bearer <JWT>`（HS256）。参见认证。                  |
| `Idempotency-Key` | yes  | 请求的唯一标识符，以避免重复收费                             |

{% hint style="warning" %}
强烈建议实现 Idempotency-Key（幂等键），以确保您的订单不会被意外重复扣款。

1. 每次逻辑扣款尝试请发送唯一的 Idempotency-Key（推荐使用 UUID）。
2. 遇到超时时，请务必使用相同的 key 仅重试完全相同的请求体（包含金额、payment\_method\_id、订单标识符等）。
3. 请在 24 小时期限内停止使用同一个 key 进行重试。TTL（生存时间）过期后，平台可能会将该请求视为全新的扣款请求。
   {% endhint %}

### **请求参数**

<table><thead><tr><th width="155.96875">值</th><th width="97.42578125">类型</th><th width="86.2734375">是否必须</th><th>介绍</th></tr></thead><tbody><tr><td><code>country</code></td><td>number</td><td>yes</td><td>数字国家代码。必须与 JWT 匹配<code>country</code>。</td></tr><tr><td><code>currency</code></td><td>number</td><td>yes</td><td>数字货币代码。必须与 JWT 匹配<code>currency</code>。</td></tr><tr><td><code>payType</code></td><td>number</td><td>yes</td><td>卡片通道 ID。必须与 JWT 匹配<code>payType</code>。</td></tr><tr><td><code>projectId</code></td><td>number</td><td>yes</td><td>与 Init 项目相同。必须匹配 JWT <code>projectId</code>。</td></tr><tr><td><code>orderId</code></td><td>string</td><td>yes</td><td><strong>您此次</strong>消费的唯一订单 ID 。必须与 JWT 匹配<code>orderId</code>。</td></tr><tr><td><code>offSessionType</code></td><td>string</td><td>yes</td><td>与保存卡片的 CIT 协议类型相同。可以是以下之一<code>Unscheduled</code>：<code>Subscriptions</code>，，<code>Installments</code>。必须与 JWT 匹配<code>offSessionType</code>。</td></tr><tr><td><code>items</code></td><td>array</td><td>yes</td><td>非空。每个项目：<code>code</code>，，<code>price</code>。<code>name</code>必须与 JWT<code>items</code>完全匹配。</td></tr><tr><td><code>paymentMethodId</code></td><td>string</td><td>yes</td><td>来自 <code>PAYMENT_METHOD_ADDED</code> 回调（<code>paymentMethod.id</code>）或支付成功通知参数 <code>PaymentMethodId</code> 中已保存的 ID。</td></tr></tbody></table>

{% hint style="info" %}
Coda 会从拥有此支付方式的购物者处获取税务管辖权信息。
{% endhint %}

#### **示例令牌付费请求体**

```json
{
  "country": 360,
  "currency": 360,
  "payType": 1005,
  "projectId": 1,
  "orderId": "1773302739024703",
  "offSessionType": "Unscheduled",
  "items": [
    {
      "code": "0a141558-3c61-45d0-b299-c867ec023543",
      "price": 1000,
      "name": "Monthly subscription"
    }
  ],
  "paymentMethodId": "pmt_sg1a9999ac56ae00000"
}
```

{% hint style="info" %}
使用与成功的 CIT-for-MIT 保存流程中绑定的已分配 `paymentMethodId` 相关的 `offSessionType`。
{% endhint %}

#### **即时响应回复**

| 值            | 类型      | 介绍                                         |
| ------------ | ------- | ------------------------------------------ |
| `txnId`      | number  | Coda 交易 ID。`0`如果请求在创建费用之前被拒绝。              |
| `resultCode` | integer | `431`= 已接受，正在处理。`0`= 成功（此路径上很少见）。其他值 = 错误。 |
| `resultDesc` | string  | 错误时的英文消息。`null`当费用被接受处理时（`431`）。           |

**已接受（处理中​​）：**

```json
{
  "resultCode": 431,
  "resultDesc": null,
  "txnId": 7883459825339273000
}
```

{% hint style="info" %}
请勿视为`431`已付款。请等待完整通知或问询。
{% endhint %}

**被拒绝的示例：**

```json
{
  "resultCode": 103,
  "resultDesc": "This transaction has been cancelled. No charges were made. (error:103).",
  "txnId": 0
}
```

***

### 身份验证（令牌支付） <a href="#authentication-token-charge" id="authentication-token-charge"></a>

Token Charge 端点使用**两个**凭证：

| Credential 身份验证     | Role 角色                                                                    |
| ------------------- | -------------------------------------------------------------------------- |
| `X-API-Key`         | 与 Init Payment API 相同的字符串/键`apiKey`。                                       |
| HMAC signing secret | Coda 会单独提供一个密钥，用于带外传输。该密钥仅用于签署 JWT。**切勿**将其放入`X-API-Key`JSON 正文、日志或 Git 中。 |

Coda 没有颁发 JWT 的端点。您的服务器会针对每个请求构建并签名 JWT。

#### **JWT 标头**

```json
{ "alg": "HS256", "typ": "JWT" }
```

{% hint style="info" %}
算法仅支持**HS256**。其他算法均不接受。
{% endhint %}

#### **JWT 声明**

`exp - iat`必&#x987B;**≤300秒**。Coda允许约30秒的时钟偏差。所有列出的声明都是必需的。签名验证后，每个声明必须与JSON正文**完全匹配（类型相同）。不匹配→返回**`resultCode` **103**错误。

| 声明                | 类型                             | 规则                                         |
| ----------------- | ------------------------------ | ------------------------------------------ |
| `iat`             | number                         | Unix 秒 UTC。必须小于等于当前时间（存在偏差）。               |
| `exp`             | number                         | Unix 秒（UTC）。必须大于当前时间，`exp - iat`且小于等于 300。 |
| `orderId`         | string                         | 匹配主体`orderId`。                             |
| `projectId`       | number                         | 匹配主体`projectId`。用于`country`解析商家。           |
| `country`         | number                         | 匹配主体`country`。                             |
| `currency`        | number                         | 匹配主体`currency`。                            |
| `payType`         | number                         | 匹配主体`payType`。                             |
| `offSessionType`  | string                         | 匹配主体`offSessionType`。                      |
| `items`           | array of `{code, price, name}` | 长度和字段与正文相同`items`。此操作用于绑定金额。               |
| `paymentMethodId` | string                         | 匹配主体`paymentMethodId`。                     |

请勿在 JWT 中包含`iss`, `jti`, `kid`, `apiKey`, `userInitiated`, `shopper`, `profile`, 或`paymentMethods`。此端点仅限 MIT 权限；Coda 会在内部设置 customer-absent。

```json
{
  "iat": 1787126400,
  "exp": 1787126700,
  "orderId": "1773302739024703",
  "projectId": 1,
  "country": 360,
  "currency": 360,
  "payType": 1005,
  "offSessionType": "Unscheduled",
  "items": [
    {
      "code": "0a141558-3c61-45d0-b299-c867ec023543",
      "price": 1000,
      "name": "Monthly subscription"
    }
  ],
  "paymentMethodId": "pmt_sg1a9999ac56ae00000"
}
```

#### **符号（节点式草图）**

```json
const jwt = require('jsonwebtoken');
const secret = process.env.CODA_TOKEN_CHARGE_HMAC; // not the API key
const now = Math.floor(Date.now() / 1000);
const token = jwt.sign(
  {
    orderId: '1773302739024703',
    projectId: 1,
    country: 360,
    currency: 360,
    payType: 1005,
    offSessionType: 'Unscheduled',
    items: [{
      code: '0a141558-3c61-45d0-b299-c867ec023543',
      price: 1000,
      name: 'Monthly subscription'
    }],
    paymentMethodId: 'pm_1234567890000',
    iat: now,
    exp: now + 300
  },
  secret,
  { algorithm: 'HS256' }
);
```

***

### IP地址白名单（令牌支付） <a href="#ip-allowlist-token-charge" id="ip-allowlist-token-charge"></a>

Coda 只接受来自您提供给您的帐户管理员的**IPv4 地址或 CIDR 范围**的令牌充值（调用 API 的**服务器**的 NAT / 负载均衡器出口- 除非是故意用于沙箱，否则不接受开发人员笔记本电脑）。

| 规则             | 细节                                                     |
| -------------- | ------------------------------------------------------ |
| 谁发送IP地址        | 你，在正式上线之前                                              |
| 格式             | 准确的 IPv4 地址和/或 CIDR 地址（例如203.0.113.10，198.51.100.0/24） |
| 如果缺失或 IP 地址未列出 | 令牌收费被拒绝                                                |

{% hint style="info" %}
当您的出口 IP 地址发生变化时，请在切换之前通知 Coda。
{% endhint %}

[<br>](https://coda-payments.gitbook.io/coda-public-technical-documentation/codapay/recurring-payments-coming-soon/initiate-payment-account-binding)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.coda.co/https-coda-payments.gitbook.io-zhong-wen-coda-private-technical-documentation/codapay/xun-huan-fu-kuan-ji-jiang-tui-chu/shi-yong-token-hua-zhi-fu-fang-shi-fa-qi-kou-kuan.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
