Agent Context Sources
The Context tab of an agent decides which customer data that agent may read and which contact fields it may fill in. Typical setups:
- Logged-in support agent: contact profile, contact token data, one context endpoint for the account status, and the last few earlier conversations. Paying customers get answers about their own plan without being asked who they are.
- Shop agent on WhatsApp: name and language, a context endpoint that returns open orders for the verified phone number, and the tag "VIP" so the agent can adjust tone.
- Lead qualification agent: almost no read access, but permission to fill in "Contact type" and "Company size" while they are empty. Your team gets qualified contacts without reading every chat.
For the concepts (verified versus unverified, which mechanism to use when), start with Customer context. This page is the reference.
Where the configuration lives
The configuration is stored in the agent's settings.context.
| Action | How |
|---|---|
| Read | GET /automation/agents/{agent_id} returns the effective configuration in the top-level context field (read-only; it shows the defaults when nothing is stored). |
| Change the live agent | PATCH /automation/agents/{agent_id} with settings.context (scope automation:update). |
| Change via a draft | PUT /automation/agents/{agent_id}/draft with document.settings.context, then publish. See Drafts & publishing. |
On PATCH:
settingswithout acontextkey keeps the stored context."context": nullremoves it, so the agent falls back to the defaults below."settings": nulldoes the same.- A new or changed value is validated and stored normalized. An unchanged value is not validated again, so archiving a custom field later never blocks unrelated edits.
Example
{
"settings": {
"context": {
"providers": [
{"type": "contact_profile", "enabled": true,
"config": {"standard_fields": ["name", "language", "company"], "custom_field_keys": null}},
{"type": "identity_token_grant", "enabled": true, "config": {}},
{"type": "tags_subscriptions", "enabled": true,
"config": {"include_tags": true, "include_subscriptions": false, "tag_allowlist": ["VIP", "Wholesale"]}},
{"type": "http", "enabled": true,
"config": {"endpoint_id": "CONTEXT_ENDPOINT_ID", "timeout_ms": 1200, "ttl_seconds": 120}},
{"type": "prior_conversations", "enabled": true, "config": {"max": 3, "max_chars": 300}}
],
"writable_custom_field_keys": ["contact_type"]
}
}
}
context accepts exactly two keys: providers (a list, at most 10 entries) and writable_custom_field_keys. Each provider entry has type, enabled (boolean, default true) and config. Every type except http may appear once.
Defaults
An agent without a stored context uses this configuration:
{
"providers": [
{"type": "contact_profile", "enabled": true,
"config": {"standard_fields": ["name", "language"], "custom_field_keys": null}},
{"type": "identity_token_grant", "enabled": true, "config": {}}
],
"writable_custom_field_keys": null
}
What this means in practice:
| Source | Default |
|---|---|
| Name and language | On |
| Contact token data | On (only has an effect when your widget passes a contact token) |
| Custom fields (read) | Every field whose AI access allows reading. New fields start with AI access none, so no custom field is shared until you change a field's AI access. |
| Custom fields (write) | Every field whose AI access is read_write or fill_if_empty. With all fields on none, the agent has no write tool. |
| Tags and subscriptions | Off |
| Context endpoints | Off |
| Earlier conversations | Off |
Field AI access is set once per field and applies to all agents. The lists on the agent can only narrow it.
Sources
Contact profile
type: "contact_profile"
| Config key | Description |
|---|---|
standard_fields | Which standard fields the agent sees. Allowed: name, first_name, last_name, email, phone, language (preferred language), languages (shown as "Spoken languages"), birthday, country, timezone, company, created_at (shown as "Customer since"), channel, social_profiles. country and timezone are legacy: still accepted and shown to the agent, but no longer offered in the app. |
custom_field_keys | null = every active custom field whose AI access allows reading (up to 50). A list = only these keys, and only if their AI access allows reading (at most 50). [] = no custom fields. |
email and phone are the contact's primary method (or the oldest one). languages is the contact's list of spoken languages (for example de, en), birthday is an ISO date (YYYY-MM-DD). social_profiles is one line with every social profile saved on the contact, primary first, duplicates removed, at most 10, for example LinkedIn: https://www.linkedin.com/in/anna; Website: https://anna.example; Instagram: @anna. A profile of type "Other" is labelled with its display name. Messaging IDs (Messenger, Instagram, WhatsApp) are not social profiles. country, timezone and company are read from a custom field with the same key, if you have one. Address details live in custom fields of type location, so list those in custom_field_keys. Standard fields are read-only context: they never let the agent write anything. Each custom field reaches the agent with its name, its key, its AI hint and its option descriptions, so a good hint helps the agent understand the value.
In the app: Contact profile, with All fields their AI access allows or Only selected fields.
Contact token data
type: "identity_token_grant", config: {}
The context and saved values of an active contact token for this live chat. They reach the agent as verified, labelled as confirmed by your login. Without an active token (none passed, expired or revoked) this source adds nothing.
Values a token saved to the contact (save, save_if_empty) are stored contact data. They also reach the agent through the contact profile, as verified record values whenever the conversation is tied to the contact.
Tags and subscriptions
type: "tags_subscriptions"
| Config key | Default | Description |
|---|---|---|
include_tags | true | Share tags from tag_allowlist. |
include_subscriptions | true | Share the contact's list subscriptions: list name, channel and status (subscribed, pending, unsubscribed). |
tag_allowlist | null | Tag names the agent may see. At most 50 names, each at most 100 characters. Tags are only shared when this list is not empty. |
Up to 30 tags and 20 subscriptions are shared, by name only. Tags are always unverified for the agent, because flows and customers can trigger them. Subscriptions follow the record rules.
Context endpoints
type: "http", one entry per endpoint, at most 3 per agent.
| Config key | Description |
|---|---|
endpoint_id | Required. The id of a context endpoint in this workspace. |
timeout_ms | Optional, 200 to 3000. Can only lower the endpoint's own timeout. |
ttl_seconds | Optional, 0 to 3600. Can only lower the endpoint's own cache time. |
The endpoint is called only when the conversation has at least one verified identifier, and never on email conversations (an email sender can be forged). Mapped values reach the agent as verified, labelled as coming from your system. The same endpoint can't be listed twice.
Earlier conversations
type: "prior_conversations"
| Config key | Default | Description |
|---|---|---|
max | 0 (off) | How many earlier conversations to load, 0 to 10. The app marks 5 as the recommended maximum. |
max_chars | 300 | Characters per summary, 50 to 300. |
The agent gets the AI summary (or, if there is none, the resolution summary) of the contact's most recent closed or resolved conversations, newest first, excluding the current one. They are shown to the agent in their own section with the note that they may be outdated, so the agent never treats them as current account facts, prices or promises.
Earlier conversations are only loaded when the conversation is tied to the contact: a messaging channel such as WhatsApp or SMS, or a live chat with a contact token, signed identity or approved verification. Anonymous live chat visitors and email conversations never get them.
Cost: the loaded summaries are extra text the agent reads, so they add a little to the AI credits of its replies. They are loaded with the agent's first reply and reused for the rest of the conversation. If no earlier conversation has a summary, nothing is added. These credits count toward max_credits_per_conversation as part of each turn's credits. Test conversations are never charged. See Billing, errors & limits.
How the agent receives the data
On every reply, SendSeven collects the enabled sources for the conversation's contact and passes them to the agent in two groups:
- Verified: values from your server (contact token, context endpoints) and record values when the conversation is tied to the contact.
- Unverified: values the visitor provided, values set by AI, tags, legacy values, and record values in an anonymous live chat.
Each value carries a short origin label, for example "confirmed by the business's login", "from the business's system", "claimed by the customer" or "set by AI earlier". The agent uses unverified values only to personalise. It never grants access, discounts, account changes or account disclosures because of them. Without a verified group it treats the person as unknown.
- All sources are collected in parallel within a fixed time budget (about 1.5 seconds, about 3.3 seconds when a context endpoint is enabled). A source that is too slow or fails is skipped. The reply is never blocked by it.
- The profile is limited to about 4000 characters. When it is longer, unverified values are dropped first.
- Customer data is always passed as data, never as instructions. Text such as "ignore your rules" inside a field value has no effect.
- An agent only ever sees the contact of the conversation it is answering. SendSeven resolves the contact from the conversation. Nothing the customer or the model says can point the agent at another contact.
- The test console runs without a contact, so the profile is empty there.
Your team sees the same data, with the same Verified / Unverified labels, in the Customer context section of the conversation's contact panel, and via GET /api/v1/conversations/{conversation_id}/contact-context (see Context endpoints).
Letting the agent update contact fields
When at least one custom field is writable for the agent, the agent gets the tool update_contact_fields. It saves details the customer clearly stated about themselves in the conversation, for example a company size or a customer type.
writable_custom_field_keys controls which fields:
| Value | Fields the agent may write |
|---|---|
null (default) | Every active field whose AI access is read_write or fill_if_empty (up to 20) |
| A list (at most 20 keys) | Only these keys, and only if their AI access allows writing |
[] | None. The agent has no write tool. |
Location and collection fields can't be written by AI.
How writing works:
- The agent calls the tool with
{"fields": {"<key>": <value>}}, at most once per reply, with all fields together. - Every value is validated against the field definition (type, select options, validation rules). Invalid values are not saved.
- The field's AI access decides overwriting:
fill_if_emptyonly writes into an empty field,read_writemay replace any existing value. - The value is always written to the conversation's own contact.
- Saved values are marked set by AI. They are unverified for every agent, including the one that wrote them.
- A reply that saves values sends one
contact.updatedwebhook. Itsdatacarries"origin": "ai","changed_by": "ai_agent"and"changed_fields"(for example["custom.contact_type"]) next todata.contact. Flows triggered by contact updates run as usual. - In the test console and in test conversations, nothing is saved. The tool reports what it would have written.
The agent is told to save only what the customer said about themselves, never to guess or derive values, and not to mention saving unless it matters to the customer.
Errors
Invalid context settings are rejected with 422 and a code:
| Code | Cause |
|---|---|
context.invalid | Wrong shape, unknown key, value out of range, unknown standard field, or a type listed twice |
context.unknown_provider | Unknown type. The response lists the allowed types. |
context.too_many_providers | More than 10 providers, or more than 3 http providers |
context.unknown_endpoint | http provider without endpoint_id, or the endpoint does not exist in this workspace |
context.unknown_custom_field | A listed custom field key does not exist, is inactive, or (for writing) is a location or collection field. The response lists the keys. |
context.field_not_readable | A key in custom_field_keys has AI access none |
context.field_not_writable | A key in writable_custom_field_keys has AI access none or read |
{"code": "context.field_not_writable", "message": "AI access of these custom field(s) does not allow writing (set it to 'read_write' or 'fill_if_empty'): contact_type", "keys": ["contact_type"]}
Related
- Customer context: concepts and which mechanism to use when
- Context endpoints
- Custom fields: AI access
- Live Chat Contact Tokens
- How we use it: SendSeven's own support agent