settlematic
Guides··15 min read·By Keshav Sharma

Crypto Invoicing API: Invoice Paid Webhooks and Integration Patterns

Integrate crypto invoicing with your backend using REST APIs and invoice.paid webhooks — HMAC verification, idempotency, retry logic, and fulfillment automation patterns.

Do this next

Create a crypto invoice

  1. Quote the invoice in fiat.
  2. Client pays USDC, USDT, or EURC.
  3. Funds settle to a wallet you already control.

TL;DR

The crypto invoicing API lets you create fiat-quoted invoices programmatically; invoice.paid webhooks fire after on-chain confirmation with tx hash, amount, network, and invoice metadata. Verify HMAC signatures, process idempotently, and use webhooks to trigger fulfillment — license keys, API access, ERP journals — without polling block explorers. Full reference at /developers; test in demo. Product: Settlematic Collect.

Settlematic webhook endpoint setup subscribing to invoice and payment events for automation

Manual invoice workflows break at scale. SaaS platforms issuing hundreds of usage invoices, marketplaces settling seller payouts, and engineering orgs closing milestone billing all need the same primitive: when this invoice pays on-chain, tell my backend reliably.

Webhooks are that primitive. This guide covers API invoice creation, webhook payload structure, security verification, integration patterns, and failure handling — the material your backend team needs before production.

API + webhook architecture

Polling GET /invoices/:id works for prototypes. Webhooks work for production — lower latency, less load, event-driven architecture.

Related: crypto payment webhooks reconciliation for broader gateway patterns; this article focuses on invoicing specifically.

Creating invoices via API

Typical request shape (illustrative — confirm against /developers):

Response includes:

FieldUse
idStore for webhook matching
payment_urlRedirect customer or embed link
statusopen → paid → expired
deposit_addressPer-network addresses if exposed
amount_displayFiat-formatted string for emails

Store id and metadata before returning payment URL to client. Webhook will echo these fields.

Idempotency

Send Idempotency-Key header on create to prevent duplicate invoices when your job retries:

Same key within 24 hours returns original invoice — critical for queue workers that at-least-once deliver.

Invoice paid webhook payload

When on-chain detection confirms payment:

Fields your fulfillment logic needs:

  • invoice_id — primary key for status update
  • transaction_hash — audit trail, explorer link
  • metadata — your correlation IDs
  • amount_crypto vs amount_fiat — verify expected payment
  • network — route to correct explorer/parser

HMAC signature verification

Never process unverified webhooks. Settlematic signs payloads with shared secret:

Implementation checklist:

  • Read raw body before JSON parse (signature is over raw bytes)
  • Extract signature from header (e.g., X-Settlematic-Signature)
  • Constant-time comparison
  • Reject if timestamp skew > 5 minutes (replay protection if timestamp included)

Rotate webhook secrets periodically; support dual secrets during rotation window.

Idempotent webhook processing

Webhooks deliver at least once. Your handler must tolerate duplicates:

Use invoice_id + transaction_hash as natural idempotency key if event IDs unavailable.

Return 2xx quickly — heavy work belongs in async queue. Timeouts cause retries that amplify duplicate risk if idempotency weak.

Integration patterns

Pattern 1: SaaS license unlock

Map metadata.internal_user_id to user record. Set plan=pro, valid_until=+1 year.

Pattern 2: ERP journal entry

Include tx hash in memo field. Finance reconciles blockchain receipt to GL.

Pattern 3: Marketplace seller notification

Non-custodial: seller already received funds on-chain; webhook triggers operational workflow only.

Pattern 4: Remote team milestone

See crypto invoicing for remote dev teams.

Pattern 5: Recurring billing cycle

Pair with recurring crypto invoices.

Polling fallback

Implement GET /invoices/:id poll every 60s as backup when:

  • Webhook endpoint down during maintenance
  • Firewall misconfiguration discovered post-deploy
  • Local dev without tunnel (use ngrok / Cloudflare tunnel for webhook dev)

Webhook primary; poll safety net. Do not poll block explorers directly — invoice API abstracts chain variance.

