Quickstart
Key in hand to first message
Three steps: mint a workspace API key, send a message with one REST call, then mount the same catalog as an MCP server so your agent can drive it natively.
1. Get an API key
API keys are minted by an operator holding the shared service key (the X-Internal-Key header). Each key belongs to one workspace and carries scopes (send-only, read-only, full — default is send-only, least privilege).
/admin/api-keysservice-key gatedcurl -X POST "$AGENTPUSH_URL/admin/api-keys" \
-H "X-Internal-Key: $INTERNAL_SERVICE_KEY" \
-H "Content-Type: application/json" \
-d '{
"workspaceId": "acme",
"label": "support-agent",
"scopes": ["full"]
}'{
"id": "5f0c2f04-…",
"key": "apk_9c41d2…", // shown exactly once — store it now
"workspaceId": "acme",
"label": "support-agent",
"scopes": ["full"]
}Local development: when the API runs without an internal service key configured, auth is bypassed entirely — every request resolves to the default workspace with full scopes. Handy locally, never in production.
2. Send your first message
Every tool in the catalog is callable over REST at POST /tools/:namewith the tool's input as the JSON body. Sending a WhatsApp message is one call:
/tools/send_messageAuthorization: Bearer <key>curl -X POST "$AGENTPUSH_URL/tools/send_message" \
-H "Authorization: Bearer apk_9c41d2…" \
-H "Content-Type: application/json" \
-d '{
"to": { "channel": "whatsapp", "address": "+33612345678" },
"content": { "text": "Hello from my agent 👋" }
}'The recipient is either a direct { channel, address } pair (E.164 number for WhatsApp/SMS, email address for mail, user id for Discord) or a { contact_id } from find_contact / upsert_contact.
// sent (or queued while the provider confirms)
{ "status": "sent", "message_id": "wamid.HBgL…" }
// blocked — not an error: read the suggestion and correct course
{
"status": "blocked",
"blocked_reason": "outside the 24h WhatsApp session window",
"suggestion": "Use a pre-approved template — call list_templates, then retry with content.templateName."
}| Status | Meaning |
|---|---|
sent | Accepted by the channel provider; a message_id is returned. |
queued | Journaled and pending provider confirmation. |
blocked | Policy stopped the send (session window, opt-out, unapproved template). Carries blocked_reason + suggestion — designed for the agent to self-correct. |
failed | The provider rejected the send. |
Invalid input returns 422 with Zod issues; an unknown tool name returns 404; a missing/invalid key returns 401.
3. Mount it as MCP
The same catalog is served as a stateless MCP server over streamable HTTP at POST /mcp, authenticated with the same Bearer key. Your agent gets typed tools with rich descriptions — no glue code.
/mcpMCP streamable HTTP, stateless{
"mcpServers": {
"agentpush": {
"type": "http",
"url": "https://<your-agentpush-host>/mcp",
"headers": { "Authorization": "Bearer apk_9c41d2…" }
}
}
}claude mcp add --transport http agentpush \
"https://<your-agentpush-host>/mcp" \
--header "Authorization: Bearer apk_9c41d2…"Discover the catalog
A public manifest lists every tool with its name, read/write tag and description — useful for building your own client or just browsing:
/toolscatalog manifestcurl "$AGENTPUSH_URL/tools"
// → { "tools": [ { "name": "find_contact", "tag": "read", "description": "…" }, … ] }- Next: connect a real channel in Channels, or go straight to receiving messages in Inbound & BYO inference.