> ## 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.

# Log outreach

> Write back to Ziplined after your sequencer or CRM sends a message.

Use this when your outbound tool sends the messages and Ziplined should know about it.

## Before you connect

* A key with scope `write`.
* The Ziplined `id` of every person your tool contacts.

> [!NOTE]
>
> Keep the person `id` in your sequencer next to the email address. It is the only thing you
> need to write back.

## Log an act

**1. Find the person, if you lost the id**

```bash theme={null}
curl -G https://api.ziplined.io/v1/people \
  -H "Authorization: Bearer $ZIPLINED_API_KEY" \
  --data-urlencode "search=https://www.linkedin.com/in/janedoe" \
  --data-urlencode "limit=1"
```

A pasted profile URL matches that one person. A bare public identifier works too.

**2. Log the act, right after you send**

```bash theme={null}
curl -X POST https://api.ziplined.io/v1/people/7b1f.../touches \
  -H "Authorization: Bearer $ZIPLINED_API_KEY" \
  -H "Idempotency-Key: 4a5b6c7d-8e9f-40a1-b2c3-d4e5f6071829" \
  -H "Content-Type: application/json" \
  -d '{
        "channel": "email",
        "note": "Step 1 of the Q4 sequence",
        "occurred_at": "2026-09-13T08:41:00.000Z",
        "tags": ["q4-sequence"]
      }'
```

`channel` is `linkedin_message`, `email`, `call` or `other`. `occurred_at` defaults to
now, so pass it only when backfilling. `tags` are added to the existing tags.

**3. Update the stage when the conversation moves**

```bash theme={null}
curl -X PATCH https://api.ziplined.io/v1/people/7b1f... \
  -H "Authorization: Bearer $ZIPLINED_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "stage": "customer", "notes": "Signed 2026-09-12, annual." }'
```

A reply, a meeting or a no is a stage change, not an outreach act. Use `disqualified`
for a hard no.

## Read the answer

```json theme={null}
{
  "data": {
    "touch": {
      "id": "d91a...",
      "channel": "email",
      "note": "Step 1 of the Q4 sequence",
      "occurred_at": "2026-09-13T08:41:00.000Z"
    },
    "person": { "id": "7b1f...", "name": "Jane Doe", "outreach_count": 0, "...": "..." }
  }
}
```

The 201 is the confirmation.

> [!WARNING]
>
> `outreach_count` and `last_outreach_at` come from a nightly rebuild, so they lag the act by
> one night. Do not treat the counter in this response as confirmation.
>
> The act itself is readable straight away on `GET /v1/people/{person_id}` under `outreach`.

## Troubleshoot

The `Idempotency-Key` is required. Derive it from something stable in your tool, such as the
sequencer's own message id.

A retry after a timeout then logs one act instead of two. The same key with a different body
is a 409.

> [accordion] Settling a whole sequence at once
>
> `PATCH /v1/people` takes a list of ids, so you can settle many stages in one call.
>
> `disqualified` beats every other stage, so that person never reads as undecided again.

## Next

The same two acts are the `log_outreach` and `update_person` MCP tools. An assistant can do
this while you talk to it. See [Tools](https://docs.ziplined.io/mcp/tools.md).


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