Error handling and retries

Your responsePlatform behavior
2xxSuccess; no retry
4xx (except 429)Usually no retry — fix handler
5xx / timeoutRetries with exponential backoff
429Retry after delay

Log failed webhook deliveries to alerting. Dashboard replay button (if available) or manual poll after fix.

Testing in sandbox

Before mainnet:

  • Create demo / sandbox API keys
  • Create test invoice via API
  • Pay with testnet USDC
  • Capture webhook with request bin or tunnel
  • Verify signature validation code
  • Confirm idempotency on replayed delivery

Test crypto payments sandbox covers environment setup.

Security hardening

RiskMitigation
Forged webhookHMAC verification
Replay attackTimestamp tolerance + idempotency store
Secret leakRotate secret; audit logs
SSRF from webhook handlerDo not fetch user-controlled URLs on webhook receipt
Invoice amount tamperingVerify amount in webhook matches your order record

Crypto payment security best practices apply to integration layer.

Observability

Log structured fields:

  • invoice_id, event, transaction_hash, network
  • Processing duration
  • Idempotency skip vs fresh process

Metrics: webhook lag (paid_at → processed_at), failure rate, duplicate rate.

Alert if lag exceeds SLA — customer waiting for license key while payment confirmed on-chain erodes trust.

API authentication

Production API keys via Bearer token or signed requests — see /developers. Separate keys per environment (sandbox vs production). Never commit keys; use secret manager.

Scoped permissions: invoice create/read vs admin settlement config.

Partial and failed payment events

Additional events (names illustrative):

EventAction
invoice.partially_paidNotify collections; hold fulfillment
invoice.expiredCancel pending order
invoice.createdAnalytics only

Subscribe only to events you handle — reduces noise.

Non-custodial implication for webhooks

Webhook confirms detection of payment to your bound address — not custody release. Unlike custodial processors, there is no "payout completed" event because funds never entered platform custody. Your fulfillment obligation may start at detection; funds are already yours on-chain.

Understand custodial vs non-custodial to set internal policy correctly.

Comparison: build vs buy chain monitoring

ApproachCostComplexity
DIY RPC + indexer + reorg handlingEngineering monthsHigh
Settlematic API + webhooksSubscriptionLow

DIY makes sense at hyperscale with dedicated blockchain team. Everyone else ships product faster with invoicing API.

Webhook delivery guarantees and SLAs

Production webhook expectations:

MetricReasonable SLA
Delivery after detection<30 seconds p95
Retry window24–72 hours exponential backoff
Max retries10–20 attempts
Dead letterDashboard alert after exhaustion

Implement monitoring on your endpoint — 5xx rates during deploys cause retry storms. Use blue-green deploy or queue webhooks during maintenance.

Rate limits and batch invoice creation

API rate limits protect platform stability:

OperationTypical limit strategy
POST /invoices100/min per API key
GET /invoices/:id1000/min
Webhook deliveriesPlatform-controlled

Batch billing run at month-end: queue invoice creation with backoff; use idempotency keys per row. Burst creation without keys duplicates invoices when worker retries.

Versioning and backward compatibility

Webhook payload fields may expand — design consumers to ignore unknown fields (forward compatibility). Pin API version in URL path (/v1/) and subscribe to changelog for breaking changes.

Never branch fulfillment logic on undocumented fields — stick to documented invoice_id, transaction_hash, metadata.

Local development workflow

Keep sandbox webhook secret separate from production — common leak vector when copying .env files.

Production deployment checklist

Before switching webhook URL to production:

  • [ ] HMAC verification unit tests pass
  • [ ] Idempotency store (DB/Redis) deployed
  • [ ] Endpoint HTTPS with valid cert
  • [ ] 2xx response within 5 seconds
  • [ ] Alerting on 5xx rate >1%
  • [ ] Runbook for replay after outage documented
  • [ ] Sandbox end-to-end test logged this week

Ship fulfillment integration only after checklist complete — test sandbox catches 90% of issues.

Mapping webhook events to your database schema

Recommended tables:

