Skip to main content
Webhooks notify your application in real time when transaction events occur. Configure a webhook URL to receive updates for deposits, conversions, transfers, onramp requests, and offramp requests.

Setup

Configure your webhook URL through the dashboard or programmatically via the Update Webhook URL endpoint. Your endpoint must be a publicly accessible POST URL that returns a 200 status code immediately. Process events asynchronously after acknowledging receipt.

Receiving events

Every webhook payload includes three fields:
FieldTypeDescription
eventstringThe event type (e.g., Deposit, Convert, Transfer)
dataobjectEvent-specific payload
signaturestringRSA signature for verification
import express from "express";

const app = express();
app.use(express.json());

app.post("/webhook", (req, res) => {
  const { signature, data, event } = req.body;

  // Verify signature before processing (see below)
  // ...

  console.log("Received event:", event, data);
  res.sendStatus(200);
});

app.listen(3000, () => console.log("Webhook server running on port 3000"));

Supported events

EventDescription
DepositA fiat or crypto deposit was received
ConvertA currency conversion completed
TransferA transfer (payout/withdrawal) status changed
OnrampAn onramp (fiat-to-crypto) request status changed
WithdrawalA withdrawal was processed
OfframpAn offramp (crypto-to-fiat) request status changed

Example: Deposit event

{
  "event": "Deposit",
  "data": {
    "amount": 5001,
    "toUser": "merchant-username",
    "currency": "NGN",
    "toAccount": "merchant-username",
    "status": "completed",
    "sessionId": "3c58db9",
    "transactionMemo": "Payment from customer"
  },
  "signature": "m9STu6pcsviYMfgu5JBjuR..."
}

Verifying signatures

Every webhook includes an RSA signature. Always verify the signature before processing an event to confirm it came from Partna. The signature is generated by signing the JSON-encoded data field with Partna’s RSA private key using SHA-256 with PSS padding. Verify it against the corresponding public key for your environment.
import crypto from "crypto";

const PUBLIC_KEY = `-----BEGIN RSA PUBLIC KEY-----
...your environment's public key...
-----END RSA PUBLIC KEY-----`;

function verifySignature(data, signature) {
  return crypto.verify(
    "sha256",
    Buffer.from(JSON.stringify(data), "utf8"),
    {
      key: PUBLIC_KEY,
      padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
    },
    Buffer.from(signature, "base64")
  );
}

// In your webhook handler:
const { event, data, signature } = req.body;
const isValid = verifySignature(data, signature);

if (!isValid) {
  console.error("Invalid webhook signature");
  return res.sendStatus(401);
}

// Process the event...

Public keys

Use the correct public key for your environment.

Staging

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAv2ipgHLFFHgGHr9VpsPN8V1HIbCrlmTZRU/CYSDaoVX+xerJOMGX
qmwgQMQH5T81VaMw4rtIA8tT4DkJgjb+7G0x4CGK1OPdlvhEGP2mOFy02onkEnMv
uN3glVc4YKLvWDTG0KT7q9mARBIkO2Nrwy6IVHAl9pMXMJTRS22c0cIbuRmkYsGZ
trylUv50knbRSgy5EA6523+j3PPJB4TgsigGSJxJGuksaxnDQGRE558xnyw/0gJm
mAIdbxboQTGMqod/My/kAssRkUNu1QtqrsdhZmGYHS+pIPJSaxqHEy8eiTahoqqq
8KgNUfQfwduG+Kc4f/t5JHetSt1dgulmswIDAQAB
-----END RSA PUBLIC KEY-----

Production

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAoGmOqVUxIGq92P8J5KqwJbwucsNeUwfS76saj0UPgT1IsK/mvceR
Ges7dsgE4EVx7Wsd5PPNeAfaNt8d0plBLhHRW64WFyv6jYcYp8eVdHUxWLA6p5gZ
9rGrZiwqKqunppTPlV04gdDC32rAbpAR3IMYmMJLuPy63Oumszl4qk69A1o60Son
r0KYBaRK7aQsFT9IFexicDUhrF1SohaNH/msTdvJb0SwSGiV92EhmmC2R8CL83/B
S8QC5c9PWtZ4a26CRLHe0IfaGGz8ClhlO8IFxz0cNrpoRa4JRsffezQ+RMQqCxhc
igC7wHfqZr5BtziQOYJjUknVzsd81HEYlwIDAQAB
-----END RSA PUBLIC KEY-----

Best practices

Always verify signatures. Never process a webhook event without verifying the signature first. This prevents spoofed events from affecting your system. Return 200 immediately. Acknowledge receipt before processing. If your endpoint takes too long to respond, the delivery may be retried. Handle duplicates. Use the sessionId or rampReference in the event data as an idempotency key. The same event may be delivered more than once. Log raw payloads. Store the raw webhook body for debugging. If something goes wrong, the raw payload is essential for troubleshooting.