Skip to content
mittr

Poll-Based Delivery

Poll-based delivery lets consumers pull events from Mittr instead of receiving HTTP pushes. This is useful when your consumer can’t expose a public URL, runs behind a firewall, or needs to control the rate of processing.

  1. Create an endpoint with deliveryMode set to poll
  2. Your consumer calls GET /api/v1/poll to fetch pending events
  3. Process the events
  4. Acknowledge successful events with POST /api/v1/poll/ack
  5. Unacknowledged events are redelivered after the visibility timeout
Terminal window
curl -X POST https://app.mittr.io/api/v1/endpoints \
-H "X-API-Key: mtr_your_key" \
-H "Content-Type: application/json" \
-d '{
"url": "poll://my-consumer",
"deliveryMode": "poll",
"eventTypes": ["order.*"]
}'

The url field is a label for poll endpoints — no HTTP requests are made to it.

Long-poll for pending events:

Terminal window
curl "https://app.mittr.io/api/v1/poll?endpoint_id=ep_uuid&limit=50&timeout=30" \
-H "X-API-Key: mtr_your_key"
ParameterTypeDefaultDescription
endpoint_idstringrequiredThe poll endpoint ID
limitinteger10Max events to return (1-100)
timeoutinteger30Long-poll timeout in seconds (1-60)
{
"events": [
{
"id": "evt_abc",
"eventType": "order.created",
"payload": { "orderId": "ord_123", "amount": 9900 },
"headers": { "X-Source": "shop-prod" },
"createdAt": "2026-04-14T10:30:00Z"
}
],
"count": 1
}

The event id is used as the acknowledgement key.

  • If events are available, they are returned immediately
  • If no events are available, the request blocks until events arrive or timeout elapses
  • An empty response with "events": [] means no events arrived during the timeout

After processing, acknowledge events to remove them from the queue:

Terminal window
curl -X POST https://app.mittr.io/api/v1/poll/ack \
-H "X-API-Key: mtr_your_key" \
-H "Content-Type: application/json" \
-d '{
"endpoint_id": "ep_uuid",
"event_ids": ["evt_xyz", "evt_abc"]
}'

Acknowledged events are marked as delivered. Unacknowledged events become visible again after the visibility timeout and are redelivered on the next poll.

async function pollLoop(endpointId, apiKey) {
const baseUrl = 'https://app.mittr.io/api/v1';
while (true) {
try {
// Long-poll for events (blocks up to 30 seconds)
const res = await fetch(
`${baseUrl}/poll?endpoint_id=${endpointId}&limit=50&timeout=30`,
{ headers: { 'X-API-Key': apiKey } }
);
const { events } = await res.json();
if (events.length === 0) continue;
// Process events
const acked = [];
for (const event of events) {
try {
await processEvent(event);
acked.push(event.id);
} catch (err) {
console.error(`Failed to process ${event.id}:`, err);
// Don't acknowledge — will be redelivered
}
}
// Acknowledge processed events
if (acked.length > 0) {
await fetch(`${baseUrl}/poll/ack`, {
method: 'POST',
headers: { 'X-API-Key': apiKey, 'Content-Type': 'application/json' },
body: JSON.stringify({ endpoint_id: endpointId, event_ids: acked })
});
}
} catch (err) {
console.error('Poll error:', err);
await new Promise(r => setTimeout(r, 5000)); // Back off on error
}
}
}
import requests
import time
def poll_loop(endpoint_id: str, api_key: str):
base_url = "https://app.mittr.io/api/v1"
headers = {"X-API-Key": api_key}
while True:
try:
res = requests.get(
f"{base_url}/poll",
params={"endpoint_id": endpoint_id, "limit": 50, "timeout": 30},
headers=headers,
timeout=35, # slightly longer than poll timeout
)
events = res.json().get("events", [])
if not events:
continue
acked = []
for event in events:
try:
process_event(event)
acked.append(event["id"])
except Exception as e:
print(f"Failed to process {event['id']}: {e}")
if acked:
requests.post(
f"{base_url}/poll/ack",
json={"endpoint_id": endpoint_id, "event_ids": acked},
headers={**headers, "Content-Type": "application/json"},
)
except Exception as e:
print(f"Poll error: {e}")
time.sleep(5)
Push (default)Poll
Consumer has public URLYesNot required
Real-time latencySub-secondDepends on poll interval
Rate controlMittr controls rateConsumer controls rate
Behind firewallNeeds ingressWorks with egress only
ScalingMittr distributes loadConsumer pulls at own pace

Use push delivery for most cases. Use poll when your consumer can’t accept inbound connections or needs precise control over processing rate.