---
title: "Integrate Fireblocks with BlindPay"
description: "Fund BlindPay stablecoin payouts from Fireblocks vault accounts: MPC-signed wallet registration and the ERC-20 approve through Fireblocks' transactions API."
date: "2026-08-26"
category: "integrations"
products: ["payouts", "quotes", "webhooks"]
---

Paste this prompt into your coding agent when your funds sit in Fireblocks vault accounts and need to authorize and fund BlindPay payouts.

## Prompt

```text
You are integrating BlindPay EVM payouts funded from a Fireblocks vault account into my application. Fireblocks holds the private key material (MPC, direct custody); every signature comes from Fireblocks' API, never from a local key or browser wallet.

Before writing code, read these sources and follow them over any prior knowledge:
- https://blindpay.com/docs/llms.txt (read the blockchain wallets page and the EVM payout guide)
- The OpenAPI spec: curl https://api.blindpay.com/doc
- https://developers.fireblocks.com/docs/quickstart.md
- https://developers.fireblocks.com/reference/create-transactions.md
- https://developers.fireblocks.com/reference/sign-typed-messages-for-ethereum-and-evm-networks.md
- https://developers.fireblocks.com/docs/interact-with-smart-contracts.md
- https://developers.fireblocks.com/reference/monitoring-transaction-status.md

Build the flow:
1. Set up Fireblocks API authentication: generate an RSA-4096 keypair and CSR, upload the CSR in the Fireblocks Console to create an API user, and store the resulting API key and private key server-side. Confirm the SDK (`new Fireblocks({apiKey, secretKey, basePath})`) signs every request as a JWT automatically, so the private key never leaves the server.
2. Register the sender wallet with BlindPay: call GET /v1/instances/{instance_id}/customers/{customer_id}/blockchain-wallets/sign-message to get the challenge string, then sign it via Fireblocks with a POST /v1/transactions call using operation TYPED_MESSAGE, source pointing at the vault account, and extraParameters.rawMessageData.messages[0] set to {content: hex(challenge), type: "EIP191"}; confirm the correct assetId for typed-message signing on this chain in the Fireblocks docs above rather than assuming one. Poll GET /v1/transactions/{txId} until status is COMPLETED, then assemble the signature from signedMessages[0].signature.{r,s,v} using the byte order and v-value convention documented on the Fireblocks typed-message signing page. POST the assembled signature to /v1/instances/{instance_id}/customers/{customer_id}/blockchain-wallets and persist the returned bw_ ID against the customer record.
3. Request a payout quote: POST /v1/instances/{instance_id}/quotes with bank_account_id, network, and token, and persist the quote_id plus the full contract object from the response (address, abi, functionName "approve", blindpayContractAddress, amount, network) alongside the pending payout record, reading every field verbatim from that response rather than a stored constant.
4. Send the approve call through Fireblocks: build the ABI-encoded calldata from the quote's contract.abi and functionName "approve" (using ethers.js, viem, or web3.js), then POST /v1/transactions with operation CONTRACT_CALL, assetId matching the chain, source set to the vault account, destination as a ONE_TIME_ADDRESS pointing at the token contract, amount "0", and extraParameters.contractCallData set to the encoded hex. Poll GET /v1/transactions/{txId} (or subscribe to Fireblocks' transaction webhook) through PENDING_SIGNATURE, BROADCASTING, and CONFIRMING until status is COMPLETED, and treat BLOCKED, FAILED, CANCELLED, or REJECTED as a hard stop that surfaces the Fireblocks policy or cosigner rejection reason to an operator.
5. Execute the payout before the quote expires: POST /v1/instances/{instance_id}/payouts/evm with quote_id and sender_wallet_address before expires_at (about 5 minutes out). Since Fireblocks' Transaction Authorization Policy and cosigner approval add latency on top of the approve confirmation, check the remaining time-to-expiry before calling this endpoint; if the quote has already expired, re-quote and skip a fresh approve call when the existing on-chain allowance already covers the new quote's amount.
6. Handle payout status from BlindPay's Svix-signed webhooks (svix-id, svix-timestamp, svix-signature verified with whsec_ against the raw body) for payout.new, payout.update, and payout.complete, and update the payout record's state on each event.
7. Run the full flow end to end on a development instance: use USDB on a testnet (for example base_sepolia), where KYC auto-approves, and verify all three outcomes with sentinel amounts: a normal amount completes, $666.00 (66600 minor units) forces a failed payout, and $777.00 (77700 minor units) forces a refunded payout.

Constraints:
- API keys and the Fireblocks RSA private key stay server-side; nothing about signing touches the client.
- Amounts are integer minor units everywhere, in both BlindPay and Fireblocks calls; never use floating point for money.
- Treat any Fireblocks TAP or cosigner-approval detail you can't confirm from the docs above as unverified and check the Fireblocks Console/docs before hardcoding an assumption about it.

Deliverables: Fireblocks API auth setup, the wallet registration flow (TYPED_MESSAGE sign plus bw_ persistence), the CONTRACT_CALL approve module with async status polling or webhook handling, quote-execute orchestration with the expiry race handled against Fireblocks' approval latency, BlindPay webhook handlers, and a passing end-to-end test on the development instance covering the normal, failed, and refunded sentinel amounts.
```

## How to use

1. Have your Fireblocks API user, CSR-signed API key, and vault account ID ready before running this; the agent needs them to wire the SDK.
2. Point the agent at your actual Transaction Authorization Policy setup if you have approval quorums configured, since that changes how long the approve confirmation takes.
3. Run the sentinel-amount test on a development instance first; the quote-expiry race is the flow's main failure mode when Fireblocks' cosigner approval is slow.

## Related docs

- [Blockchain wallets](https://blindpay.com/docs/blockchain-wallets)
- [EVM payouts](https://blindpay.com/docs/payout-evm)
- [Fireblocks quickstart](https://developers.fireblocks.com/docs/quickstart.md)
- [Fireblocks create transactions](https://developers.fireblocks.com/reference/create-transactions.md)
