Pass Context to Tool Parameters
Declare accepted conversation context on a service, supply values at creation, and bind them to tool parameters in the active Context Graph state.
Use start-time conversation context to pass application values to a tool without asking the model to supply those parameters. There are three configuration points: the service declares accepted keys, the conversation create request supplies values, and the Context Graph's state-to-tool binding selects which parameters receive them.
This Platform API task extends Build and Prove for an already configured service and tool. The map supplies inputs for one conversation; declaring it does not update world-model facts, create memory, or grant tool access.
Choose the Right Context Feature
Supply a typed application value to a tool for one conversation
The start-time context map and state binding in this guide
Supply a verified value to a tool after a voice call has started
Set Context on a Live Voice Call, from a trusted backend
Add free-text guidance to a turn or an opening WebSocket exchange
The separate text fields in Conversations or Sessions
Read or retain facts about a person across conversations
The World Model and Functional Memory, under their own write and retrieval contracts
Supply verified identity for an integration's authentication
External User Subject-Key Binding, rather than caller-supplied application context
Add stored user information through the Classic API
Inspect a service's neutral configuration and tool descriptors
Harness Context, a read-only discovery operation
Before You Start
Use a test workspace with permission to update its service, publish a Context Graph version, and create and inspect conversations. You need a configured read-only test tool whose input and result you can inspect. The example assumes that tool accepts two string parameters, region and query, and can report which region it actually received.
Use the regional API base and credentials assigned to that workspace; see Choose Credentials. Save the current service schema and selected graph version before changing them. This guide does not provision a service, integration, or channel.
Platform SDK 0.109.1 and later type accepted_context on services and the context map on conversation create and outbound call requests. The tool-call spec types include context_bindings but not context_binding_aliases as of 0.110.0; use the HTTP contracts embedded below when you need aliases.
The synthetic test below uses a blocking tool with result_persistence: "accumulate" so its result can be inspected in history. If your workflow requires ephemeral results, keep that policy and verify the received input at the test tool instead; see Tool Result Persistence.
How the Values Reach the Tool
1. Declare the Schema on the Service
Set accepted_context in the top-level request body when creating or updating the service:
Create a service with its schema
POST /v1/{workspace_id}/services
Read the current schema
GET /v1/{workspace_id}/services/{service_id}
Replace an existing service's schema
PUT /v1/{workspace_id}/services/{service_id}
Service updates use PUT, not PATCH. For the complete contracts, see Services.
For a dedicated test service, this is a complete update body:
The Console service detail page displays declared context keys, types, required status, and descriptions read-only. Use the service API to change accepted_context. The text Playground presents these keys as input fields when you start a test session.
Read the service back and confirm the schema before starting a conversation. A supplied list replaces the entire previous accepted_context list. Preserve any existing keys you still need; omission or null leaves the list unchanged, while [] accepts no caller-supplied context keys.
Each entry requires key, type, description, and required. Keys must be unique, 2-63 characters, and contain only lowercase letters, digits, and internal hyphens. Underscores and leading or trailing hyphens are invalid. Types are string or number; the service accepts at most 100 key declarations.
Adding a required key affects subsequent create requests validated against this service. Update callers together with the service schema.
accepted_context is service-level configuration. Selecting a previous graph version does not restore a previous context schema; save and restore that schema separately when rolling back.
2. Bind a Parameter in the Context Graph
The binding belongs to the tool call specification on the state, not the tool's create/update body. The underlying tool must already declare the parameter.
Read the service's selected Context Graph version. In the action state that calls your test tool, add context_bindings to its existing action_tool_call_specs entry, or to exit_condition_tool_call_specs when that is where the tool is used:
This is a ToolCallSpec fragment, not a complete graph or tool creation request. Replace lookup_test_hours with the exact model-callable tool name, including a prefix such as fn_ or wsq_ for Platform Functions. The execution and persistence values select the test behavior described above. Retain the entry's other settings and the graph's other states and bindings.
Each context_bindings list item uses the same name for the accepted context key and tool parameter. Use context_binding_aliases when the names differ:
This is another ToolCallSpec fragment: the left side is the tool parameter, and the right side is the service’s accepted context key. The target parameter is hidden from the model and filled at dispatch. An alias takes precedence over a same-name binding for the same target. A missing alias source rejects the tool call before execution, even if the model supplies a value or the input schema has a default. Several parameters can map to one source key.
Declare the binding in each state where it is needed, using that state's tool-spec list. Keep a tool's bindings consistent across states, especially for voice runtimes that advertise one tool schema for the whole call.
Publish the complete revised graph using:
Create a new version of a context graph. Version number is auto-incremented. Requires ContextGraph.create permission for the first version and ContextGraph.update permission afterward.
API key issued via POST /v1/{workspace_id}/api-keys. Pass the returned api_key value as a Bearer token.
""[][][]Successful Response
Missing or invalid API key.
Insufficient permissions.
Not found.
Name already taken.
Invalid request body.
POST /v1/{workspace_id}/context-graphs/{context_graph_id}/versions HTTP/1.1
Host: platform.api-us.concurrence.com
Authorization: Bearer YOUR_SECRET_TOKEN
Content-Type: application/json
Accept: */*
Content-Length: 2640
{
"description": "",
"states": [
{
"type": "text",
"name": "text",
"objective": "text",
"actions": [
{
"description": "text",
"filler_hint": "text"
}
],
"intra_state_navigation_guidelines": [
"text"
],
"action_guidelines": [
"text"
],
"boundary_constraints": [
"text"
],
"exit_conditions": [
{
"description": "text",
"next_state": "text",
"filler_hint": "text"
}
],
"action_tool_call_specs": [
{
"tool_id": "text",
"additional_instruction": "",
"navigate_on_completion": false,
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
},
"result_persistence": "accumulate",
"delivery": "interrupt",
"failure_delivery": "interrupt",
"failure_delivery_by_class": {
"ANY_ADDITIONAL_PROPERTY": "interrupt"
},
"execution": "blocking",
"lifecycle": "independent",
"context_bindings": [
"text"
],
"context_binding_aliases": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"audio_fillers": [
"text"
],
"audio_filler_triggered_after": 1
}
],
"exit_condition_tool_call_specs": [
{
"tool_id": "text",
"additional_instruction": "",
"navigate_on_completion": false,
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
},
"result_persistence": "accumulate",
"delivery": "interrupt",
"failure_delivery": "interrupt",
"failure_delivery_by_class": {
"ANY_ADDITIONAL_PROPERTY": "interrupt"
},
"execution": "blocking",
"lifecycle": "independent",
"context_bindings": [
"text"
],
"context_binding_aliases": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"audio_fillers": [
"text"
],
"audio_filler_triggered_after": 1
}
],
"wait_for": "surface_submission",
"guardrails": [
{
"name": "text",
"description": "text",
"enforcement": "hard"
}
],
"channel_overrides": {
"ANY_ADDITIONAL_PROPERTY": {
"objective": "text",
"action_guidelines": [
"text"
],
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
}
}
},
"surface_spec_template": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"turn_policy": {
"barge_in_enabled": true,
"safety_response": "stay_empathize",
"context_strategy": "full",
"degradation_threshold": -1,
"block_forward_call": false,
"block_forward_call_after_turns": -1,
"stt_eot_threshold": 1,
"stt_eager_eot_threshold": 1,
"stt_eot_timeout_ms": 1
},
"preload": [
{
"tool_id": "text",
"params": {
"ANY_ADDITIONAL_PROPERTY": "anything"
}
}
]
}
],
"new_user_initial_state": "text",
"returning_user_initial_state": "text",
"terminal_state": "text",
"global_intra_state_navigation_guidelines": [
"text"
],
"global_action_guidelines": [
"text"
],
"global_boundary_constraints": [
"text"
],
"topology_description": "text"
}{
"id": "123e4567-e89b-12d3-a456-426614174000",
"workspace_id": "123e4567-e89b-12d3-a456-426614174000",
"context_graph_id": "123e4567-e89b-12d3-a456-426614174000",
"version": 1,
"description": "text",
"states": [
{
"type": "text",
"name": "text",
"objective": "text",
"actions": [
{
"description": "text",
"filler_hint": "text"
}
],
"intra_state_navigation_guidelines": [
"text"
],
"action_guidelines": [
"text"
],
"boundary_constraints": [
"text"
],
"exit_conditions": [
{
"description": "text",
"next_state": "text",
"filler_hint": "text"
}
],
"action_tool_call_specs": [
{
"tool_id": "text",
"additional_instruction": "",
"navigate_on_completion": false,
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
},
"result_persistence": "accumulate",
"delivery": "interrupt",
"failure_delivery": "interrupt",
"failure_delivery_by_class": {
"ANY_ADDITIONAL_PROPERTY": "interrupt"
},
"execution": "blocking",
"lifecycle": "independent",
"context_bindings": [
"text"
],
"context_binding_aliases": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"audio_fillers": [
"text"
],
"audio_filler_triggered_after": 1
}
],
"exit_condition_tool_call_specs": [
{
"tool_id": "text",
"additional_instruction": "",
"navigate_on_completion": false,
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
},
"result_persistence": "accumulate",
"delivery": "interrupt",
"failure_delivery": "interrupt",
"failure_delivery_by_class": {
"ANY_ADDITIONAL_PROPERTY": "interrupt"
},
"execution": "blocking",
"lifecycle": "independent",
"context_bindings": [
"text"
],
"context_binding_aliases": {
"ANY_ADDITIONAL_PROPERTY": "text"
},
"audio_fillers": [
"text"
],
"audio_filler_triggered_after": 1
}
],
"wait_for": "surface_submission",
"guardrails": [
{
"name": "text",
"description": "text",
"enforcement": "hard"
}
],
"channel_overrides": {
"ANY_ADDITIONAL_PROPERTY": {
"objective": "text",
"action_guidelines": [
"text"
],
"progress": {
"deterministic": false,
"phrases": [
"text"
],
"trigger_delay_ms": 1,
"interval_ms": 1,
"mode": "auto",
"progress_class": "lookup",
"expected_latency_ms": 1,
"custom_phrase": "text"
}
}
},
"surface_spec_template": {
"ANY_ADDITIONAL_PROPERTY": "anything"
},
"turn_policy": {
"barge_in_enabled": true,
"safety_response": "stay_empathize",
"context_strategy": "full",
"degradation_threshold": -1,
"block_forward_call": false,
"block_forward_call_after_turns": -1,
"stt_eot_threshold": 1,
"stt_eager_eot_threshold": 1,
"stt_eot_timeout_ms": 1
},
"preload": [
{
"tool_id": "text",
"params": {
"ANY_ADDITIONAL_PROPERTY": "anything"
}
}
]
}
],
"new_user_initial_state": "text",
"returning_user_initial_state": "text",
"terminal_state": "text",
"global_intra_state_navigation_guidelines": [
"text"
],
"global_action_guidelines": [
"text"
],
"global_boundary_constraints": [
"text"
],
"topology_description": "text",
"created_at": "2026-01-01T00:00:00.000Z",
"updated_at": "2026-01-01T00:00:00.000Z"
}Select that graph version in the test service's version set. Preserve its agent and model selections. A new graph version does not change a version set pinned to an older one.
Check: The selected graph version contains the binding in the action state that will execute the tool. The tool's original input schema still declares region; the runtime removes it from the model-visible schema for the bound call.
3. Supply Values When Creating the Conversation
Send the map in context on POST /v1/{workspace_id}/conversations. Replace the synthetic service UUID with your test service ID:
The create request accepts at most 50 context keys. String values are limited to 8,192 characters. Service validation returns 422 for unknown keys, missing required keys, and values that do not match the declared type after request parsing. Send a JSON number for number, not a numeric string or a boolean. Arrays, objects, and null values are not context values.
Validation edge case: The public contract excludes booleans, but the current conversation-create parser can coerce true and false to 1 and 0 before service validation. Validate your application's values before sending them; do not rely on a boolean producing 422.
An empty context map works only when the service has no required keys. If an optional key in the legacy same-name context_bindings list is absent from a text conversation, the runtime leaves that parameter unchanged; the tool can apply its own default or reject missing input. In contrast, a missing context_binding_aliases source rejects the call. Do not bind a required tool parameter to an optional key unless that absence is handled.
On voice calls, a binding to a declared key that the call did not start with refuses to run until the key is set on the live call; see Set Context on a Live Voice Call.
Save the returned conversation ID before sending a turn. Context is stored for the conversation and restored on subsequent text turns. The turn request's text context field is a different feature; it does not update this map. See Conversation operations.
Outbound Requests
Outbound SMS and iMessage use the same create operation with the channel's required recipient and use_case_id. The service's accepted_context validates the map before dispatch. Existing channel permissions, provisioning, and delivery requirements still apply.
Outbound voice uses POST /v1/{workspace_id}/calls/outbound and its context map. Those values reach the live call's bound tools, and each key is then set for the call, so a later live-call update to a different value is rejected. Validation and routing use the service bound to the supplied use_case_id; this request does not select a service through service_id. Follow Calls for the required phone, patient, and routing inputs. Its goal and system_prompt supply startup instructions; metadata supplies correlation data. None replaces the typed context map. The 50-key and 8,192-character limits above describe the conversation-create body, not a universal limit for every context-bearing route.
4. Verify the Bound Input
Send a message that triggers the read-only lookup, such as “Use the test lookup to show opening hours.” The model supplies query; the runtime supplies region from the conversation context when the bound action-state tool executes.
Use the test tool's observed request or a result that explicitly echoes its received parameters to verify:
The exact query wording may vary. Confirm that the tool received region: "test-east", that its result reached durable conversation history under this test's accumulate policy, and that the selected service and graph versions match your test record. Ephemeral bindings retain execution metadata instead of raw arguments and results. Tool telemetry is useful when available; model narration alone does not prove which parameters reached the tool.
Repeat in a fresh conversation with a different synthetic region to check that the value is conversation-specific. Also try omitting region, adding an undeclared key, and sending attempt: "one"; each create should return 422 before a conversation is created. Resolve ambiguous network outcomes by inspecting retained state before retrying.
Close successful test conversations and verify closure through the close and detail operations. Restore the saved service schema and version selection if the test configuration is temporary. Closing a conversation does not erase its retained context or undo an external operation.
Supported Tool Paths
The runtime resolves the tool's binding from the state where the call starts and carries that binding into execution. This includes action, decision, and data-collection states. The example above uses an action state.
Direct integration endpoint
Context parameters are injected before the integration call when the launching state's spec binds that exact tool name. Integration authentication and grants still apply.
Direct world tool
Uses the same injection path. Its existing parameter schema, validation, and execution policy still apply.
SQL-backed platform function or workspace data query
Uses the direct-tool path when exposed to the conversation. Parameter names must also satisfy the SQL tool's own naming rules. Use context_binding_aliases to map a hyphenated context key to an underscore-containing SQL parameter.
Companion skill input
Receives the bound context before the companion starts, including on background execution. A mapped source must exist. Passing that skill input to an integration sub-tool requires its own skill_input_bindings; see Skills. On voice calls, a skill input bound to a declared key the call did not start with is refused; bind that key on the sub-tool instead.
Decision or data-collection state
The binding resolves from that state's tool_call_specs list. Action states use action_tool_call_specs and exit_condition_tool_call_specs. Annotation states do not bind tools.
Realtime voice runtime
The call stays in its initial state, so bindings resolve across the whole graph. When states bind the same parameter differently, the initial state wins, then the first state in graph order. Keep a tool's bindings consistent across states.
Standalone tool test or direct function invocation
Has no conversation context binding merely because the tool is used in a graph. Supply the endpoint's required inputs through that operation's contract.
Context bindings are distinct from identity bindings and authorization-bound SQL parameters. Keep their parameter names separate; do not context-bind credential or access-control parameters. Caller-supplied context is application input, not proof of identity or permission. Removing a parameter from the model's tool schema does not make its value a secret: tool results, retained context, or telemetry can expose it. Do not put credentials in this map.
Tool result persistence governs the tool journal and later prompts; it does not clear the separately stored start-time context map. Apply your retention requirements to both.
Reserved Channel Identity
The reserved key is channel-id, with a hyphen. It is not channel_id, a use-case ID, a conversation UUID, or the business's sending address.
The initialization rule fills a declared string channel-id from a non-empty caller/channel address, overriding the value in the initialization map. Voice uses the caller or destination phone number; messaging adapters carry their channel-specific sender identifier. The current text path preserves this initialized map for tool execution and re-derives the channel address when a session is restored. The separately persisted start-time context remains the originally supplied map, so it can differ from the effective tool input.
On the inbound voice path reviewed September 16, 2026, valid caller numbers are normalized to E.164. Withheld, anonymous, invalid, and non-phone caller identifiers are treated as unidentified, so they supply no phone address for automatic filling. An absent address does not erase a caller-supplied context value; do not use a supplied channel-id as a fallback identity. Even a valid phone address is not proof of the caller's identity or authority.
When preparing a supported deployment for automatic filling, declare channel-id as type: "string" and required: false. API validation occurs before initialization, so required: true can reject a create request that omits it before any auto-fill occurs. An absent caller address also means there is nothing to auto-fill. Do not send a placeholder value to bypass that validation.
Use an explicitly supplied, non-reserved key for ordinary application context. It remains caller-supplied data and must not replace the tool's authorization checks.
Troubleshooting
Service update returns 405
Use PUT /services/{service_id}, not PATCH or PUT on the collection.
Schema or create request returns 422
Check key spelling, uniqueness, scalar types, required keys, and request limits. channel_id is not a valid accepted-context key.
Bound parameter is missing
Check the selected graph version, launching state, deployed state coverage, exact tool name and parameter name, and whether the optional context key was supplied.
A warehouse parameter uses underscores
Add an explicit context_binding_aliases mapping from that tool parameter to the accepted context key. There is no implicit translation.
Model is still asked for the value
Confirm the binding is on the active state's ToolCallSpec, rather than on the tool definition or an unselected graph version.
Voice tool returns a missing-context rejection
The key is declared but the call did not start with it. Set it with live call context before the agent needs the tool, or remove the declaration if nothing will supply it.
channel-id is absent or differs from the sender
Check the service declaration, channel adapter address, and effective tool input; do not infer identity from a supplied value.
Continue with Verify an Integration Action when the tool performs an external write, and Build and Prove for a reviewed configuration rollout.
Last updated
Was this helpful?

