curl, jq, a tunnel tool
(cloudflared or ngrok) and one of Node.js 18+, Python 3.9+ or Go 1.22+.
The Free plan includes one Testnet endpoint, and Testnet deliveries cost no
credits.
1
Create a webhook key
Open app.lumeus.dev, select Testnet, then go to
Webhooks > Webhook keys and choose Create webhook key. The key starts
with
whk_ and is shown once. Webhook keys belong to one network, and lum_
API keys do not work here.Set these in your first terminal. The host selects the network:
webhooks-testnet.lumeus.dev is Testnet, webhooks.lumeus.dev is Mainnet.2
Download a receiver
Each receiver listens on port 3000 (set
PORT to change it), verifies the
signature and the signed delivery context, ignores duplicates and answers
204. Download one into a new folder:- Node.js
- Python
- Go
3
Start the receiver
Start the receiver now, before the subscription exists, so the first live
events find it running. Open a second terminal in the It prints
lumeus-webhook folder:listening on http://localhost:3000 and keeps running. It reads the
signing secret from webhook-secret.txt on every request; until the create
step writes that file, it answers 503.4
Expose port 3000 over HTTPS
Lumeus delivers only to public Back in the first terminal, save the printed URL. A new tunnel can take up to a
minute before its name resolves; repeat this
https:// URLs, so open a tunnel in a third
terminal and leave it running:curl until it prints 503
(your receiver, reached through the tunnel, without a secret yet) instead of
000:5
Create the subscription
Subscribe to transfers of the sample account. The response contains the
signing secret (Then create the subscription. The command writes the secret to
If the request fails,
hmac_secret) only this once. Pick one idempotency key for
this create and keep it for any retry. On Linux without uuidgen, the command
falls back to /proc/sys/kernel/random/uuid (or use
python3 -c 'import uuid; print(uuid.uuid4())'):webhook-secret.txt only on 201 or 202, and never overwrites an existing
secret file:Response (201, example values, secret removed)
subscription.json holds the error: 400 for a URL
that is not public HTTPS or does not resolve yet, or for an unknown body field
(the host already selects the network, so there is no network field), and
403 if your organization already has its Free endpoint (delete it or
upgrade). Fix the cause and run the same command again with the same
CREATE_KEY. A retry of a create that already succeeded returns 200 with
the same subscription and no secret; if you lost the secret, rotate the
signing key.6
Wait until the endpoint is active
Live matching starts once
effective_state is active. Free and paid
endpoints are active in the 201 create response, so you can skip this step.
If yours shows activating (the create returned 202), poll until it changes.
A test sent while it is activating returns 409 with Retry-After: 5.7
Send a test event
A test sends one signed
webhook.test event to your receiver and reports what
it answered. It needs the subscription’s current ETag in If-Match:Response (200, example values)
status is delivered when your receiver answered 2xx. Otherwise it is
rejected with the response_code or a last_error such as receiver timed out, or uncertain if the outcome was lost (read it again at the Location
URL). The receiver prints:8
Watch live events
The sample account sends Testnet XLM all the time, so live transfers start
arriving within a minute:Each line is a delivery whose signature and signed context passed
verification. To see what failed instead, list recent deliveries:
9
Clean up
The sample account is busy: about 335 matching transfers an hour, so it uses
the Free plan’s 1,000 deliveries a day in about 3 hours. After that, the
endpoint pauses until 00:00 UTC (see Plans).
Delete the subscription when you are done; this also frees your Free endpoint:Stop the receiver and the tunnel with Ctrl+C.
Next
- Receive and verify: every header, retries, timeouts and deduplication for production receivers.
- Webhooks overview: event types, filters, plans and delivery guarantees.
- Manage subscriptions: pause, change filters or the target, and rotate the signing key.
- Go live on Mainnet: the Mainnet host, key and plan.