Each app has one HTTPS endpoint. GramPayBot sends JSON POST requests for invoice and billing events.
Configure the URL
In the bot open the app and choose 🪝 Webhooks → Configure URL. The same screen has Send test webhook, Rotate secret, Delivery logs, Enable and Disable. The webhook secret is separate from the API token and is shown once.
Headers
| Header | Value |
|---|---|
Content-Type | application/json |
GramPay-Event | Event name |
GramPay-Delivery-ID | Unique delivery ID |
GramPay-Timestamp | Send time in ISO 8601 |
GramPay-Signature | sha256=<hex> |
- GramPay-Eventinvoice_paid
- GramPay-Signaturesha256=8f21…d491
{
"update_type": "invoice_paid",
"payload": {
"public_id": "GU91XHr8AUNQ8l9r",
"status": "paid",
"amount_usd": "180.00",
"paid_token": "usdt",
"tx_hash": "8f21…d491"
}
} ✓ invoice_paid Verify the signature
Compute HMAC-SHA256 over the exact raw request bytes with the webhook secret, prefix the lowercase hex digest with sha256=, and compare in constant time.
const expected = 'sha256=' + crypto.createHmac('sha256', secret).update(rawBody).digest('hex');
const valid = given.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(given), Buffer.from(expected));
Reject missing or invalid signatures with a non-2xx response. Do not parse and reserialize JSON before calculating HMAC.
Three-request setup audit
Saving or testing a URL sends the same webhook_test body three times: unsigned, incorrectly signed and correctly signed. The valid request must return 2xx within 5 seconds. Phoenix does not follow redirects, so register the exact URL. Accepting invalid probes does not block setup but produces a security warning.
Your handler must accept webhook_test without business logic. Setup probes are synchronous and are not retried.
Delivery and retries
Only HTTP 2xx succeeds. Real events are retried up to 17 times over about four days with increasing delays. After the last failure, the endpoint becomes disabled_by_failures, the owner is notified, and it must be enabled again after the problem is fixed.
Handler rules
- Verify and persist the event, return
2xxquickly, then process asynchronously. - Deduplicate by
GramPay-Delivery-IDor an event-specific stable key. - Make fulfilment idempotent; a retry must not grant the product twice.
- Log and acknowledge unknown event types so future additions do not cause retry storms.
See events and payloads for the two body shapes.