SendStackr API Reference
Trigger workflows, call AI models, track email opens, and ingest webhooks — all via a single API token.
Authentication
All API requests (except /health) require an API workflow token.
1. Create an API token
- Sign in to the SendStackr dashboard
- Open Project Settings → API Tokens
- Click Create Token, give it a name (e.g. "Production"), and optionally set an expiry
- Copy the token — it starts with
mhk_and is only shown once
2. Send the token
Include it as a Bearer token in the Authorization header:
Authorization: Bearer mhk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx3. Token scoping
Each token is scoped to a specific project. You can only trigger workflows and access resources within that project. Create separate tokens for development and production environments.
Quick Start
Trigger your first workflow in 2 minutes.
Step 1: Get your workflow ID
Find it in the dashboard URL: /dashboard/projects/PROJECT_ID/workflows/WORKFLOW_ID, or list all workflows via the API:
curl -X GET https://api.sendstackr.com/v1/workflows \
-H "Authorization: Bearer mhk_YOUR_TOKEN"Step 2: Trigger it
Send a POST with your workflow ID and input data. The response includes a run_id you can use to poll for results.
curl -X POST https://api.sendstackr.com/v1/workflows \
-H "Authorization: Bearer mhk_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"workflow_id": "550e8400-e29b-41d4-a716-446655440000",
"input": {
"from": "[email protected]",
"subject": "Need help with my order",
"body": "Hi, I placed order #12345 and haven't received a confirmation."
}
}'Step 3: Check the result
curl -X GET https://api.sendstackr.com/v1/runs/RUN_ID \
-H "Authorization: Bearer mhk_YOUR_TOKEN"Workflows
Trigger workflows from your applications. Workflows execute asynchronously — you get a run_id back immediately.
/v1/workflowsTrigger a workflow with custom input data.
Request Body
| Field | Type | Description |
|---|---|---|
| workflow_id | string (UUID) | The ID of the workflow to trigger. Get it from the dashboard or GET /v1/workflows. |
| input | object | Key-value pairs passed to your workflow. Available to nodes as {{ trigger.key_name }} template variables. |
Idempotency
Pass an Idempotency-Key header to safely retry without creating duplicate runs. The key is stored for 24 hours.
Response (200)
{
"status": "ok",
"run_id": "550e8400-e29b-41d4-a716-446655440099"
}Input examples by trigger type
Email Received workflow
For workflows with email_received trigger:
{
"from": "[email protected]",
"to": "[email protected]",
"subject": "Question about pricing",
"body": "Hi, I'd like to know more about the Ultra plan..."
}Available as {{ Email_Received.from }}, {{ Email_Received.subject }}, {{ Email_Received.body }}
WhatsApp workflow
For workflows with whatsapp_message_received trigger:
{
"from": "+6281234567890",
"body": "Halo, saya mau booking villa untuk 15 Agustus"
}API trigger (OTP / reset password)
For OTP or reset-password template workflows:
{
"to": "[email protected]",
"otp_code": "849201",
"expiry_minutes": "10",
"project_name": "My App"
}{
"to": "[email protected]",
"reset_link": "https://myapp.com/reset?token=abc123",
"expiry_minutes": "60",
"project_name": "My App"
}Manual trigger (test run)
For workflows with manual trigger type. Pass any JSON — template variables use {{ Manual_Booking_Payload.body }} etc. depending on the data you send and the first node label in your workflow.
{
"subject": "Test booking",
"body": "{\"calendar\":{\"summary\":\"Demo call\",\"start\":\"2026-06-15T14:00:00Z\",\"end\":\"2026-06-15T15:00:00Z\"}}"
}/v1/workflowsList all workflows accessible with your API token.
Response (200)
{
"workflows": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Support Reply Flow",
"trigger_type": "email_received",
"enabled": true,
"created_at": "2026-05-15T08:00:00Z",
"updated_at": "2026-06-01T12:30:00Z"
}
]
}/v1/workflows/{workflow_id}Get a single workflow with full detail including node graph and settings.
Path Parameters
| Parameter | Description |
|---|---|
| workflow_id | The workflow UUID |
Run Status
After triggering a workflow, poll the run endpoint to check its status and get step-by-step outputs.
/v1/runs/{run_id}Get the status and output of a workflow run.
Response (200)
{
"id": "550e8400-...-00099",
"workflow_id": "550e8400-...-00000",
"status": "completed",
"input": {
"from": "[email protected]",
"subject": "Need help with my order",
"body": "Hi, I placed order #12345..."
},
"steps": [
{
"node_id": "n1",
"node_type": "email_received",
"label": "Email Received",
"status": "completed",
"output": {},
"started_at": "2026-06-01T12:30:00Z",
"completed_at": "2026-06-01T12:30:00Z"
},
{
"node_id": "n2",
"node_type": "ai_analysis",
"label": "AI Analysis",
"status": "completed",
"output": {
"result": "Customer is asking about order #12345..."
},
"started_at": "2026-06-01T12:30:01Z",
"completed_at": "2026-06-01T12:30:03Z"
},
{
"node_id": "n4",
"node_type": "send_email",
"label": "Send Email",
"status": "completed",
"output": { "sent": true },
"started_at": "2026-06-01T12:30:03Z",
"completed_at": "2026-06-01T12:30:04Z"
}
],
"started_at": "2026-06-01T12:30:00Z",
"completed_at": "2026-06-01T12:30:04Z"
}status values: running · completed · failed · cancelled
/v1/runsList recent runs, optionally filtered by workflow ID or status.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| workflow_id | UUID | Filter by specific workflow |
| status | enum | Filter: running, completed, or failed |
| limit | integer | Max results (default 20, max 100) |
Chat Completions (OpenAI Compatible)
Drop-in replacement for the OpenAI chat completions endpoint. Use your SendStackr API token in place of an OpenAI key. Supports streaming, multi-modal (images), and agentic RAG.
/v1/chat/completionsOpenAI-compatible chat completion with optional RAG augmentation.
Supported Models
gpt-4o— most capablegpt-4o-mini— fast, cost-effectiveclaude-sonnet-4-20250514— Anthropicgemini-2.5-flash— Google- Any model enabled in your project's AI provider settings
Agentic RAG
Send the header x-agentic-rag: true to automatically augment each request with relevant context from your project's knowledge base. No additional code required — the RAG pipeline handles document retrieval and context injection.
Non-streaming request
curl -X POST https://api.sendstackr.com/v1/chat/completions \
-H "Authorization: Bearer mhk_YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-4o-mini",
"messages": [
{"role": "system", "content": "You are a helpful customer support agent."},
{"role": "user", "content": "What is your return policy?"}
],
"max_tokens": 256
}'Non-streaming response
{
"id": "chatcmpl-abc123",
"object": "chat.completion",
"model": "gpt-4o-mini",
"choices": [
{
"index": 0,
"message": {
"role": "assistant",
"content": "Our return policy allows returns within 30 days..."
},
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 45,
"completion_tokens": 120,
"total_tokens": 165
}
}Streaming
Set "stream": true to receive Server-Sent Events:
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Our"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":" return"},"finish_reason":null}]}
data: {"id":"chatcmpl-123","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: [DONE]Webhooks (Inbound)
Ingest events from external platforms — Stripe, Paymentku, Shopify, custom CRM — into your workflows.
/v1/webhooks/{project_id}Receive events from external platforms. Matched against your workflow trigger conditions.
Setup
- Find your project ID in the dashboard URL
- Set your webhook URL in the external platform:
https://api.sendstackr.com/v1/webhooks/YOUR_PROJECT_ID - Optionally set a shared secret in Project Settings → Webhooks for HMAC verification
Signature Verification
When a shared secret is configured, include the x-webhook-signature header with the HMAC-SHA256 hex digest of the raw request body:
x-webhook-signature: SHA256(payload + secret)Example payloads
{
"type": "payment_intent.succeeded",
"data": {
"object": {
"id": "pi_3NxEXAMPLE",
"amount": 2999,
"currency": "usd",
"metadata": { "order_id": "ord_789" }
}
}
}{
"type": "payment.success",
"data": {
"trx_id": "PKU-20260525-001",
"amount": "150000",
"status": "paid",
"customer_email": "[email protected]"
},
"timestamp": "2026-05-25T11:51:31Z",
"signature": "hmac_sha256_hex_digest"
}{
"event": "lead.created",
"lead": {
"email": "[email protected]",
"source": "website_form",
"score": 85
}
}Email Open Tracking
Track when recipients open your emails with a 1×1 transparent GIF pixel.
/v1/pixel/{workflow_id}.gifReturns a 1×1 transparent GIF and records the email open event.
How to use
Embed this image tag anywhere in your HTML email:
<img
src="https://api.sendstackr.com/v1/pixel/WORKFLOW_ID.gif?token=mhk_YOUR_TOKEN&[email protected]"
width="1"
height="1"
alt=""
/>Query Parameters
| Parameter | Required | Description |
|---|---|---|
| token | Yes | Your mhk_* API token |
| to | No | Recipient email for analytics |
What happens
When the pixel loads, the API records the open event (including user agent and IP) and fires the email_opened trigger on matching project workflows. The pixel always returns successfully — it never breaks email rendering.
Enable this in your workflow by adding an email_opened trigger node in the workflow builder, then use the workflow's ID in the pixel URL.
Usage & Limits
Monitor your token consumption and plan limits.
/v1/usageGet daily and monthly token usage plus plan limits.
Response (200)
{
"daily_used": 12450,
"monthly_used": 87650,
"daily_limit": null,
"monthly_limit": 100000,
"is_suspended": false
}daily_limit / monthly_limit are null when unlimited.is_suspended is true when you've exceeded your plan limits.
Rate Limits
| Endpoint | Limit |
|---|---|
| Chat completions | 60 requests per minute |
| Workflow triggers | 120 requests per minute |
| Webhook ingestion | Background job (no rate limit) |
Exceeding a limit returns 429 Too Many Requests with a Retry-After header.
Error Handling
All error responses follow the same structure:
{
"error": "bad_request",
"message": "workflow_id is required",
"details": {},
"request_id": "req_Xa7Bc9Dd3Ee"
}Error Codes
| Status | Code | Meaning |
|---|---|---|
| 400 | bad_request | Missing or invalid parameters |
| 401 | unauthorized | Missing, expired, or invalid API token |
| 402 | payment_required | Insufficient credits for the request |
| 404 | not_found | Workflow or run not found |
| 429 | rate_limited | Rate limit exceeded — check Retry-After header |
| 500 | internal_error | Server error — include request_id when contacting support |