---
title: "Create or update a context entry"
method: PUT
path: "/context"
tags: ["context"]
---

# Create or update a context entry

`PUT /context`

Save context (ICP, Messaging Playbook, user profile). POST is accepted as an alias for PUT on this path. Each write REPLACES the full content — merge new info with the existing entry first. Pass real newline characters, not escaped \n strings. If LITERAL_NEWLINE_IN_CONTEXT error, retry the same turn with real newlines. Each type takes exactly one scope shape and the server rejects the others, so read the scope field before writing. Save immediately when the user says save/remember; identity facts → type:"user-profile".

## Request body

- object
  - `type` string, required — Context type — closed set (server rejects anything else with 400 INVALID_CONTEXT_TYPE). Pick the canonical slot that matches the content; free-form "custom:*" slugs are rejected. Per-slot contracts: • "user-profile" — Who the operator is — name, role, company, background. Saved once globally; personalises every message. • "offering" — What the operator sells — products, services, agencies, anything they deliver to clients. Saved once globally. • "icp" — Who this chat targets — titles, industries, seniority, geography, company size. Guides discovery and qualification. • "playbook" — How outreach is WRITTEN for this chat — strategy, angle, value-prop, voice/tone, and the first DM. Follow-up sequences are not part of this chat; use the Claude connector for multi-step waits.
  - `content` string — Markdown content.
  - `scope` string — One shape per type; the "user" default is rejected for icp and playbook. user-profile, offering, operator-context → "user". icp → "user:icp:<slug>", slug being a short kebab-case name for that audience. playbook → "campaign:<id>", a real campaign id.
  - `label` string — Display label
  - `postTicketId` string — Internal ticket id from a prior tool result. Omit unless a result supplied it.

## Response `200`

Context saved

- object
  - `success` true, required
  - `entry` object, required
    - `id` string, required — Unique entry ID
    - `type` string, required
    - `label` string, nullable, required
    - `content` string, required — Full content (present when fullContent=true) or a 200-char preview
    - `contentPreview` string — First 200 chars of content — present when fullContent is not requested
    - `scope` string, required
    - `updatedAt` 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/32391e7c6322/schema)
