Skip to main content
Data streams send Lobyco events to your endpoint as signed, authenticated HTTPS POST requests, one request per event. This guide is for the developer who builds that endpoint. An integration admin sets up the subscription in Lobyco Nexus and gives you its signing key.
Lobyco delivers every event at least once. The same event can reach you twice, so your endpoint must recognise a repeat and skip it. Use the idempotency key says how.

Before you start

  • A callback URL. Give the admin an HTTPS address at a public host name. Nexus refuses an IP address, and Lobyco refuses an address in a private network when the subscription is saved and again on every request.
  • An authentication method. Agree with the admin how Lobyco signs in to your endpoint: OAuth 2.0 client credentials, HTTP Basic or custom headers. The admin stores it in Nexus as the subscription’s auth integration. Authentication describes the three types.
  • The signing key. Nexus shows it once, when the subscription is saved; get it from the admin. It is a base64 string. Keep it in a secret store, never in source code.
  • A durable store. A table or a queue where your endpoint keeps each event before it answers. Lobyco recommends one keyed on the delivery id, as in Use the idempotency key.

Handle a delivery

Your endpoint does the same for every request:
1

Read the request without parsing it

Read the headers, and read the body as raw bytes. Do not parse the JSON yet: the signature covers the exact bytes Lobyco sent, and parsing and re-serialising changes them. The request lists every header.
2

Check the credentials

Check the Authorization header, or your custom headers, against the credentials in the subscription’s auth integration. Answer 401 to a request without valid credentials. This keeps anonymous callers out before your endpoint does any other work.
3

Check the signature

Compute the HMAC-SHA256 of <t>.<webhook id>.<raw body> with the signing key, and compare it with every v1 value in x-lobyco-signature. Answer 401 when none matches. Verify the signature has the details, code and a test vector.
4

Claim the delivery id

Insert the x-lobyco-webhook-id value into your store in one atomic write. If the id is already there, this is a repeat: answer 2xx and stop. Use the idempotency key has the rules.
5

Store the event and answer 2xx

Store the raw body with its id, then answer any 2xx status. Lobyco ignores the response body. Answer within 10 seconds, counted from the start of the attempt, including Lobyco’s sign-in to your endpoint. A later 2xx counts as a timeout, and Lobyco sends the event again.
6

Process the event from your store

Process the event after you have answered, from your store. Route it on x-lobyco-event, for example offer.redeemed. Skip webhook.test, which is a test request from Nexus. Do not rely on the order events arrive in: see Handle events out of order.
7

Check it works with a test

Ask the admin to select Test on the subscription in Nexus. Nexus shows your status code and response time. A Success with your 2xx means the credentials, the address and your signature check all work.Then ask for Test payload on one of the subscription’s events. Your endpoint gets a sample body in the shape it will receive for that event, again marked webhook.test.

The request

The four x-lobyco-* header names are lower case and reserved. A custom-headers integration cannot override them. It can set its own User-Agent or Accept, which then replaces Lobyco’s.

The body

By default, the body is the event’s data exactly as the owning service published it. Lobyco does not wrap it in an envelope, rename fields or add fields: everything Lobyco adds is in the headers. The body therefore matches the event’s schema in the Events catalogues. If the admin set a payload transformation for the event, the body is the JSON it produces instead. The headers are the same either way, and the signature covers the body actually sent. The publishing services follow different conventions, and your parser must accept all of them:

Verify the signature

Lobyco signs every delivery with HMAC-SHA256 and the subscription’s signing key. Signing cannot be switched off. Check the signature before you trust the body.
  • What is signed: the text <t>.<webhook id>. followed by the raw request body. <t> is the t value from x-lobyco-signature, and <webhook id> is the x-lobyco-webhook-id header.
  • The key: base64-decode the signing key and use the resulting 32 bytes as the HMAC key. Do not use the text of the base64 string.
  • The header: t=<unix seconds>, v1=<hex>, with a comma and a space between entries. While the admin rotates the key, the header carries one v1 entry per valid key. Accept the request if any entry matches.
Step by step:
  1. Read the raw body before any JSON parsing.
  2. Split x-lobyco-signature on commas, trim each part, and read t and every v1 value.
  3. Reject the request if t is more than 5 minutes from your clock. Lobyco recommends this replay window but does not enforce one. A retry carries a fresh t.
  4. Compute HMAC-SHA256(key, "<t>." + webhook id + "." + raw body) as lowercase hex.
  5. Compare it with each v1 value in constant time. Accept the request if one matches.
The signature covers t, x-lobyco-webhook-id and the body. It does not cover x-lobyco-event or x-lobyco-timestamp. Apply your replay window to t, never to x-lobyco-timestamp, and treat x-lobyco-event as routing, not as proof.

Test your implementation

Both rows use the raw body {"offerId":"offer-1"}, t = 1758182400 and the webhook id 9c36b36d1f50d772916352c6499fd695ebdece031df828e05aa454c02b34e7fe. During a rotation from the second key to the first, the header is t=1758182400, v1=4fcc76…e4aba4, v1=fd9567…a9f597. A check with either key must accept it. This t is in the past, so switch off the replay window for this test only, never in production.

Rotate the key

