> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cbpayapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 厄瓜多尔 USD 人工付款

> 当运营人员在银行门户中手动完成付款时，使用厄瓜多尔 USD 银行转账通道。

export const EnvUrls = ({lang = "en"}) => {
  const T = {
    en: {
      test: "Test",
      live: "Live",
      hint: "Same API on both environments — build against test first, then go live by swapping the base URL and the key.",
      guide: "Environments and testing",
      href: "/en/environment-testing"
    },
    es: {
      test: "Test",
      live: "Live",
      hint: "La misma API en ambos ambientes — construye primero contra test y pasa a live cambiando la URL base y la key.",
      guide: "Entorno y pruebas",
      href: "/es/environment-testing"
    },
    zh: {
      test: "Test",
      live: "Live",
      hint: "两个环境的 API 完全一致——先在 test 环境构建，再通过切换基础 URL 和密钥上线。",
      guide: "环境与测试",
      href: "/zh/environment-testing"
    }
  };
  const t = T[lang] || T.en;
  const row = (label, url, keyPattern, badgeCls) => <div className="flex flex-wrap items-center gap-2 px-3 py-2">
      <span className={"rounded px-1.5 py-0.5 text-xs font-semibold uppercase tracking-wide " + badgeCls}>
        {label}
      </span>
      <code className="text-xs">{url}</code>
      <span className="text-xs text-gray-400 dark:text-zinc-500">·</span>
      <code className="text-xs">{keyPattern}</code>
    </div>;
  return <div className="my-4 rounded-xl border border-gray-200 dark:border-zinc-700 divide-y divide-gray-200 dark:divide-zinc-700 text-sm not-prose">
      {row(t.test, "https://cryptobank.qbank.cl/platform", "pk_test_...", "bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300")}
      {row(t.live, "https://api.qbank.cl/platform", "pk_...", "bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300")}
      <p className="px-3 py-2 text-xs text-gray-500 dark:text-zinc-400 m-0">
        {t.hint} <a href={t.href}>{t.guide} →</a>
      </p>
    </div>;
};

<EnvUrls lang="zh" />

## 适用范围

该通道仅适用于 `country=EC`、`currency=USD` 和
`method=bank_transfer`。它使用人工调度模式：payout 保持
`processing`，并带有 `status_code=manual_dispatch`，直到授权运营人员在
银行门户完成付款并确认结果。该路由不会自动调用或对账银行。

供应商选择和凭据属于部署配置，不属于 CBPay 的公开合同。

## 环境顺序

先在 staging 中使用模拟通道和合成收款人测试此通道。只有 staging
通过后，才能在生产环境验证相同的集成。生产环境验证需要运营数据，以及
对环境和测试范围的明确授权。

## 流程

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
sequenceDiagram
  participant I as 集成方
  participant C as CBPay
  participant O as 运营人员
  participant B as 银行门户
  I->>C: 创建 EC/USD bank_transfer payout
  C-->>I: processing / manual_dispatch
  O->>B: 在银行门户手动付款
  O->>C: 使用银行参考号确认已付款
  C-->>I: completed / manual_confirmed
```

## 创建并读取 payout

使用标准 payout 接口和合成收款人：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/payouts
Authorization: Bearer <API_KEY>
Content-Type: application/json
Idempotency-Key: ec-manual-<unique-key>
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "country": "EC",
  "currency": "USD",
  "method": "bank_transfer",
  "amount": "125.00",
  "beneficiary": {
    "name": "Example Recipient",
    "document_value": "0900000000",
    "bank_code": "000000",
    "account_number": "0000000000",
    "account_type": "CACC",
    "country_code": "EC",
    "sender_name": "Example Sender"
  },
  "description": "Invoice 1001",
  "idempotency_key": "ec-manual-<unique-key>"
}
```

金额必须为 USD `1.00` 至 `10000.00`（含边界），并且按数值最多两位
小数。使用十进制字符串，不使用浮点数。

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
GET /v1/payouts/{payoutID}
Authorization: Bearer <API_KEY>
```

厄瓜多尔手动通道生成的银行参考号格式为 `ECM` 加 13 位连续数字。这是该通道
的参考号格式，并非所有银行参考号的通用限制。创建响应通常包含：

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "payout_id": "00000000-0000-4000-8000-000000000001",
  "status": "processing",
  "status_code": "manual_dispatch",
  "idempotency_hit": false
}
```

## 确认银行付款

核心运营人员确认已人工支付的 payout：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/ops/payouts/{payoutID}/confirm-manual-paid
Authorization: Bearer <CORE_ADMIN_KEY>
Content-Type: application/json
Idempotency-Key: confirm-ec-<unique-key>
```

平台管理员使用核心代理路由：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/admin/core/payouts/{payoutID}/confirm-manual-paid
Authorization: Bearer <PLATFORM_ADMIN_KEY>
Content-Type: application/json
Idempotency-Key: confirm-ec-<unique-key>
```

