Messaging
Send asynchronous messages, enqueue jobs, and batch deliver payloads to any HTTP endpoint — no Upstash account, no queue infrastructure, just API calls.
Quick Example
Section titled “Quick Example”import { withSapiom } from "@sapiom/axios";import axios from "axios";
const client = withSapiom(axios.create(), { apiKey: process.env.SAPIOM_API_KEY, serviceName: "Messaging Publish", agentName: "my-agent",});
// Publish a message to a webhookconst { data } = await client.post( "https://upstash.services.sapiom.ai/v1/qstash/publish/https://example.com/webhook", { type: "job.created", payload: { id: "job_123" } }, { headers: { "Content-Type": "application/json" } });
console.log("Message ID:", data.messageId);import { createFetch } from "@sapiom/fetch";
const sapiomFetch = createFetch({ apiKey: process.env.SAPIOM_API_KEY, serviceName: "Messaging Publish", agentName: "my-agent",});
// Publish a message to a webhookconst response = await sapiomFetch( "https://upstash.services.sapiom.ai/v1/qstash/publish/https://example.com/webhook", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ type: "job.created", payload: { id: "job_123" }, }), });
const data = await response.json();console.log("Message ID:", data.messageId);How It Works
Section titled “How It Works”Sapiom routes messaging requests through Upstash QStash, a serverless message queue and delivery service. The SDK handles payment negotiation so you don’t need a separate Upstash account.
There are three delivery modes:
- Publish — Fire-and-forget delivery to any HTTP endpoint. QStash handles retries automatically.
- Enqueue — Ordered delivery through a named queue. Messages in the same queue are processed sequentially.
- Batch — Send multiple messages in a single request. Each message can target a different destination or queue.
The destination URL receives your message body as an HTTP POST with the headers you specified.
Provider
Section titled “Provider”Powered by Upstash QStash. QStash provides serverless messaging with automatic retries, at-least-once delivery, and dead letter queues.
API Reference
Section titled “API Reference”Endpoints
Section titled “Endpoints”Base URL: https://upstash.services.sapiom.ai
| Method | Path | Description |
|---|---|---|
| POST | /v1/qstash/publish/*destination | Publish a message to a URL |
| POST | /v1/qstash/enqueue/:queueName/*destination | Enqueue a message to a named queue |
| POST | /v1/qstash/batch | Send multiple messages in one request |
Publish
Section titled “Publish”Endpoint: POST https://upstash.services.sapiom.ai/v1/qstash/publish/{destination}
Send a message to any HTTP endpoint. The destination URL is appended to the path.
// The destination URL is part of the request pathawait client.post( "https://upstash.services.sapiom.ai/v1/qstash/publish/https://example.com/webhook", { event: "user.signup", userId: "usr_123" }, { headers: { "Content-Type": "application/json" } });The message body can be any content type — JSON, plain text, binary, etc. It is forwarded as-is to the destination.
- Destination must start with
http://orhttps:// - Path traversal patterns are rejected
- Callback, cron, and flow-control headers are stripped before forwarding
Enqueue
Section titled “Enqueue”Endpoint: POST https://upstash.services.sapiom.ai/v1/qstash/enqueue/{queueName}/{destination}
Add a message to a named queue for ordered processing. Messages in the same queue are delivered sequentially.
// Enqueue to the "email-queue" queueawait client.post( "https://upstash.services.sapiom.ai/v1/qstash/enqueue/email-queue/https://example.com/send-email", { headers: { "Content-Type": "application/json" } });Queue names are automatically scoped to your account — no collisions with other users.
Endpoint: POST https://upstash.services.sapiom.ai/v1/qstash/batch
Send multiple messages in a single request. The body must be a non-empty JSON array.
Request
Section titled “Request”[ { "destination": "https://example.com/webhook-a", "headers": { "Content-Type": "application/json" }, "body": "{\"event\":\"order.created\",\"orderId\":\"ord_1\"}" }, { "destination": "https://example.com/webhook-b", "headers": { "Content-Type": "application/json" }, "body": "{\"event\":\"notification.send\",\"userId\":\"usr_1\"}", "queue": "notifications" }]Each item in the array can target a different destination and optionally specify a queue for ordered delivery.
Error Codes
Section titled “Error Codes”| Code | Description |
|---|---|
| 400 | Invalid request — destination must be a valid URL, batch body must be a non-empty array |
| 402 | Payment required — ensure you’re using the Sapiom SDK |
| 429 | Rate limit exceeded |
Complete Example
Section titled “Complete Example”import { withSapiom } from "@sapiom/axios";import axios from "axios";
const client = withSapiom(axios.create(), { apiKey: process.env.SAPIOM_API_KEY, serviceName: "Messaging Publish", agentName: "my-agent",});
const baseUrl = "https://upstash.services.sapiom.ai/v1/qstash";
async function processOrder(orderId: string) { // Fire-and-forget: notify the fulfillment service await client.post( `${baseUrl}/publish/https://api.example.com/fulfillment`, { orderId, action: "ship" }, { headers: { "Content-Type": "application/json" } } );
// Ordered queue: send confirmation emails sequentially await client.post( `${baseUrl}/enqueue/email-queue/https://api.example.com/send-email`, { orderId, template: "order-confirmation" }, { headers: { "Content-Type": "application/json" } } );
// Batch: notify multiple services at once await client.post(`${baseUrl}/batch`, [ { destination: "https://api.example.com/analytics", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ event: "order.completed", orderId }), }, { destination: "https://api.example.com/inventory", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "decrement", orderId }), }, ]);
console.log(`Order ${orderId} processing dispatched`);}
await processOrder("ord_456");import { createFetch } from "@sapiom/fetch";
const sapiomFetch = createFetch({ apiKey: process.env.SAPIOM_API_KEY, serviceName: "Messaging Publish", agentName: "my-agent",});
const baseUrl = "https://upstash.services.sapiom.ai/v1/qstash";
async function processOrder(orderId: string) { // Fire-and-forget: notify the fulfillment service await sapiomFetch( `${baseUrl}/publish/https://api.example.com/fulfillment`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ orderId, action: "ship" }), } );
// Ordered queue: send confirmation emails sequentially await sapiomFetch( `${baseUrl}/enqueue/email-queue/https://api.example.com/send-email`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ orderId, template: "order-confirmation" }), } );
// Batch: notify multiple services at once await sapiomFetch(`${baseUrl}/batch`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify([ { destination: "https://api.example.com/analytics", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ event: "order.completed", orderId }), }, { destination: "https://api.example.com/inventory", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "decrement", orderId }), }, ]), });
console.log(`Order ${orderId} processing dispatched`);}
await processOrder("ord_456");Pricing
Section titled “Pricing”| Operation | Cost |
|---|---|
| Publish (per message) | $0.00001 |
| Enqueue (per message) | $0.00001 |
| Batch (per message in array) | $0.00001 |