# List drafts

Source: https://docs.emelia.io/docs/inbox-api/list-drafts

Guide: [Inbox API](https://docs.emelia.io/docs/inbox-api.md)

`GET https://api.emelia.io/inbox/api/v1/drafts`

Returns the most recent drafts of the workspace (rows with `isDraft: true`, all mailboxes), most recent first. Not paginated: there is no cursor, so at most `limit` drafts (200 maximum) can ever be read. Read a draft body with `GET /emails/{draftId}/body`.

## Authentication

Send your API key in the `Authorization` header: `Authorization: <your API key>`.

## Query parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `limit` | integer | no | Page size. Above 200 it is clamped to 200; an unreadable or non positive value falls back to 50 (no error). Default: `50`. Range: 1 to 200. |

## Example request

**cURL**

```bash
curl -X GET "https://api.emelia.io/inbox/api/v1/drafts" \
  -H "Authorization: $EMELIA_API_KEY"
```

**JavaScript**

```js
const response = await fetch('https://api.emelia.io/inbox/api/v1/drafts', {
  method: 'GET',
  headers: { Authorization: process.env.EMELIA_API_KEY },
});
console.log(await response.json());
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://api.emelia.io/inbox/api/v1/drafts",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
)
print(response.json())
```

## Responses

### 200: Drafts.

| Field | Type | Required | Description |
|---|---|---|---|
| `items` | array of object | yes |  |
| `items[].id` | string | yes | Inbox id of the email. |
| `items[].mailboxId` | string | yes |  |
| `items[].folderId` | string | yes |  |
| `items[].messageId` | string | yes | RFC 5322 Message-ID header. Needed to reply in a thread. |
| `items[].threadId` | string or null | yes | Provider conversation id (Gmail, Microsoft), null for IMAP. |
| `items[].subject` | string | yes |  |
| `items[].from` | object | yes | An address as returned by the API. `name` is null when unknown. |
| `items[].to` | array of object | yes |  |
| `items[].cc` | array of object | yes |  |
| `items[].date` | string (date-time) | yes |  |
| `items[].snippet` | string | yes | Short text preview (about 200 characters). |
| `items[].isRead` | boolean | yes |  |
| `items[].isStarred` | boolean | yes |  |
| `items[].isDraft` | boolean | yes |  |
| `items[].waitingForReply` | boolean | yes | Estimate that a sent email still expects an answer. |
| `items[].hasAttachments` | boolean | yes |  |
| `items[].attachments` | array of object | yes |  |
| `items[].inReplyTo` | string or null | yes |  |
| `items[].references` | array of string | yes |  |
| `items[].bcc` | array of object | yes | Only known on sent messages and drafts. |
| `items[].labels` | array of string | yes | Provider labels (for example Gmail `INBOX`, `UNREAD`, `IMPORTANT`), NOT inbox labels. |
| `items[].isAutoReply` | boolean | yes | Sent automatically by an auto-reply. |
| `items[].isAutoForward` | boolean | yes | Sent automatically by an auto-forward rule. |
| `items[].scheduledStatus` | enum: `PENDING`, `QUEUED`, `SENDING`, `FAILED`, `null` | yes | For a scheduled draft: its sending state. |
| `items[].scheduledSendAt` | string or null (date-time) | yes |  |

```json
{
  "items": [
    {
      "id": "cmdracme0000000000000001",
      "mailboxId": "cmbxacme0000000000000001",
      "folderId": "cmfdacme0000000000000001",
      "messageId": "<draft-cmdracme0000000000000001@acme.com>",
      "threadId": "18c2acme0001",
      "subject": "Re: Partnership with Acme",
      "from": {
        "email": "john.doe@acme.com",
        "name": null
      },
      "to": [
        {
          "email": "jane.roe@example.com",
          "name": "Jane Roe"
        }
      ],
      "cc": [],
      "bcc": [],
      "date": "2026-10-08T09:12:44.000Z",
      "snippet": "Hello Jane, Tuesday 10am works for me.",
      "isRead": true,
      "isStarred": false,
      "isDraft": true,
      "hasAttachments": false,
      "attachments": [],
      "inReplyTo": "<CAJacme.0001@mail.example.com>",
      "references": [
        "<20261008091500.acme01@acme.com>",
        "<CAJacme.0001@mail.example.com>"
      ],
      "labels": [],
      "waitingForReply": false,
      "isAutoReply": false,
      "isAutoForward": false,
      "scheduledStatus": null,
      "scheduledSendAt": null
    }
  ]
}
```

### 401: Missing, malformed, unknown or disabled key. No `X-RateLimit-*` headers.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 403: `WORKSPACE_SUSPENDED`: the Emelia subscription has expired.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 429: `RATE_LIMIT_EXCEEDED`: per minute limit of the workspace (wait `Retry-After`). `QUOTA_EXCEEDED`: monthly quota exhausted until the 1st of next month UTC (in Emelia the plan cannot be upgraded).

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```

### 500: `INTERNAL_ERROR`: unexpected failure. The message is generic in production.

| Field | Type | Required | Description |
|---|---|---|---|
| `code` | enum: `INVALID_API_KEY`, `WORKSPACE_SUSPENDED`, `FORBIDDEN`, `PLAN_REQUIRED`, `VALIDATION_FAILED`, `REQUEST_ERROR`, `PAYLOAD_TOO_LARGE`, `NOT_FOUND`, `EMAIL_NOT_FOUND`, `DRAFT_NOT_FOUND`, `MAILBOX_NOT_FOUND`, `LABEL_NOT_FOUND`, `VIEW_NOT_FOUND`, `RULE_NOT_FOUND`, `FILTER_NOT_FOUND`, `SIGNATURE_NOT_FOUND`, `MAILBOX_INACTIVE`, `INVALID_SENDER_ALIAS`, `NO_TRASH_FOLDER`, `INVALID_TAG`, `CONFLICT`, `DUPLICATE_TAG_NAME`, `DUPLICATE_RULE`, `DUPLICATE_FILTER`, `SCHEDULED_SEND_IN_PROGRESS`, `DRAFT_ALREADY_EXISTS`, `QUERY_TIMEOUT`, `RATE_LIMIT_EXCEEDED`, `QUOTA_EXCEEDED`, `INTERNAL_ERROR` | yes | Codes that the Inbox API can return, as found in the code. Branch on `code`, never on `error`. The HTTP status is derived from the code (unknown business codes are 400). |
| `error` | string | yes | Human readable. |
| `details` | object | no | Optional context: faulty fields, bounds, ids. |

```json
{
  "code": "INVALID_API_KEY",
  "error": "string",
  "details": {}
}
```
