Skip to main content
Use mock tool calls so test runs never create real bookings or read live data, and so each test case gets the result it needs, such as “two slots open on Thursday” or “order not found”.

How it works

Mocking is set on the agent and applies to every simulation on that agent. Live traffic is never mocked.
  1. Open the agent’s Simulation Settings and turn on Mock tool calls. Every tool the agent has is listed.
  2. Pick a mode for each tool. Tools start on Generated.
  3. Run a simulation. Each tool call gets its answer from Bluejay.
The agent's Simulation Settings with Mock tool calls on and each tool set to Generated For each tool call, Bluejay uses the first of these:
  1. The Digital Human’s Tool Response Overrides entry for the tool.
  2. The agent’s Fixed response for the tool.
  3. A generated result, unless the tool is on Real backend.
  4. Your real tool.
Generated results usually take a second or two. If generation fails, the tool gets an error result on every platform. Your real tool never runs.

Override a tool for one test case

Edit the Digital Human and fill in Tool Response Overrides for the tool, as JSON or plain text. Leave it empty to use the agent’s mode. A Digital Human's Tool Response Overrides with check_availability set to an empty slot list Overrides are separate from Tool Adherence. Tool Adherence grades which tools the agent calls. Overrides only decide what the tools return.

Example

Your scheduling agent has check_availability and lookup_patient. You want to test that it reads back the times your calendar returns.
  1. Turn on Mock tool calls in the agent’s Simulation Settings.
  2. Set check_availability to Fixed with {"slots": ["Thursday 7:40 AM", "Thursday 4:05 PM"]}. Leave lookup_patient on Generated.
  3. Create a Digital Human who asks for a Thursday appointment, with the success criterion “The agent reads back the Thursday times that check_availability returned.”
The agent gets the Digital Human’s own details from the lookup, and Thursday at 7:40 AM and 4:05 PM from the availability check. No real calendar or patient record is read. To test a fully booked day in one test case, give that Digital Human an override for check_availability of {"slots": []}.

Set up by platform

“Native” means you only turn on Mock tool calls. “Your tool server asks Bluejay” means your tool handler calls the resolver before it runs the real tool.

ElevenLabs

Bluejay mocks ElevenLabs agents natively on web and chat simulations. Your agent needs versioning turned on in ElevenLabs. When you turn mocking on, Bluejay creates a branch named bluejay-mocks on the agent in your ElevenLabs workspace.
  • The branch is a copy of your live version. It has a client tool in place of each webhook tool, with the same name and schema. Tools on Real backend stay webhooks and call your server.
  • The branch takes 0% of traffic. Live callers and your main version are never touched.
  • Bluejay reuses the branch for every run. When you publish a new live version, Bluejay rebuilds the branch the next time you queue a run. Changing a tool to or from Real backend rebuilds it right away.
  • Don’t edit the branch. Bluejay overwrites it.
In a simulation, every tool call comes back to Bluejay instead of your server, including calls the agent makes early or drops after an interruption. If Bluejay can’t produce a result, the tool gets the error “No mock result is available for this tool in this test.” To turn mocking off, turn off Mock tool calls. Bluejay archives the branch and deletes its tool copies. Turning it on again creates a new branch. ElevenLabs phone and SIP agents use the resolver, because ElevenLabs can’t route a phone call to a branch. Bluejay sends X-Simulation-Result-Id on every SIP call. Pass it to your tool webhook as a dynamic variable.

Google CES and Dialogflow CX

When Google hands a tool call to Bluejay during a simulation, Bluejay answers it. This works for voice and chat.
  • A tool on Real backend gets an error result, since nothing can run your real tool on this path.
  • A result that is not a JSON object arrives as {"result": <value>}.
  • Tools that Google runs itself, such as OpenAPI tools, still call your real system. Bluejay can’t mock them yet.

Retell, Vapi and other platforms

Your tool server asks Bluejay for the mock before it runs the real tool.
  1. Read the Bluejay test id from the call.
  2. Call POST /v1/tool-mocks/resolve with your Bluejay API key.
  3. If mocked is true, return result and skip the real tool. On mocked: false, run the real tool.
