# Quickstart

> Make your first Emelia API call in two minutes, then create a list and add a contact to it.

Source: https://docs.emelia.io/docs/quickstart

By the end of this page you will have an API key, a working request, a list, and a contact in that list.

### Get your API key

Open **Settings, API & Webhooks** in the Emelia app and create a key.

[Get your API key](https://v3.emelia.io/settings/api)

Store it in an environment variable rather than in your code:

```bash
export EMELIA_API_KEY="your_48_character_api_key"
```

### Check that the key works

List your campaigns. This call changes nothing.

[`GET /advanced/campaigns`](https://docs.emelia.io/docs/campaigns/list-campaigns.md)

**curl**

```bash
curl https://api.emelia.io/advanced/campaigns \
  -H "Authorization: $EMELIA_API_KEY"
```

**JavaScript**

```js
const res = await fetch('https://api.emelia.io/advanced/campaigns', {
  headers: { Authorization: process.env.EMELIA_API_KEY },
});
console.log(res.status, await res.json());
```

**Python**

```python
import os
import requests

res = requests.get(
    "https://api.emelia.io/advanced/campaigns",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
)
print(res.status_code, res.json())
```

A `200` with a `campaigns` array means you are in. A `401` means the key is wrong or disabled: see [Authentication](https://docs.emelia.io/docs/authentication.md).

### Create a list

Contacts live in lists. Create one:

[`POST /lists/list`](https://docs.emelia.io/docs/lists/create-list.md)

**curl**

```bash
curl -X POST https://api.emelia.io/lists/list \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Q4 SaaS founders"}'
```

**JavaScript**

```js
const res = await fetch('https://api.emelia.io/lists/list', {
  method: 'POST',
  headers: {
    Authorization: process.env.EMELIA_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ name: 'Q4 SaaS founders' }),
});
const { listId } = await res.json();
```

**Python**

```python
res = requests.post(
    "https://api.emelia.io/lists/list",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
    json={"name": "Q4 SaaS founders"},
)
list_id = res.json()["listId"]
```

The response is a `201`:

```json
{ "success": true, "listId": "66f1c0ffee5a7d3b2c4e8a10", "name": "Q4 SaaS founders" }
```

### Add a contact

Send a flat object: one key per field. Emelia recognises the standard fields (`firstName`, `email`, `companyName`...) and turns any other key into a custom variable you can use in your messages.

[`POST /lists/list/{listId}/contacts`](https://docs.emelia.io/docs/lists/add-contact.md)

**curl**

```bash
curl -X POST https://api.emelia.io/lists/list/66f1c0ffee5a7d3b2c4e8a10/contacts \
  -H "Authorization: $EMELIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Claire",
    "lastName": "Fontaine",
    "email": "claire.fontaine@nexora.io",
    "companyName": "Nexora",
    "icebreaker": "your move to Postgres 16 last month"
  }'
```

**JavaScript**

```js
const listId = '66f1c0ffee5a7d3b2c4e8a10';
const res = await fetch(`https://api.emelia.io/lists/list/${listId}/contacts`, {
  method: 'POST',
  headers: {
    Authorization: process.env.EMELIA_API_KEY,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    firstName: 'Claire',
    lastName: 'Fontaine',
    email: 'claire.fontaine@nexora.io',
    companyName: 'Nexora',
    icebreaker: 'your move to Postgres 16 last month',
  }),
});
console.log(await res.json());
```

**Python**

```python
list_id = "66f1c0ffee5a7d3b2c4e8a10"
res = requests.post(
    f"https://api.emelia.io/lists/list/{list_id}/contacts",
    headers={"Authorization": os.environ["EMELIA_API_KEY"]},
    json={
        "firstName": "Claire",
        "lastName": "Fontaine",
        "email": "claire.fontaine@nexora.io",
        "companyName": "Nexora",
        "icebreaker": "your move to Postgres 16 last month",
    },
)
print(res.json())
```

```json title="Response"
{
  "success": true,
  "leadId": "66f2a1b2c3d4e5f6a7b8c9d0",
  "companyId": "66f2a1b2c3d4e5f6a7b8c9e0",
  "duplicate": false,
  "updated": false,
  "createdCustomVariables": [{ "technicalName": "icebreaker", "displayName": "icebreaker", "schema": "lead" }]
}
```

Send the same contact again and nothing is created: the response carries the existing `leadId` with `duplicate: true`. The match is on the exact `email`, then on the exact LinkedIn URL. A contact with neither is created again on every call, so give each contact an email or a LinkedIn URL before you retry.

### Attach the list to a campaign

In the app, open a campaign and select the list as its recipients, or do it by API:

[`PATCH /advanced/campaigns/{campaignId}/recipients`](https://docs.emelia.io/docs/campaigns/set-contact-lists.md)

From then on, every contact you add to the list enters the campaign on its own, even while it runs.

## Next steps

- [Lists & contacts](https://docs.emelia.io/docs/lists): Batches of 100 contacts, updates, lookups, field mapping.

- [Build a campaign by API](https://docs.emelia.io/docs/campaigns): Sequence, schedule, senders, start.

- [Skip the code](https://docs.emelia.io/docs/ai/mcp): Ask Claude or Cursor to do the same through the MCP server.
