How-to guide

Distribute event streams to integration partners with Queuey Connect

Queuey Connect is webhooks as a service, built on your queues. You publish an event stream once. The integration partners you invite — integrators, in the console — subscribe to it from a workspace on their own Queuey account, point it at their own endpoint, and receive the events for the customers you activate for them. Every integrator gets its own copy in its own queue, with its own retries, dead-letter queue and replay, so an integrator whose endpoint is down holds up neither you nor the other integrators.

How an event reaches an integrator

A stream does not deliver to an endpoint of its own. For each event it accepts, Queuey writes a copy into the queue every subscribed integrator has for that stream — when both of these hold:

  • The integrator subscribes to the stream. Integrators subscribe themselves, to any stream you have published and not blocked for them.
  • You have activated the event's customer key for that integrator. The customer key — the GroupKey — says which of your customers the event belongs to. You send it with every event.

An event without a customer key is stored on the stream and copied to no one.

In the consoleWhat it is
StreamA queue in your workspace that you have published. Integrators see its name, description, event types and payload schema.
IntegratorAn integration partner you invited by email. It receives in a workspace on its own Queuey account.
Customer keyThe GroupKey on each event: which of your customers it belongs to. You activate customer keys per integrator, and an activation covers every stream that integrator takes.
PackageA named group of streams. An integrator can subscribe to a whole package at once, and you can block one for an integrator in one step.

As the producer

1 — Publish a stream

Streams live in a workspace of type Integration hub. Create one under New workspace, or turn a workspace you already have into one with Enable integrations on its Integrations page (app.queuey.ai/console/t/<workspace id>/integrations). Either way the Integrations view becomes the workspace's dashboard, with Streams, Packages and Integrators; queues already in the workspace keep running.

Under Streams, New stream takes a name and, optionally, the event types the stream carries, a description and a JSON Schema of the payload. Integrators see the name, event types and description when they browse, and the schema's fields once they subscribe, where their filter builder offers them.

The name is also the name of the stream's queue and part of the address you publish to: lowercase letters, digits, ., - and _, starting with a letter or digit, up to 64 characters. sandbox is reserved.

2 — Require a key to publish

A new queue accepts events without a key, and a stream copies what it accepts to every integrator activated for the event's customer key. Require an API key on the workspace before the first event. Every queue in the workspace inherits it, streams included, and from the next event on a publisher without a key is refused — so do it in a workspace that holds only streams, or give its other publishers a key first. The Integrations view has no ingress setting, so this is one call — with a Full access key from the API keys tab on the license's Home page, and the license id (lic_…) shown under the license name there:

require an API key on the workspace
curl -X PATCH "https://api.queuey.ai/tenants/ten_yourTenant/ingress" \
  -H "X-Api-Key: qak_yourFullAccessKey" \
  -H "X-License-PublicId: lic_yourLicense" \
  -H "Content-Type: application/json" \
  -d '{ "authMode": "ApiKey" }'

After that, a publish without a valid key is refused with 401.

3 — Invite an integrator

Invite integrator, with the address of the person who will set up the receiving side. Queuey emails them a link, and the invitation also shows on the console home of anyone signed in with that address. Only that address can accept it. The integrator is Pending until they do.

4 — Activate customers

Once the integrator has accepted, open them under Integrators and choose Activate a customer. Enter the customer key exactly as you send it on events: keys are compared as written, so ACME and acme are two customers. From the next event on, that customer's events on every stream the integrator subscribes to reach them. Deactivate stops it from the next event; copies already in the integrator's queue stay there.

5 — Publish events

Publishing to a stream is an ordinary publish to its queue, with two more headers: whose event it is, and what kind. A Limit to ingress key scoped to the workspace is all the publishing code needs:

publish to the orders stream
curl -X POST "https://ingress.queuey.ai/events/ten_yourTenant/orders" \
  -H "X-Api-Key: qak_yourKey" \
  -H "X-Queuey-Group-Key: acme" \
  -H "X-Queuey-Event-Type: order.shipped" \
  -H "Idempotency-Key: order-10042-shipped" \
  -H "Content-Type: application/json" \
  -d '{ "orderId": "10042", "customerId": "acme", "status": "shipped" }'
  • X-Queuey-Group-Key — the customer key. Without it, the event is copied to no one.
  • X-Queuey-Event-Type — the event type integrators see and filter on.
  • Idempotency-Key — a retried publish with the same key is stored once within the dedup window (24 hours by default), and integrators receive the key on every delivery attempt, so they can deduplicate too.
  • The body reaches integrators as you sent it. Put the customer's id in it: by default, Connect does not add the customer key or the event type to the request an integrator receives.

Queuey answers 202 Accepted once the event is stored. The copies are written after that, so an integrator never slows down your publish.

As the integrator

The receiving side runs in the Queuey console, on the integrator's own account.

1 — Accept the invitation

