{"_id":"@dieugene/tochka-webhook-dispatcher","name":"@dieugene/tochka-webhook-dispatcher","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@dieugene/tochka-webhook-dispatcher","version":"0.1.0","description":"Lightweight module to accept Tochka webhook (JWT) and POST stored callback payload","main":"index.js","type":"commonjs","publishConfig":{"access":"public"},"engines":{"node":">=18"},"keywords":["tochka","webhook","payments","jwt"],"dependencies":{"@dieugene/payments-db":"*","axios":"^1.6.0","jsonwebtoken":"^9.0.0","jwk-to-pem":"^2.0.5"},"_id":"@dieugene/tochka-webhook-dispatcher@0.1.0","_nodeVersion":"20.16.0","_npmVersion":"10.8.1","dist":{"integrity":"sha512-LiAhuMFL+F1K1XjwJcGxaek1+4OSm0CqDKw+mRWHWOVp4A+urq2kYIrKo8X82XXxmnCpd1hhTLdpi9HxS9AfzA==","shasum":"38952e35a17c3adbb96abc4f654c4efded5e8a66","tarball":"https://registry.npmjs.org/@dieugene/tochka-webhook-dispatcher/-/tochka-webhook-dispatcher-0.1.0.tgz","fileCount":4,"unpackedSize":8261,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIBYMmyDG3450sVV1s4zaNRY0gTwxq0Q1N6qHrFXe2mbcAiBqatynoFe2ja0jjVTdVW2IR4nVp9Uz85OHrc6T5xbZVw=="}]},"_npmUser":{"name":"di.eugene","email":"ditkovsky.eugene@gmail.com"},"directories":{},"maintainers":[{"name":"di.eugene","email":"ditkovsky.eugene@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/tochka-webhook-dispatcher_0.1.0_1757672778499_0.29547861103145334"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-12T10:26:18.366Z","0.1.0":"2025-09-12T10:26:18.707Z","modified":"2025-09-12T10:26:19.020Z"},"maintainers":[{"name":"di.eugene","email":"ditkovsky.eugene@gmail.com"}],"description":"Lightweight module to accept Tochka webhook (JWT) and POST stored callback payload","keywords":["tochka","webhook","payments","jwt"],"readme":"Accept Tochka webhook (JWT) and dispatch stored callback payload\r\n\r\n### What it does\r\n- Accepts Tochka bank webhook as a JWT string (body may be plain or base64-encoded)\r\n- Verifies the JWT signature against Tochka public JWK\r\n- Extracts `operationId` from payload and loads the invoice from `@dieugene/payments-db`\r\n- Sends a POST request to the stored callback URL with stored payload\r\n\r\n### Install\r\n```bash\r\nnpm i @dieugene/tochka-webhook-dispatcher\r\n```\r\n\r\n### Requirements\r\n- Node.js >= 18 (built-in `fetch` is used)\r\n- Environment variable `PAYMENTS_DB_ADDRESS` must be set for `@dieugene/payments-db`\r\n\r\n### Input formats\r\n`handler(input)` accepts any of the following:\r\n- String: the JWT string\r\n- Buffer: the JWT in a Buffer\r\n- Object with `{ body, isBase64Encoded }` fields (e.g., AWS/GCP/serverless)\r\n- Fetch Request-like object with a `text()` method (e.g., Cloudflare/Vercel)\r\n\r\nIf `isBase64Encoded === true`, `body` will be decoded from base64 before verification.\r\n\r\n### Minimal usage (serverless HTTP handler)\r\n```javascript\r\nconst { handler } = require('@dieugene/tochka-webhook-dispatcher');\r\n\r\nmodule.exports.handler = async (event) => {\r\n  return await handler({ body: event.body, isBase64Encoded: event.isBase64Encoded });\r\n};\r\n```\r\n\r\n### Expected JWT payload structure\r\nAfter verification/decoding, the module expects one of the following shapes (actual payload from Tochka):\r\n- `{ Data: { operationId: string, ... } }`\r\n- `{ operationId: string, ... }`\r\n\r\n`operationId` is used to look up the invoice in the database.\r\n\r\n### Database contract (`@dieugene/payments-db`)\r\nThe invoice is read by id/uuid equal to `operationId`. The dispatcher expects the invoice to contain:\r\n```json\r\n{\r\n  \"data\": {\r\n    \"callback_data\": {\r\n      \"url\": \"https://example.com/callback\",\r\n      \"payload\": { \"any\": \"json\" }\r\n    }\r\n  }\r\n}\r\n```\r\n- `url`: destination endpoint\r\n- `payload`: JSON body sent as-is\r\n\r\n### Return value\r\nThe `handler` always returns HTTP 200 with a JSON body describing dispatch result.\r\n\r\nOn success:\r\n```js\r\n{ statusCode: 200, body: { dispatched: true, invoice_id: \"<id>\", reason: \"\" } }\r\n```\r\n\r\nIf a callback cannot be dispatched:\r\n```js\r\n{ statusCode: 200, body: { dispatched: false, reason: \"<reason>\" } }\r\n```\r\n\r\nPossible reasons:\r\n- `no_invoice_ident` — no `operationId` in payload\r\n- `invoice_not_found` — invoice missing in DB\r\n- `no_callback_url` — callback URL is absent\r\n- `no_global_fetch` — global `fetch` is not available\r\n\r\n### Optional configuration\r\nBy default, the public JWK is fetched from:\r\n`https://enter.tochka.com/doc/openapi/static/keys/public`\r\n\r\nYou may override via options if you call lower-level functions directly (`decode_webhook`, etc.).\r\n\r\n### Notes\r\n- The module does not add retries or extra validation. It is minimal by design.\r\n- Ensure `PAYMENTS_DB_ADDRESS` is configured and reachable at runtime.\r\n\r\n\r\n","readmeFilename":"README.md","_rev":"1-10192a691c25454a9c8ca4d282559e1d"}