---
title: "End Call Request"
method: POST
path: "/vapi/end-call"
tags: ["Vapi"]
---

# End Call Request

`POST /vapi/end-call`

## Request

- Base URL: `https://api.openintake.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.openintake.ai/vapi/end-call`
- Auth: HTTP bearer

Hang up the call — but only if the caller is actually finished.

This replaces Vapi's built-in `endCall` tool for Brian J Levy. The model can
now only *request* an ending; the hangup itself happens here, so the rule
"never hang up on a caller who still wants something" is enforced by code
instead of by prompt wording that measurably could not hold it (see
app/vapi/end_call_gate.py for the measurements).

Flow: evaluate the last exchange of the conversation so far — read from this
call's persisted CallTranscriptEvent rows, falling back to Vapi's
`message.artifact.messages` snapshot (see end_call_gate.select_turns for why
the events win); on a refusal return a tool error and the model keeps
helping; on an allow, speak the goodbye and hang up via Live Call Control by
POSTing
{"type": "say", ..., "endCallAfterSpoken": true} to the call's
monitor.controlUrl — the same mechanism /transfer-destination uses.

The goodbye text comes from `message.assistant.endCallMessage`, which is
still set on all 12 assistants: removing the built-in endCall tool also
removes the automatic goodbye Vapi speaks for it, so we speak it ourselves
and the yamls stay the one source of truth.

The tool takes no arguments on purpose — a required argument makes the model
treat filling it in as having done the thing (see
configs/tools/brianjlevy/routetransfer.yaml). The server already has the
transcript; it does not need the model to quote it back.

Trade-off accepted: the hangup path now depends on this endpoint. If it is
down, calls linger until the assistant's 120s silenceTimeoutSeconds. The
gate's own judge fails open, so only a full outage has that effect.

## Request body

- VapiCustomToolRequest: Wrapper for Vapi custom tool requests.
  - `message` VapiMessage, required
    - `type` string, required
    - `toolCallList` VapiToolCall[], required
      - `id` string, required
      - `type` string
      - `function` VapiToolCallFunction, required
        - `name` string, required
        - `arguments` object, required
    - `call` VapiCallObject
      - `id` string, required
    - `artifact` object, nullable
    - `assistant` object, nullable

## Response `200`

Successful Response

- VapiCustomToolResponse: Standard Vapi custom tool response format.
  - `results` VapiToolResult[], required
    - `toolCallId` string, required
    - `result` string, required

## Other responses

- `422`: Validation Error

## Changes

- **2026-09-14** `2ad5aecbce08`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/openintake/apis/openintake-api/changes/vapi/end-call/post.md)

---

[API](https://skmtc.dev/openintake/apis/openintake-api.md) - [All operations](https://skmtc.dev/openintake/apis/openintake-api/llms.txt) - [OpenAPI document](https://skmtc.dev/openintake/apis/openintake-api/revisions/de90a8dcbc07?raw)
