Pushary REST API reference
Call the Pushary REST API with curl. Ask a person a question and wait for the answer, send a push notification, and generate a client from the OpenAPI spec.
The Pushary REST API lets any program ask a person a question on their phone, wait for the answer, and send push notifications, using plain HTTP and a Bearer API key. Use it from n8n, Zapier, a shell script or your own backend when an MCP connection is not an option. The full API is published as an OpenAPI 3.1 document you can feed to a client generator.
Your first request
Create a key in the dashboard
Open Settings > API keys at pushary.com/dashboard/agent/settings, click Create Key, and copy the key. It looks like pk_xxx.xxx and is shown only once. Export it:
export PUSHARY_API_KEY="pk_xxx.xxx"Already ran npx pushary@latest setup? The key it saved works for /ask and /send too. The subscriber list, campaign, template and flow endpoints need a key created here.
Ask a question and wait for the answer
curl -X POST https://pushary.com/api/v1/server/ask \
-H "Authorization: Bearer $PUSHARY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"question":"Deploy the new build to production?","agentName":"Deploy bot","timeoutSeconds":50}'Your phone shows a yes or no question while the call waits. Tap an answer and the call returns:
{
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"question": "Deploy the new build to production?",
"type": "confirm",
"status": "answered",
"answered": true,
"value": "yes"
}The question goes to the Pushary phone app, to browsers subscribed to your site, and to Slack if you connected it. The response also carries liveUrl, pollUrl, expiresInSeconds (600) and mode, your approval mode.
Send a notification
curl -X POST https://pushary.com/api/v1/server/send \
-H "Authorization: Bearer $PUSHARY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"title":"Build finished","body":"All 214 tests passed on main."}'A success returns "success": true, "status": "queued" and the queued count.
POST /send reaches browsers, not the phone app
POST /api/v1/server/send delivers to browser push subscribers only. If your site has none, it returns 400 No subscribers found matching criteria, even with the phone app connected. It also needs a paid plan with API access. To notify the phone app, use the MCP send_notification tool, or ask with POST /ask.
Ask parameters
| Field | What it does |
|---|---|
question | Required. Up to 500 characters |
type | confirm (default), select or input |
options | At least 2 choices, required for select |
context, placeholder, agentName | Background text, the input hint, and the label shown on the push |
wait | true by default. false returns "status": "pending" at once |
timeoutSeconds | How long the call waits, 1 to 55 seconds. Default 30 |
callbackUrl | HTTPS webhook that receives the answer |
subscriberIds, externalIds, tags | Send only to matching browser subscribers |
No answer in time returns "status": "timeout" and a hint. The question stays open for 10 minutes. Read it again with GET /api/v1/server/ask/{correlationId}?wait=30 (up to 55 seconds), or withdraw it with DELETE /api/v1/server/ask/{correlationId}. In Terminal mode the question is stored but no push is sent.
Where the API lives
| What | Where |
|---|---|
| OpenAPI specification | https://pushary.com/openapi.json |
| Same document, YAML media type | https://pushary.com/openapi.yaml |
| Base URL | https://pushary.com/api/v1/server |
| MCP server | https://pushary.com/api/mcp/mcp (Streamable HTTP) |
| MCP manifest | https://pushary.com/.well-known/mcp |
| Site index for agents | https://pushary.com/llms.txt |
curl -s https://pushary.com/openapi.json | jq '.info.title, (.paths | keys | length)'Authentication
Every endpoint takes a Pushary API key as a Bearer token:
curl https://pushary.com/api/v1/server/identity \
-H "Authorization: Bearer pk_xxx.xxx"What a key can call depends on where it came from:
| Key | Can call |
|---|---|
| Created with Create Key in the dashboard | Every endpoint your plan includes |
Made by npx pushary@latest setup, pushary login, phone pairing or the Mac app | Runtime calls such as identity, site, channels, machines, send, ask and Partner decisions. Not campaigns, templates, flows or the subscriber list |
| Claude or ChatGPT connector | send and identity only |
A setup or pairing key that calls an endpoint outside its list gets a 403 with the message This key cannot access this endpoint. For a Partner integration, create a server-side key in the dashboard. See Get your API key for where keys come from and how to revoke them.
The MCP endpoint also accepts OAuth 2.0. Discovery starts at /.well-known/oauth-protected-resource, which names the authorization server.
Errors
Errors are JSON with an error message. Shared authentication and validation errors also carry diagnostic fields, as below. Some endpoint errors return fewer fields. Branch on the HTTP status and on code when present, not on the readable message.
{
"error": "Unauthorized",
"code": "unauthorized",
"status": 401,
"message": "Invalid or missing API key. Use Authorization: Bearer pk_xxx.sk_xxx",
"hint": "Create a key with `npx pushary@latest setup`, or in Dashboard > Agent > Settings.",
"documentation": "https://pushary.com/docs/agents/api-key"
}That message is quoted exactly as the server sends it. It shows an old key format: a real key has no sk_ part and looks like pk_xxx.xxx.
A request to a path with no endpoint behind it returns the same shape with code: "not_found" and an openapi field pointing back at the specification. Shared code values are unauthorized, forbidden, invalid_request, not_found and method_not_allowed.
| Status | When |
|---|---|
| 401 | Missing or invalid key |
| 403 | The key cannot call this endpoint, or the workspace has no active plan (code: "subscription_required", with an upgradeUrl) |
403 partner_decision_required | A Partner workspace called /ask. Use POST /api/v1/server/decisions instead |
| 429 | Rate limit. The body has error, resetIn and limit, and the Retry-After and X-RateLimit-* headers say when to try again. /ask past 25 pending questions returns only error, with no Retry-After |
Function calling
Published operations carry an operationId and request and response schemas. Use them to build tool definitions for an OpenAPI-aware agent framework. The example below extracts an operation index; map each operation's schemas separately for your framework.
const spec = await fetch('https://pushary.com/openapi.json').then((r) => r.json())
const tools = Object.entries(spec.paths).flatMap(([path, item]) =>
Object.entries(item)
.filter(([method]) => ['get', 'post', 'patch', 'delete'].includes(method))
.map(([method, op]: [string, any]) => ({
name: op.operationId,
description: op.description,
path,
method,
})),
)SDKs
Use a server SDK for Partner integrations. The ask helper creates a decision and polls for an answer within a bounded wait. Persist decision IDs in your workflow, supply a stable idempotency key across retries, and handle transient HTTP failures in your application. SDK requests do not retry on their own.
npm install @pushary/serverpip install pusharySee Framework adapters for the Vercel AI SDK, LangGraph, CrewAI, Mastra, Eve and the OpenAI Agents SDK.
What the API covers
| Group | Operations |
|---|---|
| Decisions | Create a decision (asynchronous by default), read it, record an answer, cancel it, and manage the webhook secret |
| Authorization | Evaluate an action against the workspace policy: allow, deny or requires_human |
| Enrollment | Connect one of your own end users to phone approvals with a single-use link |
| Keys | Issue and revoke per-end-user API keys for multi-tenant agent runtimes |
| Notifications | Send a push notification, read one back |
| Subscribers | List, read, update, delete and count the people a site can notify |
| Campaigns | Create, schedule, send, pause, resume and read stats |
| Templates | Reusable notification content |
| Flows | Event-triggered notification automations |
| Account | Identify the calling key, read the site, count reachable channels, list agent machines |
POST /ask and GET or DELETE /ask/{correlationId} are live but not yet listed in the OpenAPI document.
Markdown for agents
Any documentation or blog URL serves raw Markdown two ways: append .md, or send an Accept: text/markdown header.
curl -H "Accept: text/markdown" https://pushary.com/docs/agents/reference/api
curl https://pushary.com/docs/agents/reference/api.mdNext steps
Connect any agent over HTTP
Full ask, poll and cancel examples for n8n, Zapier, LangChain and scripts.
Use the MCP tools instead
send_notification reaches the phone app, and ask_user handles the wait for you.