*REST API › Endpoint reference › CRM › Contacts*

# Look up contacts by external reference

> From a list of your references, says which ones already exist in Filmo and which do not.

`notFound` are the ones to create. It is the primitive of any synchronization: without it, the alternative is one call per reference and guessing from the 404. It writes NOTHING, even though it is a POST: the list of references does not fit in a query string.

`POST /api/v1/contacts/lookup` — scope `contacts:read`

Scope: `contacts:read` · 120/min · Inherited tenancy · MCP: `filmo_contacts_lookup`

## Authorizations

Bearer API key with the scope below. `contacts:read`

## Body

Body schema: `ContactsLookupBody`

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `references` | string[] | Yes | External references to look up. At least one, at most 200. |

## Request examples

*Look up contacts by external reference*

**cURL**

```bash
curl https://app.filmo.io/api/v1/contacts/lookup \
  --request POST \
  --header "Authorization: Bearer $FILMO_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "references": [
    "ERP-CLI-0042",
    "ERP-CLI-0043",
    "ERP-CLI-9999"
  ]
}'
```

**Node.js**

```javascript
fetch('https://app.filmo.io/api/v1/contacts/lookup', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer YOUR_FILMO_API_KEY',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    references: ['ERP-CLI-0042', 'ERP-CLI-0043', 'ERP-CLI-9999']
  })
})
```

**Python**

```python
import requests

requests.post(
    "https://app.filmo.io/api/v1/contacts/lookup",
    headers={
      "Authorization": "Bearer YOUR_FILMO_API_KEY",
      "Content-Type": "application/json"
    },
    json={
      "references": [
        "ERP-CLI-0042",
        "ERP-CLI-0043",
        "ERP-CLI-9999"
      ]
    }
)
```

## Response

Response schema: `ContactsLookupResultDto`

| Status | Description |
| --- | --- |
| 200 | Successful response. |
| 400 | Invalid request (validation_error): malformed query or body. `errors[]` lists every offending field with its stable code. |
| 401 | Authentication failed (unauthorized, api_key_invalid, api_key_revoked, api_key_expired, api_key_owner_inactive, api_key_owner_not_admin). |
| 403 | Not allowed (insufficient_scope: the API key does not have the required scope, named in `requiredScope`; forbidden: the owner of the key lacks the permission the operation requires). `insufficient_scope` is answered before the request counts against the rate limit, so it carries no `RateLimit-*` headers; `forbidden` does. |
| 404 | Resource not found (not_found): it does not exist or is outside the scope of the API key. |
| 409 | Conflict (conflict): the current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation. |
| 429 | Rate limit exceeded (rate_limited): retry after `Retry-After` seconds; `RateLimit-*` says which quota ran out. |
| 500 | Internal error (internal_error). |

**200**

| Name | Type | Description |
| --- | --- | --- |
| `data` | object | Result of looking up contacts by external reference. |
| `data.contacts` | object[] | Contacts that matched at least one reference. |
| `data.contacts.id` | string | Identifier of the contact in Filmo. |
| `data.contacts.name` | string | Contact name. |
| `data.contacts.contactNumber` | string | Filmo contact number. |
| `data.notFound` | string[] | References that did not match any contact. These are the ones to create. |
| `meta` | object | Additional information about the response. |
| `meta.warnings` | object[] | Lifecycle warnings; present only when the operation is deprecated. |
| `meta.warnings.code` | string | Stable warning code. `deprecated` |
| `meta.warnings.message` | string | For people: what is deprecated, until when, and what to use. |
| `meta.warnings.sunset` | string | Day (YYYY-MM-DD) the operation stops being served. |
| `meta.warnings.replacement` | string | `operationId` of the operation to use instead, or null if there is none. |
| `meta.warnings.link` | string | Where the deprecation is documented (the changelog). |

*Example response · 200*

```json
{
  "data": {
    "contacts": [
      {
        "id": "contact_9f3a2b",
        "name": "Example contact",
        "contactNumber": "2026-0001"
      }
    ],
    "notFound": [
      "Example not found"
    ]
  }
}
```

## Errors

| Status | Codes | Meaning |
| --- | --- | --- |
| 400 | `validation_error` | Malformed query or body. `errors[]` lists every offending field with its stable code. |
| 404 | `not_found` | It does not exist or is outside the scope of the API key. |
| 409 | `conflict` | The current state of the resource prevents the operation, a request with that Idempotency-Key is already in progress, or another conditional write (`If-Match`) held the resource for more than five seconds. `errors[0].code` says which: `in_progress` and `lock_timeout` are solved by retrying; `invalid_state` is not, because the state of the resource forbids the operation. |

## Deprecation

This operation is not deprecated. Deprecations are announced with a Deprecation header and a sunset date.

---

Canonical URL: https://docs.filmo.io/rest-api/endpoint-reference/contacts/look-up-contacts-by-external-reference  
Last updated: 2026-10-25