OuiPay
Webhooks

Webhook Security

Signing secrets, timestamp replay protection, IP allowlisting, and secret rotation.

Signing secrets

Each webhook subscription has its own signing secret, issued once at creation. The secret is used to compute an HMAC-SHA256 signature over every delivery payload.

  • Store the secret in your secrets manager, never in source control.
  • If lost, rotate the subscription and create a new one.
  • Each subscription has an independent secret; compromising one does not affect others.

Timestamp replay protection

Every delivery includes an X-OuiPay-Timestamp header (Unix seconds). Your verification logic should reject timestamps older than 5 minutes:

if abs(now - timestamp) > 300 seconds → reject

This prevents an attacker who captures a valid signed payload from replaying it later.

Event deduplication

Deliveries are at-least-once. The event_key field uniquely identifies each event. Before performing any side-effect (credit, fulfill, mark-paid), check whether you have already processed that event_key.

A payment.completed replay that credits the customer twice is a financial loss. event_key is the guard.

HTTPS only

OuiPay delivers webhooks only to https:// endpoints. Plain HTTP endpoints are rejected at subscription creation.

IP allowlisting

For defense-in-depth, you can restrict inbound webhooks to OuiPay's delivery IP ranges. Contact support for the current IP list. This is a supplementary measure: always verify signatures regardless of source IP.

Rotating a signing secret

If you suspect a signing secret has been compromised:

  1. Create a new webhook subscription with the same URL and events.
  2. Update your verification code with the new secret.
  3. Delete the old subscription.

During the transition, you may briefly receive deliveries from both subscriptions. Your event_key deduplication handles this.

Common mistakes

MistakeRiskFix
Not verifying signaturesAttacker can forge eventsAlways verify before side-effects
Verifying parsed JSON instead of raw bytesSignature mismatchVerify against the raw request body
No timestamp checkReplay attacksReject timestamps older than 5 minutes
No event_key deduplicationDouble-creditingStore and check processed event_key values
Slow handler (>10s)Retries cause duplicatesAck fast, process async

On this page