The link opens the invitation. Signed in with the invited address, the integrator chooses which of their accounts receives — one they own or administer — or, with no account yet, names their organization and Queuey creates a free account. No payment details are needed. They name the workspace, and Queuey creates it on that account. A receiving workspace and its stream queues don't count against the account's workspace and queue limits.

2 — Subscribe

Discover lists the streams the producer has published and not blocked for them, that they don't take yet, grouped by package. Subscribe takes one stream; Subscribe to all takes every stream in a package that has more than one. Each subscription gives the integrator a queue for that stream in their workspace, listed under Your streams.

That queue has no endpoint yet. Until it has one, it stores what arrives without sending it, and those events are not sent later on their own — so set the endpoint when you subscribe.

3 — Set the endpoint

Delivery holds the workspace's defaults, which every stream inherits: a base URL, how Queuey authenticates to the endpoint, request signing, a rate limit, a timeout, and how failures are handled — retries, the dead-letter queue, how long events are kept. On a stream, Endpoint either inherits the base URL and adds a path such as /orders, or overrides it with a full URL and its own authentication: none, a bearer token or an API key header, with optional HMAC-SHA256 signing the endpoint can verify.

4 — Filter, if you only want part of a stream

Filter keeps the events that match: conditions on top-level fields of the JSON payload, or on $eventType, compared with eq, ne, gt, gte, lt, lte, contains or exists, and combined with And or Or. An event that doesn't match is not copied to the integrator and costs nothing. Copies already waiting when the filter changes are checked again before delivery; those that no longer match are kept as Filtered instead of sent.

5 — What arrives

Each copy is delivered by the integrator's queue as an ordinary Queuey delivery — here to a base URL of https://hooks.partner.example/queuey with the path /orders and a bearer token:

what the integrator's endpoint receives
POST /queuey/orders HTTP/1.1
Host: hooks.partner.example
Content-Type: application/json
Authorization: Bearer <the integrator's own token>
Idempotency-Key: order-10042-shipped
X-Queuey-Event-Id: evt_…          # the integrator's copy
X-Queuey-Path: que_…,que_…        # the stream, then the integrator's queue

{ "orderId": "10042", "customerId": "acme", "status": "shipped" }

The body is the payload as the producer published it. Idempotency-Key is the key the producer published with — or the one Queuey assigned when it accepted the event — and it is the same on every attempt and replay. X-Queuey-Event-Id names the integrator's copy. Authentication and signing are the integrator's own settings — Verify deliveries shows how to check a signature.

The event type stays with the copy, and the stream's Events view in the integrator's console filters by it. The customer key is stored with the copy but not shown there. From here it is the integrator's queue. Failures are retried or held by type, an event that cannot be delivered goes to the dead-letter queue instead of disappearing, and every attempt is recorded with the endpoint's answer. Inspect, skip and replay from the stream's Events view — see the operational runbook.

Control what each integrator receives

Everything you publish is open to every integrator who has accepted an invitation from you. Two levers narrow it, per integrator:

  • Customer keys. An integrator gets only the customers you activated for them.
  • Blocks. On an integrator's page, block a stream they take (from its row under their subscriptions), or a whole package, for that integrator. A block stops new subscriptions and pauses the ones they have; routing to them stops within seconds, and events published while the block holds are not kept for them. Unblocking resumes the subscription — endpoint and filter intact — from the next event. A stream in a blocked package stays blocked even when another package it belongs to is not.

Who pays

The producer pays for distribution. The event it publishes and every copy written to an integrator's queue are metered on the producer's tokens, one token per started 16 KB of payload. A copy the integrator's filter rejects is not billed. Receiving costs the integrator nothing; inspecting and skipping are free, and a replay costs that event's tokens on the integrator's own account, which a free account includes.

What Connect does not do

  • It does not send one event to several endpoints from one queue. Each integrator receives from its own queue, with its own endpoint and failure handling — which is why one integrator's outage never holds up another. When the receivers are your own systems, the receiving side can be your own account: invite an address on your team and choose your account when accepting.
  • It does not distribute an event without a customer key.
  • A stream does not also deliver to an endpoint of its own.
  • By default, it does not add the customer key or the event type to the request an integrator receives.
  • It does not show the producer an integrator's endpoints, credentials or events. The producer sees who is invited, which streams each integrator takes, which customers are activated for them, and how many of each stream's events were handled over the last seven days.
  • Filters read top-level JSON fields only, and one integrator takes at most 1,000 streams.
Over the API
The producer steps are the WaaS producer API — PUT /waas/streams (declarative, safe to repeat), POST /waas/integrations, POST and DELETE /waas/activations, packages and blocks. Those endpoints take a signed-in console session with the Owner or Admin role, or an API key whose profile has the Connect permissions. The keys you create on the API keys tab today don't: they publish events and, with Full access, change workspace settings such as the ingress call in step 2, but they can't publish streams, invite integrators or activate customers.

Related