Preskoči na sadržaj

Webhook-ovi

Dokaz da je svaka payment notifikacija od Perpera prije fulfill-a. Ovo je merchant trust surface (Stripe: Verify signatures).

Zašto ovo postoji

Svako može otvoriti lažni success URL u browseru. Vaš apiUrl mora kriptografski provjeriti da je Perper potpisao opaque order data vašim project secretom. Tek tada označite narudžbu plaćenom.

Callback ugovor (apiUrl POST)

Polja JSON tijela:

  • status — success | fail
  • data — opaque string koji ste poslali na /pay (npr. order id)
  • hash — HS256 JWT tog data stringa, potpisan project secretom
  • transactionId — na uspjehu kad je ledger transfer završen
  • customId — echo kad ste ga dali na /pay ili Contabo QR

Verifikacija hash-a (obavezno)

Backend potpisuje sa jwt.sign(dataString, projectSecret) (HS256). Istu provjeru radite na serveru. Ako verify padne, odgovorite 400 i ne radite fulfill.

Pinuj algorithms: ['HS256']. Odbij alg=none / RS*. Pogrešan secret → invalid signature.

javascript
const jwt = require("jsonwebtoken");

/** Same as Perper backend generateHash — HS256 of opaque data string */
function verifyPayHash({ data, hash, secret }) {
  const payload = jwt.verify(hash, secret, { algorithms: ["HS256"] });
  if (payload !== data) throw new Error("mismatch");
  return data;
}

// apiUrl POST body: { status, data, hash, transactionId?, customId? }
app.post("/perper/webhook", (req, res) => {
  const { status, data, hash, transactionId } = req.body;
  try {
    verifyPayHash({
      data,
      hash,
      secret: process.env.PERPER_PROJECT_SECRET,
    });
  } catch {
    return res.sendStatus(400); // never fulfill
  }
  // de-dupe on transactionId || data, then fulfill once
  res.sendStatus(200);
});

Idempotency

Contabo trenutno šalje svaki success webhook jednom (single fetch). I dalje de-dupe po transactionId kad postoji, inače po opaque data / customId — duplikat ne smije double-fulfill.

Dva hash ugovora

Pay callback / redirect hash = JWT samo opaque data stringa. checkStatus hash = JWT od { projectId, customId }. Ne miješajte payload-e.

Status vokabular

Redirect query koristi status=success|error. Webhook body koristi status=success|fail. error i fail tretirajte kao isti failure class.

Failure režimi

Ovo je reject / investigate — nikad fulfill:

  • Unsigned — data i hash nedostaju (legacy ili pogrešno konfigurisan success path).
  • Invalid / mismatch — tampered data, loš JWT ili algorithms confusion.
  • Pogrešan secret — JsonWebTokenError invalid signature (rotirajte ili zalijepite trenutni project secret).

Dokaz u portalu (live)

Giants imaju Dashboard “Send test webhook”. Perper daje isti loop bez CLI-ja:

  1. Detalj projekta → zalijepi secret → Pošalji success/fail callback na apiUrl.
  2. Ili /demo sa apiUrl = https://sdk.perper.net/api/demo/callback i pregled na /demo/callbacks. /demo · /demo/callbacks
  3. Na /demo/callbacks zalijepi project secret → Verify → badge Verified / Invalid / Unsigned. Secret se ne čuva.

Šta znači “Verified”

Verified = jwt.verify(hash, secret, { algorithms: ['HS256'] }) vratio isti data string. To je system proof da je Perper autor callback-a. Invalid / Unsigned = ne radite fulfill.

Test mode (sk_test_)

Samo portal BFF sandbox: sk_test_ živi u store-u SDK website-a, ne u Contabo ledgeru. Koristite Pošalji test callback (Test mode) da dokažete endpoint — stanje se ne pomjera. Prave pay webhook-ove potpisuje Contabo project secret. Ishodi dostave su na stranici projekta (Nedavne webhook dostave).

Dalje: ugradite ovo u produkcijski checkout, pa skenirajte Plaćanja za hostovani /pay URL. Plaćanja · Bezbednost (bankarski nivo)