---
title: "Publicly re-fetch a list of contacts"
method: POST
path: "/public/enrich"
tags: ["public"]
---

# Publicly re-fetch a list of contacts

`POST /public/enrich`

Does not return email or phone. Do not call this when the user asked for email or phone. Re-fetch public profile data for a specific list of your own contacts (contact ids from a list already shown, not raw profile URLs): the way to visit many people at once instead of one visit_profile per person. Public and cookieless: no connected account is touched. When the target is ambiguous and the pool is large, ask which people rather than defaulting to everyone. qualify:true grades against the ICP and spends AI credits, only when the user asked to be graded; plain visit or enrich is data only.

## Request body

- object
  - `contactIds` string[], required — Which of your own contacts to (re)fetch. An explicit list — not a filter — so nothing is enriched by accident.
  - `campaignId` string — Link newly-touched contacts to this campaign (slug or id).
  - `qualify` boolean — Also grade each enriched contact against the campaign's bound ICP (requires campaignId — the ICP is campaign-scoped). Off by default: enrichment is the common case, grading is something to ask for explicitly, since it spends AI credits.

## Response `200`

Batch result (or a stillRunning partial for a batch that outlived this call's wait)

- object
  - `source` 'public', required
  - `batchId` string, required — Pass this to GET the same endpoint if stillRunning is set, to check on it later.
  - `total` integer, required — How many contacts were actually queued (already-fresh and unreachable ones are skipped up front).
  - `visited` integer, required — Successfully re-fetched.
  - `failed` integer, required — Could not be reached (deleted, restricted, or no public page).
  - `skipped` integer, required — Deferred, not attempted this call.
  - `qualified` integer — Graded against the ICP, when qualify was requested.
  - `status` 'processing' | 'completed' | 'partial' | 'failed', required
  - `failureReason` string
  - `stillRunning` boolean — The batch outlived this call's wait and is still working — everything above is real and already landed, not a failure. Check back with GET ?batchId=.

## 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)
