API Doc - Webhook Signing & Payload Guide
AllScale Open API Version: v5 Last Updated: 2026-04-30
Overview
AllScale delivers event notifications to your server via Webhook callbacks.
Each webhook request is authenticated using HMAC-SHA256 request signing, providing:
Sender authentication (shared secret)
Payload integrity (tamper-proof)
Replay attack protection (timestamp + nonce)
Stateless verification (no session required)
Webhook payloads are plaintext JSON (not encrypted).
Credentials
When your integration/store is created, you receive:
api_key
Public identifier
api_secret
Secret key used for signature verification
Important Notes
api_secretis shown only onceIt cannot be retrieved again
Store it securely
Treat it like a password or private key
Webhook Request
Method
Content-Type
Required Headers
X-API-Key
API key
X-Webhook-Id
Unique webhook ID
X-Webhook-Timestamp
Unix timestamp(seconds)
X-Webhook-Nonce
Unique per-request nonce
X-Webhook-Signature
HMAC signature
Signature Header Format
Replay Protection
To prevent replay attacks:
Requirements
Timestamp must be within ±5 minutes
Each nonce must be used only once
Recommended Implementation
Store
noncein RedisTTL: 600 seconds
Reject duplicate nonces
Canonical String (v1)
Webhook signatures are generated using a canonical string.
Canonical Format
Field Description
METHOD
HTTP method (uppercase)
PATH
URL path only
QUERY_STRING
Query string without ?
WEBHOOK_ID
From X-Webhook-Id
TIMESTAMP
From X-Webhook-Timestamp
NONCE
From X-Webhook-Nonce
BODY_SHA256
SHA256 hex of raw body bytes
⚠️ Important
BODY_SHA256 must be calculated from the raw request body bytes,
before JSON parsing or re-serialization.
Signature Algorithm
Algorithm
Encoding
Formula
Header Example
Webhook Payload
The request body sent by AllScale is exactly the following JSON structure.
JSON Field Definitions
all_scale_transaction_id
string
✅
AllScale transaction ID for this payment/transfer
all_scale_checkout_intent_id
string
✅
AllScale checkout intent ID associated with the payment
webhook_id
string
✅
Unique webhook ID (must match X-Webhook-Id)
amount_cents
integer
✅
Always the integer the merchant submitted on POST /v1/checkout_intents/. For fiat-priced intents this is fiat cents; for stable-coin-priced intents it is stable-coin "cents" (1.00 coin = 100 cents, equivalent to int(amount_coins * 100)).
currency
integer | null
➖
Currency enum value (int). Must be interpreted using AllScale Currency enum mapping. null when the intent was priced natively in a stable coin — read coin_symbol instead.
currency_symbol
string | null
➖
Fiat currency symbol (e.g., USD, CAD, CNY). null when the intent was priced natively in a stable coin — read coin_symbol instead.
amount_coins
string
✅
Stablecoin amount as a decimal string (to avoid float issues), e.g. "12.340000"
coin_contract_address
string
✅
Official ERC-20 token contract address
coin_symbol
string
✅
Stablecoin symbol (e.g., USDT, USDC)
chain_id
integer
✅
EIP-155 chainId identifying the EVM network (https://chainid.network/)
tx_hash
string
✅
On-chain transaction hash
tx_from
string
✅
Sender wallet address
payment_method_type
integer
✅
Payment method type used for this transaction. Value must correspond to the PaymentMethodType enum: 0=UNKNOWN, 1=WALLET_SCAN, 2=WALLET_CONNECT, 3=ALL_SCALE_PAY.
user_id
string | null
➖
Optional merchant/user identifier
order_id
string | null
➖
Optional merchant order identifier
user_name
string | null
➖
Optional customer/user display name
extra_obj
object | null
➖
Optional arbitrary JSON object with extra fields
Actual Webhook Body Example (Matches Real Structure)
Fiat-priced intent (merchant created with currency)
Stable-coin-priced intent (merchant created with stable_coin)
amount_cents is still an integer and equals amount_coins * 100. currency and currency_symbol are null — the buyer paid the merchant directly in coin_symbol, no fiat currency is involved.
Verification Flow (Your Server Side)
Extract headers
Validate timestamp (±300 seconds)
Validate nonce (store with TTL)
Read raw request body bytes (before parsing JSON)
Compute SHA256 of raw body
Rebuild canonical string
Compute expected signature
Timing-safe compare
Only after verification → process payload
Response Expectations
Your endpoint should respond:
200 OKif processed successfullyNon-200 if rejected (signature invalid, timestamp invalid, etc.)
AllScale will log the HTTP status and may retry depending on configured policy.
Best Practices
✅ Always verify X-Webhook-Signature before processing
✅ Validate timestamp within ±5 minutes
✅ Cache nonce for replay protection
✅ Use idempotency via webhook_id
✅ Convert amount_coins using Decimal (not float)
❌ Never log secrets or signatures
Troubleshooting
Signature mismatch
Body modified
Use raw bytes exactly as received
Signature mismatch
Wrong path/query
Use the exact request path and query string
Signature mismatch
Wrong secret
Verify correct api_secret
Timestamp rejected
Clock drift
Sync server time (NTP)
Replay rejected
Nonce reused
Generate unique nonce; store with TTL
End of Document
Last updated