Receiving Webhooks

Once you have subscribed to webhooks, Remote sends a signed HTTPS request to your callback URL every time a matching event fires. This guide covers how to receive those deliveries safely: what arrives, how to respond, and how to recover events you missed.

What a delivery looks like

Each delivery is an HTTP POST to your callback URL with a JSON body and three headers set by Remote:

  • X-Remote-Timestamp: when Remote sent the delivery, as Unix time in milliseconds.
  • X-Remote-Signature: the signature you use to confirm the delivery is genuine.
  • Content-Type: always application/json.

Your endpoint must be publicly reachable over HTTPS and should respond quickly.

Verify every delivery

Because your endpoint is open to the internet, confirm that each request really came from Remote before you act on it. Verify the signature and timestamp before you parse or trust the body. The full procedure, using the signing_key from registration, is in Verifying Webhooks.

Respond fast, then process

Remote treats a quick 2xx response as received. Acknowledge the delivery right away and do the heavy work, such as database writes, third-party calls, and notifications, in a background worker rather than inside the request. A slow handler holds the connection open and risks a failed delivery.

Retries and delivery outcomes

Remote decides what to do with a delivery based on how your endpoint responds:

  • A 2xx response means the delivery succeeded.
  • A 4xx or 5xx response is treated as delivered. Remote does not retry it.
  • A transport failure, such as a timeout or a connection, DNS, or TLS error, is the only case Remote retries.

Remote retries a failed delivery up to 5 times, on this schedule: 30 seconds, 5 minutes, 1 hour, 6 hours, and 18 hours after the first attempt.

Because a 4xx or 5xx is not retried, do not return an error status to ask Remote to send the event again. If you cannot process an event yet, accept it with a 2xx and queue it on your side.

Handle duplicates

Assume at-least-once delivery. The same event can arrive more than once because of retries, replays, or network hiccups. De-duplicate on the event id in the payload and make your processing idempotent, so a repeated delivery has no extra effect. The timestamp is not a de-duplication key, because each attempt is signed with its own fresh timestamp.

Recover missed deliveries

If deliveries fail or you need to reprocess events, inspect the delivery history and replay events.

List delivery events with the List Webhook Events endpoint. Filter by event type, company, date range, and delivery status:

curl "https://gateway.remote.com/v1/webhook-events?event_type=timeoff.requested&successfully_delivered=false" \
  -H "Authorization: Bearer $REMOTE_API_TOKEN"

Replay one or more events with POST /v1/webhook-events/replay, either by id or by filter:

curl -X POST https://gateway.remote.com/v1/webhook-events/replay \
  -H "Authorization: Bearer $REMOTE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "0073fcb5-b669-4e4a-b963-2a47744e75a1"
    ]
  }'

A replay redelivers the original payload with a fresh timestamp and signature, so your endpoint verifies and de-duplicates it exactly as it would a first delivery.

📘

The webhook-events list and replay endpoints require an OAuth integration token (client credentials) with the webhook.read and webhook.write scopes. A Customer API token is not tied to an integration and receives a 404 on these endpoints. If you manage webhooks with a Customer API token, use the CLI below or the Sandbox trigger to test deliveries.

Inspect and replay from the CLI

The Remote CLI covers the same ground for your active company:

# Browse delivery history (filter by type, date, or delivery status)
remotecli webhooks event-history --event-type timeoff.requested --successfully-delivered false

# Replay by id, or by filter
remotecli webhooks event-replay <event-id>
remotecli webhooks event-replay --event-type timeoff.requested --successfully-delivered false

# Tail new deliveries while you test
remotecli webhooks listen --event-type timeoff.requested

Test before you go live

When you develop locally, Remote cannot reach localhost. Use a tunneling service such as ngrok to expose your local endpoint, then register that public URL as your callback.

🚧

Only use ngrok for Sandbox testing. Do not use the free version of ngrok in production. It assigns URLs randomly, so if you forget to delete a callback after shutting ngrok down, your URL may be reassigned to another user and your webhook data would be sent to them.

In Sandbox, fire a test delivery with the Trigger a Webhook endpoint to confirm your endpoint verifies and processes a real payload. This endpoint is not available in production.

curl -X POST https://gateway.remote-sandbox.com/v1/sandbox/webhook-callbacks/trigger \
  -H "Authorization: Bearer $REMOTE_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "employment_id": "5e9e8861-9ead-4a2a-a402-c130bcfac5d6",
    "event_type": "payslip.released"
  }'

When your endpoint verifies Sandbox deliveries, register your production callback against https://gateway.remote.com and go live.

Next steps



Did this page help you?