Ověření a testování
Ověřujte původní tělo požadavku, zpracovávejte duplicity a bezpečně testujte příjemce.
Před použitím payloadu ověřte každý webhook a poté odešlete test, abyste si potvrdili, že příjemce funguje od začátku do konce.
Než začnete
- Uložená cílová adresa a její podpisový klíč
twhsec_.... K ověřování webhooků nepoužívejte Server Secret Token. - Routa příjemce, která dokáže načíst původní tělo požadavku dřív, než ho změní jakýkoli JSON parser.
- Úložiště s unikátním omezením na
idudálosti, aby byly duplicity bezpečné.
Přijetí webhooku
Načtěte původní tělo
Tapaya posílá JSON požadavek POST s těmito hlavičkami. Tělo ponechte jako původní bajty; rozparsované a znovu serializované tělo už podpisu neodpovídá.
Content-Type: application/json
X-Tapaya-Event-Id: 019a0000-0000-7000-8000-000000000001
X-Tapaya-Signature: t=1793361600,v1=<lowercase hexadecimal HMAC-SHA256>- V Express použijte pro tuto routu
express.raw({ type: "application/json" })před globálním JSON parserem.
Ověřte podpis
Vypočítejte HMAC-SHA256 z časového razítka, tečky a původního těla a porovnejte ho s v1 v konstantním čase.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyTapayaWebhook(rawBody, signatureHeader, secret, now = Date.now()) {
if (!Buffer.isBuffer(rawBody) || typeof signatureHeader !== "string") {
throw new Error("Missing raw body or signature");
}
if (typeof secret !== "string" || !secret.startsWith("twhsec_")) {
throw new Error("Missing signing secret");
}
const match = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(signatureHeader);
if (!match) throw new Error("Malformed signature");
const timestamp = Number(match[1]);
if (!Number.isSafeInteger(timestamp) || Math.abs(now / 1000 - timestamp) > 300) {
throw new Error("Expired signature");
}
const expected = createHmac("sha256", Buffer.from(secret, "utf8"))
.update(`${match[1]}.`, "utf8")
.update(rawBody)
.digest();
const received = Buffer.from(match[2], "hex");
if (!timingSafeEqual(expected, received)) throw new Error("Invalid signature");
return JSON.parse(rawBody.toString("utf8"));
}- Jako klíč v UTF-8 použijte celý řetězec
twhsec_.... Klíč nedekódujte a neodstraňujte jeho prefix. - Odmítněte časová razítka vzdálená od vašich hodin více než pět minut a udržujte hodiny synchronizované.
- Během obměny podpisového klíče nejprve zkuste nový klíč, poté starý, dokud se fronta nevyprázdní.
Uložte a potvrďte
Událost potvrďte až po jejím bezpečném uložení, aby chyba na vaší straně vyvolala opakovaný pokus.
import express from "express";
import { verifyTapayaWebhook } from "./verify-tapaya-webhook.mjs";
import { saveEventOnce } from "./events.mjs"; // your store, unique on event id
const app = express();
app.post(
"/webhooks/tapaya",
express.raw({ type: "application/json" }),
async (req, res) => {
let event;
try {
event = verifyTapayaWebhook(
req.body,
req.get("X-Tapaya-Signature"),
process.env.TAPAYA_WEBHOOK_SECRET,
);
} catch {
return res.sendStatus(400);
}
if (event.organizationId !== process.env.TAPAYA_ORGANIZATION_ID) {
return res.sendStatus(400);
}
await saveEventOnce(event); // skips an id it already stored
res.sendStatus(204);
},
);- Pro událost, kterou už máte uloženou, vraťte
2xx. Opakované pokusy zachovávají stejnéidi tělo, ale mají nové časové razítko a podpis. - Pokud novou událost nelze uložit, vraťte odpověď mimo
2xx, aby se doručení opakovalo. - Uložené události zpracovávejte z vlastní fronty. Pořadí doručení není zaručené, proto starší snímky porovnávejte s aktuálním stavem.
Odešlete testovací webhook
Testovací akce v Platform odešle jeden podepsaný požadavek webhook.test na uloženou URL. Funguje i tehdy, když jsou webhooky vypnuté nebo typ není ve vašem odběru, a nevytváří žádnou platbu, vratku ani obchodníka.
- Otevřete API Keys své organizace a uložte cílovou adresu.
- Použijte testovací akci webhooku.
- Zkontrolujte výsledek, dobu trvání a odeslaný JSON, které Platform zobrazí.
{
"id": "019a0000-0000-7000-8000-000000000010",
"type": "webhook.test",
"apiVersion": "1",
"organizationId": "019a0000-0000-7000-8000-000000000002",
"merchantId": null,
"createdAt": "2026-10-30T12:00:00.000000Z",
"test": true,
"data": {
"message": "This is a test webhook from Tapaya. No payment was created."
}
}Lokální a automatizační příjemci
Když váš produkční server ještě není připravený, nasměrujte webhook na vývojový počítač nebo no-code nástroj.
Řešení chyb
Typy událostí
Vyberte změny plateb, vratek, obchodníků a onboardingu, které vaše integrace potřebuje.
Přehled
Přijímejte platby kartou všude, kde se vaši obchodníci setkávají se zákazníky, od pokladny v obchodě přes stůl v restauraci až po nabíječku elektromobilů, na telefonech a tabletech, které už používají.