Transfer calls using API Request and Transfer Call tools
Use an API Request tool to look up the branch that serves a caller, then use a Transfer Call tool to connect them. This guide configures one assistant with two tools: lookup_branch calls your HTTPS API, and transferCall transfers to one of two predefined phone numbers.
The lookup API returns a branch identifier, not a phone number. The assistant uses that identifier and the transfer destinations’ descriptions to choose the matching phone number.
The system prompt guides tool ordering and destination selection; it does not enforce them as backend rules. If the model sends a destination that matches no configured phone number, Vapi transfers the call to the assistant’s forwarding phone number if one is set, or otherwise to the first destination in the Transfer Call tool.
Choose a transfer approach
Use this two-tool example when a lookup selects from predefined branch or department phone numbers. It suits a conversation where the assistant can wait for the lookup result, then offer a transfer.
Use Dynamic call transfers when your server must control transfer execution, finish asynchronous work, or determine a destination phone number that is not preconfigured. That guide uses an asynchronous Function tool and Live Call Control.
The table compares the examples in these two guides, not every configuration the tools support.
Use this example to route a confirmed ZIP code to a configured branch. Use the backend-controlled pattern to create a support case, find the assigned specialist, and transfer only after your server validates the result.
Prerequisites
- A private Vapi API key
- Node.js 22 or later to run the setup script
- An HTTPS lookup endpoint that accepts and returns the JSON described below
- A Custom Credential in the same Vapi organization that authenticates requests to your lookup endpoint
- A Vapi phone number for inbound testing and two destination phone numbers staffed by your team
Configure branch routing
Define the lookup response
Configure your endpoint to accept a POST request with a confirmed five-digit ZIP code:
Keep zipCode as a string to preserve leading zeros. Validate it on your server and use your service-area data to choose a branch.
For a match, return HTTP 200 with the branch identifier and display name:
This example uses two branchId values, north and south. For the South branch, return "branchId": "south" and "branchName": "South branch".
When no branch serves the ZIP code, return HTTP 200 with this JSON response:
A no-match result is a successful lookup, not a server failure. When the API cannot complete the request, return a non-2xx status with a short error message in the body. The model receives the body text as the tool result, so an empty error body gives it nothing to act on.
The API Request tool makes a successful JSON response available to the model. This example uses the result directly, so it does not need a response schema or variable extraction. See Use API Request tool response data.
Set the connection values
Set these environment variables in the terminal where you will run the setup script:
Replace the example URL with your deployed endpoint. api.example.com is a placeholder, not a hosted lookup service. Replace both fictional phone numbers with team-controlled test destinations in E.164 format.
VAPI_API_KEY authenticates the setup request to Vapi. BRANCH_LOOKUP_CREDENTIAL_ID identifies the stored credential Vapi uses to authenticate to your lookup API. It is not the endpoint’s secret value.
Create the assistant with both tools
Save the following as create-assistant.mjs. The script sends one request to the Create Assistant endpoint and defines both tools inline in model.tools.
Run the script and save the returned assistant ID:
The body schema defines the input to lookup_branch. The Transfer Call tool derives its destination choices from destinations; each destination’s description connects a branch identifier to a configured phone number. The model makes that match. Vapi does not map response fields to destinations automatically.
The prompt instructs the assistant to keep the lookup and the transfer in separate turns. If the model calls both tools in one turn, the transfer runs before the model reads the lookup result.
The example uses blind transfer, which does not provide a spoken introduction to the receiving branch. The destination’s message is the announcement to the caller.
Connect a test phone number
Assign the returned assistant to a team-controlled Vapi phone number using the phone-number setup guide. Check the assistant’s model and voice settings before testing.
Keep the test phone number separate from your production phone number until you have verified both destination routes and the failure cases below. Test calls incur normal call charges.
Test the lookup and transfer
Prepare lookup responses for both branch identifiers, a no-match result, and an API failure. Use ZIP codes from your test data rather than assuming the sample ZIP code maps to a particular branch. The table describes the intended prompt-guided behavior; verify it in test calls.
Open each test call in call logs and check the Messages tab. Confirm that lookup_branch completes before the assistant offers a branch, and that transferCall runs only after the caller agrees. Have a teammate answer each destination phone and confirm that both parties can hear each other. A successful tool result alone does not prove the receiving phone connected.
Test both routes and every no-transfer case. If your application must reject invalid transfer attempts instead of using a fallback, keep that decision on your server, as shown in Dynamic call transfers.