# Contacts

## List contacts

`GET /v1/c/{slug}/contacts` · Scopes: `contacts:read`

Most active first. `q` searches name or phone; `tag` filters by tag; `before` (the last one's `lastActivityAt`) brings the next page.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |

### Query parameters

| Field | Type | Required | Notes |
|---|---|---|---|
| `q` | string | no | up to 200 characters |
| `limit` | integer | no | up to 100; at least 1; default `50` |
| `before` | string (date-time) | no |  |
| `tag` | string (uuid) | no |  |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/contacts" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "contacts": [
    {
      "id": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
      "displayName": "Ana Souza",
      "address": "5548999990001",
      "channelKind": "whatsapp",
      "source": "api",
      "externalRef": "erp-88213",
      "fields": {
        "cpf": "529.982.247-25",
        "plano": "anual"
      },
      "isBlocked": false,
      "lastActivityAt": "2026-10-22T18:40:02.000Z",
      "createdAt": "2026-09-23T22:19:30.396Z",
      "tags": [
        {
          "id": "01a12150-3610-7c00-b680-188c2b4c7313",
          "name": {
            "pt-BR": "VIP",
            "en": "VIP",
            "es": "VIP"
          },
          "color": "#92400e"
        }
      ]
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Create a contact

`POST /v1/c/{slug}/contacts` · Scopes: `contacts:write`

To create or update many at once (or one that may exist), use `POST /contacts/import`.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `displayName` | string | yes | up to 200 characters |
| `phone` | string | yes |  |
| `locale` | one of `pt-BR`, `es`, `en` | no |  |
| `fields` | object | no |  |
| `externalRef` | string | no | up to 200 characters |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/contacts" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "displayName": "Ana Souza",
  "phone": "+5548999990001",
  "externalRef": "erp-88213",
  "fields": {
    "cpf": "529.982.247-25"
  }
}'
```

### Response 201

```json
{
  "contact": {
    "id": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
    "displayName": "Ana Souza",
    "address": "5548999990001"
  }
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `409` `contact_exists`
- `422` `validation_failed`
- `429` `rate_limited`

## Create or update contacts (up to 1,000)

`POST /v1/c/{slug}/contacts/import` · Scopes: `contacts:write`

By phone: existing contacts are updated (name, fields, tags), new ones created. Each row comes back with the contact's id. A bad row does not stop the others.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `rows` | list of object | yes | up to 1000 |
| `rows[].phone` | string | yes | up to 40 characters |
| `rows[].name` | string | no | up to 200 characters |
| `rows[].fields` | object | no |  |
| `rows[].tags` | list of string | no | up to 20 |
| `rows[].externalRef` | string | no | up to 200 characters |
| `rows[].marketingOptIn` | boolean | no |  |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/contacts/import" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "rows": [
    {
      "phone": "+5548999990001",
      "name": "Ana Souza",
      "tags": [
        "VIP"
      ],
      "externalRef": "erp-88213"
    },
    {
      "phone": "48 99999-0002",
      "name": "Bruno Lima",
      "fields": {
        "plano": "mensal"
      },
      "marketingOptIn": true
    }
  ]
}'
```

### Response 200

```json
{
  "created": 1,
  "updated": 1,
  "errors": [
    {
      "row": 2,
      "reason": "invalid_phone"
    }
  ],
  "contacts": [
    {
      "row": 0,
      "contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
      "created": false
    },
    {
      "row": 1,
      "contactId": "01a0d05a-3ee3-75bd-9db5-dc9856f079c9",
      "created": true
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Get a contact

`GET /v1/c/{slug}/contacts/{id}` · Scopes: `contacts:read`

The contact with its fields, numbers, consents, last conversations and tags, plus the company's field definitions.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/contacts/:id" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "contact": {
    "id": "01a0d05a-3ee3-75bd-9db5-dc9856f079c8",
    "displayName": "Ana Souza",
    "address": "5548999990001",
    "channelKind": "whatsapp",
    "source": "api",
    "externalRef": "erp-88213",
    "fields": {
      "cpf": "529.982.247-25",
      "plano": "anual"
    },
    "isBlocked": false,
    "lastActivityAt": "2026-10-22T18:40:02.000Z",
    "createdAt": "2026-09-23T22:19:30.396Z",
    "firstName": "Ana",
    "lastName": "Souza",
    "locale": "pt-BR",
    "timezone": null,
    "blockedReason": null
  },
  "identities": [
    {
      "id": "01a0d05a-3ee3-75bd-9db5-dc9856f079c9",
      "channel_kind": "whatsapp",
      "address": "5548999990001",
      "external_id": null,
      "provider_display_name": "Ana",
      "is_primary": true,
      "last_seen_at": "2026-10-22T18:40:02.000Z"
    }
  ],
  "consents": [
    {
      "purpose": "marketing",
      "channel_kind": "whatsapp",
      "status": "opted_in",
      "source": "api",
      "occurred_at": "2026-10-01T10:00:00.000Z"
    }
  ],
  "conversations": [
    {
      "id": "01a3c0de-7a11-7b22-8c33-9d44e55f6677",
      "status": "closed",
      "source_kind": "campaign",
      "imported_from": null,
      "created_at": "2026-10-24T12:00:04.000Z",
      "closed_at": "2026-10-24T12:20:41.000Z",
      "channel_id": "01a0cccc-0000-7000-8000-000000000002",
      "outcome_code": "converted",
      "is_success": true
    }
  ],
  "tags": [
    {
      "id": "01a12150-3610-7c00-b680-188c2b4c7313",
      "name": {
        "pt-BR": "VIP",
        "en": "VIP",
        "es": "VIP"
      },
      "color": "#92400e"
    }
  ],
  "fieldDefinitions": [
    {
      "key": "cpf",
      "label": {
        "pt-BR": "CPF",
        "en": "CPF",
        "es": "CPF"
      },
      "type": "cpf",
      "options": null,
      "ai_extractable": true,
      "required": false,
      "sort": 1
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `contact_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Edit a contact

`PATCH /v1/c/{slug}/contacts/{id}` · Scopes: `contacts:write`

`fields` merges with the contact's fields; send `null` in a field to clear it.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `displayName` | string | no | up to 200 characters |
| `firstName` | string | no | up to 100 characters; null |
| `lastName` | string | no | up to 100 characters; null |
| `locale` | one of `pt-BR`, `es`, `en` | no | null |
| `externalRef` | string | no | up to 200 characters; null |
| `fields` | object | no |  |
| `isBlocked` | boolean | no |  |
| `blockedReason` | string | no | up to 200 characters; null |

### Request example

```bash
curl -X PATCH "https://api.donetalk.com/v1/c/demo/contacts/:id" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "fields": {
    "plano": "anual"
  },
  "externalRef": "erp-88213"
}'
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `contact_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Record consent

`POST /v1/c/{slug}/contacts/{id}/consents` · Scopes: `contacts:write`

Opt-in or opt-out per purpose (service, utility, marketing). A marketing opt-out keeps the contact out of marketing campaigns.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `purpose` | one of `service`, `utility`, `marketing` | yes |  |
| `status` | one of `opted_in`, `opted_out` | yes |  |
| `source` | one of `form`, `import`, `api`, `message`, `keyword` | no | default `"form"` |
| `evidence` | object | no |  |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/contacts/:id/consents" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "purpose": "marketing",
  "status": "opted_in",
  "source": "api"
}'
```

### Response 201

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `contact_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

## Add a tag

`PUT /v1/c/{slug}/contacts/{id}/tags/{tagId}` · Scopes: `contacts:write`

May start the flows that begin when this tag is added.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |
| `tagId` | The tag's id. |

### Request example

```bash
curl -X PUT "https://api.donetalk.com/v1/c/demo/contacts/:id/tags/:tagId" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Remove a tag

`DELETE /v1/c/{slug}/contacts/{id}/tags/{tagId}` · Scopes: `contacts:write`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |
| `tagId` | The tag's id. |

### Request example

```bash
curl -X DELETE "https://api.donetalk.com/v1/c/demo/contacts/:id/tags/:tagId" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Context cards

`GET /v1/c/{slug}/contacts/{id}/context-cards` · Scopes: `contacts:read`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X GET "https://api.donetalk.com/v1/c/demo/contacts/:id/context-cards" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "cards": [
    {
      "key": "erp",
      "source": "ERP Captei",
      "title": "Cliente desde 2023",
      "status": "Plano anual",
      "tone": "success",
      "fields": [
        {
          "label": "Pedidos",
          "value": "14"
        }
      ],
      "link": {
        "url": "https://erp.captei.com.br/clientes/88213",
        "label": "Abrir no ERP"
      },
      "updatedAt": "2026-10-23T13:02:11.000Z"
    }
  ]
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Show a card to the attendant

`PUT /v1/c/{slug}/contacts/{id}/context-cards/{key}` · Scopes: `contacts:write`

A card from your system shown beside the conversation (plan, orders, balance). The same `key` replaces the previous one.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |
| `key` | The key (of the field or the card). |

### Request body

| Field | Type | Required | Notes |
|---|---|---|---|
| `title` | string | yes | up to 120 characters |
| `source` | string | no | up to 60 characters |
| `status` | string | no | up to 60 characters; null |
| `tone` | one of `neutral`, `success`, `warning`, `danger`, `info` | no | default `"neutral"` |
| `fields` | list of object | no | up to 12; default `[]` |
| `fields[].label` | string | yes | up to 60 characters |
| `fields[].value` | string | yes | up to 300 characters |
| `link` | object | no | null |
| `link.url` | string (uri) | yes | up to 2000 characters |
| `link.label` | string | no | up to 60 characters |

### Request example

```bash
curl -X PUT "https://api.donetalk.com/v1/c/demo/contacts/:id/context-cards/:key" \
  -H "Authorization: Bearer $DONETALK_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Cliente desde 2023",
  "source": "ERP Captei",
  "status": "Plano anual",
  "tone": "success",
  "fields": [
    {
      "label": "Pedidos",
      "value": "14"
    }
  ],
  "link": {
    "url": "https://erp.captei.com.br/clientes/88213",
    "label": "Abrir no ERP"
  }
}'
```

### Response 200

```json
{
  "card": {
    "key": "erp",
    "source": "ERP Captei",
    "title": "Cliente desde 2023",
    "status": "Plano anual",
    "tone": "success",
    "fields": [
      {
        "label": "Pedidos",
        "value": "14"
      }
    ],
    "link": {
      "url": "https://erp.captei.com.br/clientes/88213",
      "label": "Abrir no ERP"
    },
    "updatedAt": "2026-10-23T13:02:11.000Z"
  }
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Remove a card

`DELETE /v1/c/{slug}/contacts/{id}/context-cards/{key}` · Scopes: `contacts:write`

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |
| `key` | The key (of the field or the card). |

### Request example

```bash
curl -X DELETE "https://api.donetalk.com/v1/c/demo/contacts/:id/context-cards/:key" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `422` `validation_failed`
- `429` `rate_limited`

## Erase the contact's data (LGPD)

`POST /v1/c/{slug}/contacts/{id}/erase` · Scopes: `contacts:delete`

At the person's request: the contact and their messages are anonymised for good. It cannot be undone.

### Path parameters

| Field | Notes |
|---|---|
| `slug` | The company's identifier in DoneTalk (the key's own). |
| `id` | The record's id. |

### Request example

```bash
curl -X POST "https://api.donetalk.com/v1/c/demo/contacts/:id/erase" \
  -H "Authorization: Bearer $DONETALK_KEY"
```

### Response 200

```json
{
  "ok": true
}
```

### Possible errors

- `401` `unauthorized`
- `403` `insufficient_scope`
- `404` `contact_not_found`
- `422` `validation_failed`
- `429` `rate_limited`