TableKey columns
invoicesid, external_invoice_id, status, amount_cents
paymentsinvoice_id, tx_hash, network, paid_at
webhook_eventsevent_id, processed_at, payload_hash

Unique index on tx_hash prevents duplicate payment rows when webhook retries.

GraphQL vs REST for invoice status

REST GET /invoices/:id suffices for polling fallback. GraphQL optional if your stack already uses it — no functional advantage for webhook-primary architecture. Choose REST for simpler cache semantics and curl-debuggable integrations during incident response.

Multi-environment webhook routing

Use separate webhook URLs per environment:

EnvironmentURLSecret
Developmentngrok tunneldev_secret
Stagingstaging.app/webhooksstaging_secret
Productionapp/webhooksprod_secret

Never point staging webhook at production fulfillment DB — classic source of test invoices unlocking real licenses. Environment isolation is non-negotiable for payment automation.

Event ordering and out-of-sequence delivery

Webhook consumers must handle events arriving out of chronological order. A client may pay invoice inv_002 before inv_001 if AP processes invoices in reverse due date order. Your handler should update each invoice independently — never assume invoice.paid events sort by created_at in the delivery stream.

Edge cases to code for:

  • invoice.expired followed by invoice.paid — Client paid during grace period after expiry job ran. Policy: accept payment if on-chain confirmation occurred before hard cutoff; otherwise manual review.
  • invoice.partially_paid then invoice.paid — Fulfillment should wait for final event unless business rules allow partial delivery.
  • Duplicate invoice.paid with identical tx_hash — Idempotency store returns 200 without re-fulfilling.

State machine recommendation:

Persist state transitions in your database with from_status, to_status, and event_id for audit. Debugging "customer says paid but no access" almost always traces to missing transition handling, not webhook failure.

Load testing webhook endpoints before launch

Payment automation fails embarrassingly under load when month-end billing creates 500 invoices in an hour and treasury pays in a burst. Before production:

  • Synthetic webhook replay — Replay captured sandbox payloads 100× concurrent against staging endpoint; verify idempotency and p95 latency under 2 seconds.
  • Queue depth monitoring — If fulfillment runs async, alert when queue depth exceeds 50 for more than 5 minutes.
  • Database connection pool — Webhook handler opening new DB connection per request exhausts pools under burst; use connection pooling.
  • Circuit breaker on downstream — If license API is down, return 503 to trigger platform retry rather than 200 with silent failure.
Load scenarioTarget p95 handler timeMax acceptable error rate
10 concurrent webhooks<500ms0%
100 concurrent webhooks<2s<0.1%
Sustained 50/min for 1 hour<1s<0.01%

Document load test results in runbook — enterprise clients ask about payment burst handling during security reviews.

Webhook vs polling: operational comparison

DimensionWebhook (invoice.paid)Polling (GET /invoices/:id)
LatencySeconds after confirmationDepends on poll interval
Server loadEvent-driven, minimalLinear with open invoice count
ReliabilityRequires endpoint uptime + retriesWorks through brief outages
ComplexityHMAC verify, idempotencySimpler handler
Best useProduction fulfillmentBackup reconciliation job

Run both: webhooks for real-time fulfillment, hourly poll for invoices stuck in open status more than 24 hours past expected payment — catches missed webhooks from deploy blips without polling block explorers.

Contract testing and schema validation

Webhook payloads evolve — new fields appear without breaking old consumers if you follow forward-compatible parsing. In CI:

  • Store golden JSON fixtures from sandbox invoice.paid events per network (Solana signature format vs EVM tx hash).
  • Validate your parser against fixtures on every deploy.
  • Alert if production webhook payload schema drifts from fixture (optional JSON schema validation in staging proxy).

Fields your fulfillment must never ignore: invoice_id, transaction_hash, amount_crypto, network, metadata. Fields safe to ignore until needed: payer_address, confirmations, fee_paid.

Version API client libraries when /developers documents breaking changes — pin settlematic-sdk version in production requirements.

Webhook dead-letter queues and manual replay procedures

