BTCPay Server Greenfield API Create Invoice Webhook Documentation: Complete Guide

BTCPay Server Greenfield API Create Invoice Webhook Documentation

For a closer look at the topic, consider btcpay server greenfield api create invoice alongside the options and criteria discussed below.

BTCPay Server provides a self-hosted, open-source payment infrastructure that gives merchants full control over cryptocurrency transactions. The Greenfield API is the modern REST interface for interacting with BTCPay Server programmatically. Creating invoices through this API and setting up webhook notifications forms the backbone of any automated crypto payment integration. This guide walks through the entire flow — from generating an invoice to receiving and validating webhook events — using practical examples across multiple languages.

Whether you are building a custom checkout flow or connecting an existing e-commerce platform, understanding how the btcpay server greenfield api create invoice mechanism works alongside webhooks will save significant development time and prevent common integration pitfalls.

Why Use the Greenfield API for Invoice Creation

The Greenfield API replaced the original BitPay-compatible API in 2020. It exposes every feature available in the BTCPay Server UI through predictable REST endpoints. Unlike the older API, which was designed primarily for compatibility, Greenfield was built from the ground up to support programmatic automation.

Key advantages include versioned endpoints under /api/v1/, JSON request and response bodies, token-based authentication, and full coverage of store operations. Because the API mirrors the UI’s capabilities, anything you can do manually — creating invoices, managing refunds, configuring webhooks — can be scripted.

Authentication and API Key Setup

Before creating invoices or registering webhooks, you need a properly scoped API key. Navigate to Account > Manage account > API keys in your BTCPay Server instance to generate one. For invoice creation and webhook management, the minimum required permissions are:

Permission Scope Required Capability
btcpay.store.cancreateinvoice Create new invoices
btcpay.store.canviewinvoices View invoice details
btcpay.store.canmodifyinvoices Modify and refund invoices
btcpay.store.webhooks.canmodifywebhooks Register and update webhooks
btcpay.store.canviewstoresettings Access store configuration
btcpay.store.cancreatenonapprovedpullpayments Create pull payments

Scope each API key to the specific store(s) it needs access to. Avoid granting broad administrative permissions when a narrower scope suffices. Store your API key securely on the server side — never expose it in browser code or client-side scripts.

Creating an Invoice Programmatically

Invoice creation uses the POST /api/v1/stores/{storeId}/invoices endpoint. The request body accepts several parameters, but the core fields are amount, currency, and optional metadata.

curl --fail-with-body \
  -X POST \
  -H "Authorization: token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  --data '{"amount":"10.00","currency":"USD","metadata":{"orderId":"ORDER-123"}}' \
  "https://your-btcpay.example/api/v1/stores/YOUR_STORE_ID/invoices"

The response returns an invoice object containing the unique id, a checkoutLink for redirecting customers, and the current status. Store the invoice ID alongside your order record — you will need it to correlate incoming webhook events with your internal data.

Minimal Invoice Request Fields

Field Type Required Description
amount string Yes Invoice amount in the specified currency
currency string Yes Currency code (e.g., USD, EUR, GBP)
metadata.orderId string No Your internal order identifier
metadata.buyerEmail string No Customer email address
redirectURL string No URL to redirect after payment
paymentTiming integer No Seconds before the invoice expires

Keep customer data minimal on the invoice itself. Storing redundant information increases exposure risk if the invoice data is ever compromised. An order ID is typically sufficient to correlate records between systems.

Registering Webhooks for Invoice Events

Webhooks notify your backend when invoice state changes occur. You can register them programmatically via the POST /api/v1/stores/{storeId}/webhooks endpoint or manually through the BTCPay Server UI under Settings > Webhooks.

curl -s \
  -H "Authorization: token YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{"url":"https://example.com/webhook","subscribedEvents":["InvoicePaid"]}' \
  "https://your-btcpay.example/api/v1/stores/YOUR_STORE_ID/webhooks"

The response includes a secret value. Save this secret immediately — it is used to verify incoming webhook signatures and is not displayed again.

Available Webhook Event Types

Event Name Trigger Condition
InvoiceCreated A new invoice is generated
InvoiceReceivedPayment Payment detected in the mempool (unconfirmed)
InvoiceReceivedBTC Payment confirmed on-chain
InvoiceModified Invoice data has been updated
InvoicePaymentSettled Payment is fully confirmed and settled
InvoiceExpired Invoice passed its expiration time without full payment
InvoiceInvalid Payment window elapsed or funds overpaid
InvoiceSettled Invoice reached final settled state

You can subscribe to all events by passing null for subscribedEvents, or specify a subset. Filtering reduces unnecessary payload deliveries and simplifies event handling logic.

Validating Incoming Webhook Payloads

Every webhook delivery includes a BTCPay-Sig header containing an HMAC-SHA256 signature computed over the raw request body using your webhook secret. Always validate this signature before processing any event data.

const crypto = require('crypto');

function verifyWebhookSignature(rawBody, sigHeader, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(Buffer.from(rawBody))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(sigHeader),
    Buffer.from(expected)
  );
}

Use a constant-time comparison function like timingSafeEqual to prevent timing attacks. Do not parse or act on the JSON payload until the signature check passes. Each webhook payload contains an invoiceId property that links the event to a specific invoice.

Processing Webhook Events Safely

Once validated, process the event based on the type field in the payload. Different events map to different business actions — marking an order as paid, shipping goods, or sending confirmation emails.

Two critical practices protect against incorrect state transitions:

  1. Idempotency: Process the same event multiple times safely. BTCPay Server retries failed deliveries after 10 seconds, 1 minute, and up to six times over 10 minutes. Your handler should track processed invoice IDs and skip duplicates.

  2. Independent settlement verification: Never trust a payment notification alone. After receiving an InvoicePaid or InvoiceReceivedBTC event, call GET /api/v1/stores/{storeId}/invoices/{invoiceId} to confirm the invoice status is truly Settled. Partial payments, overpayments, and edge cases mean that a received payment does not always equal final settlement.

Common Invoice States

Status Meaning Action
WaitingForPayment Invoice created, awaiting transaction Monitor for payment events
Processing Payment received, confirming Wait for confirmations
Settled Payment confirmed and finalized Fulfill order, ship product
Expired Invoice expired before payment Mark as unpaid, optionally retry
Invalid Overpaid or payment window elapsed Review and reconcile manually

Testing and Debugging Your Integration

BTCPay Server includes built-in tools for testing webhook integrations without moving real funds. On the invoice details page, you can manually re-trigger webhook events to verify your endpoint handles payloads correctly. Use a tunneling service like ngrok to expose your local development server to BTCPay Server during testing.

When debugging, log the raw request body alongside the parsed payload. This makes it easier to reproduce signature verification issues and inspect the exact bytes that were hashed. Check the additionalStatus field on the invoice object for nuanced states that standard status values do not capture — such as partial payments or overpayments.

Refunding Invoices Through the API

Greenfield supports both full and partial refunds through the POST /api/v1/stores/{storeId}/invoices/{invoiceId}/refund endpoint. Specify the cryptocurrency network and whether the refund applies to the full amount or a portion. Refunds broadcast directly from your store’s wallet; they do not involve any third-party intermediary.