Webhooks — list of endpoints
Every endpoint in the Webhooks section of the API Reference →. Click any row to open the full reference page with the request body, response body, examples, and the Try it widget.
These endpoints are the management surface for the webhooks we send you. They do not deliver webhooks — they configure and inspect them. How a webhook is signed and delivered is covered in the Webhooks guide.
At a glance
| Method | Endpoint | What it does |
|---|---|---|
| GET | /webhooks/public-key | The public key you verify every webhook signature with. |
| PUT | /webhooks/secret | Set or rotate the secret your webhooks are signed with. |
| GET | /webhooks/events | Every supported event type and whether it is currently on. |
| PATCH | /webhooks/events | Switch one or more events on or off. |
| GET | /logs/webhooks | Your own delivery history — one row per delivery attempt. |
All paths are relative to the Partner API base URL (https://api.card-management-staging.paynovus.com/api/partner). Every endpoint is scoped to the partner whose JWT you sent — you can never read or change another partner's configuration.
These endpoints are what you call. The webhook itself arrives at your url as a POST — see the
Webhooks guide for the body you receive, the signature scheme,
and the guarantee that one final outcome produces one webhook.
Get the public key
Fetches the Ed25519 public key your receiver verifies signatures with. Cache it by keyId; the X-Payload-Key-Id header on each webhook tells you which key signed it, so you can pick the right one after a rotation.
Request body: none.
Response body
{
"success": true,
"keyId": "9f86d081884c7d65",
"algorithm": "ed25519",
"publicKey": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n"
}
Validation
| Field | Type | Required | Rules |
|---|---|---|---|
success | boolean | — | Always true on success. |
keyId | string | — | The signing key id, matching X-Payload-Key-Id. |
algorithm | string | — | Always ed25519. |
publicKey | string | — | SPKI PEM. |
Errors: 401 when the JWT is missing or invalid; 503 when signing is not configured on the environment (no webhooks are sent there either).
Set or rotate the secret
PUT /webhooks/secret
Sets the secret your webhooks are signed with. The secret is stored encrypted and is write-only — no endpoint returns it again, so store it when you set it. Rotation applies to webhooks sent after the call, with no grace period for the old secret.
Request body
{
"secretKey": "my-own-long-random-secret"
}
Omit the body entirely and we generate a strong random secret and return it once in the response.
Request validation
| Field | Type | Required | Rules |
|---|---|---|---|
secretKey | string | No | 8–200 characters. Trimmed before it is stored. Unknown properties are rejected. |
secretKey is the only accepted property. A misspelled field (for example secret) is rejected with 400 rather than being silently ignored, so you always know which secret is in force.
Response body
{
"success": true,
"hasSecret": true,
"secretKeyGenerated": false
}
| Field | Type | Rules |
|---|---|---|
success | boolean | Always true on success. |
hasSecret | boolean | Always true — a secret is stored either way. |
secretKeyGenerated | boolean | true when we generated the secret, false when we used the value you supplied. |
secretKey | string | Present only when secretKeyGenerated is true, and only this once. |
Errors: 400 for an invalid length or an unknown request property; 401 when the JWT is missing or invalid.
Validation error body
A failed validation returns the offending field and the reason:
{
"message": "Validation failed",
"details": [{ "field": "secretKey", "message": "secretKey must be at least 8 characters" }],
"type": "validation error"
}
List the event subscriptions
GET /webhooks/events
Returns every event type the platform can send, with its current on/off state. An event you have never touched is on — webhooks are opt-out, so a newly introduced event type reaches you without any change.
Request body: none.
Response body
{
"success": true,
"count": 8,
"data": [
{ "event": "b2b_account_created", "isActive": true },
{ "event": "b2b_cardholder_approved", "isActive": false }
]
}
| Field | Type | Rules |
|---|---|---|
success | boolean | Always true on success. |
count | integer | The number of supported event types. |
data | array | One entry per event type, each { event, isActive }. |
The supported event types
event | Meaning |
|---|---|
individual_onboarding_applicant_created | An individual onboarding was created. |
individual_onboarding_applicant_declined | The individual onboarding ended without a usable account. |
b2b_account_created | A B2B account request was approved. |
b2b_account_declined | A B2B account request was declined. |
b2b_cardholder_approved | A B2B cardholder request was approved. |
b2b_cardholder_declined | A B2B cardholder request was declined. |
b2b_iban_settings_updated | An IBAN settings change was applied or declined. |
b2b_iban_linked | An IBAN link request was linked or declined. |
Errors: 401 when the JWT is missing or invalid.
Switch event subscriptions
PATCH /webhooks/events
Sets the state of one or more events at once. Events you do not mention keep their current state, so the request is safe to repeat.
Request body
{
"events": [
{ "event": "b2b_cardholder_approved", "isActive": false },
{ "event": "b2b_iban_linked", "isActive": true }
]
}
Request validation
| Field | Type | Required | Rules |
|---|---|---|---|
events | array | Yes | At least one entry. Unknown properties are rejected. |
events[].event | string | Yes | One of the supported event types listed above. |
events[].isActive | boolean | Yes | true to receive the event, false to skip it. |
isActive must be a real JSON boolean — the string "false" is rejected, not coerced. Unknown fields, in the body or inside an event entry, are rejected too.
Response body: the same shape as the list endpoint — the full event list after the change.
Errors: 400 for an empty array, an unknown event type, or a non-boolean isActive; 401 when the JWT is missing or invalid.
Validation error body
A failed validation returns the offending field and the reason:
{
"message": "Validation failed",
"details": [{ "field": "events", "message": "events must include at least one event" }],
"type": "validation error"
}
Delivery also requires the master webhook switch (webhooks.isActive), which your PayNovus administrator controls. Switching an event off here does not change the master switch or your url.
Read the delivery history
GET /logs/webhooks
Every webhook we send to you leaves a delivery log row. This endpoint returns those rows so you can see what was sent, to which url, and whether it arrived. It is read-only — there is no resend or modify action here.
Query parameters
| Parameter | Type | Default | Rules |
|---|---|---|---|
page | integer | 1 | Page number. |
limit | integer | 50 | Rows per page. |
Response body
{
"success": true,
"count": 2,
"data": [
{
"_id": "6adf2f5bfe545da555d81245",
"event": "b2b_cardholder_approved",
"webhookUrl": "https://your-domain.example/webhooks/cip",
"payloadSent": { "status": "success", "type": "b2b_cardholder_approved" },
"responseStatus": 200,
"responseBody": { "received": true },
"error": null,
"createdAt": "2026-01-15T10:30:00.000Z"
}
],
"pagination": { "total": 2, "page": 1, "limit": 50, "pages": 1, "hasNextPage": false, "hasPrevPage": false }
}
| Field | Type | Rules |
|---|---|---|
event | string | The event type — the same value as the body's type. |
webhookUrl | string | The url we delivered to. |
payloadSent | object | The exact body we sent, or null. |
responseStatus | integer | The HTTP status your endpoint returned, or null if it never answered. |
responseBody | object | The body your endpoint returned. |
error | object | The error details, when the delivery failed, otherwise null. |
createdAt | string | When the attempt was made (ISO 8601). |
The signing secret is never included.
Errors: 401 when the JWT is missing or invalid.