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

# 创建付款

> 从预存余额向收款方发送资金

## 前提条件

创建付款之前，您需要：

1. **预存账户** — 通过 `POST /api/v2/customers/pre-fund/create` 创建
2. **足够的余额** — 通过 `GET /api/v2/customers/balances` 验证
3. **收款方详情** — 收款人的银行账户、钱包地址或支付别名

<Card title="设置预存账户" icon="vault" href="/zh/guides/pre-fund/pre-fund-accounts">
  还没有预存账户？从这里开始。
</Card>

## 完整付款流程

<Steps>
  <Step title="检查可用余额">
    在提交付款前确认有足够资金。

    ```bash theme={null}
    GET /api/v2/customers/balances
    ```

    ```json 响应 theme={null}
    [
      {
        "id": "balance-id",
        "currency": "COP",
        "amount": "10000000.00",
        "accountId": "prefund-account-id"
      }
    ]
    ```
  </Step>

  <Step title="创建付款">
    提交包含预存账户、金额和收款方的付款请求。

    ```bash theme={null}
    POST /api/v2/payouts
    ```
  </Step>

  <Step title="跟踪状态">
    轮询付款或监听 webhooks，直到达到终态（`COMPLETED`、`FAILED`、`REJECTED`、`ERROR` 或 `REFUNDED`）。
  </Step>
</Steps>

