---
title: "Delete contacts"
method: POST
path: "/v1/sites/{site_id}/contacts/delete"
tags: ["Contacts"]
---

# Delete contacts

`POST /v1/sites/{site_id}/contacts/delete`

## Request

- Base URL: `https://api.getsitecontrol.com`
- URL: `https://api.getsitecontrol.com/v1/sites/{site_id}/contacts/delete`
- Auth: HTTP bearer

Deletes the named contacts, by `ids` from `upsert_contact` or `list_contacts`,
or by `emails` as the other system has them, compared without case; one of
the two, up to 100 per call.

The answer reports every one in the order given: `updated` with
`changed: ["is_deleted"]` when deleted, `unchanged` when it was deleted
before, `failed` with `contact_not_found` when the site has no such contact.
A deleted contact disappears from `list_contacts` and `get_contact` gives
404. A widget submission, an import, `upsert_contact`, `upsert_contacts` or
`run_automation` with the same e-mail restores it with its old data, and it
shows up in `updated_since` again.

## Path parameters

- `site_id` integer, required

## Headers

- `Idempotency-Key` string: Makes a retry of a POST safe: a repeat with the same key, body and GSC-Version returns the stored response with `Idempotency-Replayed: true` instead of running again. The key protects against repeated execution while the key store works. Saving the change and storing the response under the key are not atomic: if the process or the key store fails between them, the change is kept, the key is released after 15 minutes and a retry runs the request again. After a timeout or a 5xx, read the resource to check the result before retrying. 5xx and 429 responses and responses over 256 KB are not stored, so a repeat runs the request again. A key is kept for 24 hours. The same key with another body or version is 422; a repeat while the first request runs is 409.

## Request body

- ContactsDelete: Exactly one of `ids` and `emails`.
  - `ids` integer[]: Contact ids from `upsert_contact` or `list_contacts`, up to 100, each once
  - `emails` string[]: Addresses as the other system has them, compared without case, up to 100, each once

## Response `200`

Successful Response

- ContactsBatch
  - `items` ContactBatchItem[], required: Every item, in the order given
    - `index` integer, required: Position of the item in the request, from 0
    - `id` integer, nullable: The contact; a failed item of `update_contacts` or `delete_contacts` keeps the id it was given. Null when no contact was found
    - `result` 'created' | 'updated' | 'restored' | 'unchanged' | 'failed', required: created: a new contact, by `upsert_contacts` or `upsert_contact`. updated: something was written, `changed` names it; in `delete_contacts` the contact was deleted. restored: the address belonged to a deleted contact, which is back with its old data and the item applied over it. unchanged: nothing to change, nothing written; in `delete_contacts` the contact was deleted before. failed: nothing of this item was written, see `reason`.
    - `changed` string[], required: Names of the fields whose stored value changed, from is_deleted, email, status, first_name, last_name, phone, country, timezone, language, fields, tags; empty when none did. A new contact names `email`, `status` and every field it was given; a restored one starts with `is_deleted`
    - `reason` 'contact_not_found' | 'contact_email_taken' | 'contact_tag_invalid' | 'contact_field_invalid' | 'contact_unreadable' | 'contact_status_transition' | 'contact_value_invalid': contact_not_found: no contact of the site has this id or e-mail; in `update_contacts` also a deleted one. contact_email_taken: the e-mail belongs to another contact of the site, live or deleted, or another request took it at the same moment. contact_tag_invalid: a tag name is empty or too long, see `detail`. contact_field_invalid: an unknown field, a field of the other type or a value of another type, see `detail`. contact_unreadable: the stored contact cannot be read; it can only be deleted. contact_status_transition: the status change is not allowed, the other fields were written; `detail` says why. contact_value_invalid: an e-mail, country, phone, time zone or language that cannot be read, `detail` names it.
    - `detail` string, nullable
    - `contact` ContactRef
      - `id` integer, required
      - `email` string, required: As stored
      - `status` 'subscribed' | 'unsubscribed' | 'bounced', required: After the call
  - `created` integer, required
  - `updated` integer, required
  - `restored` integer, required
  - `unchanged` integer, required
  - `failed` integer, required

## Other responses

- `400`: Unsupported GSC-Version
- `401`: Missing or invalid API key or access token
- `403`: `forbidden`: the key or token lacks `contacts.edit`
- `404`: Not found
- `409`: `idempotency_in_progress`: a repeat of a request still running
- `413`: Request body too large
- `422`: `validation_failed`: the body is invalid: both `ids` and `emails` or neither, more than 100, a key repeated. `idempotency_key_reused`: the `Idempotency-Key` was sent before with another body or version
- `429`: Rate limited
- `503`: `temporarily_unavailable`: the request took too long, or limits or idempotency keys cannot be enforced; retry later

---

[API](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api.md) - [All operations](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/getsitecontrol/apis/getsitecontrol-public-api/revisions/084fcad80e75?raw)
