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

# Relay integration

> Your backend talks to Patchwork with a workspace API key. Use this for Slack, WhatsApp, email, or any channel you already own.

Relay is for channels Patchwork does not render. Your backend is the caller. The user never talks to Patchwork directly.

```
Slack / WhatsApp / email / your API
        ↓
Your backend  →  Patchwork  (Bearer sk_… + Patchwork-Subject)
```

Same agents, same traces, same patches as [direct](/guides/loom-direct). Different credential.

## Authenticate

Use a workspace secret key. Identify the end user with a header — do not put a user id in the URL.

```bash theme={null}
curl https://api.usepatchwork.co/v1/loom/threads \
  -H "Authorization: Bearer sk_live_..." \
  -H "Patchwork-Subject: slack:U0APP" \
  -H "Patchwork-Connection: <connection-uuid>" \
  -H "Content-Type: application/json" \
  -d '{"agent": "agent_..."}'
```

<ParamField header="Authorization" type="string" required>
  `Bearer` plus a workspace secret (`sk_…`). Leftover `sk_test_` secrets still authenticate and spend the same workspace balance.
</ParamField>

<ParamField header="Patchwork-Subject" type="string" required>
  Stable id for the person in this channel. Prefix by channel so Slack and WhatsApp users do not collide: `slack:U0APP`, `wa:15551234567`.
</ParamField>

<ParamField header="Patchwork-Connection" type="string">
  Connection id or name. Sets which host tools this call uses. Required when the agent has unpinned customer tools.
</ParamField>

You can also pass `subject_ref` in the create-thread body. The header wins if both are present.

<Warning>
  The workspace key is a secret. It lives on your server. If it leaks, rotate it in the dashboard.
</Warning>

## Post a message

```bash theme={null}
curl https://api.usepatchwork.co/v1/loom/threads/<thread-uuid>/messages \
  -H "Authorization: Bearer sk_live_..." \
  -H "Patchwork-Subject: slack:U0APP" \
  -H "Content-Type: application/json" \
  -d '{"content": "What is Jane'\''s account number?"}'
```

`202` with a `run_id`. Your backend waits for the run — poll or subscribe — then writes the assistant's reply back to Slack (or WhatsApp, or email).

## When the agent asks a question

The run enters `awaiting_input`. Collect the user's next message in your channel, then `POST` it to the same thread. The run resumes.

## When the agent calls a tool you host

The run enters `awaiting_outcome`. Confirm the side effect:

```bash theme={null}
curl https://api.usepatchwork.co/v1/loom/runs/<run-uuid>/outcome \
  -H "Authorization: Bearer sk_live_..." \
  -H "Patchwork-Subject: slack:U0APP" \
  -H "Content-Type: application/json" \
  -d '{
    "tool_call_id": "<tool-call-uuid>",
    "state": "occurred"
  }'
```

`state` is `occurred` or `failed`. The agent continues from there.

Verifying the tool call itself is the same as [direct](/guides/loom-direct#5-verify-tool-calls-you-host): `Patchwork-Signature` over your request secret, plus the subject token.

## Subject tokens (mint URL)

When a run needs a subject token to call your tools, Patchwork POSTs to your workspace `mint_url`. The request is presenter-signed.

```
POST <your mint_url>
Patchwork-Signature: t=…,v1=…
{ "subject": "slack:U0APP" }
```

Verify the signature, then return a short-lived token for that user:

```json theme={null}
{ "token": "<minted token>", "expires_in": 300 }
```

Your backend never forwards a token in the Loom request body. The API key names the workspace; `Patchwork-Subject` names the person.

## Thread identity

Threads are scoped to the subject. The same Slack user talking to the same agent reuses their thread. A different channel prefix is a different person.

Do not put emails or phone numbers in `Patchwork-Subject` if you can avoid it. Use the channel's stable user id.
