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

# Pay a Vendor Bill

> Create a vendor, record what you owe them, and pay it by ACH, check, or international wire

This is the accounts-payable workflow end to end: set up the vendor and how they get paid, record the bill, pay it from one of your payment methods on file, and track the money until it arrives. For the objects involved and the payment lifecycle, see [How Bill Payments Work](/concepts/bill-payments).

<Info>
  **Before you start**: You need a sandbox API key (see the [Quickstart](/guides/quickstart)) and at least one funding source on file — the bank accounts and cards you've connected in the Nickel dashboard. Step 4 shows where to add one. Amounts are in cents throughout.
</Info>

<Steps>
  <Step title="Create the vendor">
    A vendor is who you pay. Create one with [`POST /vendor`](/api-reference/vendor/create-a-vendor):

    ```bash theme={null}
    curl -X POST https://rest.staging.nickel.com/vendor \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Brooklyn Paper Supply",
        "emails": ["billing@brooklynpapersupply.com"],
        "type": "BUSINESS",
        "address": {"street1": "412 Atlantic Ave", "city": "Brooklyn", "state": "NY", "zip": "11217", "country": "US"}
      }'
    ```

    ```json theme={null}
    {
      "id": "cmra1j4un00013u02spto0xz7",
      "name": "Brooklyn Paper Supply",
      "emails": ["billing@brooklynpapersupply.com"],
      "address": "412 Atlantic Ave",
      "city": "Brooklyn",
      "state": "NY",
      "zip": "11217",
      "type": "BUSINESS",
      "vendorDeliveryMethods": []
    }
    ```

    <Note>
      Pass `"syncToQbo": true` to also create the vendor in QuickBooks Online if your account has it connected — see [QuickBooks](/concepts/quickbooks).
    </Note>
  </Step>

  <Step title="Add a delivery method">
    A **delivery method** is how the vendor receives funds. Set it yourself if you have their details — or better, [let the vendor enter their own bank details](/guides/collect-vendor-details) so you never handle them.

    <Tabs>
      <Tab title="ACH (bank transfer)">
        ```bash theme={null}
        curl -X PUT https://rest.staging.nickel.com/vendor/cmra1j4un00013u02spto0xz7/deliveryMethod/ach \
          -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
          -H "Content-Type: application/json" \
          -d '{"routingNumber": "101050001", "accountNumber": "5550123456", "accountType": "checking"}'
        ```
      </Tab>

      <Tab title="Check (mailed)">
        ```bash theme={null}
        curl -X PUT https://rest.staging.nickel.com/vendor/cmra1j4un00013u02spto0xz7/deliveryMethod/check \
          -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
          -H "Content-Type: application/json" \
          -d '{"street": "412 Atlantic Ave", "city": "Brooklyn", "state": "NY", "zip": "11217"}'
        ```
      </Tab>

      <Tab title="Wire (international)">
        ```bash theme={null}
        curl -X PUT https://rest.staging.nickel.com/vendor/cmra1j4un00013u02spto0xz7/deliveryMethod/wire \
          -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
          -H "Content-Type: application/json" \
          -d '{
            "swiftCode": "DEUTDEFF",
            "iban": "DE89370400440532013000",
            "countryCode": "DE",
            "recipientAddress": "Taunusanlage 12",
            "recipientCity": "Frankfurt",
            "recipientState": "HE",
            "recipientZip": "60325"
          }'
        ```

        This delivery method is an international SWIFT wire to a non-US beneficiary bank. Bill payments to it incur a \$20 fee, collected as a separate ACH debit from your funding source.

        Some destinations use country-specific fields instead of IBAN — India takes `indianAccountNumber` + `ifscCode`, China takes `chineseAccountNumber`. See the [wire endpoint reference](/api-reference/vendor-delivery-method/update-vendor-wire-delivery-method) for the full list.
      </Tab>
    </Tabs>

    <Warning>
      These endpoints return **only** `{"vendorId": "..."}` — not the delivery method. Fetch the vendor to get the `vendorDeliveryMethods[].id` you'll need when paying:
    </Warning>

    ```bash theme={null}
    curl https://rest.staging.nickel.com/vendor/cmra1j4un00013u02spto0xz7 \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY"
    ```

    ```json theme={null}
    {
      "id": "cmra1j4un00013u02spto0xz7",
      "name": "Brooklyn Paper Supply",
      "vendorDeliveryMethods": [
        {
          "id": "cmra1jcxw00033u02rdotftsr",
          "type": "ACH",
          "routingNumber": "101050001",
          "accountType": "checking",
          "bankName": "First Bank of the United States",
          ...
        }
      ],
      ...
    }
    ```
  </Step>

  <Step title="Create the bill">
    Record what you owe with [`POST /bill`](/api-reference/bill/create-a-bill):

    ```bash theme={null}
    curl -X POST https://rest.staging.nickel.com/bill \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "vendorId": "cmra1j4un00013u02spto0xz7",
        "amountCents": 3500,
        "dueDateEpochMillis": 1785542400000,
        "reason": "August paper delivery",
        "billNumber": "BPS-1042"
      }'
    ```

    <Warning>
      Bill dates are **epoch milliseconds** (`1785542400000` is 2026-08-01), unlike invoices which use `YYYY-MM-DD` strings. Mixing them up creates bills due in 1970.
    </Warning>

    ```json theme={null}
    {
      "id": "cmra1lpku000111021gzwnia4",
      "amountDueInCents": 3500,
      "totalAmountInCents": 3500,
      "vendorId": "cmra1j4un00013u02spto0xz7",
      "vendorName": "Brooklyn Paper Supply",
      "dueDate": "2026-08-01T00:00:00.000Z",
      "reference": "BPS-1042",
      "status": "Open",
      "documents": []
    }
    ```

    Note the naming shift: the `billNumber` you send comes back as `reference`. A new bill is `Open` and flips to `Paid` once a payment covers it — or as soon as one is scheduled (see step 5). The `scheduledWithdrawalDate` field distinguishes the two: non-null means scheduled, not settled.
  </Step>

  <Step title="Pick your funding source">
    A funding source is one of your **own** payment methods — the bank account or card the bill is paid from. Funding sources are added in the dashboard, not through the API: in the [Nickel dashboard](https://app.nickel.com/dashboard/settings/accounts-payable), go to **Settings → Bill Pay** and click **Add new**, then either connect a bank account (Nickel walks you through linking it with Plaid) or enter a credit card.

    Once added, list the payment methods your organization can pay from with [`GET /billPaymentMethods`](/api-reference/bill-payment-method/list-bill-payment-methods):

    ```json theme={null}
    {
      "billPaymentMethods": [
        {
          "id": "cmp0x7q6p002ntf02cktmo34p",
          "type": "ACH",
          "achDetails": {
            "bankName": "EXAMPLE BANK",
            "routingNumber": "110000000",
            "accountNumberLastFour": "7890"
          },
          ...
        }
      ]
    }
    ```

    The `id` is the `merchantPaymentMethodId` for the next step.
  </Step>

  <Step title="Pay it">
    [`POST /bill/pay`](/api-reference/bill/pay-bills) is a batch: each item names the bill, the vendor, your funding source, the vendor's delivery method, and who to notify:

    ```bash theme={null}
    curl -X POST https://rest.staging.nickel.com/bill/pay \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "payments": [
          {
            "billId": "cmra1lpku000111021gzwnia4",
            "vendorId": "cmra1j4un00013u02spto0xz7",
            "merchantPaymentMethodId": "cmp0x7q6p002ntf02cktmo34p",
            "vendorDeliveryMethodId": "cmra1jcxw00033u02rdotftsr",
            "notificationEmails": ["ap@yourcompany.com"],
            "vendorMemo": "Invoice BPS-1042"
          }
        ],
        "idempotencyKey": "bill-run-2026-07-06"
      }'
    ```

    <Warning>
      Always send an `idempotencyKey`. If the request times out and you retry with the same key, Nickel won't pay the same bills twice.
    </Warning>

    ```json theme={null}
    {
      "billPayments": [
        {
          "id": "cmra1lqiq00051102m6o0dpiq",
          "status": "PENDING",
          "amountInCents": 3500,
          "createdAt": 1783392088706,
          "vendorDeliveryMethodId": "cmra1jcxw00033u02rdotftsr",
          "billPayableId": "cmra1lpuq00031102ol4yf1a1"
        }
      ],
      "billErrors": [],
      "scheduled": []
    }
    ```

    Two things to handle in the response:

    * **Per-bill failures** land in `billErrors[]` (`{billId, error}`) while valid items still go through — check it on every call. Bills that are already paid, or that already have a pending scheduled payment, are reported here too (they no longer fail the whole batch) and are omitted from `billPayments[]` so any pre-existing payments on those bills aren't surfaced as if this batch created them.
    * **Batch-level problems** — like malformed input — fail the whole request with a top-level `{"error": "..."}` instead.

    **Scheduling**: add `withdrawalDateEpochMillis` (when to debit you) or `arrivalDateEpochMillis` (when it should reach the vendor — Nickel back-computes the withdrawal date from the payment rail's delivery time; dates too soon for the rail are rejected). A scheduled item creates **no bill payment until the withdrawal day** — instead the response acknowledges it in `scheduled`:

    ```json theme={null}
    {
      "billPayments": [],
      "billErrors": [],
      "scheduled": [{ "billId": "cmra1lpku000111021gzwnia4", "withdrawalDate": "2026-07-10" }]
    }
    ```

    While it's pending, `GET /bill/{billId}` reports the day in `scheduledWithdrawalDate` (and the bill already reads `status: "Paid"`, even though nothing has moved yet). No webhook fires at scheduling time. On the withdrawal day the payment executes and rejoins the flow below — a real bill payment appears and `bill_payment.succeeded` or `bill_payment.failed` fires. A failed scheduled payment is not retried: the bill returns to `Open` and you submit a new `POST /bill/pay`. See [Scheduled payments](/concepts/bill-payments#scheduled-payments) for the full contract.
  </Step>

  <Step title="Track it">
    Poll [`GET /billPayment/{billPaymentId}`](/api-reference/bill/get-a-bill-payment-by-id) or subscribe to [webhooks](/guides/receive-webhooks): `bill_payment.succeeded`, `bill_payment.failed`, and `bill_payment.cancelled`, plus the check lifecycle (`check.sent` → `check.delivered` → `check.deposited`, with `check.returned` / `check.failed` for problems) when paying by mailed check. An ACH bill payment sits in `PENDING` while the debit and transfer run their course — see [the lifecycle](/concepts/bill-payments#bill-payment-lifecycle).
  </Step>

  <Step title="Cancel if you need to">
    A payment that hasn't been sent to the payment network yet can be stopped with [`POST /billPayment/{billPaymentId}/cancel`](/api-reference/bill/cancel-a-bill-payment):

    ```bash theme={null}
    curl -X POST https://rest.staging.nickel.com/billPayment/cmra1lqiq00051102m6o0dpiq/cancel \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY"
    ```

    ```json theme={null}
    {
      "id": "cmra1lqiq00051102m6o0dpiq",
      "status": "FAILED",
      "amountInCents": 3500,
      ...
    }
    ```

    <Note>
      A cancelled payment currently reports `status: "FAILED"` — the same terminal status as a genuine failure. Use the `bill_payment.cancelled` webhook (or the fact that you called cancel) to tell the two apart.
    </Note>

    A **scheduled** payment has no bill payment to cancel yet — cancel it through its bill instead with [`POST /bill/{billId}/cancelScheduledPayment`](/api-reference/bill/cancel-a-bills-scheduled-payment):

    ```bash theme={null}
    curl -X POST https://rest.staging.nickel.com/bill/cmra1lpku000111021gzwnia4/cancelScheduledPayment \
      -H "Authorization: Bearer $NICKEL_SANDBOX_KEY"
    ```

    The response is the refreshed bill — `status` back to `Open`, `scheduledWithdrawalDate` back to null. A `404` means there's no pending scheduled payment to cancel: it never existed, it already executed, or it was already cancelled (cancellation emits no webhook, so check `GET /bill/{billId}` when in doubt).
  </Step>
</Steps>

<Note>
  Bills and bill payments you create through the API are **never** written to QuickBooks. Paying a bill that was *imported from* QuickBooks is — see [QuickBooks](/concepts/quickbooks) for the full table.
</Note>

## Where to go next

<Columns cols={2}>
  <Card title="Collect vendor bank details" href="/guides/collect-vendor-details" icon="envelope-open-text">
    Let vendors enter their own details on a secure form.
  </Card>

  <Card title="Receive webhooks" href="/guides/receive-webhooks" icon="bolt">
    Hear about bill\_payment and check events as they happen.
  </Card>

  <Card title="How bill payments work" href="/concepts/bill-payments" icon="money-bill-transfer">
    The objects and lifecycle behind this guide.
  </Card>

  <Card title="QuickBooks" href="/concepts/quickbooks" icon="book">
    What does and doesn't appear in your books.
  </Card>
</Columns>
