Overview
The public VPOS.am webhook contract delivers the signed payment.status_changed event with a server-verified payment status.
Signature contract
Verify the timestamped HMAC against the raw request body before parsing or changing business state.
X-VPOS-Event-Id: <event_id>
X-VPOS-Event-Type: payment.status_changed
X-VPOS-Webhook-Timestamp: <unix_timestamp>
X-VPOS-Signature: t=<unix_timestamp>,v1=<current_secret_hmac>[,v1=<grace_secret_hmac>]
signed_payload = <timestamp>.<raw_request_body>
signature = HMAC-SHA256(webhook_secret, signed_payload)
| Field | Contract |
|---|---|
| Header | X-VPOS-Signature |
| Signed value | <timestamp>.<raw_request_body> |
| Algorithm | HMAC-SHA256 |
| Timestamp tolerance | 5 minutes |
| Delivery timeout | 5 seconds |
| Default maximum attempts | 8 attempts |
| Retry schedule | Exponential from 30 seconds, capped at 1 hour |
| Acknowledgement | Return a fast 2xx response |
| Secret rotation | The header can contain multiple v1 values. Accept only when at least one matches the current or unexpired grace secret. |
| Processing | Verify the signature, persist the event id, then queue side effects. |
Public event contract
The current public merchant contract documents one event type: payment.status_changed. Its top-level payload contains id, type, livemode, createdAt and data; data.payment includes the payment id, merchantOrderId, provider, amountMinor, currency, status and fiscalStatus.
fiscalStatus is a field in the payment projection, not a promise of separate public fiscal or reconciliation events. Treat a new event type as available only after it appears in the published OpenAPI contract.
Signature verification
X-VPOS-Signature uses the format t=<unix_timestamp>,v1=<hex_hmac_sha256>. During rotation it may contain multiple v1 values: accept the event when any candidate securely matches the current or a still-valid grace-period secret. Compute HMAC-SHA256 over the exact bytes of <timestamp>.<raw_request_body> before JSON transformation.
Reject an invalid signature or a timestamp outside the default 5-minute tolerance, and record it in the security log without changing an order, invoice or CRM status. Delivery also includes X-VPOS-Event-Id, X-VPOS-Event-Type and X-VPOS-Webhook-Timestamp.
Repeated delivery and downstream failures
VPOS.am may deliver the same event more than once, so persist the event id and processing result before starting side effects. A duplicate should return a safe 2xx response without creating a second charge, order, receipt or CRM action.
Return 2xx within the default 5-second timeout and move CRM, ERP, e-mail and other downstream work to a queue. VPOS.am makes up to 8 attempts by default, starting at 30 seconds with exponential backoff capped at 1 hour.
FAQ
Which webhook event is part of the public contract?
Only payment.status_changed is currently documented publicly. fiscalStatus may appear inside data.payment, but separate fiscal and reconciliation events are not available unless they are published in OpenAPI.
How should X-VPOS-Signature be verified?
Compute HMAC-SHA256 over the exact bytes of <timestamp>.<raw_request_body> and securely compare it with every v1 in the header; during rotation any match against the current or still-valid grace-period secret is valid. Apply the five-minute timestamp tolerance and do not update orders before verification.