# Sends and events

Every email the project sent, what happened to it, and the event stream by type.

## List sends

`GET /projects/{project_id}/sends`

Every email the project sent, newest first, from every source. Filter by one of email, contact_id, campaign_id, broadcast_id (a broadcast’s recipients) or status=failed at a time.

### Parameters

| Name | In | Type | Notes |
| --- | --- | --- | --- |
| `project_id` | path | string | Required |
| `email` | query | string \| null | Optional |
| `contact_id` | query | string \| null | Optional |
| `campaign_id` | query | string \| null | Optional |
| `broadcast_id` | query | string \| null | Optional |
| `status` | query | "failed" \| null | Optional |
| `cursor` | query | string \| null | Optional |
| `limit` | query | integer | Optional, default 50 |

```sh Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/sends?campaign_id=h5dnsipzz5fk2z9ri19r0wyojfljooa5" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
```

### Response

```json 200
{
  "sends": [
    {
      "id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
      "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
      "contact_id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
      "to": "maya@example.com",
      "subject": "Welcome to Acme, Maya",
      "source": {
        "type": "campaign_step",
        "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
        "step_id": "j8gxbenyjqwx4hh5344tfjgvq4k7bn7x",
        "enrollment_id": "j3j4wj99ibag7i1mnbqns6puq80idw37"
      },
      "status": "delivered",
      "has_opened": true,
      "has_clicked": true,
      "has_replied": false,
      "accepted_at": 1790000120000,
      "failed_at": null,
      "ext_provider_message_id": "4ef9a1c2-7d3b-4f0e-9a51-2c8e6b1d0f73",
      "created_at": 1790000120000
    }
  ],
  "next_cursor": null
}
```

### Errors

| Status | Type | Example message |
| --- | --- | --- |
| 400 | `invalid_data` | limit: Too big: expected number to be <=200 |
| 401 | `unauthorized` | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | `project_not_found` | Project not found. |
| 422 | `invalid_reference` | No template with that id in this project. |
| 429 | `rate_limited` | Too many requests. Try again in 12 seconds. |

## Get a send

`GET /sends/{send_id}`

One email to one address and what happened to it: events oldest first (up to 15 of each type) and every provider attempt that failed. An erased address reads as null to, subject and contact_id.

### Parameters

| Name | In | Type | Notes |
| --- | --- | --- | --- |
| `send_id` | path | string | Required |

```sh Request
curl "https://sendocado.com/api/v1/sends/$SEND_ID" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
```

### Response

```json 200
{
  "id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
  "project_id": "ujzde8gxd6ncf10epf91dhodzdoc9is0",
  "contact_id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
  "to": "maya@example.com",
  "subject": "Welcome to Acme, Maya",
  "source": {
    "type": "campaign_step",
    "campaign_id": "h5dnsipzz5fk2z9ri19r0wyojfljooa5",
    "step_id": "j8gxbenyjqwx4hh5344tfjgvq4k7bn7x",
    "enrollment_id": "j3j4wj99ibag7i1mnbqns6puq80idw37"
  },
  "status": "delivered",
  "has_opened": true,
  "has_clicked": true,
  "has_replied": false,
  "accepted_at": 1790000120000,
  "failed_at": null,
  "ext_provider_message_id": "4ef9a1c2-7d3b-4f0e-9a51-2c8e6b1d0f73",
  "created_at": 1790000120000,
  "events": [
    {
      "type": "delivered",
      "url": null,
      "detail": null,
      "created_at": 1790000180000
    },
    {
      "type": "opened",
      "url": null,
      "detail": null,
      "created_at": 1790005700000
    },
    {
      "type": "clicked",
      "url": "https://acme.example/setup",
      "detail": null,
      "created_at": 1790005760000
    }
  ],
  "failures": []
}
```

### Errors

| Status | Type | Example message |
| --- | --- | --- |
| 401 | `unauthorized` | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | `send_not_found` | Send not found. |
| 429 | `rate_limited` | Too many requests. Try again in 12 seconds. |

## List email events of one type

`GET /projects/{project_id}/email-events`

One type per request, newest first. For everything that happened to one email, get its send instead.

### Parameters

| Name | In | Type | Notes |
| --- | --- | --- | --- |
| `project_id` | path | string | Required |
| `type` | query | "delivered" \| "delivery_delayed" \| "soft_bounced" \| "opened" \| "clicked" \| "bounced" \| "complained" \| "unsubscribed" \| "failed" | Required |
| `cursor` | query | string \| null | Optional |
| `limit` | query | integer | Optional, default 50 |

```sh Request
curl "https://sendocado.com/api/v1/projects/$PROJECT_ID/email-events?type=clicked" \
  -H "Authorization: Bearer $SENDOCADO_API_KEY"
```

### Response

```json 200
{
  "email_events": [
    {
      "id": "qm2plppjsmuezqp67og3cga4o2xcsohd",
      "type": "clicked",
      "send_id": "thjxjqi3ogz5kok16zv0mwufxbv932by",
      "contact_id": "j8ht9lgmxg9edn581u33xtplpft75v2s",
      "url": "https://acme.example/setup",
      "detail": null,
      "created_at": 1790005760000
    }
  ],
  "next_cursor": null
}
```

### Errors

| Status | Type | Example message |
| --- | --- | --- |
| 400 | `invalid_data` | limit: Too big: expected number to be <=200 |
| 401 | `unauthorized` | Send a valid API key as "Authorization: Bearer sc_…", or sign in. |
| 404 | `project_not_found` | Project not found. |
| 429 | `rate_limited` | Too many requests. Try again in 12 seconds. |
