Webhooks
MeerPartners inbound webhooks: deposit credit from a payment provider and MeerID identity events. Format, HMAC signature and idempotency by delivery id.
MeerPartners has inbound webhooks — the platform receives server-side notifications from trusted systems. All of them are signature-protected and idempotent.
There are no outbound event subscriptions yet
At this time the platform does not dispatch outbound webhooks for affiliate-program events (conversion approved, payout processed, etc.) — you cannot subscribe to them via the API. If you need to know the state of conversions, poll the data through the cabinet/read endpoints. This page describes only the inbound webhooks that the platform receives.
The deposit credit webhook
When a business tops up its escrow balance, the actual credit does not happen immediately: first a pending intent is created (POST /api/v1/merchant/deposit), and the money is credited via a server-side webhook from the payment provider.
/api/v1/merchant/deposit/webhook🔒 HMACThis is an S2S endpoint: it is called by the trusted payment provider, not the browser. The signature is verified before the body is parsed.
Signature
X-Provider-Signature: <hex(HMAC_SHA256(secret, signing_string))>
X-Timestamp: 1717200000The signing_string is the same scheme as for the postback:
{METHOD}\n{PATH}\n{X-Timestamp}\n{SHA256_hex(raw_body)}The secret is the shared deposit-webhook secret configured by the operator (DEPOSIT_WEBHOOK_SECRET). Verification is constant-time.
Body
{
"provider": "card",
"provider_tx_id": "yk_2f9a1c",
"deposit_intent_id": 88,
"amount": "5000.00",
"currency": "RUB",
"status": "success"
}| Field | Value |
|---|---|
provider | The provider identifier |
provider_tx_id | The provider's transaction ID — the idempotency key |
deposit_intent_id | The ID of the intent created at POST /api/v1/merchant/deposit |
amount | The amount as a string |
currency | The currency, ISO-4217 |
status | success / failed / refunded |
Idempotency and protection
- Dedup by
provider_tx_id: a redelivery will not credit the deposit twice. - Anti-replay:
X-Timestampwithin ±5 minutes; a replay of the same signature within the memory window is rejected. The memory window lives in Redis. - Fail-closed: if the webhook secret is not configured, the request is rejected (
503) rather than let through. This closes the hole of an under-configured environment on a money endpoint.
| Code | HTTP | When |
|---|---|---|
DEPOSIT_WEBHOOK_UNCONFIGURED | 503 | The webhook secret is not set (fail-closed) |
DEPOSIT_WEBHOOK_SIGNATURE_INVALID | 401 | Missing headers, an invalid signature, a timestamp outside the window, or a replay |
DEPOSIT_WEBHOOK_REPLAY_STORE_UNAVAILABLE | 503 | The replay-protection store is unavailable (fail-closed) |
INVALID_PAYLOAD | 400 | Invalid JSON in the body |
This is an operator-to-provider integration
The deposit webhook is configured on the platform side and the payment provider side. A business does not need to wire it up itself during normal operation — topping up the balance goes through the cabinet.
MeerID identity webhooks
Because sign-in goes through MeerID, the platform receives identity events from it in order to revoke access in time (a ban, an account deletion) and to synchronize merges. This is part of the SSO loop and is handled by the portal — you do not need to embed these into your own integration.
Back-channel logout
/api/v1/auth/meerid/backchannel-logout🔒 —An OIDC Back-Channel Logout receiver. The body is application/x-www-form-urlencoded with a logout_token field. The token is verified against the JWKS (RS256: iss, aud, exp, the presence of a logout event, the absence of nonce). Based on the result, all of the user's sessions are revoked. An unknown subject → a no-op 200. An invalid token → LOGOUT_TOKEN_INVALID (401).
Identity webhook
/api/v1/auth/meerid/webhook🔒 HMACAccepts the account.merged and account.erased events.
- HMAC-SHA256 over the raw body, using the string
{timestamp}.{raw_body}and theMEERID_WEBHOOK_SECRETsecret (constant-time). - Freshness
|now − ts| ≤ 300 s(anti-replay), otherwiseWEBHOOK_TIMESTAMP_STALE(401). - Dedup by the
X-MeerID-Deliveryheader (at-least-once safe). event_typeis taken only from the signed body (headers are not covered by the signature).- An unknown
event_type→ a200no-op (forward-compatible). - If the secret is not set — fail-closed: any webhook is rejected.
| Event | Platform action |
|---|---|
account.merged | Rebind meerid_sub; on a collision — revoke sessions and deactivate the old record |
account.erased | Deactivation, clearing of the PII cache, revocation of all the user's sessions |
More on the access-revocation model is in the engineering documentation Auth and security.
Webhook idempotency — the general principle
Any inbound webhook may arrive more than once (a retry after a timeout on the sender's side). The platform suppresses duplicates by the idempotency key:
| Webhook | Dedup key |
|---|---|
| Deposit | provider_tx_id |
| MeerID identity | X-MeerID-Delivery |
If you are writing your own sender system, send a stable delivery identifier and retry the request on failures: a duplicate will do no harm.