When webhook delivery exhausts platform retry budgets, events land in a dead-letter state requiring operator intervention. Production teams should configure dashboard alerts or API polling for failed deliveries — do not discover dead-letter backlog only when customers complain about missing licenses three days after payment. Runbook steps: identify failed invoice.paid events in the webhook delivery log, verify payment confirmed on-chain via explorer, confirm your endpoint returned 5xx during the incident window, fix the handler bug or complete deploy, then trigger manual replay from the dashboard or request platform support replay. Document each manual replay in your incident tracker with invoice_id, original failure timestamp, and root cause category.

Dead-letter events differ from idempotent duplicates. Duplicates are healthy retries where the handler already processed successfully; dead-letter events never received a successful 2xx acknowledgment. Your nightly reconciliation job should cross-reference open invoices with on-chain payments regardless of webhook health — dead-letter recovery is backup, not primary detection. Enterprise deployments processing more than five hundred payments monthly should dedicate on-call rotation familiar with replay procedures and maintain a staging endpoint that replays production payloads with PII redacted for regression testing after handler fixes.

Maintain dead-letter dashboard widget visible to engineering and finance — payment confirmed on-chain but fulfillment pending more than one hour triggers automatic escalation regardless of whether root cause is webhook DLQ or handler bug.

Staging parity for webhook integration testing

Staging webhook environments should mirror production handler code paths, not simplified mocks that skip signature verification or database writes. Parity checklist: same HMAC verification code with environment-specific secrets, same idempotency store schema, same async queue infrastructure, same database transaction boundaries. Engineers testing against simplified handlers routinely ship bugs where staging passes but production fails under real payload shapes or connection pool exhaustion.

Synthetic load tests belong in staging before production URL swap — replay one hundred concurrent sandbox invoice.paid payloads and measure handler p95 latency. Staging should also receive webhooks from actual testnet USDC payments, not only replayed JSON fixtures, because real delivery exercises TLS, DNS, and firewall allowlists that local curl tests skip. Document staging and production webhook URLs in the team wiki; quarterly verify both endpoints respond to health checks and that ngrok tunnels for local development are not accidentally registered as production destinations after engineer laptop sleep cycles break tunnel URLs.

Rotate staging secrets on the same calendar cadence as production — teams that never rotate staging secrets leak them into production .env copies during rushed deploys. Include webhook handler version in deployment tags so incident response can correlate failed deliveries with specific release.

Contract-test staging endpoint against production handler Docker image — environment parity means same container artifact, different secrets and database URLs, not forked handler code paths maintained separately.

Record staging load-test results in release checklist — no production webhook URL change without documented staging p95 under two seconds at expected burst volume.

Include webhook delivery success rate in weekly engineering metrics review alongside API error rates and deployment frequency.

Production crypto invoicing integrates at the webhook boundary: create invoices via API, verify signed invoice.paid events, fulfill idempotently. Settlematic Collect provides REST APIs and webhooks without custodial settlement delay. Read /developers, test in demo, and compare pricing before shipping automation.

Frequently asked questions

How fast do invoice.paid webhooks arrive?
Typically seconds after configured confirmation threshold on chain — often faster than card settlement notification to merchant for cross-border wires.
Can I register multiple webhook URLs?
Platform-dependent — often one primary + backup endpoint or routing via your event bus from single endpoint.
What if my server misses a webhook during deploy?
Retries cover short outages. Run poll reconciliation job hourly for open invoices near expiry.
Do webhooks include payer wallet address?
Often yes — useful for sanctions screening and CRM. Confirm field in API docs.
Can I create invoices in USD via API and settle USDC?
Yes — standard pattern from invoice USD get paid crypto.
Is webhook delivery guaranteed exactly once?
No — at-least-once delivery is industry standard. Idempotent handlers required.
How do webhooks relate to accounting exports?
Webhooks trigger real-time ops; exports batch for finance month-end. Use both — accountants want CSV/JSON exports.

Continue reading

Start invoicing and accepting crypto payments

Collect and Gateway on one non-custodial platform - funds always sweep to wallets you control.