Skip to main content
Webhooks allow your application to receive real-time HTTP notifications when events occur in your TRXN account. Instead of polling the API for changes, you register a URL and TRXN sends a POST request to that URL whenever a relevant event fires.

How webhooks work

1

Create an endpoint

Register a webhook endpoint URL and choose which events to subscribe to. You can subscribe to specific events or use ["*"] to receive all events.See the webhook endpoints API reference for CRUD operations.
2

Store the signing secret

When you create an endpoint, TRXN returns a signing secret (format: whsec_<64_hex_chars>). Store this securely — it is only shown in full once, at creation time.
3

Receive events

When a subscribed event occurs, TRXN sends an HTTP POST request to your endpoint with a JSON payload describing the event.
4

Verify and process

Your server verifies the request signature, returns a 2xx response, then processes the event asynchronously.

Payload format

Every webhook delivery sends a JSON body with this structure:
{
  "event": "invoice.created",
  "payload": {
    "id": "inv_xxx",
    "object": "invoice",
    "customer_id": "cus_xxx",
    "status": "pending",
    "total_amount": "100.00"
  },
  "timestamp": "2025-01-14T12:00:00Z"
}

Signature verification

TRXN signs every webhook request with HMAC-SHA256 so you can verify that the request genuinely came from TRXN.

Signature header format

Every webhook request includes an X-Trxn-Signature header:
X-Trxn-Signature: t=<unix_timestamp>,v1=<signature>
Example:
X-Trxn-Signature: t=1704067200,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Verification steps

  1. Extract the timestamp (t) and signature (v1) from the header
  2. Check that the timestamp is within 5 minutes of the current time (prevents replay attacks)
  3. Compute the expected signature: HMAC-SHA256(secret, "<timestamp>.<raw_body>")
  4. Compare signatures using constant-time comparison
Use the full signing secret including the whsec_ prefix as the HMAC key. This matches Stripe’s implementation pattern.

Code examples

def verify_webhook(payload, signature_header, secret)
  parts = signature_header.split(",").to_h { |p| p.split("=", 2) }
  timestamp = parts["t"].to_i
  signature = parts["v1"]

  # Check timestamp is within 5 minutes
  return false if (Time.now.to_i - timestamp).abs > 300

  # Compute expected signature (use full secret including whsec_ prefix)
  signed_payload = "#{timestamp}.#{payload}"
  expected = OpenSSL::HMAC.hexdigest("SHA256", secret, signed_payload)

  # Constant-time comparison
  ActiveSupport::SecurityUtils.secure_compare(expected, signature)
end

Available events

Customer events

EventDescription
customer.createdA new customer has been created
customer.updatedA customer has been updated
customer.deletedA customer has been deleted

Product events

EventDescription
product.createdA new product has been created
product.updatedA product has been updated
product.deletedA product has been deleted

Price events

EventDescription
price.createdA new price has been created
price.updatedA price has been updated
price.deletedA price has been deleted

Invoice events

EventDescription
invoice.createdA new invoice has been created
invoice.updatedAn invoice has been updated
invoice.paidAn invoice has been marked as paid
invoice.overdueAn invoice has become overdue

Subscription events

EventDescription
subscription.createdA new subscription has been created
subscription.activatedA subscription has become active
subscription.canceledA subscription has been canceled
subscription.renewedA subscription has been renewed

Subscription phase events

EventDescription
subscription_phase.createdA new subscription phase has been created
subscription_phase.updatedA subscription phase has been updated
subscription_phase.deletedA subscription phase has been deleted
Payload example:
{
  "event": "subscription_phase.created",
  "payload": {
    "id": "sub_phase_xxx",
    "object": "subscription_phase",
    "subscription_id": "sub_xxx",
    "start_date": "2025-02-01T00:00:00Z",
    "end_date": "2025-03-01T00:00:00Z",
    "items": [
      {
        "id": 123,
        "price_id": "price_xxx",
        "quantity": 1,
        "overridden_price_amount": null
      }
    ],
    "created_at": "2025-01-26T12:00:00Z",
    "updated_at": "2025-01-26T12:00:00Z"
  },
  "timestamp": "2025-01-26T12:00:00Z"
}

Wallet events

EventDescription
wallet.createdA new wallet has been created

Crypto address events

EventDescription
crypto_address.createdA new crypto address has been added to a wallet
crypto_address.deletedA crypto address has been deleted

Payment claim events

EventDescription
payment_claim.submittedA customer has submitted a payment claim
payment_claim.approvedA payment claim has been approved
payment_claim.rejectedA payment claim has been rejected

Crypto transaction events

EventDescription
crypto_transaction.receivedA crypto transaction has been received
crypto_transaction.allocatedA transaction has been allocated to an invoice

Transaction allocation events

EventDescription
transaction_allocation.createdA new transaction allocation has been created

Response handling

Your endpoint must respond with a 2xx status code to indicate successful receipt. If your endpoint returns a non-2xx status code, TRXN retries with exponential backoff for up to 11 attempts.

Error handling

Error typeBehavior
Connection errorEndpoint is disabled to prevent further delivery attempts
Timeout errorRetry with exponential backoff
TLS errorRetry with exponential backoff
Non-2xx responseRetry with exponential backoff

Event retention

TRXN retains webhook events for 30 days.

Best practices

Return a 2xx response before any complex processing. Process the event asynchronously after responding to avoid timeouts.
  1. Respond quickly — return a 2xx response before any complex logic that could cause a timeout. Process the event asynchronously after responding.
  2. Handle duplicates — webhook endpoints may occasionally receive the same event more than once. Make your event processing idempotent by tracking the id from the payload.
  3. Handle out-of-order delivery — events may not arrive in chronological order. Use the timestamp field to determine the sequence rather than assuming arrival order.
  4. Always verify signatures — use the X-Trxn-Signature header to verify all incoming webhooks. Reject any webhook that fails signature verification.
  5. Use HTTPS — always use HTTPS endpoints for security.
  6. Store secrets securely — store your signing secrets in environment variables or a secrets manager, never in source code.
  7. Monitor failures — check webhook events in the dashboard to monitor delivery status.
  8. Regenerate compromised secrets — if you suspect your signing secret has been compromised, regenerate it immediately via the API.

Managing webhook endpoints

For creating, updating, deleting, and regenerating secrets for webhook endpoints, see the webhook endpoints API reference.