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
| Event | Fires when |
|---|---|
transaction.created | A committed transaction was recorded. |
transaction.calculated | Tax was calculated for a committed transaction. |
transaction.voided | A transaction was voided. |
transaction.refunded | A refund was created against a transaction. |
transaction.adjusted | A committed reversal and replacement revision were created. |
transaction.tax_only_credited | A linked tax-only credit was created. |
api_key.created | An API key was created (or issued during rotation). |
api_key.revoked | An 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) <= toleranceDelivery, 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.
