Skip to main content

Introduction

Webhooks allows the client to set a callback URL on which the client will receive a POST request containing event data relating to a specific system event or API request.

An event may be raised as the outcome of a specific operation initiated by a client via Order Management API, and Checkout API.

info

When a new payment method is added Update Subscription needs to be called , to get the events for the new payment method.

URL requirements

  • Webhook URLs must accept HTTPS connections using TLS v1.2 or higher.
  • Webhook URLs must accept POST requests.
  • Webhook URLs must accept media type “application/json”.
  • Webhook URLs must indicate successful reception of event by returning 2xx response.

Request Body

The body of a webhook request contains event data with mandatory fields as well as event specific fields based on the type of operation that caused the event to be raised.

Mandatory fields

NameDescriptionType
EventName

The event type, this is used to determine the type of event received.

String
CorrelationId

The correlation id provided in the origin request if the event is raised based on the outcome of a client-initiated operation.

Guid
TimestampUtc

A timestamp representing the moment in time when the event was raised.

Timestamp

Delivery Guarantees

  • Events might be delivered more than once, so duplicates are possible.
  • Events are not guaranteed to be delivered in chronological order.
  • Events are not guaranteed to be delivered in scenarios where the receiving webhook endpoint is unavailable.
  • If a request does not receive a 2xx response, the system will retry with exponential backoff over a set period until a maximum number of attempts is reached or a successful response is received.
info

To avoid some failures and to minimize retries Svea recommends a few practices when integrating support for webhook events.

Recommendations

  • Since the webhook URL can be invoked more than once for the same event, we recommend that clients make their event processing idempotent. This is to avoid duplicates on the client side.
  • We recommend that the client adds the incoming events to a queue for future processing so that a response can be returned to our API as quickly as possible.
  • Since event delivery is not guaranteed if the client endpoint is unavailable for the full retry attempt duration, we recommend that data is also synched through GET Order
  • A good practice is also to implement support for full order sync when receiving the generic order updated event for an order.

HMAC Signature Verification

When creating or updating a subscription, you can provide an optional Secret field. If a secret is set, every webhook request sent to your callback URL will include HMAC signature headers that you can use to verify the authenticity of the request. The secret used for verification must be the same value you provided in the Secret field when you created or last updated the subscription.

Headers

When a secret is configured, the following headers are included in each webhook request:

HeaderDescription
X-Signature-512HMAC-SHA512 signature generated from the timestamp and request payload.
X-TimestampUnix timestamp (seconds since epoch) when the request was created.

Signature Generation

The signature is computed using HMAC-SHA512 with your secret as the key:

  1. Construct the signed payload: {timestamp}.{request_body}
    • timestamp is the value from the X-Timestamp header
    • request_body is the raw JSON body of the request (empty string if no body)
  2. Compute HMAC-SHA512 using the secret you provided when creating (or updating) the subscription (UTF-8 encoded) as the key and the payload (UTF-8 encoded) as the message.
  3. The signature is the Base64-encoded representation of the resulting hash bytes.

Signed Payload Format

{timestamp}.{request_body}

Example

Given a timestamp of 1713001200, body {"orderId":123,"status":"confirmed"}, and secret your-secret-key:

The signed payload:

1713001200.{"orderId":123,"status":"confirmed"}

The signature is Base64(HMAC-SHA512(key="your-secret-key", message="1713001200.{\"orderId\":123,\"status\":\"confirmed\"}")).

Verification Examples

using System.Security.Cryptography;
using System.Text;

public static class WebhookSignatureVerifier
{
public static bool VerifySignature(string requestBody, string secret, string receivedSignature, string timestampHeader)
{
var payload = $"{timestampHeader}.{requestBody}";
var secretBytes = Encoding.UTF8.GetBytes(secret);
var messageBytes = Encoding.UTF8.GetBytes(payload);

using var hmac = new HMACSHA512(secretBytes);
var hashBytes = hmac.ComputeHash(messageBytes);
var computedSignature = Convert.ToBase64String(hashBytes);

return CryptographicOperations.FixedTimeEquals(
Encoding.UTF8.GetBytes(computedSignature),
Encoding.UTF8.GetBytes(receivedSignature));
}
}

Recommendations

  • Always verify the X-Signature-512 header before processing the webhook payload.
  • Use the X-Timestamp header to reject requests that are too old (e.g., older than 5 minutes) to guard against replay attacks.
  • Use a constant-time comparison function (as shown in the examples) to prevent timing attacks.
  • Store your secret securely and never expose it in client-side code. This is the same Secret value you provided when creating or updating the subscription.