组织管理员使用组织代理路由：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/org/treasury/manual-payouts/{payoutID}/confirm-manual-paid
Authorization: Bearer <ORG_ADMIN_KEY>
Content-Type: application/json
Idempotency-Key: confirm-ec-<unique-key>
```

请求体包含 `bank_reference`、`paid_amount` 和 `reason`。通过
`POST /v1/ops/payouts/{payoutID}/confirm-manual-paid` 确认时必须提供
`Idempotency-Key`（推荐使用 header，也可以在 JSON body 中发送
`idempotency_key`）。缺少 key 时，接口返回 `400
idempotency_key_required`。如果请求超时，先重新读取 payout；如果状态仍不
确定，必须使用同一个 key 和完全相同的证据重试，绝不能盲目发送或生成新
key。使用相同证据 replay 会返回原始结果并带有 `idempotency_hit: true`；
证据不同则返回 `409 idempotency_conflict`。成功响应返回带有人工确认终态
的 payout 资源。

## 人工 payin

确认已公告的 `EC/USD/push/bank_transfer` payin 收款是双人操作
（maker-checker）。在第二个审批完成之前不划账。所有步骤都不使用客户端幂
等键：调用通过 payin ID 和银行证据来识别操作，诚实重放会返回原始结果并
带 `idempotency_hit: true`。

\*\*第 1 步 — 请求（maker）。\*\*拥有 `org_operations`/`ops:write` 权限且使用
人工会话的组织管理员登记银行证据。payin 保持 `pending`；此时不入账：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/payins/{payinID}/confirm-received
Authorization: Bearer <ORG_ADMIN_KEY>
Content-Type: application/json
```

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bank_reference": "ECM0000000000001",
  "received_amount": "125.00"
}
```

响应是确认请求（`id`、`status`、`bank_reference`、`received_amount`、
`account_id`、`maker`、`created_at`）。用相同证据重发该 maker 请求会重放
原始请求并命中；证据不同则返回 `409 invalid_state`。请求不会过期：一直处
于打开状态，直到 checker 批准或 maker（或任意 god 管理员）取消。

\*\*第 2 步 — 批准（checker）。\*\*与 maker 不同的一名具名 god 管理员批准已打
开的请求。批准接口无请求体：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
POST /v1/payins/{payinID}/confirm-approve
Authorization: Bearer <GOD_ADMIN_KEY>
Content-Type: application/json
```

批准后立即通过标准定价、防火墙与入账链路记账。同一管理员不能批准自己的请
求（`409 second_approver_required`）。如果 payin 自请求以来发生变化
（`confirm_account_mismatch`、`bank_ref_conflict`），或该参考号属于资金库
结算（`deposit_settled_treasury_trade`），批准会诚实失败，payin 保持
`pending`；请重读两个资源后再重试。

\*\*取消。\*\*Maker 或任意 god 管理员可以用
`POST /v1/payins/{payinID}/confirm-cancel`（同样无请求体）取消已打开的请
求。已取消的请求永远不再记账；如需确认，只能发起新请求。

任何超时之后先读取 payin。如果已用相同证据入账，重放会返回原始结果；如果
仍为 pending，则重新读取确认请求并重试同一操作。不要尝试用不同证据去"推
动"确认。

## 入金指令

读取已有 payin instrument 的入金指令：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
GET /v1/payins/deposit-instructions
Authorization: Bearer <API_KEY>
```

响应保持 provider-clean，只返回该账户和通道适用的指令。不要从 payout
推断银行信息。

对于厄瓜多尔银行代码，使用实时目录：

```http theme={"theme":{"light":"github-light","dark":"github-dark"}}
GET /v1/payouts/banks?country=EC
Authorization: Bearer <API_KEY>
```

响应格式为 `{ "items": [{ "code": "...", "name": "..." }], "meta": {
"retrieved": 1 } }`，其中 `retrieved` 是返回的条目数量。将返回的 `code`
用作 `beneficiary.bank_code`。

## 运营规则

* 运营人员在银行门户付款，并记录银行参考号。
* 银行操作出现不确定结果时，不要使用新 key 重新发送。
* 对于 `confirm-received`，请求与批准是两名管理员的两个独立步骤；timeout
  后先读取 payin 与确认请求，再重试同一操作。
* 以上示例均为合成数据；只能替换为经过授权的运营数据。

## 状态与错误

| 状态或代码 | 含义 | 操作 |
| - | - | - |
| `processing` + `manual_dispatch` | payout 等待运营人员完成银行操作。 | 只在银行门户付款一次，然后确认已有 payout。 |
| `completed` + `manual_confirmed` | 运营人员已确认银行付款。 | 重新读取 payout 并保留银行参考号。 |
| `invalid_payload` | 必填字段、金额、账户或确认字段无效。 | 修正请求；不要为同一操作创建替代请求。 |
| `idempotency_conflict` | 同一 key 搭配不同数据或不兼容状态被重复使用。 | 读取原资源；只有真正的新操作才使用新 key。 |
| `second_approver_required` | 批准人必须是与 maker 不同的管理员。 | 由另一名具名 god 管理员批准已打开的请求；maker 不能批准自己的请求。 |
| `confirm_account_mismatch` | 自确认请求以来，payin 的账户发生了变化。 | 读取 payin 与请求；先取消，再用新证据发起新请求。 |
| `confirm_request_conflict` | 该 payin 已有另一个打开的确认。 | 先读取已存在的请求并批准或取消，再创建新请求。 |
| `treasury_check_unavailable` | 无法完成 payin 的 ownership 或资金库冲突检查。 | 不要贷记 payin；依赖恢复后再使用同一 key 重试。 |
| `deposit_settled_treasury_trade` | 银行参考号属于资金库结算。 | 不要将其分配或贷记为客户 payin。 |

请参阅[完整错误目录](/zh/errors)，了解通用响应格式和错误处理规则。

## 常见问题

<AccordionGroup>
  <Accordion title="CBPay 会自动发送厄瓜多尔银行转账吗？">
    不会。运营人员完成银行操作，然后在 CBPay 中确认已有 payout。
  </Accordion>

  <Accordion title="`manual_dispatch` 是什么意思？">
    这表示 payout 仍在处理中，等待授权运营人员完成并确认银行操作。
  </Accordion>

  <Accordion title="timeout 后应该怎么做？">
    先读取 payout。如果结果仍不确定，只能使用相同的幂等 key 重试原请求。
    在确认银行结果前，不能使用新 key 再次提交银行转账。
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.