The admin can generate a new signing key in Nexus at any time, and Nexus shows it once. The previous key stays valid for 24 hours. During that time, every delivery carries a v1 signature for each of the two keys.
  1. Add the new key next to the old one, and accept a request that matches either.
  2. Remove the old key within 24 hours.
If the key has leaked, skip the overlap. Ask the admin to select Generate new key twice, which stops the leaked key at once, and load the key shown last straight away. Until you load it, your signature check rejects every delivery.

Use the idempotency key

x-lobyco-webhook-id is the idempotency key. Lobyco sets it once per subscription and published event. It repeats it unchanged on every retry and on every resend by Lobyco Support.
  1. Verify the signature first. The signature covers the id, so the id on a request that passes the check is genuine. Never record the id of a request that fails it.
  2. Claim the id in one atomic write. Insert it into a table keyed on the id, or use a conditional put. If the write succeeds, this is the first copy. If it conflicts, it is a repeat. Do not read first and write later: a second copy can arrive while you still handle the first, for example after a timeout.
  3. Answer 2xx to a repeat. Any other answer counts as a failure: Lobyco retries the delivery or sets it aside, as in Failure and edge cases.
  4. Do not let the check lose an event. Store the event together with its id and process it afterwards. Or record the id in the same transaction as the work it triggers. If you record the id and the work then fails, the retry is skipped as a repeat and the event is lost.
  5. Keep the ids for at least 30 days. Retries run for about 45 hours, and Lobyco Support can resend a set-aside delivery for up to 30 days, with the same id. Expiring ids after 31 days covers both.
The id is per subscription. Two subscriptions that send the same events to your endpoint deliver each event once each, under different ids. Avoid that set-up, or also deduplicate on the event’s content. Rarely, the service that owns an event publishes it twice. Lobyco then delivers it twice, under two different ids. If a repeat would do harm, also check the event’s content, such as the customer id and the offer or member id with its timestamp. Do not rely on the event’s own EventId alone: on member.updated it changes when the event is published again.

Handle events out of order

Do not rely on the order events arrive in.
  • Events about the same customer normally arrive in the order they happened. A retried delivery can still be overtaken by a later event, and a resend by Lobyco Support can arrive days later.
  • Definition events have no order at all. An inbound_api.updated can arrive before the inbound_api.created of the same Inbound API block.
  • A member’s loyalty-card events are ordered per card. They can arrive before or after that member’s other events.
Definition events (*.created, *.updated), every inbound_api.* event and member.updated carry the full current state of the item. Keeping the newest version you have received is therefore safe. Decide which version is newer from the time of the change, never from the order of arrival:
  • For most events, compare the event’s timestamp.
  • For an Inbound API event, compare the time of its own change per triggerId: createdAt, updatedAt, publishedAt, stoppedAt or deletedAt.
Campaign and Inbound API times are to the second. Two changes in the same second carry the same time and can arrive in either order.

Recognise test requests

The admin can test a subscription from Nexus in two ways. Both send one request, signed and authenticated like a real delivery, with x-lobyco-event: webhook.test.
  • Test sends a fixed body:
  • Test payload sends a sample of one of the subscription’s events. It has real field names and made-up values, run through the event’s saved payload transformation. Only the x-lobyco-event header tells it apart from a real event.
Check that header, and never process a webhook.test request as real data. Verify its signature and answer 2xx, like any other request. Test requests are never retried.

Secure the endpoint

  • Protect personal data. Check the data carried by customer events and Inbound API events. A delivery Lobyco could not deliver is kept, body included, for 30 days.
  • Revoke credentials through the admin. To stop Lobyco using a set of credentials, ask the admin to switch the subscriptions to another auth integration, or to disable them. Deleting the integration is not enough: see Manage a subscription.

Limits

  • No delivery history for you. You cannot see your failed deliveries or request a replay. Lobyco Support handles deliveries that were set aside.
  • No automatic pause. A subscription stays enabled even if every delivery fails, until an admin disables it.
  • No rate limit per subscription. Lobyco limits how many deliveries run at the same time and honours Retry-After. Answer 429 with Retry-After to slow Lobyco down.
  • Managed in Nexus only. There is no API to manage subscriptions.

Failure and edge cases

Your answer decides what Lobyco does next: Lobyco’s sign-in to your endpoint follows the same rule. If your identity provider is unavailable, with a timeout, a 429 or a 5xx, Lobyco retries. If it refuses the credentials or answers 404, the delivery is set aside without retrying. A delivery has up to 10 attempts. Before each retry, Lobyco waits a little longer, give or take 20%: That is a window of about 45 hours. If every attempt fails, the delivery is set aside.
  • Set-aside deliveries are kept for 30 days, then deleted. Lobyco Support can resend them once the cause is fixed, with the same x-lobyco-webhook-id.
  • Disabling discards waiting deliveries. During an outage, ask the admin to leave the subscription enabled: see Manage a subscription.
  • A failed payload transformation sends nothing. When the transformation cannot produce valid JSON for an event, Lobyco sets the delivery aside without calling your endpoint. Ask the admin to fix it, then ask Lobyco Support to resend.
  • Data streams: set up a subscription — what the admin does in Nexus: events, auth integration, signing key, tests and enabling.
  • Events — event types, Data streams availability, timing and JSON Schemas.
  • OutboundAPI connection — the auth integration types, and how a campaign calls your system at one chosen step.
Last modified on November 12, 2026