Webhooks

Subscribe HTTPS endpoints to signed events from the Developer Console. Each subscription chooses its events and environment; the signing secret is shown exactly once at creation.

Events

EventFires when
transaction.createdA committed transaction was recorded.
transaction.calculatedTax was calculated for a committed transaction.
transaction.voidedA transaction was voided.
transaction.refundedA refund was created against a transaction.
transaction.adjustedA committed reversal and replacement revision were created.
transaction.tax_only_creditedA linked tax-only credit was created.
api_key.createdAn API key was created (or issued during rotation).
api_key.revokedAn API key was revoked (including the old key during rotation).

Signature

Every delivery is signed over the exact request body with an X-ITMS-Signature header of the form t=<unix_ts>,v1=<hmac_sha256>. Verify it against the raw body and reject stale timestamps to prevent replay:

# Verify an ITMS webhook signature (X-ITMS-Signature: t=<ts>,v1=<hmac>)
import hashlib, hmac, time

def verify(secret: str, body: bytes, header: str, tolerance=300) -> bool:
    parts = dict(item.split("=", 1) for item in header.split(","))
    ts = int(parts["t"])
    expected = hmac.new(secret.encode(), f"{ts}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts["v1"]) and abs(time.time() - ts) <= tolerance

Delivery, retries & replay

The first delivery is attempted immediately. Failed deliveries retry automatically with backoff up to a fixed number of attempts, then are marked exhausted; a background scheduler processes due retries. You can also replay any delivery manually from the Developer Console, and a delivery log shows attempts, status, and timing.

Security

  • Webhook URLs must be HTTPS and must resolve to publicly routable addresses; internal, private, and metadata addresses are refused (at creation and again at each delivery).
  • Redirects are never followed.
  • Response bodies are never stored — delivery records keep only the status code and a generic reason.
  • Signing secrets are stored encrypted and shown once; rotate by creating a new subscription if a secret is lost.