Skip to content

Create Blockchain Webhooks for Deposits

To receive deposit notifications from Chaingateway you need two parts: a receiver endpoint on your server and a webhook that you create with POST /api/v2/{chain}/webhooks. When a transaction matches the filter of the webhook, Chaingateway sends an HTTP POST request with the transaction data to your endpoint. This tutorial builds both parts for incoming TRC20 deposits on TRON. The same steps work for Ethereum, BNB Smart Chain, Polygon, Arbitrum and Bitcoin. Solana has no webhooks.

Read Webhooks first if you want the concepts and the payload format. You need an API token from the Quickstart.

Tutorial steps: write the receiver, make it reachable from the internet, create the webhook, send a test payload, handle failed deliveries 1. Write the receiver POST endpoint that answers 200 2. Make it reachable public HTTPS URL 3. Create the webhook POST /api/v2/tron/webhooks with url and filter 4. Test with a payload curl against your own receiver 5. Handle failures list failed notifications, retry them
Steps 1 and 2 come before step 3, because the URL must work when the first event arrives.

A receiver is a server endpoint that accepts HTTP POST requests with a JSON body and answers with status 200. Keep the handler short: store the payload, answer, and do the slow work afterwards in a queue or a background job. The examples below log the payload and acknowledge it.

const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.post('/webhook', (req, res) => {
console.log('Received webhook:', req.body);
res.status(200).send('Webhook received');
});
app.listen(port, () => {
console.log(`Webhook receiver listening at http://localhost:${port}`);
});

Chaingateway can only reach a public URL. During development, expose your local port through a tunnel and use the tunnel’s HTTPS address as the webhook url. Check the signature of every request before you act on it, as Webhooks Security describes.

Send POST /api/v2/tron/webhooks with the url of your receiver and a filter. The filter decides which transactions trigger a notification.

  • url (required): the address of your receiver. It must be a valid URL.
  • from and to: the sender and receiver address, Tron format. At least one of them is required, unless you provide contractaddress and token_id instead.
  • contractaddress: the contract of the token to track.
  • token_id: an NFT token id.
  • type: one of TRX, TRC10, TRC20, TRC721.
  • reference: your own label of up to 255 characters, for example an order number.

The example watches for TRC20 transfers of one token to one deposit address.

Terminal window
curl --request POST \
--url https://app.chaingateway.io/api/v2/tron/webhooks \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_TOKEN' \
--data '{
"url": "https://example.com/webhook",
"to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp",
"contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"type": "TRC20",
"reference": "order-1042"
}'

The response has status 201 and the id of the webhook in data.webhook. Keep the id, because you need it to update or delete the webhook.

{
"status": 201,
"ok": true,
"message": "Webhook created",
"data": {
"webhook": "9b2b4dcc-1479-4bcd-9b8a-015673e80f46"
}
}

On other chains the path and the type values change. Ethereum and Arbitrum accept ETH, ERC20 and ERC721, Polygon accepts MATIC, ERC20 and ERC721, BNB Smart Chain accepts BNB, BEP20 and BEP721, and Bitcoin takes only url, from and to. Addresses on the EVM chains must match 0x followed by 40 hex characters. To test on a test network, add the header X-Network: testnet to the creation request.

How can I test the receiver before a real deposit arrives?

Section titled “How can I test the receiver before a real deposit arrives?”

Send a sample notification to your own endpoint with curl. The body below has the same fields as a real notification. If your receiver logs it and answers 200, the endpoint works. After that, send a small testnet transfer to the watched address to see the real event.

Terminal window
curl --request POST \
--url https://example.com/webhook \
--header 'Content-Type: application/json' \
--data '{
"id": "9d18457f-c71c-4be4-ae7c-ce04e48359ed",
"webhook_id": "9b2b4dcc-1479-4bcd-9b8a-015673e80f46",
"from": "TTd9qHyjqiUkfTxe3gotbuTMpjU8LEbpkN",
"to": "TUwmZghA7u2GxGxKaxM1mkCmsTF4wHs4vp",
"blocknumber": "65542464",
"datetime": "2024-09-25 14:48:27",
"tokenid": null,
"type": "TRC20",
"contractaddress": "TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t",
"txid": "18f52f2a55b94a6e3705de4abb18e95dfce79970f27b29450705c561e12b6988",
"amount": 108935
}'

What do I do with failed deliveries and old webhooks?

Section titled “What do I do with failed deliveries and old webhooks?”

Chaingateway does not retry failed deliveries automatically. GET /api/v2/tron/webhooks/notifications/failed lists them, and POST /api/v2/tron/webhooks/notifications/{id}/retry sends one again. Use GET /api/v2/tron/webhooks to list your webhooks, PUT /api/v2/tron/webhooks/{id} to change one and DELETE /api/v2/tron/webhooks/{id} to remove it. Delete a webhook once it has done its job, for example after the payment for an order has arrived.

  • The receiver must be publicly reachable and accept HTTP POST requests.
  • Verify the origin and integrity of each request with the X-Signature header.
  • Make the receiver idempotent. Use the txid to detect a notification that you have already processed.
  • Keep your API token in a secrets store, not in the receiver’s source code.