Approve sends

Hold an agent's or person's sends until a different person approves or denies them, and react to the pending event.

A mailbox send either goes out immediately or waits for a person. The send mode of the principal decides which, and you can change it at any time without issuing a new key.

Send modeWhat happens to a send
sendIt runs at once, within your account's limits. This is the default.
approvalIt is held until a person other than the sender approves it.

Set the mode on a grant, on a mailbox-scoped key, or when you install an extension. The same mailbox can let a person send directly while an agent's replies wait for review.

What a held send returns

A send, reply, reply to all, forward, or draft send from a principal in approval mode returns status: "pending_approval". Nothing is sent and no message exists yet.

{
  "actionId": "mbxact_...",
  "messageId": null,
  "threadId": "thread_...",
  "status": "pending_approval",
  "waitReason": null,
  "reviewExpectedAt": null,
  "skippedRecipients": [],
  "createdAt": "2026-10-07T14:05:00.000Z"
}

actionId identifies the held send, and messageId is null until it is sent. A send that is not held returns status: "sent" with the sent message's messageId. skippedRecipients lists any recipient Samva did not send to, with the reason. Retrying with the same Idempotency-Key and body returns the original receipt, held or not.

Know when a send is waiting

Subscribe to mailbox.action.pending_approval. It carries the action, who proposed it, and the recipients and subject of the draft, so a reviewer can decide without opening the mailbox. See Events for the payload.

List a mailbox's actions with GET /v1/mailboxes/{id}/actions to find sends awaiting a decision. An action in state approvalRequired is waiting.

Approve or deny

Approve with POST /v1/mailboxes/{id}/actions/{actionId}/approve. Samva sends the message and returns the executed action.

curl -X POST https://api.samva.dev/v1/mailboxes/$MAILBOX_ID/actions/$ACTION_ID/approve \
  -H "Authorization: Bearer $SAMVA_OAUTH_TOKEN" \
  -H "x-org-slug: acme"

Deny with POST /v1/mailboxes/{id}/actions/{actionId}/deny and a reason. Nothing is sent, and the send returns to its author as an editable draft.

curl -X POST https://api.samva.dev/v1/mailboxes/$MAILBOX_ID/actions/$ACTION_ID/deny \
  -H "Authorization: Bearer $SAMVA_OAUTH_TOKEN" \
  -H "x-org-slug: acme" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Wrong recipient." }'

Both need an admin grant on the mailbox. Resolving an action that is no longer waiting is a 409.

Hold or refuse sends with a policy

A mailbox policy applies to every send from the mailbox, whoever proposes it. An enabled policy with outcome requireApproval holds each send for a person; one with outcome deny refuses it, and deny wins when both apply. Policies are part of configuring the mailbox, which needs an admin grant.

require-approval-policy.ts
const policy = await samva.mailboxes.createPolicy({
  id: "mbx_...",
  name: "Review every send",
  outcome: "requireApproval",
  reason: "A person reviews outbound mail from this mailbox.",
});

// Stop it applying without deleting it.
await samva.mailboxes.updatePolicy({ id: "mbx_...", policyId: policy.id, enabled: false });

Deleting a policy does not release sends it already holds: they stay held until a person approves or denies them. See create a policy for the limit on policies per mailbox.

Who can decide

  • Only a person decides. Someone signed in to the dashboard or the CLI, or an OAuth connection that person approved, can approve or deny. An API key never can, whatever its owner may do, and an extension never can.
  • Nobody decides their own send. A person in approval mode cannot approve what they proposed, so their sends need a different admin. A 403 says which rule applied.
  • The hosted MCP tools cannot approve or deny.

Next steps

Related documentation

On this page