> ## Documentation Index
> Fetch the complete documentation index at: https://developers.govworx.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Test Calls quickstart

> Generate a simulated call using your tenant’s existing GovWorx integration.

Test Calls generates a simulated recording session that follows the configured SIPREC → SIPY →
Assist/Coach integration. It does **not** dial a telephone number or contact emergency services.

> [!WARNING]
>
> Start in sandbox with a dedicated test position. Production simulations create normal backend
> records and may trigger configured integrations. Do not use a station carrying real traffic.

## Before you start

Ask your GovWorx administrator to confirm:

* Your tenant has the intended SIPY subscriber and Assist test position configured.
* The station ID you will send identifies that test position.
* You have a **tenant-wide Coach API Bearer Token** with **Invoke Test Calls** permission.
  `ADMIN` is also accepted, but a least-privilege role is preferred. Agency-restricted keys cannot
  use this tenant-wide API. See [creating an API key](https://developers.govworx.ai/authorization.md).
* Optional location delivery is configured if you intend to send coordinates.

The key determines the tenant. Do not send a tenant ID, agency ID, destination, domain or caller
header in the request. The API does not check whether the supplied station exists in Assist.

`stationId` must be nonblank, already trimmed, XML-valid and free of control characters. It is
limited to **128 UTF-16 code units**, not 128 Unicode code points: an emoji uses two units, so
64 emoji fit the length bound while 70 do not. The schema's `maxLength` counts code points and
is only an approximation of that runtime limit; it does not replace server XML validation.
With location delivery, use a printable ASCII station ID.

Examples use `2025550100` from NANPA's [reserved fictional number range](https://nanpa.com/numbering/555-line-numbers).
This is mock caller ANI, not a destination to dial.

## 1. Select the environment

Use the same environment for the Coach key, token exchange and all call requests.

| Environment | Base URL |
| - | - |
| Sandbox | `https://api.gw-coach-sandbox.com` |
| Development | `https://api.gw-coach-dev.com` |
| Production | `https://api.govworx.net` |

The examples use shell variables. Load secrets from your approved secret manager; do not paste
them into shared scripts, screenshots, command history or logs. Do not enable shell tracing.

```bash theme={null}
export BASE_URL='https://api.gw-coach-sandbox.com'
# COACH_API_KEY must already be loaded securely into your environment.
```

## 2. Exchange your Coach key for an access token

Send an empty POST with the Coach key. There is no JSON body, `grant_type`, `scope`, client ID or
client-secret field.

```bash theme={null}
TOKEN_RESPONSE=$(curl --fail-with-body --silent --show-error \
  --request POST "$BASE_URL/test-calls/v1/token" \
  --header "Authorization: Bearer $COACH_API_KEY")
export ACCESS_TOKEN=$(printf '%s' "$TOKEN_RESPONSE" | jq -er '.access_token')
unset TOKEN_RESPONSE
```

The response fields are `access_token`, `token_type` (`Bearer`) and `expires_in` (`3600` seconds).
Reuse this token for calls in that environment for up to one hour, then exchange the Coach key
again. Token expiry does not disconnect an already admitted call. Refresh it before polling or
cancelling after expiry. Never send the Coach key in SIP signaling or share the service signing key.

## 3. Start a call

This is the smallest **one-off manual request**, without automatic retry protection. It defaults
to **no audio**, **no location** and a **60-second** maximum. Replace the station with your configured
test station. For automation or retries, generate and retain `requestId` **before the first POST**,
as explained below.

```bash theme={null}
curl --fail-with-body --silent --show-error \
  --request POST "$BASE_URL/test-calls/v1/startcall" \
  --header "Authorization: Bearer $ACCESS_TOKEN" \
  --header 'Content-Type: application/json' \
  --data '{"stationId":"2202","phoneNumber":"2025550100"}'
```

To play the default domestic-disturbance scenario, add `"needAudio": true`. Use
[audio scenarios](https://developers.govworx.ai/connections-platform/test-calls/audio-scenarios.md) for other bundled scripts,
custom transcripts and mixed-language turns.

An accepted request returns `202`, a status URL in the `Location` response header and a body like:

```json theme={null}
{
  "runId": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "tenantIdentifier": "42",
  "stationId": "2202",
  "state": "Running",
  "createdAt": "2026-10-27T19:00:00+00:00",
  "expiresAt": "2026-10-28T19:00:00+00:00",
  "recordingCallId": "example-recording@testcalls",
  "locationSent": null,
  "error": null
}
```

> [!NOTE]
>
> `202` and `Completed` describe the simulator—not confirmed delivery to Assist or another
> integration. Verify that the intended position, ANI, recording and downstream records appear.

## 4. Check status or cancel

Set `RUN_ID` to the actual `runId` from your response, not `recordingCallId` or `requestId`.

```bash theme={null}
curl --fail-with-body --silent --show-error \
  "$BASE_URL/test-calls/v1/calls/$RUN_ID" \
  --header "Authorization: Bearer $ACCESS_TOKEN"

curl --fail-with-body --silent --show-error \
  --request POST "$BASE_URL/test-calls/v1/calls/$RUN_ID/cancel" \
  --header "Authorization: Bearer $ACCESS_TOKEN"
```

`Cancelled` confirms simulator cleanup. A still-running or uncertain result does not.
Cancelling an already completed call returns its completed receipt without changing history.

## New calls versus retries

* **New intentional call:** omit `requestId` (the server generates it), or supply a new unique ID.
* **Retry after a timeout:** supply the **same** ID and identical payload to avoid duplicate calls.
  For automated retries, generate and save an ID before the first POST.
* A retained ID with the same payload returns the original result, even if `Completed`.
* Reusing a retained ID with different fields returns `409 request_id_conflict`.

Do not hardcode one ID into every test. Conversely, do not automatically generate a new ID when
retrying an uncertain request. A server-generated `requestId` is not returned, and `runId` is not
a substitute for it. If a request without an explicit ID loses its response, sending it again
can create another call. Receipts normally last 24 hours, but terminal history can be
evicted earlier; replay protection is not permanent. See
[lifecycle and errors](https://developers.govworx.ai/connections-platform/test-calls/lifecycle-and-errors.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.