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

# Delete a contact

> Delete a contact. It disappears from the list and from `GET /v1/contacts/{id}`, and every endpoint that takes its `id` (including `POST /v1/messages` with `contact_id`) returns `404 not_found`. Deleting it again also returns `404`.

What stays: its messages and conversations, which `GET /v1/messages` still lists under the old `contact_id`; messages already accepted for it and still waiting, which still go out (cancel them in the dashboard to stop them); and its opt-out, which belongs to the number.

Upserting the same number, sending to it with `to`, or an inbound message from it creates a **new** contact with a new `id`. Names, tags and a block are not carried over; an opt-out is.

### Delete a contact

**Method:** `DELETE` | **Endpoint:** `/v1/contacts/{contact_id}`

**Description:** Remove a contact from your account. It disappears from [List contacts](https://docs.ibubbl.com/api-reference/contacts/list.md) and from every endpoint that takes its ID. Its message history stays.

**Authentication:** API key in the `Authorization` header: `Authorization: Bearer ib_pk_<64 hex>`. Create keys in the dashboard under **Settings → API access**.

#### Request Body

None. The path parameter `contact_id` is the contact's ID (a UUID).

#### What deleting does

* **The ID stops working.** [Retrieve](https://docs.ibubbl.com/api-reference/contacts/retrieve.md), [Update](https://docs.ibubbl.com/api-reference/contacts/update.md), the tag, opt-out and block endpoints, and [Send a message](https://docs.ibubbl.com/api-reference/messages/send.md) with this `contact_id` all return `404 not_found`. Deleting it again also returns `404`.
* **History stays.** Its messages and conversations are kept, and [List messages](https://docs.ibubbl.com/api-reference/messages/list.md) still returns them with the old `contact_id`.
* **Waiting messages still go out.** A message already accepted for the contact and still waiting (held for [sending hours](https://docs.ibubbl.com/concepts/working-hours.md), or queued) is not cancelled. Cancel it in the dashboard first if it shouldn't be sent.
* **The number can come back as a new contact.** [Creating or updating a contact](https://docs.ibubbl.com/api-reference/contacts/upsert.md) with the same number, sending to it with `to`, or an inbound message from it creates a **new** contact with a new `id`. Names, tags and a [block](https://docs.ibubbl.com/api-reference/contacts/block.md) are not carried over.
* **An opt-out is never lost.** An [opt-out](https://docs.ibubbl.com/api-reference/contacts/opt-out.md) belongs to the phone number, not the contact. A new contact for an opted-out number starts with `opted_out: true`, and sends to it return `422 contact_opted_out`. Deleting a contact is not a way to message someone who opted out.

No webhook fires for a deletion.

```bash cURL theme={null}
curl -X DELETE https://api.ibubbl.com/v1/contacts/c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f \
  -H "Authorization: Bearer $IBUBBL_API_KEY"
```

```typescript TypeScript theme={null}
const contactId = "c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f";

const res = await fetch(`https://api.ibubbl.com/v1/contacts/${contactId}`, {
  method: "DELETE",
  headers: { Authorization: `Bearer ${process.env.IBUBBL_API_KEY}` },
  signal: AbortSignal.timeout(10_000),
});

// 204 has no body; only an error does.
if (!res.ok) {
  const data = await res.json();
  throw new Error(`${res.status} ${data.detail?.error}`);
}
console.log("deleted:", res.status);
```

```python Python theme={null}
import os

import requests

API_KEY = os.environ["IBUBBL_API_KEY"]

contact_id = "c8a1f4e2-3b9d-4f7c-a8e5-1d2c3b4a5e6f"

res = requests.delete(
    f"https://api.ibubbl.com/v1/contacts/{contact_id}",
    headers={"Authorization": f"Bearer {API_KEY}"},
    timeout=10,
)
# 204 has no body; only an error does.
if not res.ok:
    data = res.json()
    raise RuntimeError(f"{res.status_code} {data['detail']['error']}")
print("deleted:", res.status_code)
```

```text 204 No Content theme={null}
(empty body)
```

```json 404 Not Found theme={null}
{
  "detail": {
    "error": "not_found",
    "message": "Contact not found"
  }
}
```

#### Responses

**204 No Content**

The contact is deleted. The response has no body.

**401 Unauthorized**

```json theme={null}
{
  "detail": {
    "error": "unauthorized",
    "message": "Invalid or revoked API key"
  }
}
```

Other `message` values: `Authorization Bearer token required`, `API key required (use Authorization: Bearer ib_pk_…)`, `Invalid API key format`, `Customer account not found`.

**403 Forbidden**

```json theme={null}
{
  "detail": {
    "error": "forbidden",
    "message": "Account is suspended"
  }
}
```

Your iBubbl account is suspended or cancelled (`message` is then `Account is cancelled`). Every API-key endpoint returns this.

**404 Not Found**

```json theme={null}
{
  "detail": {
    "error": "not_found",
    "message": "Contact not found"
  }
}
```

Also returned for a malformed ID, a contact that is already deleted, and a contact that belongs to another account. If a retried delete gets `404`, the first attempt already deleted it.


## OpenAPI

````yaml DELETE /v1/contacts/{contact_id}
openapi: 3.1.0
info:
  title: iBubbl API
  version: v1
  description: >-
    The iBubbl REST API. Send iMessages, manage contacts, and subscribe to
    webhook events from your backend.


    Authenticate every request with a Bearer API key (`ib_pk_<hex>`) — generate
    one from your dashboard's API Access settings. See the
    [Authentication](/authentication) guide.
servers:
  - url: https://api.ibubbl.com
security:
  - BearerAuth: []
tags:
  - name: Messages
  - name: Contacts
  - name: Conversations
  - name: Webhooks
  - name: Inbound Events
paths:
  /v1/contacts/{contact_id}:
    delete:
      tags:
        - Contacts
      summary: Delete a contact
      description: >-
        Delete a contact. It disappears from the list and from `GET
        /v1/contacts/{id}`, and every endpoint that takes its `id` (including
        `POST /v1/messages` with `contact_id`) returns `404 not_found`. Deleting
        it again also returns `404`.


        What stays: its messages and conversations, which `GET /v1/messages`
        still lists under the old `contact_id`; messages already accepted for it
        and still waiting, which still go out (cancel them in the dashboard to
        stop them); and its opt-out, which belongs to the number.


        Upserting the same number, sending to it with `to`, or an inbound
        message from it creates a **new** contact with a new `id`. Names, tags
        and a block are not carried over; an opt-out is.
      operationId: v1_delete_contact_v1_contacts__contact_id__delete
      parameters:
        - name: contact_id
          in: path
          required: true
          schema:
            type: string
            title: Contact Id
      responses:
        '204':
          description: Deleted.
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '403':
          description: '`forbidden`: your iBubbl account is suspended or cancelled.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
        '404':
          description: Contact not found.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
components:
  schemas:
    ApiError:
      properties:
        detail:
          allOf:
            - $ref: '#/components/schemas/ApiErrorDetail'
          description: >-
            Error envelope. Every `/v1` error response wraps a stable `error`
            code and a human-readable `message` in `detail`.
      type: object
      required:
        - detail
      title: ApiError
      example:
        detail:
          error: validation_error
          message: >-
            Exactly one of contact_id, to, chat_guid, or participant_phones is
            required
    ApiErrorDetail:
      properties:
        error:
          type: string
          title: Error
          description: >-
            Stable machine-readable error code. Use this for branching logic in
            your integration; the human-readable `message` is subject to change.
            See the Error Reference for the catalog.
          examples:
            - validation_error
        message:
          type: string
          title: Message
          description: Human-readable description of what went wrong.
          examples:
            - >-
              Exactly one of contact_id, to, chat_guid, or participant_phones is
              required
      type: object
      required:
        - error
        - message
      title: ApiErrorDetail
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: ib_pk_<64 hex>
      description: >-
        Bearer API key. Format: `Authorization: Bearer ib_pk_<64 hex>` (70
        characters). Generate keys from Dashboard → Settings → API Access.

````

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