## 实现示例

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://sandbox.killb.app/api/v2/payouts \
    -H "Authorization: Bearer 您的TOKEN" \
    -H "Content-Type: application/json" \
    -H "Idempotency-Key: payout-2024-001" \
    -d '{
      "preFundAccountId": "prefund-account-id",
      "amount": 500000,
      "externalId": "payout-2024-001",
      "beneficiary": {
        "type": "BANK",
        "account": {
          "firstName": "Maria",
          "lastName": "Garcia",
          "email": "maria@example.com",
          "phone": "3001234567",
          "document": { "type": "CC", "number": "12345678" },
          "accountNumber": "123456789",
          "bankCode": "001",
          "type": "savings",
          "countryCode": "CO"
        }
      }
    }'
  ```

  ```javascript Node.js theme={null}
  const createPayout = async (preFundAccountId, amount, beneficiary) => {
    const response = await fetch(
      'https://sandbox.killb.app/api/v2/payouts',
      {
        method: 'POST',
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          preFundAccountId,
          amount,
          beneficiary
        })
      }
    );

    if (!response.ok) {
      const error = await response.json();
      throw new Error(`付款失败: ${JSON.stringify(error)}`);
    }

    return response.json();
  };

  // 示例：通过 Bank Transfer 发送 500,000 COP
  const payout = await createPayout(
    'prefund-account-id',
    500000,
    {
      type: 'BANK',
      account: {
        firstName: 'Maria',
        lastName: 'Garcia',
        email: 'maria@example.com',
        phone: '3001234567',
        document: { type: 'CC', number: '12345678' },
        accountNumber: '123456789',
        bankCode: '001',
        type: 'savings',
        countryCode: 'CO'
      }
    }
  );

  console.log('付款 ID:', payout.id);
  console.log('状态:', payout.status);
  ```

  ```python Python theme={null}
  import requests

  def create_payout(pre_fund_account_id, amount, beneficiary, access_token):
      response = requests.post(
          'https://sandbox.killb.app/api/v2/payouts',
          headers={
              'Authorization': f'Bearer {access_token}',
              'Content-Type': 'application/json',
              'Idempotency-Key': f'payout-{pre_fund_account_id}-{amount}'
          },
          json={
              'preFundAccountId': pre_fund_account_id,
              'amount': amount,
              'beneficiary': beneficiary
          }
      )
      response.raise_for_status()
      return response.json()

  # 示例：通过 Bank Transfer 发送 500,000 COP
  payout = create_payout(
      pre_fund_account_id='prefund-account-id',
      amount=500000,
      beneficiary={
          'type': 'BANK',
          'account': {
              'firstName': 'Maria',
              'lastName': 'Garcia',
              'email': 'maria@example.com',
              'phone': '3001234567',
              'document': {'type': 'CC', 'number': '12345678'},
              'accountNumber': '123456789',
              'bankCode': '001',
              'type': 'savings',
              'countryCode': 'CO'
          }
      },
      access_token=token
  )

  print(f"付款已创建: {payout['id']} — {payout['status']}")
  ```
</CodeGroup>

**响应：**

```json theme={null}
{
  "id": "payout-abc123",
  "amount": 500000,
  "currency": "COP",
  "status": "PENDING",
  "externalId": "payout-2024-001",
  "beneficiary": {
    "type": "BANK",
    "account": { ... }
  },
  "createdAt": "2024-01-15T10:30:00.000Z",
  "updatedAt": "2024-01-15T10:30:00.000Z"
}
```

## 收款方类型

<Tabs>
  <Tab title="Bank Transfer（哥伦比亚）">
    通过 Bank Transfer 系统进行标准哥伦比亚银行账户转账。

    ```json theme={null}
    {
      "type": "BANK",
      "account": {
        "firstName": "Maria",
        "lastName": "Garcia",
        "email": "maria@example.com",
        "phone": "3001234567",
        "document": {
          "type": "CC",
          "number": "12345678"
        },
        "accountNumber": "123456789",
        "bankCode": "001",
        "type": "savings",
        "countryCode": "CO"
      }
    }
    ```

    **必填字段：** `firstName` 或 `companyName`、`lastName`、`email`、`phone`、`document`、`accountNumber`、`bankCode`、`type`、`countryCode`

    使用 `GET /api/v2/banks` 查询有效的 `bankCode` 值。
  </Tab>

  <Tab title="BREB（哥伦比亚）">
    通过已注册的别名（手机号、邮箱、身份证或 BREB 别名）付款。

    ```json theme={null}
    {
      "type": "BREB",
      "account": {
        "firstName": "Carlos",
        "lastName": "Lopez",
        "email": "carlos@example.com",
        "phone": "3109876543",
        "document": {
          "type": "CC",
          "number": "87654321"
        },
        "aliasType": "PHONE",
        "alias": "3109876543",
        "countryCode": "CO"
      }
    }
    ```

    **别名类型：** `NATIONAL_ID`、`PHONE`、`EMAIL`、`ALPHANUMERIC`、`BUSINESS_ID`
  </Tab>
</Tabs>

## 付款前检查余额

在发送大额付款之前，始终验证可用余额：

```javascript theme={null}
const checkBalance = async (preFundAccountId, requiredAmount) => {
  const balances = await fetch('/api/v2/customers/balances', {
    headers: { 'Authorization': `Bearer ${token}` }
  }).then(r => r.json());

  const account = balances.find(b => b.accountId === preFundAccountId);

  if (!account || parseFloat(account.amount) < requiredAmount) {
    throw new Error(
      `余额不足。可用: ${account?.amount ?? 0}，需要: ${requiredAmount}`
    );
  }

  return account;
};
```

## 幂等性

为防止网络重试时产生重复付款，每次创建付款请求时请传入唯一的 `Idempotency-Key` 请求头。如果相同的 key 被接收两次，KillB 将返回原始付款而不是创建新记录。

```bash theme={null}
Idempotency-Key: <您的唯一付款参考>
```

<Tip>
  使用稳定唯一的标识符作为 key——您的内部付款 ID 或与业务交易绑定的 UUID 都是好的选择。
</Tip>

## 查询付款列表

使用可选筛选条件获取所有付款记录：

```javascript theme={null}
const listPayouts = async ({ status, externalId, page = 1, limit = 20 } = {}) => {
  const params = new URLSearchParams({ page, limit });
  if (status) params.set('status', status);
  if (externalId) params.set('externalId', externalId);

  const response = await fetch(
    `https://sandbox.killb.app/api/v2/payouts?${params}`,
    { headers: { 'Authorization': `Bearer ${token}` } }
  );

  return response.json(); // { payouts: [...], totalPage: N }
};

// 获取所有待处理的付款
const pending = await listPayouts({ status: 'PENDING' });
```

## 下一步

<CardGroup cols={2}>
  <Card title="状态跟踪" icon="chart-line" href="/zh/guides/payouts/payout-status">
    通过轮询和 webhooks 监控付款
  </Card>

  <Card title="配置 Webhooks" icon="bell" href="/zh/guides/webhooks/setup">
    配置 PAYOUT webhook 通知
  </Card>
</CardGroup>
