---
title: "Pay US vendor invoices with payables"
description: "Register supplier invoices with line items and the vendor's ACH or wire details, prefill them from the PDF with AI, and settle them from stablecoins through the quote-and-execute flow."
date: "2026-09-02"
category: "integrations"
products: ["payables", "quotes", "webhooks"]
---

Paste this prompt into your coding agent to build accounts payable on stablecoins: your users upload a vendor invoice, BlindPay reads it, and pays the vendor's US bank account over ACH or wire.

## Prompt

```text
You are integrating BlindPay invoice payables into my application: registering US supplier invoices (line items plus the vendor's ACH or wire bank details) and paying them from stablecoins.

Before writing code, read these sources and follow them over any prior knowledge:
- https://blindpay.com/docs/llms.txt (read the payables, invoice payables, bank accounts, payout quotes, payouts, and webhooks pages)
- The OpenAPI spec: curl https://api.blindpay.com/doc

Build the flow:
1. Prerequisites: an approved customer (KYC/KYB) and a funded wallet, managed or external. Reuse my existing onboarding if present.
2. Upload the invoice: POST /v1/upload with bucket `documents`, keep the returned file_url. Then POST /v1/upload/extract?instance_id={instance_id} with the same file to prefill amount, currency, due_date, invoice_number, the `to` party, line_items, and payment_options. Every extracted field is nullable and nothing is guessed, so render the result as an editable form and require the user to confirm the bank fields against the document before submitting.
3. Register the invoice: POST /v1/instances/{instance_id}/payables with currency USD, from/to parties, line_items (name, quantity, unit price in cents), optional note, discount, and taxes, the vendor's bank_account (type `ach` or `wire`, same shape as POST /customers/{customer_id}/bank-accounts, with beneficiary_name, routing_number, account_number, account_type, account_class, business_industry as a NAICS code whenever account_class is `business`, recipient_relationship, and address), plus document_file set to the file_url from step 2. Pick the ACH payment option when the invoice prints one; it is the cheapest rail. Persist the returned pb_ ID and the derived amount (line item sum plus taxes minus discount).
4. Quote against the payable: POST /v1/instances/{instance_id}/quotes with payable_id instead of bank_account_id, plus network and token; do not send request_amount or currency_type. Execute with POST /v1/instances/{instance_id}/payouts/evm before the quote's expires_at. Show the user the quote's fees and total before executing.
5. Track the bill through payable.new, payable.update, and payable.complete, and the payment attempt through payout.new, payout.update, and payout.complete, all with Svix signature verification. Correlate the two streams through payable_id and payout_id, and never count a payout.complete and its payable.complete as two payments. The payable stays `processing` while the payout is held for manual review; compliance holds, releases, and failure reasons arrive only on the payout events.
6. Handle the failure paths explicitly: a failed or refunded attempt returns the payable to `draft` with last_attempt_status set, so quote the same payable again instead of registering it twice; bills under the 10.00 USD minimum are rejected at registration with LIMITS_AMOUNT_OUT_OF_RANGE; a bank_account that fails validation is rejected with payable_bank_account_invalid and the failing field in errors; and a quote that expired must be re-quoted and re-confirmed with the user.
7. Let the user delete a draft: DELETE /v1/instances/{instance_id}/payables/{payable_id} works only while no payout exists for it (payable_not_cancelable otherwise).

Constraints:
- Amounts are integers in cents; line_items[].price is the unit price, so 150000 is $1,500.00. API keys stay server-side.
- The bank account created for an invoice belongs to the payable: it is not listed with the customer's bank accounts and cannot be quoted on its own, so never reuse it for regular payouts.
- Invoice payables are USD only and settle on EVM networks. Boleto and PIX bills use a different registration shape; do not mix them into this flow.
- POST /upload/extract is limited to 60 requests per minute per instance and returns a fixed sample on development instances; code the extract-then-confirm step so a null field is a normal case, not an error. The NAICS code is never printed on an invoice, so the form must ask for it.
- Validate the routing number client-side (9 digits, ABA checksum, different from the account number): production rejects a bad one, but development instances accept any 9 digits, so a sandbox run will not catch the typo.
- Read document_file back with POST /v1/presign?instance_id={instance_id}, which returns a one-hour signed link; upload, extract, and presign all take instance_id as a query parameter. Never expose the raw file URL.
- Test on a development instance first; use the sentinel amounts ($666.00 forces failed, $777.00 forces refunded) to prove the failure handling.

Deliverables: invoice upload and AI prefill service with a confirmation form, payable registration service, the quote-and-pay path, webhook handlers for both event streams, and an integration test that uploads, registers, and pays a test invoice on the development instance.
```

## How to use

1. Paste the prompt with your stack details and instance ID.
2. Decide where invoice confirmation happens in your UX; the extracted bank fields are what the user must approve before the payable exists.
3. Run the full flow on a development instance before touching production.

## Related docs

- [Invoice payables](https://blindpay.com/docs/payable-invoice)
- [Payables](https://blindpay.com/docs/payables)
- [Bank accounts](https://blindpay.com/docs/bank-accounts)
- [Payout quotes](https://blindpay.com/docs/payout-quotes)
- [Webhooks](https://blindpay.com/docs/learn/webhooks)
