> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ziplined.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Clay

> Pull warm, well-fitting people into a Clay table.

Use the Clay integration when you want every person as a row, with fit, warmth, company and
engagement recency as columns.

## Before you connect

* A key with scope `read`.
* Add scope `contacts` too if you want `email` in Clay.
* A Clay table to enrich.

> [!NOTE]
>
> Without `contacts` the email fields are absent rather than empty. Clay then shows no column
> instead of a blank one.

## Connect Clay

**1. Test the query first**

```bash theme={null}
curl -G https://api.ziplined.io/v1/people \
  -H "Authorization: Bearer $ZIPLINED_API_KEY" \
  --data-urlencode "min_fit=70" \
  --data-urlencode "country=NL,BE" \
  --data-urlencode "max_outreach_count=0" \
  --data-urlencode "engaged_since=2026-08-30" \
  --data-urlencode "sort=warmth" \
  --data-urlencode "limit=100"
```

This asks for people in NL or BE who engaged since 30 August. Fit at least 70, never
approached. Read `total` to see how many rows this will be.

**2. Add the HTTP API column**

In your Clay table, add an enrichment of type **HTTP API**.

| Field | Value |
| - | - |
| Method | `GET` |
| URL | `https://api.ziplined.io/v1/people` |
| Headers | `Authorization: Bearer zpl_...` |

Put the filters in the query params: `min_fit=70`, `country=NL,BE`,
`max_outreach_count=0`, `sort=warmth`, `limit=100`.

**3. Page through the results**

```
?cursor=<the previous next_cursor>
```

Add a `cursor` query parameter and feed it the previous `next_cursor`. Stop when it is
`null`. Do not build a cursor yourself.

## Map the fields

Clay reads the JSON body. The rows are under `data`.

| Ziplined field | Clay column |
| - | - |
| `id` | Ziplined person id |
| `name`, `job_title` | Name, Title |
| `linkedin_url` | LinkedIn profile |
| `company`, `company_id` | Company, Company id |
| `company_industry` | Industry |
| `company_size.min`, `company_size.max` | Employee band |
| `country`, `location`, `seniority` | Country, Location, Seniority |
| `fit.score`, `fit.tier` | Fit |
| `warmth.score`, `warmth.tier` | Warmth |
| `stage` | Stage |
| `last_engaged_at`, `last_engaged_type` | Last engaged |
| `engagements_30d` | Engagements, 30 days |
| `outreach_count`, `last_outreach_at` | Times approached |
| `email`, `email_status` | Email |

Keep `id`. You need it to write back. `email` and `email_status` need the `contacts` scope.

> [accordion] Shapes that surprise people
>
> `company_size` is two numbers, because that is what LinkedIn gives.
>
> `fit` and `warmth` are always an object, with `null` inside when there is nothing to score.

## Troubleshoot

An unknown query parameter is a 400, so a filter typo shows up as an error. It never reads
as a full list that looks filtered.

> [accordion] Rate limits during a refresh
>
> 60 requests a minute per credential. Every response tells you where you stand in
> `RateLimit-Remaining`.
>
> At `limit=100` that is 6000 rows a minute, which is more than enough for a table refresh.

## Next

Close the loop after your sequence runs, so `max_outreach_count=0` keeps meaning "never
approached". See [Log outreach](https://docs.ziplined.io/integrations/log-outreach.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.