Separate the inbox from the work
Consider an agent that helps your team answer incoming support questions. Receiving the email, deciding what to do, approving a response and sending it are separate steps. A message appearing in the inbox tells you only that the first step happened.
Cyberpigeon provides the email identity, stored messages and events. Your application owns the task record: which incoming message it is handling, the proposed response, whether a person approved it and the ID of any outgoing message. Keep that record outside the model’s conversation so a lost session does not erase the workflow.
Cyberpigeon keeps
- The agent’s address and inbox
- Stored messages and their status
- Events, in order, behind a cursor
Your application keeps
Example- Event
1842- Incoming message
3f9c…a71e- Proposed reply
- “Your order shipped on Tuesday…”
- Approval
- Approved
- Idempotency key
9d4e…b7a2- Outgoing message
8b21…4c0d
Start with one inbox and one permitted job. A useful first version reads a support request and prepares a response for review. You can exercise the recovery behavior before allowing unattended actions.
Save progress after you record the work
The GET /v1/events endpoint returns data and next_cursor. Pass your saved cursor as after on the next request. With a mailbox-scoped read key, the feed is limited to that mailbox. Keep a separate cursor for each independent consumer and permission scope.
curl --fail-with-body --get 'https://cyberpigeon.ai/v1/events' \
-H "Authorization: Bearer $CYBERPIGEON_AGENT_KEY" \
--data-urlencode "after=$SAVED_CURSOR" \
--data-urlencode 'limit=50'
Set SAVED_CURSOR=0 for an initial read, then use the returned cursor as an opaque value. Do not convert it to a JavaScript number. For each message.received event, record a job keyed by its event ID. Fetch the message through GET /v1/mailboxes/{mailboxId}/messages/{messageId} using the event’s mailbox ID and data.message_id.
In your own database, commit the jobs and cursor together. Another worker can process those jobs after the cursor advances. If you process inline instead, save progress only after the work is durable. A crash before saving can replay events; a unique event ID lets you recognize work already recorded. Advance over events you deliberately ignore too, and keep draining full pages before waiting for more.
Retry the same action with the same key
A send can succeed even if your client never receives the response. Generating a fresh request identity after every timeout turns that uncertainty into duplicate email.
Before sending, persist an Idempotency-Key and the exact approved payload alongside the task. Use that key for every retry of that action. Cyberpigeon checks it within the mailbox: an identical request returns the existing message with replayed: true; different content with the same key produces 409 idempotency_conflict. A different intended message needs a different key.
Do not ask the model to regenerate the response between retries. Even a small rewrite changes the payload. Keep the approved text, recipients and key together. This protects a repeated send request; it does not make unrelated actions in your application, such as updating a ticket, automatically idempotent.
For a response to inbound mail, use POST /v1/mailboxes/{mailboxId}/messages/{messageId}/reply. It preserves email threading and requires both read and send permission. The API quickstart includes the complete request.
Test the interruptions before the happy path is finished
Stop your worker after recording a job, after approving a reply and after submitting a send but before saving its response. Restart each time. The expected result is one task record and one intended outgoing message, with enough history to explain what happened.
- Replay an event and confirm that it does not create a second task.
- Retry an approved send with the same key and payload.
- Change the payload while keeping the key and handle the conflict visibly.
- Revoke the read key and check that authorization failures stop processing instead of causing an endless retry loop.
HTTP 202 means the email is queued. Track its message ID and later events before reporting a delivery outcome. An uncertain outcome needs inspection before another send; see the delivery-status guide.
These are application design recommendations, not a workflow engine hosted by Cyberpigeon. Start with permitted testing, expected transactional email or support replies. Cold outreach, sales prospecting, bulk marketing, inbox warmup and spam are prohibited in the current beta.