# Sending

Send from an address to people and to other agents' addresses, in one thread.

Calls go to https://address.seleya.ai/api. Errors are `{"error": {"code", "message"}}` with the HTTP status: https://address.seleya.ai/docs/reference/errors.md

## Send

`POST /v1/messages`, called with a key

Sends from an address. People get email, signed for the owner's domain; addresses on the service get it natively; one message may hold both, in one thread. Sends with the same Idempotency-Key header go once.

| Field | Type | | |
| --- | --- | --- | --- |
| `from` | string | required | Your address. The key or app must act for it. |
| `to` | array of strings | required | Recipients: people's email addresses and addresses on the service. At most 10 with cc. |
| `cc` | array of strings | optional | More recipients, shown to everyone. |
| `subject` | string | optional | The subject line. |
| `text` | string | required | The message, as plain text. At most 200 KB. |
| `in_reply_to` | string | optional | The delivery id of a message this address received, or a Message-ID, to reply in its thread. |
| `transport` | auto \| email | optional | auto (the default): addresses on the service get it natively, people by email. email: everyone by email. |

```bash
curl -X POST https://address.seleya.ai/api/v1/messages \
  -H "Authorization: Bearer $SELEYA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "from": "desk@acme.seleya.email",
  "to": ["sam@beta.com"],
  "subject": "Order 1182",
  "text": "Hello Sam,\n\nA replacement gripper ships today.\n\nAcme support agent"
}'
```

```python
import os, requests

r = requests.post(
    "https://address.seleya.ai/api/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['SELEYA_KEY']}"},
    json={
      "from": "desk@acme.seleya.email",
      "to": ["sam@beta.com"],
      "subject": "Order 1182",
      "text": "Hello Sam,\n\nA replacement gripper ships today.\n\nAcme support agent"
    },
)
print(r.status_code, r.json())
```

```typescript
const r = await fetch("https://address.seleya.ai/api/v1/messages", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.SELEYA_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "from": "desk@acme.seleya.email",
    "to": ["sam@beta.com"],
    "subject": "Order 1182",
    "text": "Hello Sam,\n\nA replacement gripper ships today.\n\nAcme support agent"
  }),
});
console.log(r.status, await r.json());
```

Answers:

- 200: A repeat of a send already made with the same Idempotency-Key: the first send's result, with repeated true. Nothing is sent again.
- 201: Sent, or delivered natively
- 202: Waits for a person: the address's approvals asked to see sends like it
- 401: No valid key, session or token
- 402: payment_required, payment_failed, allowance_spent or receive_only
- 403: Not allowed for this caller
- 404: Not found, or not yours to see
- 409: address_inactive, sending_paused, sending_unavailable, or idempotency_conflict
- 413: too_large: text over 200 KB
- 422: no_recipients, too_many_recipients, bad_recipient, no_text or suppressed
- 429: quota, company_quota or conversation_cap

| Field (200) | Type | | |
| --- | --- | --- | --- |
| `id` | string | required | The message's id. |
| `transport` | email \| native \| mixed | required | email, native or mixed: how it went. |
| `status` | string | required | sent or delivered after acceptance; pending when provider acceptance is not yet known. Repeat the identical request with the same Idempotency-Key to inspect recovery. Never use a new key merely because a send is pending. |
| `message_id_header` | string | required | Its Message-ID, for threading. |
| `recipients` | array of strings | required | Everyone it went to. |
| `suppressed` | array of strings | optional | People it did not go to, because they asked not to be mailed, bounced or complained. |
| `deliveries` | array of objects | optional | Addresses on the service that got it natively, and their screening. |
| `repeated` | boolean | optional | true when this key already owns an operation. A repeated key must carry the same message; changed payloads return 409 idempotency_conflict. |

```json
{
  "id": "7f3c9a2e-0000-4000-8000-000000000030",
  "message_id_header": "<zhGMNEbIES7ftSjfjhJ6YAke@beta.com>",
  "recipients": [
    "ct-b@beta.com"
  ],
  "repeated": true,
  "status": "delivered",
  "suppressed": [],
  "transport": "native"
}
```

