← 返回 API 文档

Customers

代用户提现

先在本地冻结用户余额,再调用 POST /v1/user-withdrawals 提交链与收款地址;根据 withdrawal.complete 确认扣款,或在 withdrawal.failed 时解冻。

代用户提现

用户已经有 Customer,并且充值已进入你的商户资金池(同时你也在本地给用户记了余额)之后,可以通过 User Withdrawal 把资金打到用户自己的地址。

本文只讲 Integration 对接路径:一次请求里带上 chain 和 to_address。商户门户里的「Prepare → 邮件 → Hosted Claim」不在本文范围;对接接口调用 prepare 会得到 403 portal_only。

开始前请先完成:为用户创建客户并获取充值地址、Webhooks。

1. 整体流程

用户在 App 里申请提现
  → 你先冻结本地用户余额
  → POST /v1/user-withdrawals(Secret)
  → 状态变为 requested(商户资金池已扣减)
  → webhook:requested → submitted → complete 或 failed
  → complete:确认扣减本地冻结
  → failed:解冻本地用户余额
要点说明
先有客户external_user_id 必须等于已存在 Customer 的 ref_id
先动本地账调 API 前,先在你的系统冻结 / 扣减用户余额
扣的是商户池提现花费的是你的商户加密货币余额
不是商户自提出金把钱提到你自己的冷钱包,是另一套 MerchantPayout

2. 发起提现

POST /v1/user-withdrawals
鉴权: Secret + X-DoggiePay-Request-Id
强烈建议同时带 Idempotency-Key(若它是 UUID,有机会直接作为 withdrawal_id,方便和本地冻结单对齐)。

请求体

字段类型必填说明
external_user_idstring(UUID)是等于 Customer 的 ref_id
amountstring是正数金额,例如 "10.00"
currencystring是例如 USDC
chainstring是到账链,例如 ETH
to_addressstring是用户收款地址(每次可以不同)

请求示例

curl -sS https://api.doggiepay.com/v1/user-withdrawals \
  -H "Authorization: Bearer dp_live_sk_YOUR_SECRET" \
  -H "X-DoggiePay-Request-Id: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
  -H "Idempotency-Key: $(uuidgen | tr '[:upper:]' '[:lower:]')" \
  -H "Content-Type: application/json" \
  -d '{
    "external_user_id": "6ded84e7-5449-4a2b-9c1d-0afcce047b29",
    "amount": "10.00",
    "currency": "USDC",
    "chain": "ETH",
    "to_address": "0xCustomerWallet..."
  }'

成功时的 data

字段类型说明
withdrawal_iduuid提现单 id
statusstring受理后通常为 requested

常见错误

HTTPerror.code含义
400invalid_external_user_id不是合法 UUID
400invalid_to_address地址缺失或不合法
400below_min_withdrawal低于最低提现额
400unsupported_currency / chain_or_asset_disabled币种或链未就绪
404customer_not_found尚未创建对应 Customer
422insufficient_balance商户资金池余额不足
422user_withdrawal_failed其他业务失败

3. 查询状态

方法路径说明
GET/v1/user-withdrawals/{id}单笔查询
GET/v1/user-withdrawals?external_user_id=&status=按用户、状态筛选列表

鉴权:Secret + Request-Id。

4. Webhook 与本地账务怎么对齐

type时机你建议怎么做
withdrawal.requested已受理,商户余额已扣可记「处理中」;本地一般已先冻结
withdrawal.submitted已提交到通道 / 链上可展示「广播中」
withdrawal.complete成功(常带 tx_hash)确认扣减本地冻结
withdrawal.failed失败,商户余额会退回解冻本地用户余额

data 常见字段:withdrawal_id、external_user_id、amount、currency、chain、to_address;submitted / complete 可能还有链上相关字段;failed 含 failure_reason。

补充说明:

  • 门户 Prepare 还会发 withdrawal.prepared(此时还没有最终收款地址)。纯 Integration 同步创建路径不会看到 prepared。
  • 务必验签,见 Webhooks。

5. Integration 不要调用这些接口

路径原因
POST /v1/user-withdrawals/prepare仅门户可用(403 portal_only)
POST /v1/user-withdrawals/{id}/resend-claim仅门户可用
公开 Claim 页 /w/:id面向门户邮件 Claim,不是服务端对接主路径

商户把自己的钱提到冷钱包,请用 MerchantPayout,不是本接口。

6. 上线前检查

  • Customer 已创建,且 external_user_id === ref_id
  • 调用 POST /v1/user-withdrawals 之前已冻结本地余额
  • 超时重试用稳定的 Idempotency-Key / Request-Id
  • 处理好 insufficient_balance、below_min_withdrawal、customer_not_found
  • complete 时确认扣款,failed 时解冻
  • Secret Key 只放在服务端

接下来可以把充值、提现的 webhook 处理收拢到同一处(见 Webhooks)。