@dieugene/tochka-webhook-dispatcher
v0.1.0
Published
Lightweight module to accept Tochka webhook (JWT) and POST stored callback payload
Readme
Accept Tochka webhook (JWT) and dispatch stored callback payload
What it does
- Accepts Tochka bank webhook as a JWT string (body may be plain or base64-encoded)
- Verifies the JWT signature against Tochka public JWK
- Extracts
operationIdfrom payload and loads the invoice from@dieugene/payments-db - Sends a POST request to the stored callback URL with stored payload
Install
npm i @dieugene/tochka-webhook-dispatcherRequirements
- Node.js >= 18 (built-in
fetchis used) - Environment variable
PAYMENTS_DB_ADDRESSmust be set for@dieugene/payments-db
Input formats
handler(input) accepts any of the following:
- String: the JWT string
- Buffer: the JWT in a Buffer
- Object with
{ body, isBase64Encoded }fields (e.g., AWS/GCP/serverless) - Fetch Request-like object with a
text()method (e.g., Cloudflare/Vercel)
If isBase64Encoded === true, body will be decoded from base64 before verification.
Minimal usage (serverless HTTP handler)
const { handler } = require('@dieugene/tochka-webhook-dispatcher');
module.exports.handler = async (event) => {
return await handler({ body: event.body, isBase64Encoded: event.isBase64Encoded });
};Expected JWT payload structure
After verification/decoding, the module expects one of the following shapes (actual payload from Tochka):
{ Data: { operationId: string, ... } }{ operationId: string, ... }
operationId is used to look up the invoice in the database.
Database contract (@dieugene/payments-db)
The invoice is read by id/uuid equal to operationId. The dispatcher expects the invoice to contain:
{
"data": {
"callback_data": {
"url": "https://example.com/callback",
"payload": { "any": "json" }
}
}
}url: destination endpointpayload: JSON body sent as-is
Return value
The handler always returns HTTP 200 with a JSON body describing dispatch result.
On success:
{ statusCode: 200, body: { dispatched: true, invoice_id: "<id>", reason: "" } }If a callback cannot be dispatched:
{ statusCode: 200, body: { dispatched: false, reason: "<reason>" } }Possible reasons:
no_invoice_ident— nooperationIdin payloadinvoice_not_found— invoice missing in DBno_callback_url— callback URL is absentno_global_fetch— globalfetchis not available
Optional configuration
By default, the public JWK is fetched from:
https://enter.tochka.com/doc/openapi/static/keys/public
You may override via options if you call lower-level functions directly (decode_webhook, etc.).
Notes
- The module does not add retries or extra validation. It is minimal by design.
- Ensure
PAYMENTS_DB_ADDRESSis configured and reachable at runtime.
