Skip to main content
npayload is launching soon.
npayloadDocs
Guides

Subscriptions and delivery

Webhook, queue, and consumer group subscriptions with routing filters, retry policies, and circuit breakers

Subscriptions define how messages are delivered from channels to your applications. npayload supports three subscription types: webhooks (push), queues (pull), and consumer groups (shared load-balanced pull).

Subscription types

npayload pushes messages to your HTTP endpoint as they arrive.

const sub = await npayload.subscriptions.create({
  channel: 'orders',
  type: 'webhook',
  endpoint: 'https://api.example.com/webhooks/orders',
  headers: {
    'X-Custom-Header': 'my-value',
  },
});

See the Webhooks guide for delivery lifecycle, retries, and signature verification.

Messages accumulate in a queue. Your application pulls them at its own pace.

const sub = await npayload.subscriptions.create({
  channel: 'orders',
  type: 'queue',
});

// Pull messages (up to 10 at a time)
const messages = await npayload.subscriptions.pull(sub.gid, { limit: 10 });

for (const msg of messages) {
  await processOrder(msg.payload);
  await npayload.subscriptions.ack(sub.gid, msg.gid);
}

Messages that are not acknowledged within the visibility timeout become available for re-delivery.

Multiple consumers share a queue subscription. Each message is delivered to exactly one consumer in the group, providing load balancing.

// Create the consumer group
const group = await npayload.consumerGroups.create({
  channel: 'orders',
  name: 'order-processors',
});

// Each worker joins the same group
const messages = await npayload.consumerGroups.pull(group.gid, {
  consumerId: 'worker-1',
  limit: 10,
});

for (const msg of messages) {
  await processOrder(msg.payload);
  await npayload.consumerGroups.ack(group.gid, msg.gid);
}

Best for: scaling processing across multiple workers without duplicating work.

Routing key filters

Filter which messages a subscription receives using glob patterns on routing keys.

// Only receive signup events from Europe
const sub = await npayload.subscriptions.create({
  channel: 'events',
  type: 'webhook',
  endpoint: 'https://api.example.com/eu-signups',
  routingKeyFilter: 'user.signup.eu-*',
});
PatternMatchesDoes not match
order.*order.created, order.shippedorder.item.added
order.**order.created, order.item.addeduser.signup
*.signup.*user.signup.eu, admin.signup.ususer.login.eu
user.signup.eu-*user.signup.eu-west, user.signup.eu-centraluser.signup.us-east

* matches a single segment (between dots). ** matches one or more segments. Filters are case-sensitive.

Custom retry policies

Override the default retry schedule for webhook subscriptions.

const sub = await npayload.subscriptions.create({
  channel: 'orders',
  type: 'webhook',
  endpoint: 'https://api.example.com/webhooks/orders',
  retryPolicy: {
    maxAttempts: 5,
    initialDelay: 1000,        // 1 second
    maxDelay: 300000,           // 5 minutes
    backoffMultiplier: 3,       // each retry waits 3x longer
  },
});
OptionDefaultDescription
maxAttempts6Total delivery attempts (including the first)
initialDelay1000Milliseconds before the first retry
maxDelay7200000Maximum delay between retries (2 hours)
backoffMultiplier2Multiplier applied to the delay after each retry

After all retries are exhausted, the message is moved to the dead letter queue.

Managing subscriptions

Pause and resume

Temporarily stop delivery without losing messages. Paused subscriptions queue messages until resumed.

// Pause delivery (messages queue up)
await npayload.subscriptions.pause(sub.gid);

// Resume delivery (queued messages are delivered)
await npayload.subscriptions.resume(sub.gid);

List subscriptions

// List all subscriptions for a channel
const subs = await npayload.subscriptions.list({ channel: 'orders' });

// List all subscriptions across channels
const allSubs = await npayload.subscriptions.list();

Update a subscription

await npayload.subscriptions.update(sub.gid, {
  endpoint: 'https://api-v2.example.com/webhooks/orders',
  headers: {
    'X-Version': '2',
  },
});

Delete a subscription

await npayload.subscriptions.delete(sub.gid);

Deleting a subscription is permanent. Any undelivered messages in the queue are lost. Pause the subscription instead if you want to preserve queued messages.

Circuit breaker behaviour

Webhook subscriptions have a built-in circuit breaker that protects both npayload and your endpoint from cascading failures.

StateBehaviour
Closed (normal)Deliveries proceed normally
Open (tripped)After consecutive 5xx failures, deliveries pause and messages queue
Half-open (testing)After a cooldown, npayload sends a test delivery. On success, the circuit closes

Key details:

  • Only 5xx server errors count as failures. 4xx client errors are treated as permanent rejections
  • The circuit trips after 5 consecutive failures
  • Cooldown starts at 30 seconds and increases with repeated trips
  • You can monitor circuit state via the subscription status in the SDK or dashboard
const sub = await npayload.subscriptions.get(sub.gid);
console.log(sub.circuitState); // "closed" | "open" | "half-open"

Consumer group details

Consumer groups distribute messages across workers using round-robin assignment.

// List consumers in a group
const consumers = await npayload.consumerGroups.listConsumers(group.gid);

// Remove a consumer (its unacknowledged messages become available to others)
await npayload.consumerGroups.removeConsumer(group.gid, 'worker-3');

// Get group stats
const stats = await npayload.consumerGroups.getStats(group.gid);
console.log(stats.pendingMessages);
console.log(stats.activeConsumers);

Best practices

  • Use webhook subscriptions for real-time, push-based integrations. Use queue subscriptions when your consumer controls the processing pace
  • Use consumer groups to scale processing horizontally. Each message is delivered to exactly one consumer
  • Set routing key filters to reduce unnecessary delivery. Filtering at the subscription level is more efficient than filtering in your application code
  • Configure retry policies based on your endpoint's recovery characteristics. Short-lived outages benefit from faster retries, while downstream rate limits benefit from longer backoff
  • Monitor circuit breaker state. An open circuit indicates a problem with your endpoint
  • Pause subscriptions during planned maintenance to avoid unnecessary retries and DLQ entries

Next steps

Was this page helpful?

On this page