---
title: "Unlink Channel Association"
method: DELETE
path: "/channel_associations/{channel}"
tags: ["channels"]
---

# Unlink Channel Association

`DELETE /channel_associations/{channel}`

Revoke the caller's active link on ``channel`` (#2282).

Backs the app's disconnect screen: 204 when this call revoked the link,
404 when there was nothing to unlink (never linked, or already unlinked),
so a repeat DELETE converges on the same unlinked state. The row is
revoked rather than deleted — the partial unique indexes cover live rows
only, so re-linking later works like a first link, while the account
merge's conflict check still sees the history. A replay of the old
confirmed deep-link token 409s via the revoked-link branch in
:func:`confirm_channel_association`.

The user's live ``#IMP`` codes die first: with the row revoked, nothing
blocks a re-link, so a consumed code re-sent from the same phone within
its TTL would silently undo the disconnect via the code handler's
self-heal replay (the PR #2283 review finding). Codes are deleted before
the row flips — every step is idempotent, so a failure between them
leaves a retryable DELETE, never a revoked row with a live credential.

## Path parameters

- `channel` 'whatsapp' | 'heylo', required — Messaging channel discriminator on the generic channel-associations core. One value per integrated bridge. Adding a channel = new enum value + new :class:`cheshire.channels.bridge.BridgeClient` impl + new thin webhook route. No new backend tables — every channel reuses ``channel_associations`` / ``channel_association_requests``.

## Query parameters

- `user_id` string, nullable

## Response `204`

Successful Response

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.dev/imperfect/apis/imperfect-api.md) · [All operations](https://skmtc.dev/imperfect/apis/imperfect-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/imperfect/imperfect-api/revisions/55d56c4beab4/schema)
