Event Delivery Service

The Event Delivery Service (EDS) V2 delivers real-time notifications to your integration via WebSocket, replacing the SSE-based V1 with a lower-latency, bidirectional protocol.

Prerequisites

Before connecting you need:

  • An integration API Key — used in the Authorization header of the WebSocket upgrade request.
  • A queue name — assigned to your integration. Each queue corresponds to a logical stream of events for your tenant.

Contact Empego to obtain both if you do not already have them.

In this section

  • Connection — How to open a WebSocket, authenticate, and handle disconnections and errors.
  • Protocol — Wire format, frame types, and field references.
  • Events — Event types delivered through EDS V2 and their payload fields.
  • Deduplication — At-least-once delivery semantics and how to handle duplicate events.
  • FAQ — Answers to common questions about setup, connection, acknowledgement, deduplication, and protocol.

Quick Start

The following pseudo-code sketches the full client lifecycle from first connect to graceful reconnect. Adapt it to your language and WebSocket library.

// 1. Open connection
ws = WebSocket("wss://eds.empego-dev-staging.name?queue={queueName}",
               headers: { "Authorization": "api-key {your-api-key}" })

// 2. On successful connection — start ping timer
ws.onOpen = function() {
    pingTimer = setInterval(every 2-3 minutes) {
        ws.send({ frameType: "PING" })
    }
}

// 3. On incoming message — dispatch by frame type
ws.onMessage = function(frame) {
    if frame.frameType == "EVENT" {
        if not alreadySeen(frame.framePayload.eventId) {
            markSeen(frame.framePayload.eventId)
            process(frame.framePayload)
        }
        ws.send({ frameType: "ACK_EVENT", framePayload: { receiptId: frame.framePayload.receiptId } })
    }
}

// 4. On close — reconnect unless auth failed
ws.onClose = function(code) {
    clearInterval(pingTimer)

    if code == 4401 {
        return  // fix the API key, do not retry
    }

    delay = initialDelay
    while not connected {
        wait(delay + randomJitter())
        connect()
        delay = min(delay * 2, maxDelay)
    }
}

// 5. On error — treat as a transient disconnect
ws.onError = function(err) {
    ws.close()
}

Key points:

Ping every 2–3 min

  • To stay under the 10-minute API Gateway idle timeout.

Ack always

  • Even for duplicates;
  • Dedup on eventId, ack on receiptId
  • Ack all events (even unsupported types), failure to acknowledge an event will prevent new events to be delivered.

Table of contents