POST /api/v1/invoices
invoices:write — Create an invoice; Idempotency-Key required.
DEVELOPER DOCUMENTATION / BITCOIN
Create invoices, track payment status, and receive signed callbacks. Customer payments go to the merchant’s wallet—not a BlockAck-held balance.
Not an engineer? Explore the payment-link and website-button guide. Payment Studio and reusable links are still in development.
Bitcoin payments require completed node and explorer synchronization, a configured merchant store, verified receiving addresses, and an end-to-end settlement check. Store provisioning alone is not payment readiness. Hosted Bitcoin checkout and self-service payment-link creation are not available yet. Examples do not execute payments.
Base URL: https://www.blockack.com. Send your scoped merchant API key as Authorization: Bearer YOUR_API_KEY. Never include API keys in public links, website buttons, browser JavaScript, or source control.
Create an account, connect your Bitcoin extended public key, configure your store, and create a scoped API key in the merchant console. You do not need a separate BTCPay account. Account-management endpoints use a merchant session token instead of this API key.
This server-side JavaScript example requests 25,000 sats. Use your local BlockAck store UUID and an API key with invoices:write. Check the effective USD-equivalent payment limit before submitting.
// Server-side only. Never expose your API key in browser code.
const response = await fetch("https://www.blockack.com/api/v1/invoices", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BLOCKACK_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": "order-1042-invoice",
},
body: JSON.stringify({
amount_sats: 25000,
store_id: process.env.BLOCKACK_STORE_ID,
metadata: { order_id: "1042" },
}),
});
const invoice = await response.json();
if (!response.ok) throw new Error(invoice.error ?? "Invoice creation failed");
// Save invoice.id and checkout_url against your order on your server.
// Confirm settlement before fulfilling; a successful POST is not payment.Send either amount_sats as a positive integer, or {"amount":"0.00025000","currency":"BTC"}. Do not combine these forms. Fractional satoshis are rejected rather than rounded. Fiat numeric amounts are also supported; currency defaults to USD when omitted.
Keep one Idempotency-Key (8–128 characters) per intended invoice. Reuse it with the same payload on retry. A completed replay returns Idempotency-Replayed: true. If creation is in progress or unresolved, investigate the original request; do not switch to a new key and risk a duplicate invoice.
These routes require merchant API authentication and the permission shown. List responses include pagination; cryptocurrency atomic amounts in ledger responses are strings.
/api/v1/invoicesinvoices:write — Create an invoice; Idempotency-Key required.
/v2/invoicesinvoices:read — List invoices; filter by store_id, status, dates, limit and offset.
/v2/invoices/{id}invoices:read — Read an invoice by local UUID or provider invoice ID.
/v2/invoices/{id}/receiptinvoices:write — Create or rotate an expiring shareable receipt after recorded BTC settlement. Requires receipt migration 023 and deployment.
/v2/invoices/{id}/receiptinvoices:write — Revoke the current receipt link for your invoice and key environment.
/v2/paymentspayments:read — Read your recorded payment ledger, not arbitrary blockchain history.
/v2/storesstores:read — List your stores and find the local store UUID.
/v2/webhookswebhooks:read — Inspect merchant callback delivery records.
/v2/webhooks/{id}/retrywebhooks:write — Requeue a failed callback delivery.
Receipt POST accepts an empty JSON object or {"expires_in_seconds":604800} (maximum 30 days). It returns reference, expires_at, and a bearer url whose page offers copy/share/download QR controls. Repeating POST invalidates the previous link; DELETE returns 204. An ineligible or inaccessible invoice returns 404.
Anyone with the link can view the original invoice amount, currency and recorded settlement time. No customer details or transaction identifiers are disclosed. This is stored settlement evidence, not fresh chain verification or a tax invoice. Donation wallet requests and example Studio products do not automatically create these receipts.
Configure a public HTTPS callback URL on your store. Local/private addresses, embedded credentials, and custom ports are rejected. Delivery is asynchronous and may be retried; do not assume events arrive once or in order.
Verify the BlockAck-Sig header: sha256= followed by the hexadecimal HMAC-SHA256 of the unmodified request body, using the callback signing secret. Compare signatures in constant time. This is not your API key or BTCPay’s inbound webhook secret. Securely arrange the signing secret with the platform operator; there is no self-service callback-secret retrieval endpoint documented here.
The envelope has id, type, and data. Handle invoice.settled, deduplicate by delivery id, and check the invoice against your server-side order record. Return a 2xx response after durable acceptance. A redirect, invoice-created response, or browser success screen is not proof of settlement.
Each merchant shares 1,000 free authorized API requests per UTC month across keys and stores. Starter is 10,000 sats/month or 96,000 sats/year. Paid access does not bypass short-window rate limits or payment-creation safety limits. The default API rate limit is 120 requests per key per 60 seconds.
Current launch defaults: $50 USD-equivalent per creation and 1,000 creations per merchant per UTC month, including paid accounts. Check your effective limits in Billing. Polling, authorized failures, and idempotent retries count toward free API usage.
400: fix invalid input; do not retry unchanged.401 / 403: check credentials, scopes and subscription access.409: resolve idempotency conflicts or uncertain creation before another attempt.422: a payment can exceed the configured amount limit.429: distinguish short-window rate limiting from a monthly creation limit.503: configuration, store readiness or conversion dependencies may be unavailable. This does not authorize accepting payments.Inspect the response’s error code. Use bounded backoff for transient failures, and preserve the original idempotency key. Never automatically mark an order paid when an API request fails.