Skip to content

Webhook payload

Each payment is sent as a POST with Content-Type: application/json.

{
"event_id": "uuid",
"type": "qris.payment.success",
"merchant_id": "demo_merchant",
"source_package": "com.example.merchant",
"source_app": "Demo Merchant",
"received_at": "2030-05-21T12:00:00+07:00",
"notification": {
"source_package": "com.example.merchant",
"source_app": "Demo Merchant",
"title": "string",
"text": "string",
"big_text": "string",
"received_at": "2030-05-21T12:00:00Z"
},
"payment": {
"amount": 10000,
"currency": "IDR",
"sender_name": "John Doe",
"payment_source": "Demo"
},
"raw": {
"source_package": "com.example.merchant",
"source_app": "Demo Merchant",
"title": "string",
"text": "string",
"big_text": "string",
"received_at": "2026-05-21T12:00:00Z"
}
}

If a secret is configured, the request includes:

X-Webhook-Secret: your-secret

You can add several webhooks and route each merchant to one of them. A webhook can receive several merchants (for example BRI and GoPay to the same server), and merchants without an explicit webhook use the default one. A merchant with neither is not delivered, and the app warns you on the Home screen. Each webhook has its own optional secret, and the event detail shows which URL was last used.

Send test posts a sample event to the URL you typed, without saving it. It has the same shape as a payment but type is qris.webhook.test and merchant_id is test, so receivers that filter on type won’t record it as a real payment.

Reply with a 2xx status so the event is marked Sent. Use event_id for idempotency, since an event can be delivered again on retry.

server.ts (Hono)
import { Hono } from "hono";
const app = new Hono();
app.post("/qris", async (c) => {
if (c.req.header("X-Webhook-Secret") !== process.env.WEBHOOK_SECRET) {
return c.json({ error: "unauthorized" }, 401);
}
const event = await c.req.json();
// store event.event_id, skip if it already exists
console.log(event.payment.amount, event.payment.sender_name);
return c.json({ ok: true });
});
export default app;