A Retell custom function with FastAPI:
With the resolver, every call your handler checks first gets the mock.
  • Only call Bluejay when the call has a test id or comes from a Bluejay number. Real callers then never wait on Bluejay.
  • When the call has a test id and Bluejay errors or times out, return an error result instead of running the real tool, so a test never reaches your real backend. Generated results can take a few seconds, so wait up to 10.

Phone

No platform routes a Bluejay caller to a test version on its own, so phone tests always need your tool server to ask Bluejay. Use the resolver or the SDK helper.
  • SIP calls carry X-Simulation-Result-Id. Send it as test_result_id.
  • Phone calls drop SIP headers. Send the Digital Human’s phone number as caller_number, in E.164 form. Bluejay matches it to the Digital Human calling from that number right now.
  • When your agent calls the Digital Human, the Digital Human’s number is the number your agent dialed.

LiveKit and Pipecat

When your tools run in your own code, wrap each tool with the Bluejay SDK helper. During a Bluejay simulation it returns the mocked result. On any other call it runs your real tool.
For LiveKit, add @mockable under @function_tool, and call bind_livekit(ctx) at the start of your entrypoint.
The mock is looked up by the function name. If your tool has a different name in Bluejay, use @mockable(name="check_availability"). For Pipecat, bind the call when the bot starts, then wrap the handler body with mock_or_call.
How the helper finds the call:
  • bind_livekit reads X-Simulation-Result-Id from the dispatch metadata, then from participant attributes. For SIP calls into LiveKit, map the header with headers_to_attributes on your inbound trunk.
  • On plain phone calls the header is dropped, so bind_livekit falls back to the caller’s number, sip.phoneNumber.
  • In any other server, call bind(test_result_id=...) or bind(caller_number=...) yourself.

API and MCP

The endpoints authenticate with your Bluejay API key in the X-API-Key header. They only see agents and simulations in the workspaces your key can access. With MCP or Bluejay AI, ask “mock tool calls for my scheduling agent”, then “make check_availability return Thursday 7:40 AM and 4:05 PM”. The tools are set_agent_mock_tools and set_agent_tool_mock.

Turn mocking on or off

PUT https://api.getbluejay.ai/v1/agents/{agent_id}/mock-tools Needs write access to the agent’s workspace.
Each tool setting: For ElevenLabs agents, a 400 means the agent has no versions, so turn on versioning in ElevenLabs first. A 502 means a call to the ElevenLabs API failed, and mocking stays as it was. Queuing a voice run also updates the branch to match the live agent and its tools. If that update fails, the run is not queued and the queue request answers 502. The MCP tool set_agent_mock_tools takes agent_id and enabled, and returns the same fields.

Set one tool

PUT https://api.getbluejay.ai/v1/agents/{agent_id}/mock-tools/{tool_name} The body is one tool setting, such as {"mode": "fixed", "response": {"slots": []}}. It also turns mocking on for the agent, and returns the same fields as above. The MCP tool is set_agent_tool_mock. Digital Human overrides are the tool_responses field, an object keyed by tool name, when you create or update a Digital Human.

Resolve a mock

POST https://api.getbluejay.ai/v1/tool-mocks/resolve Call it from your tool server before you run the real tool.
Send description and the schemas to mock a tool without registering it in Bluejay. Each one takes precedence over what Bluejay has stored for that tool, so the mock stays in step with your code.
  • When the call is a Bluejay simulation and Bluejay can’t produce a result, the answer is mocked: true with the result {"error": "This tool is unavailable in this test."}.
  • caller_number matches the Digital Human with that number whose conversation is running now. If none is running, the answer is mocked: false.
  • An unknown id, an id from another organization, and an id from a workspace your key can’t read all answer mocked: false. Bluejay never reveals whether the id exists.
  • The limit is 600 requests per minute per organization. Over it, the endpoint answers 429. Treat a 429 like any other error: return an error result when the call has a test id, otherwise run the real tool.

SDK helper

The helpers are in bluejay.helpers.tool_mocks in the bluejay-sdk Python package. The helper fails closed on tests:
  • A call with no test id and no caller number never contacts Bluejay.
  • With a test id, a lookup that fails, times out, or answers 429 returns {"error": "This tool is unavailable in this test."}. Your real tool never runs.
  • With only a caller number, the call may be a real caller, so a failed lookup runs your real tool.
  • A mocked result is returned as a string. Objects are JSON-encoded.

Which calls reach your real tool

Last modified on November 13, 2026