You are integrating BlindPay payables into my application: registering Brazilian bills (boleto, arrecadacao, or PIX code) 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, boleto and PIX payables, 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. Register the bill: POST /v1/instances/{instance_id}/payables with currency BRL and exactly one of boleto_barcode (a boleto digitable line or barcode, or an arrecadacao code for utility bills and tax slips; the kind is detected from the code itself) or pix_qrcode (the PIX copia e cola payload). Optionally upload the original boleto first with POST /v1/upload?instance_id={instance_id} using bucket `documents` and pass the returned file_url as document_file; PIX payables reject it. Persist the returned pb_ ID and surface the parsed bill details (amount, due date, beneficiary) back to the user for confirmation before paying.
3. 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. For a boleto the amount is re-resolved from the rail at quote time and can move with fines, interest, or day-specific discounts, so always show the quote's receiver_amount, never a cached figure. Execute with POST /v1/instances/{instance_id}/payouts/evm before the quote's expires_at.
4. 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. Compliance holds, releases, and failure reasons arrive only on the payout events.
5. Handle the failure paths explicitly: expired or already-paid boletos, bills under the 10.00 USD minimum (LIMITS_AMOUNT_OUT_OF_RANGE at registration), a code registered twice (duplicate_payable: quote the existing payable again instead), a failed or refunded attempt that returns the payable to draft with last_attempt_status set, and quote expiry (re-quote and re-confirm with the user when the amount or rate moved).
6. 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 minor units; API keys stay server-side.
- Validate the digitable line format client-side before calling the API so users get instant feedback on typos.
- Read document_file back with POST /v1/presign?instance_id={instance_id}, which returns a one-hour signed link; upload and presign both take instance_id as a query parameter. Never expose the raw file URL.
- Boleto and PIX payables are BRL only; US vendor invoices paid by ACH or wire use the invoice payable shape instead, so do not mix them into this flow.
- Test on a development instance first; use the sentinel amounts ($666.00 forces failed, $777.00 forces refunded) to prove the failure handling.
Deliverables: payable registration service with bill-detail confirmation step, the quote-and-pay path, webhook handlers for both event streams, and an integration test that registers and pays a test payable on the development instance.