Revolut
Attribute Revolut Merchant API orders to the visits that led to them.
Use this connector when your checkout creates orders through the Revolut Merchant API (Revolut Checkout widget, hosted payment page or your server). Revolut’s webhook only names the order ({"event": "ORDER_COMPLETED", "order_id": "…"}), so Seean verifies the signature and then reads the completed order from the Merchant API with your API secret key to get the amount, currency, description and metadata. Attribution is derived on Seean’s server from the buyer’s tracked visits when the order metadata carries the visitor ID.
Setup
- In Seean open Settings → Integrations → Payment providers on your own website, choose Revolut, select Enable and copy the webhook URL (
https://events.seean.io/api/connect/revolut/<site ID>; use the exact value shown). - Create a Merchant API webhook for that URL with the
ORDER_COMPLETEDevent. Revolut’s Merchant dashboard and the Merchant API both create webhooks; the API call isPOST https://merchant.revolut.com/api/webhookswith{"url": "<webhook URL>", "events": ["ORDER_COMPLETED"]}and returns the webhook’ssigning_secret(wsk_…). A webhook created in the dashboard shows its signing secret in the webhook’s details. - Paste the signing secret into Seean’s first field.
- In the Merchant dashboard open Developers → API keys and copy the Secret key (
sk_…). Paste it into Seean’s second field, then choose Save secret. Seean uses it only to read orders named by verified webhooks. - Pass the attribution metadata described below when you create orders.
Only the website owner can connect, replace or disconnect a provider; one connection per provider; demo websites cannot connect providers.
Attribution handoff
Read window.seean.attribution() in the browser, send it to your server and attach it as metadata when creating the order. Seean reads it back from the retrieved order:
// Browser
await window.seean?.ready;
const a = window.seean?.attribution?.() ?? {};
const seean = { seean_visitor_id: a.visitorId, seean_landing_path: a.landingPath, seean_converting_path: a.convertingPath, seean_campaign: a.campaign };
// send `seean` to your server with the checkout request
// Server: Revolut Merchant API
const res = await fetch("https://merchant.revolut.com/api/orders", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.REVOLUT_SECRET_KEY}`, "Revolut-Api-Version": "2026-08-17", "Content-Type": "application/json" },
body: JSON.stringify({ amount: 1999, currency: "GBP", description: "Starter plan", metadata: Object.fromEntries(Object.entries(seean).filter(([, v]) => v)) }),
});
const order = await res.json(); // use order.token with Revolut Checkout or redirect to order.checkout_url
| Key | Meaning |
|---|---|
seean_visitor_id |
Links the order to the buyer’s tracked visits; touches, first and last source, landing page and time to buy are derived from that history. |
seean_landing_path |
Used only when Seean has no tracked visit for the visitor in the 90 days before the order. |
seean_converting_path |
The page where checkout started. |
seean_campaign |
Overrides the campaign derived from the tracked history. |
Orders created without metadata, for example from a payment link, are recorded as Unattributed.
What is recorded
| Event | Result in Seean |
|---|---|
ORDER_COMPLETED |
Seean retrieves the order and records it when its state is completed: amount in currency, description as the product name (or “Revolut order”). Orders that carry subscription_data become subscription orders; others are one-time orders. |
The order ID is the Revolut order ID and the order time is the order’s created_at. ORDER_AUTHORISED and every other event are acknowledged without a lookup. If the order cannot be read, Seean returns HTTP 503 and shows the lookup error under Last event failed. This covers network failures, timeouts, rate limits, unavailable API responses and an order not yet visible. Check a wrong or rotated secret key before replaying the delivery.
Refunds
The Merchant API has no refund webhook event, so refunds are not received through this connector. Record them with the Order API using the Revolut order ID as externalId and the refund ID from the Merchant API’s refund response as refundId; they then reduce net revenue in the period of the original order.
Currency
Orders are stored in the website’s reporting currency (Settings → Integrations → Revenue integration). Revolut amounts are already in minor units. An order in another currency is acknowledged but not stored, and the reason appears under the provider.
Verify
Complete a sandbox order with a sandbox webhook and your sandbox secret key connected: Seean tries merchant.revolut.com first and falls back to sandbox-merchant.revolut.com when the production API rejects the key or does not know the order. The status line under Revolut shows the last event time and, if the last event could not be stored, the error. Then open Revenue for a range containing the order and check the amount, product and derived attribution. Duplicate deliveries return duplicate and change nothing.
Limits
- Seean verifies the
Revolut-Signatureheader (v1=hex HMAC-SHA256 overv1.<Revolut-Request-Timestamp>.<body>, every listed signature is tried during a secret rotation) and rejects deliveries whose timestamp is more than five minutes old. - Each verified
ORDER_COMPLETEDdelivery makes one Merchant API request, or two when falling back to the sandbox. Both requests share an eight-second timeout. The secret key stays on Seean’s server and is never shown again after saving. - Revolut documents three additional delivery attempts at ten-minute intervals after an HTTP error or timeout. If these expire, recover the order with the Order API using its original Revolut order ID and payment details. See Revolut’s retry policy.
- Request bodies above 64 KiB are rejected with 413. Events Seean does not handle are acknowledged with 200; rate limits return 429 and temporary ingestion failures return 503 so the provider can retry. See delivery recovery.
- Disable stops accepting events (the URL answers 404) and removes both secrets; delete the webhook in Revolut so it stops retrying. Existing orders are kept.
Related: Revenue attribution, Order API and refunds.
Something unclear? Contact support.