Webhook

Quickstart

Create an endpoint, watch a wallet and receive your first webhook.

You need a server reachable over HTTPS (port 443 or 8443) that can receive a POST, and curl.

1. Get an API key

  1. Create an account in the dashboard and confirm your email with the code we send you.
  2. Open API keys and click Create key. For this guide, tick all three permissions.
  3. Copy the key. It starts with whk_test_ and is shown once.

Then set two variables so the commands below can be pasted as they are:

export API=https://api.webhookdev.xyz
export KEY=whk_test_...

Authentication covers permissions, expiry, IP limits and rolling a key.

The examples from here on come in three flavours. The Node.js ones use the built-in fetch (Node 18 or newer); the Python ones use requests. Both read the same two environment variables, API and KEY.

2. Create an endpoint

curl -X POST $API/v1/endpoints \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/webhooks/stellar","description":"production"}'

The response contains the endpoint's id and its secret (whsec_...). The secret is also shown only once. Your server uses it to verify signatures.

3. Check that your server receives webhooks

curl -X POST $API/v1/endpoints/ENDPOINT_ID/test -H "Authorization: Bearer $KEY"

This sends a test.ping event and returns the result of the first attempt:

{ "eventId": "evt_01K...", "attempt": { "statusCode": 200, "durationMs": 84, "error": null } }

4. Watch a wallet

curl -X POST $API/v1/watches \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{
    "walletAddress": "G...",
    "label": "Shop checkout",
    "endpointId": "ENDPOINT_ID",
    "assets": [{ "code": "USDC", "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5" }],
    "amountRule": { "kind": "min", "amount": "10" },
    "memoRule": { "kind": "present" }
  }'

The response includes warnings. ACCOUNT_NOT_FOUND or NO_TRUSTLINE:USDC mean the wallet cannot receive that asset yet; the watch is still saved, so you can fix the wallet afterwards.

walletAddress is the public address, starting with G. If you paste a secret key (S...) the request is refused. Never send a secret key to any service.

Rules you can set

FieldOptions
assetsOne or more of { "code": "XLM", "issuer": null } or { "code": "...", "issuer": "G..." }.
amountRule{ "kind": "any" }, exact, min or max with amount, or range with min and max. Amounts are decimal strings; edges are inclusive.
memoRule{ "kind": "any" }, present, absent, or equals with value and type (text, id or hash).
senderAllowlistAddresses allowed to pay. Empty means anyone.
eventTypespayment.received (default). Add payment.rejected to be told about payments that fail the rules.

5. Send a payment

Pay the wallet on testnet with at least 10 USDC and any memo. See the testnet guide for funding an account and sending a payment. Within seconds your server receives:

{
  "id": "evt_01K6V8Z3M4T7Q2X9B5N1R0C8YD",
  "type": "payment.received",
  "apiVersion": "2026-10-01",
  "createdAt": "2026-10-03T20:41:22.512Z",
  "data": {
    "payment": {
      "id": "0021506181151346688-0000000000",
      "txHash": "afe052cee2d66dae5ba90e3010655a8e4ebcc5fe1db3352aa42e45036e6240d4",
      "ledger": 5007298,
      "ledgerClosedAt": "2026-10-03T20:41:17.000Z",
      "from": "GDXT3JQDWX7IXTYCSFPK4RANVX2EJDTQ57L2IZWSYBLDZIUPAFJCQAUF",
      "to": "GBFMHWFQFQV3ZGGTWFFBGJQJPTRX3UBT7ZWBMUELVHJIUBSFDP5HQD56",
      "toMuxedId": null,
      "memo": "order-1001",
      "memoType": "text",
      "asset": { "code": "USDC", "issuer": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5" },
      "amount": "10.0000000",
      "amountStroops": "100000000"
    },
    "watch": { "id": "cm...", "label": "Shop checkout", "walletAddress": "GBFM..." },
    "verification": { "outcome": "VERIFIED", "reasons": [] }
  }
}

Answer with any 2xx status within 10 seconds. Do the real work after you have answered.

What to do in your handler

  1. Verify the signature using the raw request body.
  2. Check whether you have already processed this Webhook-Id. If so, answer 200 and stop. See retries and duplicates.
  3. Record the event, answer 200, then process it.

On this page