---
title: "Bulk update contacts"
method: PATCH
path: "/contacts/bulk"
tags: ["contacts"]
---

# Bulk update contacts

`PATCH /contacts/bulk`

Update multiple contacts at once in one call instead of looping per contact. Same fields as single update, max 500 contacts per request. To discard named or picked people, set update.lifecycleStage to "rejected" (optionally with update.qualificationNotes explaining why) — discarding is reversible, it never deletes the contact, and the row still shows up in the list marked as not a fit. To undo a named not-a-fit mark, set update.lifecycleStage to "contact". A described rule is not a write: peek then propose with filter_contacts intent:"discard" or exceptContactIds. lifecycleStage, hotScore, and qualificationNotes are per-campaign fields: pass campaignId to scope the write to one campaign, or the request is rejected.

## Query parameters

- `campaignId` string — Scopes a per-campaign field write (lifecycleStage, hotScore, qualificationNotes, leadBrief) to this one campaign. Required whenever the update includes any of those fields.

## Request body

- object
  - `contactIds` string[], required — Contact IDs to update
  - `update` object, required — Fields to update on all matching contacts
    - `lifecycleStage` 'contact' | 'lead' | 'qualified' | 'rejected'
    - `hotScore` integer
    - `qualificationNotes` string
    - `leadBrief` string
    - `notes` string
    - `outreachStatus` 'none' | 'connection_sent' | 'connected' | 'dm_sent' | 'followed_up' | 'replied' | 'in_conversation' | 'meeting_booked' | 'not_interested'
    - `doNotContact` boolean
    - `tags` union — Tag operations: { add, remove } or { set }
      - object
        - `add` string[], required
        - `remove` string[]
      - object
        - `add` string[]
        - `remove` string[], required
      - object
        - `set` string[], required

## Response `200`

Bulk update results

- object
  - `success` true, required
  - `updated` integer, required
  - `skipped` integer, required
  - `errors` string[], required
  - `creditsUsed` integer, required — Credits consumed by this call. 0 for free endpoints, cached results, duplicates, and for every query that does not touch LinkedIn.
  - `retryAfter` integer, required — Seconds to wait before another call of the same type. 0 means no wait is needed.
  - `_meta` object — Credit balance carried on every response so a caller never has to ask for it separately. Absent when the caller has no connected account.
    - `credits` object, required
      - `current` number, required — Credits spent this period.
      - `limit` number, nullable, required — Period allowance, or null when unlimited.
      - `remaining` number, nullable, required — Allowance left, or null when unlimited.
      - `percentage` number, required — Share of the allowance spent, 0 to 100.
      - `isUnlimited` boolean, required
      - `accountPlan` string, required — The credential's plan.

## Other responses

- `400` — The server cannot or will not process the request due to something that is perceived to be a client error.
- `401` — Although HTTP specifies "unauthorized", this response means "unauthenticated". Authenticate to continue. NOTE: 401 is also returned with code "linkedin_not_connected" when the caller IS authenticated but has no connected LinkedIn account — connect LinkedIn (not re-authenticate) to continue.
- `403` — The client does not have access rights to the content.
- `404` — The server cannot find the requested resource.
- `409` — The request conflicts with the current state of the server.
- `410` — The requested content has been permanently deleted from the server.
- `422` — The request was well-formed but was unable to be followed due to semantic errors.
- `429` — Rate limit exceeded. Read error.retryAfter for the wait time in seconds.
- `500` — The server encountered a situation it does not know how to handle.
- `502` — LinkedIn returned a server error or the proxy connection failed. Retry after a few seconds.
- `503` — Proxy capacity temporarily exceeded. Retry after a few seconds.

---

[API](https://skmtc.net/berea/apis/bereach-api.md) · [All operations](https://skmtc.net/berea/apis/bereach-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/berea/bereach-api/revisions/9217eedacbb8/schema)
