FoxpayDocs
Custom REST APIv1.0Beta
Reference

Webhook reference

Field-level contract for Foxpay outbound webhooks. Pair this with the webhooks guide for conceptual context, and use this page to verify exact headers, payload shapes, and retry semantics.

Delivery method

HTTPS `POST` from Foxpay to the merchant-configured custom webhook URL.

Default event

transaction.status_changed on every status transition.

Trust signal

X-Foxpay-Signature: sha256=<hex> over the exact raw JSON body.

Request headers

Every delivery includes the headers below. The signature header is the authoritative trust signal; the others are for routing and observability.

HeaderPurposeExample
Content-TypeAlways JSON.application/json
User-AgentIdentifies Foxpay as the sender.Foxpay-Webhooks/1.0
X-Foxpay-SignatureHMAC-SHA256 of the raw request body using the shop webhook secret. Format: sha256=<hex>.sha256=9f8c1b…e2a4
X-Foxpay-EventEvent type for routing without parsing the body.transaction.status_changed
X-Foxpay-DeliveryUnique delivery identifier (UUIDv4). Use as your idempotency key.3a9e7b2c-…-9c1f

transaction.status_changed payload

transaction.status_changed
{
  "event": "transaction.status_changed",
  "transaction_id": "tx_123",
  "order_id": "order_1001",
  "status": "completed",
  "amount": 12345,
  "currency": "EUR",
  "timestamp": "2026-04-28T08:31:00.000Z",
  "metadata": {
    "shop_id": "merchant_fxp_ABC12345",
    "shop_name": "Foxpay Demo Merchant GmbH",
    "customerId": "cust_42"
  }
}
  • amount is integer cents for custom integrations.
  • metadata merges Foxpay context (`shop_id`, `shop_name`) with any merchant metadata you sent at initialization.
  • timestamp is the delivery preparation time in ISO 8601 UTC.

Status enum

  • pending — initialized, waiting on the buyer.
  • processing — buyer started the flow; Foxpay is in confirmation.
  • completed / paid — final success state.
  • failed — terminal failure surfaced by Foxpay or the provider.
  • cancelled — terminal cancellation.
  • expired — pending timed out (currently 30 days).

Treat any status not in this list as opaque additive content; Foxpay reserves the right to expand the set in additive releases per the versioning policy.

Verify the signature

Validate X-Foxpay-Signature before you mutate any merchant state. Use a constant-time comparison.

verifyFoxpaySignature
import crypto from 'node:crypto';

export function verifyFoxpaySignature(rawBody: string, headerValue: string, secret: string) {
  const received = headerValue.replace(/^sha256=/, '');
  const expected = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  if (received.length !== expected.length) {
    return false;
  }

  return crypto.timingSafeEqual(
    Buffer.from(expected, 'utf8'),
    Buffer.from(received, 'utf8'),
  );
}
  • Sign over the raw bytes that arrived. Re-stringifying parsed JSON will produce a different signature.
  • Use the shop webhook secret managed in the Foxpay panel; this is distinct from the API key.
  • Reject the request before persisting if verification fails. Return 401 so Foxpay logs the failure.

Retry and timeout semantics

Foxpay is rolling out a persistent retry queue per merchant. Newly onboarded and migrated shops run on the queue; legacy shops continue on the 3-attempt path until they are flipped over.

  • Queue path (new): up to 12 attempts across ~7 days. The first attempt fires inline from the originating event; subsequent attempts are scheduled at 30s, 2m, 10m, 30m, 2h, 6h, 24h (hot phase) then +24h, +24h, +36h, +48h (long-tail phase). Each delay carries ±20% jitter.
  • Legacy path: up to 3 attempts per delivery. Per-attempt timeout grows linearly 30s, 45s, 60s; backoff between attempts 2s, 4s.
  • Foxpay does not retry on terminal client errors regardless of path: 400, 401, 403, 404, 410. Fix the failure and trigger redelivery from the panel.
  • Each attempt carries a unique X-Foxpay-Delivery and an X-Foxpay-Attempt header (1-indexed). Treat re-arrivals of the same X-Foxpay-Delivery as duplicates.
  • A failed delivery (after all attempts are exhausted) raises a "webhook delivery failed" notification email to the store user. Under the queue path, the email fires once on the terminal state, not after every intermediate failure.

Recommended responder shape

  • Acknowledge with 2xx after durable persistence.
  • Use X-Foxpay-Delivery as the deduplication key for your processing pipeline.
  • Never block on downstream business logic before responding; persist + ack, then process asynchronously.
  • Do not rely on response bodies for `transaction.status_changed`; only the verification handshake reads the body back.

Manual redelivery from the Foxpay panel

Merchants can trigger a webhook redelivery for any transaction from the panel — no support ticket needed.

  • Open the transaction row in /transactions (expand via the chevron) and switch to the Technical Info tab.
  • The Webhook Delivery card shows the current status (Delivered / Pending retry / Exhausted / Dead / Cancelled), the last attempt result, the next scheduled retry, and a delivery-history timeline.
  • Click Resend now. If a delivery job already exists for this transaction it is brought due immediately and the manual-trigger counter is incremented; otherwise a fresh job is created. The worker picks it up within ~1 minute.
  • The same history is available programmatically via GET /api/transactions/{transaction_id}/webhook/history for merchants who want to surface it in their own ops UI.

Verification handshake

When a merchant runs Integration Verification in the Foxpay panel, Foxpay sends a one-shot signed foxpay.webhook_verification event. Your endpoint must verify the signature and respond with the canonical handshake JSON below.

Inbound request

Inbound POST
POST /your-webhook-url
Content-Type: application/json
X-Foxpay-Event: foxpay.webhook_verification
X-Foxpay-Signature: sha256=<hex>
X-Foxpay-Verification-Challenge: 3f1c4a6b-…
User-Agent: Foxpay-Verification/1.0

{
  "event": "foxpay.webhook_verification",
  "challenge": "3f1c4a6b-…",
  "timestamp": "2026-04-28T08:31:00.000Z",
  "merchantId": "merchant_fxp_ABC12345",
  "shopId": "shop_ABC12345",
  "expectedAuthMode": "bearer_token"
}

Expected response

Expected 200 response
HTTP/1.1 200 OK
Content-Type: application/json

{
  "challenge": "3f1c4a6b-…",
  "signatureValid": true
}

Foxpay also accepts ok: true or verified: true for backwards compatibility. Standardize new merchant code on signatureValid.

Custom vs WooCommerce delivery

  • Custom integrations deliver to the merchant-configured custom_webhook_url on the store.
  • WooCommerce integrations deliver to {store-url}/wc-api/wc_gateway_foxpay and should not be reused for custom integrations.
  • The signing secret is the same store-level secret in both cases; the URL routing is what differs.
  • Failed deliveries are logged in the webhook_deliveries table for support visibility.