Before you start
Create a beta account, select a permitted intended use and accept the terms. In the console, use API keys to create an account integration key and save its secret. Existing invited accounts can continue using their account key. Free during the beta. Send from your first agent right after signup. Cold outreach, bulk marketing, inbox warmup and spam are prohibited. There is no published SDK package yet. The interactive API reference and OpenAPI specification are public.
The examples below use cURL and placeholders. Replace the keys and UUIDs with your own values. Keep account keys in your server environment, never in a public client or prompt shared with an agent.
export CYBERPIGEON_BASE_URL='https://cyberpigeon.ai'
export CYBERPIGEON_ACCOUNT_KEY='YOUR_ACCOUNT_KEY'1. Create an agent mailbox
Use the account key to request a mailbox. The optional local_part must be available and contain 3–48 lowercase letters, digits, or internal hyphens. Omitting it requests a generated local part.
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/mailboxes" \
-H "Authorization: Bearer $CYBERPIGEON_ACCOUNT_KEY" \
-H 'Content-Type: application/json' \
-d '{"name":"Procurement agent","local_part":"procurement-demo"}'A successful response is 201 with mailbox.id, mailbox.address, and api_key.secret. Save the returned agent secret securely: it is shown only when issued. Mailbox creation is not idempotent; if a response is lost, list your mailboxes before retrying with the same address.
export CYBERPIGEON_MAILBOX_ID='RETURNED_MAILBOX_UUID'
export CYBERPIGEON_AGENT_KEY='RETURNED_AGENT_KEY'2. Verify the agent’s permissions
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/me" \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY"The response includes the key’s role, mailbox_id, scopes, and mail_enabled. A mailbox key can operate only within its assigned mailbox and scopes. Account keys can create or revoke keys and pause mailboxes; do not hand account keys to an agent.
To issue a read-only key for an existing mailbox, call POST /v1/keys with your account key and a body containing name, mailbox_id, and "scopes":["read"]. The console also exposes key management.
3. Send an email when delivery is enabled
First persist a unique idempotency key for this business action in your application. Reuse that same key and identical payload when retrying a send whose response was lost. Generate a new key for a different message.
export CYBERPIGEON_SEND_KEY='YOUR_PERSISTED_ACTION_ID'
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/mailboxes/$CYBERPIGEON_MAILBOX_ID/messages" \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY" \
-H "Idempotency-Key: $CYBERPIGEON_SEND_KEY" \
-H 'Content-Type: application/json' \
-d '{"to":["recipient@example.com"],"subject":"Quote request","text":"Please confirm availability for the items in our request."}'Use an authorized test recipient in place of the example address. The sender comes from the scoped mailbox; callers cannot supply an arbitrary From address. The current send schema supports text, optional HTML, and up to 10 recipients. It does not accept outbound attachments.
202 means durably queued, not delivered. Inspect the message and subsequent events for outcomes. Do not tell a user the email arrived solely because the send endpoint accepted it.
4. Receive messages through durable event polling
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/events?after=0&limit=50" \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY"
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/mailboxes/$CYBERPIGEON_MAILBOX_ID/messages?limit=50" \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY"The events response contains data and next_cursor. Process each event idempotently and persist the cursor after the corresponding application work commits. Use it as after on the next request. Continue through full pages, then poll with a delay and back off on errors. Crashes before saving a cursor can replay events.
The message list returns next_cursor for older messages; pass that cursor as the URL-encoded before parameter. Fetch a single message with GET /v1/mailboxes/{mailboxId}/messages/{messageId}.
Provider webhooks feed Cyberpigeon’s ingestion pipeline. Customers can poll events or configure signed incoming-email wake-ups once hosted delivery is activated. Your application is responsible for maintaining conversation or task state and deduplicating delivery.
5. Reply in the conversation
Set the ID of a received message, persist a new idempotency key for the reply, and submit the approved response.
export CYBERPIGEON_MESSAGE_ID='RECEIVED_MESSAGE_UUID'
export CYBERPIGEON_REPLY_KEY='YOUR_PERSISTED_REPLY_ACTION_ID'
curl --fail-with-body "$CYBERPIGEON_BASE_URL/v1/mailboxes/$CYBERPIGEON_MAILBOX_ID/messages/$CYBERPIGEON_MESSAGE_ID/reply" \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY" \
-H "Idempotency-Key: $CYBERPIGEON_REPLY_KEY" \
-H 'Content-Type: application/json' \
-d '{"text":"Thank you. Could you confirm the delivery date?"}'Cyberpigeon derives the reply recipient and email threading headers from the original message. The reply is queued asynchronously under the same delivery rules as a new send.
Handle errors and limits explicitly
| Response | Application behavior |
|---|---|
| 401 / 403 | Check the key, its revocation state, scopes, and mailbox. Do not retry indefinitely. |
| 409 | Inspect the error code. An address conflict or changed payload under a reused idempotency key needs a corrected request. |
| 429 | Respect the Retry-After header and account for shared sending capacity. |
| 403 sending_review_required | Sending is paused for abuse review. Stop retrying and contact support; queued mail was stopped and is not resent after release. |
| 503 mail_setup_required | Wait for provider activation; generating a new key will not enable delivery. |
| 503 provider_unavailable | Retry with backoff where appropriate. Preserve idempotency for sends. |
The free Developer plan includes 3 mailboxes and 1,000 outbound recipients per calendar month, at most 50 per UTC day. A 429 monthly_limit means the send would go over the monthly allowance (a send can be refused before the allowance is fully used, so fewer recipients may still go through), and Retry-After gives the seconds until it resets; a 429 daily_limit resets after midnight UTC. Limit errors name the plan and where a workspace owner can raise the limit. Paid plans add larger monthly mailbox and email-unit allowances and custom domains. Per-key rate limits and shared platform safeguards also apply. See pricing and availability and the console for current allowances; a paid plan does not bypass sending review.
For a full request schema, use the OpenAPI document. For workflow design, read why agents need email.