# API keys
Source: https://docs.persistence.dev/accounts/api-keys
How API keys authenticate your Persistence REST API requests, and how to store and rotate them safely.
API keys authenticate your requests to the Persistence REST API.
An API key belongs to a workspace and uses the scopes you select when you create it. A workspace can have one API key at a time.
## Create a key
In **Settings**, open **API Keys** and select **Create API key**.
Enter a key name and description, then select at least one scope. Grant only the scopes the integration needs.
Create the key, then copy or download it immediately. Persistence shows the full key only once.
## Authentication
Include your API key in the request headers:
```http theme={null}
x-api-key: YOUR_API_KEY
```
## Storing keys safely
Keep your API keys secure. Never commit them to public repositories or expose
them in client-side code.
Store keys in environment variables or a secrets manager.
## Replace a key
Revoke the existing key before you create a replacement. Revocation takes effect immediately, so integrations that still use the old key will fail.
Plan the change, revoke the key, create and store the replacement, then update every integration that authenticates to the workspace.
# Billing
Source: https://docs.persistence.dev/accounts/billing
Manage payment details and review workspace transactions.
Use **Billing** to manage the workspace payment method and billing address, and to review transaction history, usage, and invoices.
Some paid operations require workspace credit or a valid payment method. This can include buying a phone number, running a campaign, or starting a web or telephony preview.
Keep the billing address and payment method current. Use the transaction list to investigate charges associated with workspace activity.
Billing analytics can summarize usage and break it down by category or agent. Download an invoice when you need an approved record for reconciliation.
Available billing controls depend on your workspace access. Ask a workspace administrator if you cannot view or update them.
# Personal preferences
Source: https://docs.persistence.dev/accounts/preferences
Configure appearance, regional formats, navigation, profile, and notifications.
Personal settings control how Persistence appears and behaves for your account without changing the workspace configuration for other members.
Use **General** to select your appearance and regional preferences. Use **Profile** to maintain your display name, job details, time zone, email, and sign-in methods.
Changes to a personal preference apply to your account or current device as indicated by the setting. Workspace identity, defaults, access, and security policies remain under the workspace administration pages.
# Privacy and PII controls
Source: https://docs.persistence.dev/accounts/privacy
Configure workspace and agent controls for personally identifiable information.
Workspace privacy settings define the default PII behavior. Agent security settings can override that behavior for a specific workflow.
## Configure protection
Open **Settings → Privacy**, enable PII detection, and choose the protection behavior:
* **Anonymisation** replaces detected values before they are used downstream.
* **Redaction** removes detected values from stored output. Redaction is unavailable when anonymisation is enabled.
Choose the PII categories relevant to the workflow. Supported categories include identity, contact, government identifier, and financial information such as names, dates of birth, addresses, email addresses, phone numbers, IP addresses, SSNs, passports, driver's licenses, credit cards, and IBANs.
## Override an agent
Open the agent's **Security** settings to apply agent-specific PII controls. Test the exact categories and formats your callers may provide.
Detection can miss unexpected formats and context. Do not use product controls as a substitute for consent, access control, retention policy, or legal review.
# Secrets
Source: https://docs.persistence.dev/accounts/secrets
Store credentials for actions and integrations without placing them in prompts.
Use **Settings → Secrets** to store encrypted values that actions, MCP servers, and integrations need.
## Create and use a secret
Create a name that describes the credential, such as `CRM_API_TOKEN`. Avoid names that reveal the secret value.
Enter the credential in Secret Manager. Do not place the same value in an agent prompt, test variable, or documentation.
In a supported credential, header, or parameter field, insert the secret using the `{{secrets.NAME}}` form shown by the editor.
Run a simulated call that invokes the action or integration and confirm both success and failure behavior.
## Rotate a secret
Update the stored value, test each dependent workflow, and revoke the old credential at its provider. Deleting a secret can immediately break every tool or integration that references it.
# Account and workspace security
Source: https://docs.persistence.dev/accounts/security
Manage sessions, sign-in methods, and workspace security policy.
Security settings separate controls for your own account from policies that apply across a workspace.
## Personal security
Review active devices and sign out sessions you do not recognize. Keep sign-in methods current, enable the strongest supported multi-factor option, and remove a passkey or device when it is no longer controlled by you.
## Workspace security
Workspace owners can apply shared policies such as session duration, credential hygiene, release channel, and API-key controls. Evaluate the effect on integrations and automation before tightening a policy.
Treat an unfamiliar session, unexpected credential change, or unexplained role change as a security event. Revoke access first, then review activity and affected integrations.
# Sign in and onboarding
Source: https://docs.persistence.dev/accounts/sign-in
Sign in, verify your email, and create or join a workspace.
Persistence supports email passcodes and Google sign-in.
## Sign in with email
Enter your email address and select **Send passcode**.
Enter the six-digit passcode sent to your email. You can request another passcode after the resend timer finishes.
If you are new to Persistence, enter your name, organization name, and workspace name. If you have pending invitations, you can review them before creating a workspace.
You can also choose **Login with Google** and complete the Google authorization flow.
## Fix an expired sign-in flow
Start again from the Persistence dashboard when a login page or passcode has expired. Avoid reusing a bookmarked verification page because its login session may no longer be valid.
# Team access
Source: https://docs.persistence.dev/accounts/team-access
Invite users and control workspace permissions with roles.
Use **Users**, **Roles**, and **Invites** to control who can access a workspace and what they can do.
## Add a user
Create an invitation with the user's details and select a role. The recipient can accept or decline the workspace invitation before it expires. You can resend or revoke a pending invitation.
## Manage roles
A role groups permissions. Create a role with a display name, description, and the permissions required for that job. Assign roles to users through their access settings.
Follow least privilege: grant only the permissions a user needs, and review access when responsibilities change.
## Remove access
Suspending a user temporarily removes access. Deleting a user or removing all access has a broader effect. Review every workspace and role assignment before confirming either action.
# Workspaces
Source: https://docs.persistence.dev/accounts/workspaces
Organize agents, phone resources, integrations, and users in a workspace.
A workspace contains the resources your team uses together, including agents, phone numbers, integrations, contact groups, campaigns, and API access.
Use the workspace switcher to move between workspaces you can access. Check the active workspace before you create, edit, or delete a resource.
## Keep environments separate
When your organization uses separate workspaces for development and production, connect the correct phone resources and integrations in each workspace. Do not copy production credentials into prompts or test calls.
## Before deleting a workspace
Review its agents, numbers, campaigns, integrations, API access, and team membership first. Workspace deletion affects the resources contained in that workspace.
# API reference
Source: https://docs.persistence.dev/api-reference
Public API information for Persistence.
Use the Persistence API to manage agents, calls, workspaces, campaign audiences, campaigns, billing transactions, phone numbers, number pools, and knowledge bases. Each endpoint page documents its request and response contract.
All public API routes use the `https://api.persistence.dev/v1` prefix and authenticate with `X-API-Key`. The API key determines the workspace for resources whose path does not contain a workspace ID.
Create, save, and publish AI voice agents programmatically.
Start outbound batches and end active calls.
Manage workspaces and create the API keys your integrations use.
Manage the contact lists that define who a campaign calls.
Create and run outbound calling campaigns.
Manage the phone numbers your agents call from and answer on.
Group outbound phone numbers for campaign caller-ID rotation.
Create and manage reusable agent knowledge.
# Create API key
Source: https://docs.persistence.dev/api-reference/accounts/create-api-key
api-reference/accounts/openapi.json POST /v1/{workspaceId}/developer/api-keys
Issue a scoped API key for a workspace.
# Create workspace
Source: https://docs.persistence.dev/api-reference/accounts/create-workspace
api-reference/accounts/openapi.json POST /v1/workspaces
Create a workspace to hold agents, phone numbers, and API keys.
# Delete workspace
Source: https://docs.persistence.dev/api-reference/accounts/delete-workspace
api-reference/accounts/openapi.json DELETE /v1/workspaces/{workspaceId}
Delete a workspace.
# List workspaces
Source: https://docs.persistence.dev/api-reference/accounts/list-workspaces
api-reference/accounts/openapi.json GET /v1/workspaces
Page through the workspaces your API key can access.
# Accounts and workspaces
Source: https://docs.persistence.dev/api-reference/accounts/overview
Manage Persistence workspaces and create the API keys your integrations use.
A workspace is the container for your Persistence resources. Agents, phone numbers, contact lists, and API keys all belong to a workspace. Use these endpoints to manage workspaces and to create the API keys that authenticate the rest of the API.
## Base URL
```
https://api.persistence.dev
```
These endpoints are served under the public `/v1` prefix.
## Authentication
Every request requires an existing workspace API key in the `X-API-Key` header.
```bash theme={null}
curl https://api.persistence.dev/v1/workspaces \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
Treat API keys as secrets. Send them only from server-side code and never commit them to source control.
## Endpoints
`GET /v1/workspaces` — page through the workspaces the key can access.
`POST /v1/workspaces` — create a workspace.
`PUT /v1/workspaces/{workspaceId}` — change a workspace name or scope.
`DELETE /v1/workspaces/{workspaceId}` — delete a workspace.
`POST /v1/{workspaceId}/developer/api-keys` — issue a scoped API key.
## Workspace fields
`POST /v1/workspaces` and `PUT /v1/workspaces/{workspaceId}` accept the same body.
| Field | Type | Description |
| - | - | - |
| `name` | string | Workspace name. |
| `scope` | string | Workspace scope. |
A workspace returned by the API includes these fields.
| Field | Type | Description |
| - | - | - |
| `id` | string | Workspace ID, used as the `workspaceId` path parameter. |
| `name` | string | Workspace name. |
| `scope` | string | Workspace scope. |
| `path` | string | Workspace path. |
| `meta` | object | Additional workspace metadata. |
`PUT /v1/workspaces/{workspaceId}` replaces the workspace fields rather than patching individual values. Send the complete set of fields you want the workspace to have.
## Pagination and sorting
`GET /v1/workspaces` accepts these query parameters.
| Parameter | Type | Description |
| - | - | - |
| `page` | integer | Page number. |
| `perPage` | integer | Items per page. |
| `column` | string | Sort column. Only `name` is supported. |
| `order` | string | Sort order, `asc` or `desc`. |
| `searchText` | string | Filter workspaces by text. |
The response wraps the results in a paged object containing `items`, `page`, `perPage`, `totalCount`, `column`, `order`, and `searchText`.
## API key fields
`POST /v1/{workspaceId}/developer/api-keys` accepts these fields.
| Field | Type | Description |
| - | - | - |
| `name` | string | Required. Name for the key. |
| `scopes` | array of string | Required. Permission scopes granted to the key. |
| `description` | string | Description of the key. |
| `expiresAt` | string | Expiry timestamp for the key. |
| `revokeExisting` | boolean | Revoke existing keys when creating this one. |
The created key is returned with `id`, `name`, `description`, `key`, `scopes`, `status`, `spaceName`, `createdBy`, `createdAt`, `updatedAt`, `expiresAt`, and `lastUsedAt`. The `status` field is either `active` or `revoked`.
The `key` value is returned only in the creation response. Store it securely at that point, because it cannot be retrieved again.
## Errors
Errors return a `code` and an `error` message.
```json theme={null}
{
"code": "not_found",
"error": "workspace not found"
}
```
| Status | Meaning |
| - | - |
| `400` | The request body or a path parameter is invalid. |
| `401` | The `X-API-Key` header is missing or invalid. |
| `403` | The key is not permitted to perform the operation. |
| `404` | The workspace does not exist. |
| `409` | The workspace or API key conflicts with an existing one. |
# Update workspace
Source: https://docs.persistence.dev/api-reference/accounts/update-workspace
api-reference/accounts/openapi.json PUT /v1/workspaces/{workspaceId}
Change the name or scope of an existing workspace.
# Create agent
Source: https://docs.persistence.dev/api-reference/agents/create-agent
api-reference/agents/openapi.json POST /v1/agents
Create an AI voice agent from an agent template.
# Agents API
Source: https://docs.persistence.dev/api-reference/agents/overview
Create, configure, and publish AI voice agents with the Persistence Agents API.
Use the Agents API to build an AI voice agent programmatically instead of through the dashboard. The API covers the build stage of the lifecycle: create the agent, save its configuration as a draft, then publish the configuration you want live calls to use.
## Base URL
```
https://api.persistence.dev
```
## Authentication
Every request requires your workspace API key in the `X-API-Key` header.
```bash theme={null}
curl https://api.persistence.dev/v1/agents \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
Treat the API key as a secret. Send it only from server-side code and never commit it to source control.
## Endpoints
`POST /v1/agents` — create an agent from an agent template.
`PUT /v1/agents/{agentId}/save` — store configuration without affecting live calls.
`POST /v1/agents/{agentId}/publish` — release the configuration used for live calls.
## Build an agent
Send a `name` and a `templateId` to `POST /v1/agents`. The response returns the agent `id`, which is the `agentId` path parameter for the remaining calls.
Send the configuration to `PUT /v1/agents/{agentId}/save`. A draft lets you iterate without changing the behavior of live calls.
Send the configuration to `POST /v1/agents/{agentId}/publish`. The published version is the one used for live calls.
The save and publish requests take the full agent configuration, not a partial patch. Both require `systemPrompt`, `pipelineType`, `ambienceId`, and `triggers`.
## Configuration reference
The save and publish request bodies share the same fields. The tables below group them by purpose. See the individual endpoint pages for every field, type, and constraint.
### Core
| Field | Type | Description |
| - | - | - |
| `systemPrompt` | string | Required. Instructions that define the agent behavior. |
| `pipelineType` | string | Required. `cascaded` or `realtime_native`. |
| `triggers` | array | Required. Trigger definitions evaluated during the call. |
| `name` | string | Agent name, up to 64 characters. |
| `description` | string | Agent description, up to 512 characters. |
| `languageCode` | string | Language code, up to 10 characters. |
| `knowledgeBaseIds` | array of string | Public IDs of the knowledge bases to attach. |
| `tools` | array | Actions the agent can call during a conversation. |
| `dynamicVariables` | object | Variable keys and default values available to the prompt. |
### Language model
| Field | Type | Description |
| - | - | - |
| `llmProvider` | string | One of `openai`, `anthropic`, `google`, `groq`, `together`, `azure`, or `cerebras`. |
| `llmModel` | string | Model identifier for the selected provider. |
| `llmTemperature` | number | Between `0` and `2`. |
| `llmMaxTokens` | integer | Minimum `1`. |
### Voice and audio
| Field | Type | Description |
| - | - | - |
| `ttsVoiceModelId` | integer | Voice model used for speech synthesis. |
| `ttsSpeed` | number | Between `0.5` and `2`. |
| `voiceVolume` | number | Between `0` and `2`. |
| `ambienceId` | string | Required. Ambient sound applied to the call. |
| `ambienceVolume` | number | Between `0` and `2`. |
| `noiseCancellationConfig` | object | `mode` of `noise_only`, `noise_and_speech`, or `none`. |
| `digitPronunciation` | boolean | Read digits individually. |
| `vocabularySpecialization` | string | `general` or `medical`. |
### Conversation behavior
| Field | Type | Description |
| - | - | - |
| `greetingConfig` | object | `mode` of `agent_first` or `user_first`, plus the message to use. |
| `interruptionSensitivity` | number | How readily the caller can interrupt the agent. |
| `endpointingPatience` | number | How long the agent waits before deciding the caller finished. |
| `responseEagerness` | number | How quickly the agent starts responding. |
| `minConsecutiveSpeechDelay` | number | Minimum `0`. |
| `silenceTimeoutSec` | integer | Minimum `1`. |
| `maxCallDurationSec` | integer | Minimum `1`. |
| `presenceDetectionConfig` | object | `checkIntervalSec` and `maxAwayChecks`. |
### Privacy
| Field | Type | Description |
| - | - | - |
| `piiAnonymisation` | boolean | Anonymise detected personal information. |
| `piiRedaction` | boolean | Redact detected personal information. |
| `piiCategories` | array of string | Categories to detect. |
## Errors
Errors return a `code` and an `error` message.
```json theme={null}
{
"code": "bad_request",
"error": "systemPrompt is required"
}
```
| Status | Meaning |
| - | - |
| `400` | The request body or a path parameter is invalid. |
| `401` | The `X-API-Key` header is missing or invalid. |
| `403` | The key is not permitted to perform the operation. |
| `404` | The agent does not exist. |
| `409` | The agent conflicts with an existing one. |
# Publish agent
Source: https://docs.persistence.dev/api-reference/agents/publish-agent
api-reference/agents/openapi.json POST /v1/agents/{agentId}/publish
Publish the agent configuration used for live calls.
# Save agent draft
Source: https://docs.persistence.dev/api-reference/agents/save-agent-draft
api-reference/agents/openapi.json PUT /v1/agents/{agentId}/save
Save an agent configuration as a draft without affecting live calls.
# List billing transactions
Source: https://docs.persistence.dev/api-reference/billing/list-billing-transactions
api-reference/billing/openapi.json GET /v1/billing/transactions
Page through billing transactions and sort the results.
# End active call
Source: https://docs.persistence.dev/api-reference/calls/end-call
api-reference/calls/openapi.json POST /v1/calls/{roomId}/end
End an active call by its session ID.
# Calls API
Source: https://docs.persistence.dev/api-reference/calls/overview
Start outbound call batches and end active calls.
Use the Calls API to start a batch of outbound calls and to end an active call by its session ID.
Every request requires a workspace API key in the `X-API-Key` header. The API key determines the workspace, so these paths do not include a workspace ID.
`POST /v1/calls/batch` — accept up to 1,000 recipients for immediate or scheduled calling.
`POST /v1/calls/{roomId}/end` — end the active session identified by `roomId`.
Recipient `metadata` carries string values into the call. Check `acceptedRecipients` and `rejectedRecipients` in the batch response before treating a submission as fully accepted.
# Start outbound batch
Source: https://docs.persistence.dev/api-reference/calls/start-batch
api-reference/calls/openapi.json POST /v1/calls/batch
Start or schedule a batch of outbound calls from a caller ID or a number pool.
# Confirm upload
Source: https://docs.persistence.dev/api-reference/campaign-audience/confirm-upload
api-reference/campaign-audience/openapi.json POST /v1/calls/contact-lists/{id}/uploads/{uploadID}/confirm
Import a validated upload into the contact list.
# Create contact list
Source: https://docs.persistence.dev/api-reference/campaign-audience/create-contact-list
api-reference/campaign-audience/openapi.json POST /v1/calls/contact-lists
Create a contact list and get a presigned URL for uploading its CSV file.
# Create upload URL
Source: https://docs.persistence.dev/api-reference/campaign-audience/create-upload-url
api-reference/campaign-audience/openapi.json POST /v1/calls/contact-lists/{id}/get-presign-url
Get a presigned URL for uploading a new CSV file to a contact list.
# Delete contact list
Source: https://docs.persistence.dev/api-reference/campaign-audience/delete-contact-list
api-reference/campaign-audience/openapi.json DELETE /v1/calls/contact-lists/{id}
Delete a contact list.
# Get contact list
Source: https://docs.persistence.dev/api-reference/campaign-audience/get-contact-list
api-reference/campaign-audience/openapi.json GET /v1/calls/contact-lists/{id}
Retrieve a contact list and the status of its most recent upload.
# List contact list items
Source: https://docs.persistence.dev/api-reference/campaign-audience/list-contact-list-items
api-reference/campaign-audience/openapi.json GET /v1/calls/contact-lists/{id}/items
Page through the phone numbers in a contact list.
# List contact lists
Source: https://docs.persistence.dev/api-reference/campaign-audience/list-contact-lists
api-reference/campaign-audience/openapi.json GET /v1/calls/contact-lists
Page through the contact lists in your workspace.
# Campaign audience
Source: https://docs.persistence.dev/api-reference/campaign-audience/overview
Manage the contact lists that define who a campaign calls.
A contact list holds the phone numbers a campaign calls. You build a list by uploading a CSV file: create the list to get a presigned upload URL, upload the file, wait for validation, then confirm the upload to import the contacts.
## Base URL
```
https://api.persistence.dev
```
These endpoints are served under the public `/v1` prefix.
## Authentication
Every request requires a workspace API key in the `X-API-Key` header.
```bash theme={null}
curl https://api.persistence.dev/v1/calls/contact-lists \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
## Endpoints
`GET /v1/calls/contact-lists` — page through contact lists.
`POST /v1/calls/contact-lists` — create a list and get a presigned upload URL.
`GET /v1/calls/contact-lists/{id}` — retrieve a list and its upload status.
`PATCH /v1/calls/contact-lists/{id}` — change a list name or type.
`DELETE /v1/calls/contact-lists/{id}` — delete a list.
`GET /v1/calls/contact-lists/{id}/items` — page through the phone numbers in a list.
`POST /v1/calls/contact-lists/{id}/get-presign-url` — get a presigned URL for a new file.
`POST /v1/calls/contact-lists/{id}/uploads/{uploadID}/confirm` — import a validated upload.
`GET /v1/calls/contact-lists/{id}/uploads/{uploadID}/events` — follow upload progress over SSE.
## Upload a contact list
Send `POST /v1/calls/contact-lists` with `name`, `type`, and the `fileName` of the CSV you intend to upload. The response returns the new list along with `uploadUrl`, `uploadHeaders`, and `s3Key`, plus an `uploadDetails` object whose `id` is the `uploadID` used by the remaining steps.
```bash theme={null}
curl --request POST https://api.persistence.dev/v1/calls/contact-lists \
--header "X-API-Key: $PERSISTENCE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"name": "Spring outreach",
"type": "contacts",
"fileName": "contacts.csv"
}'
```
Send the CSV file directly to `uploadUrl`, including every header returned in `uploadHeaders`. This request goes to the storage provider, so do not send your API key with it.
```bash theme={null}
curl --request PUT "$UPLOAD_URL" \
--header "Content-Type: text/csv" \
--upload-file contacts.csv
```
After the file lands, the upload moves through the statuses below. Follow the progress with `GET /v1/calls/contact-lists/{id}/uploads/{uploadID}/events`, or poll `GET /v1/calls/contact-lists/{id}` and read `uploadDetails.status`.
Once the upload reaches `validated`, call `POST /v1/calls/contact-lists/{id}/uploads/{uploadID}/confirm` to import the rows into the list. Confirming before validation completes returns a `409`.
```bash theme={null}
curl --request POST \
"https://api.persistence.dev/v1/calls/contact-lists/$LIST_ID/uploads/$UPLOAD_ID/confirm" \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
To replace or extend the contents of an existing list, start at step 2 by requesting a fresh URL from `POST /v1/calls/contact-lists/{id}/get-presign-url`.
## Contact list fields
| Field | Type | Description |
| - | - | - |
| `id` | string | Contact list ID. |
| `name` | string | Contact list name. |
| `type` | string | List type: `contacts`, `dnd`, or `batch`. |
| `status` | string | List status: `draft`, `ready`, or `archived`. |
| `totalEntries` | integer | Number of entries in the list. |
| `uploadDetails` | object | The most recent upload for the list. |
| `createdAt` | string | Creation timestamp. |
| `updatedAt` | string | Last update timestamp. |
Use `contacts` for the audience a campaign calls and `dnd` for numbers a campaign must skip.
## Upload fields
`uploadDetails` describes the state of a file upload.
| Field | Type | Description |
| - | - | - |
| `id` | string | Upload ID, used as the `uploadID` path parameter. |
| `status` | string | Current upload status. |
| `s3Key` | string | Storage key for the uploaded file. |
| `metadata` | object | Row counts for the upload. |
| `errors` | array | Errors recorded during validation. |
| `errorReportS3Key` | string | Storage key for the error report. |
| `errorReportUrl` | string | Download URL for the error report. |
| `uploadedAt` | string | Time the file was uploaded. |
| `validatedAt` | string | Time validation finished. |
| `processedAt` | string | Time the import finished. |
`metadata` reports `totalRows`, `validRows`, `invalidRows`, `duplicateRows`, and `importedRows`.
### Upload statuses
| Status | Meaning |
| - | - |
| `uploaded` | The file has been received. |
| `validating` | The file is being checked. |
| `validated` | The file passed validation and can be confirmed. |
| `validation_failed` | The file failed validation. |
| `processing` | The confirmed upload is being imported. |
| `processed` | The import finished. |
| `failed` | The upload could not be processed. |
When validation fails, `errorReportUrl` points to a report describing the rejected rows.
## Track upload progress
`GET /v1/calls/contact-lists/{id}/uploads/{uploadID}/events` returns a server-sent event stream. Each event carries an `eventId`, an `eventType`, the current upload in `data`, and `errorReportUrl` when a report is available.
```bash theme={null}
curl --no-buffer \
"https://api.persistence.dev/v1/calls/contact-lists/$LIST_ID/uploads/$UPLOAD_ID/events" \
--header "X-API-Key: $PERSISTENCE_API_KEY" \
--header "Accept: text/event-stream"
```
The interactive playground on this page sends a normal request and shows a single event body. Use a client that supports server-sent events to consume the stream.
## Pagination and filtering
`GET /v1/calls/contact-lists` accepts these query parameters.
| Parameter | Type | Description |
| - | - | - |
| `page` | integer | Page number. |
| `perPage` | integer | Items per page. |
| `type` | string | Filter by list type, `contacts` or `dnd`. |
| `status` | string | Filter by list status. |
| `searchText` | string | Filter lists by text. |
`GET /v1/calls/contact-lists/{id}/items` accepts `page` and `perPage`. Both endpoints return a paged object containing `items`, `page`, `perPage`, `totalCount`, `column`, `order`, and `searchText`.
Each item in a list has a `phoneNumber` and a `metadata` object holding the other columns imported from the CSV file.
## Errors
Errors return a `code` and an `error` message.
```json theme={null}
{
"code": "not_found",
"error": "contact list not found"
}
```
| Status | Meaning |
| - | - |
| `400` | The request body or a path parameter is invalid. |
| `401` | The `X-API-Key` header is missing or invalid. |
| `403` | The key is not permitted to perform the operation. |
| `404` | The contact list or upload does not exist. |
| `409` | The list already exists, or the upload is not ready to be confirmed. |
# Stream upload status
Source: https://docs.persistence.dev/api-reference/campaign-audience/stream-upload-status
api-reference/campaign-audience/openapi.json GET /v1/calls/contact-lists/{id}/uploads/{uploadID}/events
Follow the progress of a contact list upload over server-sent events.
# Update contact list
Source: https://docs.persistence.dev/api-reference/campaign-audience/update-contact-list
api-reference/campaign-audience/openapi.json PATCH /v1/calls/contact-lists/{id}
Change the name or type of a contact list.
# Cancel campaign
Source: https://docs.persistence.dev/api-reference/campaigns/cancel-campaign
api-reference/campaigns/openapi.json POST /v1/calls/campaigns/{id}/cancel
Cancel a campaign.
# Create campaign
Source: https://docs.persistence.dev/api-reference/campaigns/create-campaign
api-reference/campaigns/openapi.json POST /v1/calls/campaigns
Create an outbound calling campaign.
# Delete campaign
Source: https://docs.persistence.dev/api-reference/campaigns/delete-campaign
api-reference/campaigns/openapi.json DELETE /v1/calls/campaigns/{id}
Delete a campaign.
# Get campaign
Source: https://docs.persistence.dev/api-reference/campaigns/get-campaign
api-reference/campaigns/openapi.json GET /v1/calls/campaigns/{id}
Retrieve a campaign and its contact groups.
# List campaign contacts
Source: https://docs.persistence.dev/api-reference/campaigns/list-campaign-contacts
api-reference/campaigns/openapi.json GET /v1/calls/campaigns/{id}/contacts
Page through the contacts in a campaign and their call status.
# List campaign conversations
Source: https://docs.persistence.dev/api-reference/campaigns/list-campaign-events
api-reference/campaigns/events-openapi.json GET /v1/calls/campaigns/{id}/events
Page through conversations produced by a campaign.
# List campaigns
Source: https://docs.persistence.dev/api-reference/campaigns/list-campaigns
api-reference/campaigns/openapi.json GET /v1/calls/campaigns
Page through the campaigns in your workspace.
# Campaigns
Source: https://docs.persistence.dev/api-reference/campaigns/overview
Create and run outbound calling campaigns.
A campaign places outbound calls to a set of contacts. It ties together the agent that speaks on the call, the phone number the call comes from, and the contact lists that define who to call. Once created, you control the campaign with the start, pause, resume, and cancel operations.
## Base URL
```
https://api.persistence.dev
```
These endpoints are served under the public `/v1` prefix.
## Authentication
Every request requires a workspace API key in the `X-API-Key` header.
```bash theme={null}
curl https://api.persistence.dev/v1/calls/campaigns \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
## Endpoints
`GET /v1/calls/campaigns` — page through your campaigns.
`POST /v1/calls/campaigns` — create a campaign.
`GET /v1/calls/campaigns/{id}` — retrieve a campaign and its contact groups.
`PATCH /v1/calls/campaigns/{id}` — change a campaign's configuration.
`DELETE /v1/calls/campaigns/{id}` — delete a campaign.
`GET /v1/calls/campaigns/{id}/contacts` — see per-contact call status.
`GET /v1/calls/campaigns/{id}/events` — page through conversations produced by the campaign.
`POST /v1/calls/campaigns/{id}/start` — begin placing calls.
`POST /v1/calls/campaigns/{id}/pause` — pause a running campaign.
`POST /v1/calls/campaigns/{id}/resume` — resume a paused campaign.
`POST /v1/calls/campaigns/{id}/cancel` — cancel a campaign.
## Before you start
A campaign references resources created through the other APIs. Gather these first.
`agentId` — the agent that speaks on the call.
`fromNumber` — the number the call comes from, or use a number pool.
`contactListIds` and `dndListIds` — who to call and who to skip.
## Create a campaign
`POST /v1/calls/campaigns` requires `name`, `agentId`, `contactListIds`, `maxConcurrency`, and exactly one of `fromNumber` or `numberPoolId`.
| Field | Type | Description |
| - | - | - |
| `name` | string | Required. Campaign name. |
| `agentId` | string | Required. Agent that places the calls. |
| `fromNumber` | string | Caller ID in E.164 format. Mutually exclusive with `numberPoolId`. |
| `numberPoolId` | string | Number pool used for caller ID rotation. Mutually exclusive with `fromNumber`. |
| `contactListIds` | array of string | Required. Contact lists to call. Must contain at least one ID. |
| `maxConcurrency` | integer | Required. Maximum simultaneous calls. Minimum `1`. |
| `dndListIds` | array of string | Contact lists whose numbers the campaign skips. |
| `retryPolicy` | object | Retry configuration for campaign calls. |
| `scheduledAt` | date-time | Required unless `sendNow` is `true`. |
| `scheduleStart` | string | Optional daily calling-window start in zero-padded `HH:MM`. |
| `scheduleEnd` | string | Optional daily calling-window end in zero-padded `HH:MM`. |
| `timezone` | string | IANA time zone used for the schedule. |
| `sendNow` | boolean | Start the campaign immediately instead of scheduling it. |
Pass `contactListIds` for the audience and `dndListIds` for numbers to exclude. Both accept IDs from the [Campaign audience API](/api-reference/campaign-audience/overview); create do-not-disturb lists with `type` set to `dnd`.
```bash theme={null}
curl --request POST https://api.persistence.dev/v1/calls/campaigns \
--header "X-API-Key: $PERSISTENCE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"name": "Spring outreach",
"agentId": "AGENT_ID",
"fromNumber": "+15551234567",
"contactListIds": ["CONTACT_LIST_ID"],
"maxConcurrency": 5
}'
```
A `422` indicates the campaign could not be created with the values supplied.
Set `scheduleStart` and `scheduleEnd` together. Do not send scheduling fields when `sendNow` is `true`.
## Control a running campaign
Four operations move a campaign through its lifecycle. Each takes only the campaign ID and returns the updated campaign.
| Operation | Endpoint |
| - | - |
| Start | `POST /v1/calls/campaigns/{id}/start` |
| Pause | `POST /v1/calls/campaigns/{id}/pause` |
| Resume | `POST /v1/calls/campaigns/{id}/resume` |
| Cancel | `POST /v1/calls/campaigns/{id}/cancel` |
```bash theme={null}
curl --request POST \
"https://api.persistence.dev/v1/calls/campaigns/$CAMPAIGN_ID/start" \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
The campaign records `pausedAt`, `resumedAt`, `stoppedAt`, and `cancelledAt` as these operations are applied, so you can read the current state from the campaign itself.
## Campaign fields
| Field | Type | Description |
| - | - | - |
| `id` | string | Campaign ID. |
| `name` | string | Campaign name. |
| `description` | string | Campaign description. |
| `status` | string | Current campaign status. |
| `direction` | string | Call direction, `inbound` or `outbound`. |
| `agentId` | string | Agent that places the calls. |
| `fromNumber` | string | Number the calls come from. |
| `lists` | array | Contact lists attached to the campaign, each with an `id` and a `role`. |
| `maxConcurrency` | integer | Maximum simultaneous calls. |
| `retryPolicy` | array of integer | Retry schedule for unanswered calls. |
| `totalContacts` | integer | Number of contacts in the campaign. |
| `targetCallCount` | integer | Target number of calls. |
| `targetConversionRate` | number | Target conversion rate. |
| `scheduledAt` | string | When the campaign is scheduled to run. |
| `scheduleStart` | integer | Start of the daily calling window. |
| `scheduleEnd` | integer | End of the daily calling window. |
| `timezone` | string | Timezone the schedule is interpreted in. |
| `startDate` | string | Campaign start date. |
| `endDate` | string | Campaign end date. |
| `pausedAt` | string | Time the campaign was paused. |
| `resumedAt` | string | Time the campaign was resumed. |
| `stoppedAt` | string | Time the campaign stopped. |
| `cancelledAt` | string | Time the campaign was cancelled. |
| `meta` | object | Additional campaign metadata. |
| `createdAt` | string | Creation timestamp. |
| `updatedAt` | string | Last update timestamp. |
When a campaign fails, `meta.failure.reason` describes why.
`GET /v1/calls/campaigns/{id}` returns these fields plus `agentName` and a `contactGroups` array, where each group has an `id`, `name`, and `type`.
## Campaign contacts
`GET /v1/calls/campaigns/{id}/contacts` lists the individual contacts in a campaign.
| Field | Type | Description |
| - | - | - |
| `phoneNumber` | string | The contact's phone number. |
| `status` | string | Call status for this contact. |
| `attempts` | integer | Number of call attempts made. |
| `createdAt` | string | Creation timestamp. |
| `updatedAt` | string | Last update timestamp. |
The endpoint accepts `page`, `perPage`, and a `status` filter.
## Pagination and filtering
`GET /v1/calls/campaigns` accepts these query parameters.
| Parameter | Type | Description |
| - | - | - |
| `page` | integer | Page number. |
| `perPage` | integer | Items per page. |
| `status` | string | Filter by status: `active`, `paused`, or `completed`. |
| `direction` | string | Filter by direction: `inbound` or `outbound`. |
| `name` | string | Filter by campaign name. |
| `searchText` | string | Filter campaigns by text. |
Both list endpoints return a paged object containing `items`, `page`, `perPage`, `totalCount`, `column`, `order`, and `searchText`.
## Errors
Errors return a `code` and an `error` message.
```json theme={null}
{
"code": "not_found",
"error": "campaign not found"
}
```
| Status | Meaning |
| - | - |
| `400` | The request body or a path parameter is invalid. |
| `401` | The `X-API-Key` header is missing or invalid. |
| `403` | The key is not permitted to perform the operation. |
| `404` | The campaign does not exist. |
| `422` | The campaign could not be created with the values supplied. |
# Pause campaign
Source: https://docs.persistence.dev/api-reference/campaigns/pause-campaign
api-reference/campaigns/openapi.json POST /v1/calls/campaigns/{id}/pause
Pause a running campaign.
# Resume campaign
Source: https://docs.persistence.dev/api-reference/campaigns/resume-campaign
api-reference/campaigns/openapi.json POST /v1/calls/campaigns/{id}/resume
Resume a paused campaign.
# Start campaign
Source: https://docs.persistence.dev/api-reference/campaigns/start-campaign
api-reference/campaigns/openapi.json POST /v1/calls/campaigns/{id}/start
Start a campaign so it begins placing calls.
# Update campaign
Source: https://docs.persistence.dev/api-reference/campaigns/update-campaign
api-reference/campaigns/openapi.json PATCH /v1/calls/campaigns/{id}
Change the configuration of a campaign.
# Create knowledge base
Source: https://docs.persistence.dev/api-reference/knowledge-bases/create
api-reference/knowledge-bases/openapi.json POST /v1/knowledge-bases
Create an empty knowledge base.
# Delete knowledge base
Source: https://docs.persistence.dev/api-reference/knowledge-bases/delete
api-reference/knowledge-bases/openapi.json DELETE /v1/knowledge-bases/{kbId}
Delete a knowledge base and its documents.
# Delete knowledge base document
Source: https://docs.persistence.dev/api-reference/knowledge-bases/delete-document
api-reference/knowledge-bases/openapi.json DELETE /v1/knowledge-bases/{kbId}/documents/{docId}
Delete one document from a knowledge base.
# Get knowledge base
Source: https://docs.persistence.dev/api-reference/knowledge-bases/get
api-reference/knowledge-bases/openapi.json GET /v1/knowledge-bases/{kbId}
Get a knowledge base and its documents.
# List knowledge bases
Source: https://docs.persistence.dev/api-reference/knowledge-bases/list
api-reference/knowledge-bases/openapi.json GET /v1/knowledge-bases
List knowledge bases in the API key's workspace.
# Knowledge Bases API
Source: https://docs.persistence.dev/api-reference/knowledge-bases/overview
Create and manage knowledge bases through the public API.
Use the Knowledge Bases API to create, list, inspect, and delete knowledge bases. You can also delete an individual document from a knowledge base.
Every request requires a workspace API key in the `X-API-Key` header.
`GET /v1/knowledge-bases`
`POST /v1/knowledge-bases`
`GET /v1/knowledge-bases/{kbId}`
`DELETE /v1/knowledge-bases/{kbId}`
`DELETE /v1/knowledge-bases/{kbId}/documents/{docId}`
The knowledge base status is derived from its documents: `empty`, `processing`, `ready`, or `failed`. Attach a knowledge base to an agent only after it is `ready`.
# Create number pool
Source: https://docs.persistence.dev/api-reference/number-pools/create
api-reference/number-pools/openapi.json POST /v1/number-pools
Create a number pool with at least one phone number.
# Delete number pool
Source: https://docs.persistence.dev/api-reference/number-pools/delete
api-reference/number-pools/openapi.json DELETE /v1/number-pools/{id}
Delete a number pool.
# Get number pool
Source: https://docs.persistence.dev/api-reference/number-pools/get
api-reference/number-pools/openapi.json GET /v1/number-pools/{id}
Get one number pool.
# List number pools
Source: https://docs.persistence.dev/api-reference/number-pools/list
api-reference/number-pools/openapi.json GET /v1/number-pools
List number pools in the workspace.
# List number pool members
Source: https://docs.persistence.dev/api-reference/number-pools/members
api-reference/number-pools/openapi.json GET /v1/number-pools/{id}/members
List the phone numbers in a pool.
# Move number pool member
Source: https://docs.persistence.dev/api-reference/number-pools/move-member
api-reference/number-pools/openapi.json POST /v1/number-pools/{id}/members/move
Move a phone number from its current pool into the target pool.
# Number Pools API
Source: https://docs.persistence.dev/api-reference/number-pools/overview
Group phone numbers for campaign caller-ID rotation.
A number pool groups phone numbers that a campaign can use instead of one fixed `fromNumber`. A phone number can belong to one pool at a time.
`GET /v1/number-pools`
`POST /v1/number-pools`
`GET /v1/number-pools/{id}`
`PATCH /v1/number-pools/{id}`
`DELETE /v1/number-pools/{id}`
`GET /v1/number-pools/{id}/members`
`POST /v1/number-pools/{id}/members/move`
`GET /v1/number-pools/{id}/validate-trunks`
Validate outbound trunks before assigning a pool to a campaign. The result reports valid and invalid member counts and identifies invalid numbers.
# Update number pool
Source: https://docs.persistence.dev/api-reference/number-pools/update
api-reference/number-pools/openapi.json PATCH /v1/number-pools/{id}
Update pool details or add and remove phone numbers.
# Validate number pool trunks
Source: https://docs.persistence.dev/api-reference/number-pools/validate-trunks
api-reference/number-pools/openapi.json GET /v1/number-pools/{id}/validate-trunks
Check outbound trunk readiness for every pool member.
# Buy phone number
Source: https://docs.persistence.dev/api-reference/telephony/buy-phone-number
api-reference/telephony/openapi.json POST /v1/telephony/phone-numbers/buy
Buy a phone number from a telephony provider.
# Get phone number
Source: https://docs.persistence.dev/api-reference/telephony/get-phone-number
api-reference/telephony/openapi.json GET /v1/telephony/phone-numbers/{id}
Retrieve a phone number and its configuration.
# Import phone numbers
Source: https://docs.persistence.dev/api-reference/telephony/import-phone-numbers
api-reference/telephony/openapi.json POST /v1/telephony/phone-numbers/import/manual
Import phone numbers with your own SIP termination.
# List phone numbers
Source: https://docs.persistence.dev/api-reference/telephony/list-phone-numbers
api-reference/telephony/openapi.json GET /v1/telephony/phone-numbers
Page through the phone numbers in your workspace.
# Telephony
Source: https://docs.persistence.dev/api-reference/telephony/overview
Manage the phone numbers your agents call from and answer on.
A phone number connects your agents to the telephone network. Buy a number, bind it to the agents that handle its inbound and outbound calls, then use it as the `fromNumber` for outbound campaigns.
## Base URL
```
https://api.persistence.dev
```
These endpoints are served under the public `/v1` prefix.
## Authentication
Every request requires a workspace API key in the `X-API-Key` header.
```bash theme={null}
curl https://api.persistence.dev/v1/telephony/phone-numbers \
--header "X-API-Key: $PERSISTENCE_API_KEY"
```
## Endpoints
`GET /v1/telephony/phone-numbers` — page through the numbers in your workspace.
`POST /v1/telephony/phone-numbers/buy` — buy a number from a provider.
`POST /v1/telephony/phone-numbers/import/manual` — import owned numbers with SIP termination.
`GET /v1/telephony/phone-numbers/{id}` — retrieve a single number.
`PATCH /v1/telephony/phone-numbers/{id}` — bind a number to agents.
## Phone number fields
| Field | Type | Description |
| - | - | - |
| `id` | string | Phone number ID. |
| `phoneNumber` | string | The number itself. |
| `friendlyName` | string | Display name for the number. |
| `label` | string | Label applied to the number. |
| `country` | string | Country the number belongs to. |
| `status` | string | Current status of the number. |
| `provider` | string | Telephony provider the number was bought from. |
| `providerMonthlyCost` | number | Monthly cost charged by the provider. |
| `providerCurrency` | string | Currency of the monthly cost. |
| `isCustomerManaged` | boolean | Whether you supplied the number rather than buying it through Persistence. |
| `isInboundReady` | boolean | Whether the number can receive calls. |
| `isOutboundReady` | boolean | Whether the number can place calls. |
| `inboundAgentPublicId` | string | ID of the agent that answers inbound calls. |
| `inboundAgentName` | string | Name of the inbound agent. |
| `inboundWebhookUrl` | string | Webhook called for inbound calls. |
| `outboundAgentPublicId` | string | ID of the agent used for outbound calls. |
| `outboundAgentName` | string | Name of the outbound agent. |
| `allowedInboundCountries` | array of string | Countries permitted to call this number. |
| `allowedOutboundCountries` | array of string | Countries this number is permitted to call. |
| `sipConfig` | object | SIP trunk configuration for the number. |
| `spaceId` | string | Workspace the number belongs to. |
| `createdAt` | string | Creation timestamp. |
| `updatedAt` | string | Last update timestamp. |
### SIP configuration
`sipConfig` describes the SIP trunk settings for the number.
| Field | Type | Description |
| - | - | - |
| `terminationUrl` | string | SIP termination URL. |
| `username` | string | SIP username. |
| `password` | string | SIP password. |
| `transport` | string | SIP transport. |
| `ipAllowlist` | array of string | IP addresses permitted to connect. |
## Buy a phone number
`POST /v1/telephony/phone-numbers/buy` requires both fields below.
| Field | Type | Description |
| - | - | - |
| `phoneNumber` | string | Required. The number to buy. |
| `provider` | string | Required. The telephony provider to buy the number from. |
Contact Persistence support for the provider values available to your workspace.
The response returns the created phone number. A `402` indicates the purchase could not be completed for billing reasons.
```bash theme={null}
curl --request POST https://api.persistence.dev/v1/telephony/phone-numbers/buy \
--header "X-API-Key: $PERSISTENCE_API_KEY" \
--header "Content-Type: application/json" \
--data '{
"phoneNumber": "+15551234567",
"provider": "PROVIDER"
}'
```
## Bind a number to agents
`PATCH /v1/telephony/phone-numbers/{id}` updates a number and controls which agents handle its calls.
| Field | Description |
| - | - |
| `friendlyName` | Display name for the number. |
| `label` | Label applied to the number. |
| `inboundAgentId` | Agent that answers inbound calls. |
| `outboundAgentId` | Agent used for outbound calls. |
| `useSameForInbound` | Use the outbound agent for inbound calls as well. |
| `outboundTermination` | Outbound termination setting for the number. |
| `allowedInboundCountries` | Countries permitted to call this number. |
| `allowedOutboundCountries` | Countries this number is permitted to call. |
Agent IDs come from the [Agents API](/api-reference/agents/overview). After binding, `isInboundReady` and `isOutboundReady` on the phone number reflect whether the number is ready to handle calls in each direction.
## Pagination and sorting
`GET /v1/telephony/phone-numbers` accepts these query parameters.
| Parameter | Type | Description |
| - | - | - |
| `page` | integer | Page number. |
| `perPage` | integer | Items per page. |
| `column` | string | Sort column, `phone_number` or `created_at`. |
| `order` | string | Sort order, `asc` or `desc`. |
| `searchText` | string | Filter numbers by text. |
The response wraps the results in a paged object containing `items`, `page`, `perPage`, `totalCount`, `column`, `order`, and `searchText`.
## Errors
Errors return a `code` and an `error` message.
```json theme={null}
{
"code": "not_found",
"error": "phone number not found"
}
```
| Status | Meaning |
| - | - |
| `400` | The request body or a path parameter is invalid. |
| `401` | The `X-API-Key` header is missing or invalid. |
| `402` | The number could not be bought for billing reasons. |
| `403` | The key is not permitted to perform the operation. |
| `404` | The phone number does not exist. |
# Update phone number
Source: https://docs.persistence.dev/api-reference/telephony/update-phone-number
api-reference/telephony/openapi.json PATCH /v1/telephony/phone-numbers/{id}
Update a phone number and bind it to the agents that handle its calls.
# Actions and tools
Source: https://docs.persistence.dev/build/actions
Let an agent act during a conversation.
Actions let an agent do more than speak. Add only the tools required for the workflow, give each one a narrow responsibility, and test its failure behavior before publishing.
## Built-in actions
| Action | Purpose |
| - | - |
| **End call** | End the current conversation when its goal is complete or a stop condition is met. |
| **Transfer call** | Transfer to a phone number, SIP URI, dynamic variable, or dynamically selected route using a cold or warm transfer. |
| **Extract dynamic variable** | Store a text, number, boolean, or fixed-choice value for later use. |
| **Capture input** | Collect keypad input with an optional timeout, digit limit, and termination key. |
| **Calendar** | Check availability, book, reschedule, or cancel through a connected calendar. |
| **Custom function** | Send an HTTP request to your service and use the response during the call. |
## Configure a custom function
Give the function a lowercase snake\_case name and explain exactly when the agent should use it.
Choose the method and URL, then add headers, query parameters, and a JSON object schema for inputs.
Decide which fields should be stored as variables and what the agent should say before, during, or after execution. You can play a typing sound while it runs.
Verify timeout, non-success response, missing field, and malformed-response behavior.
Do not place credentials directly in prompts or tool configuration. Store encrypted values under **Settings → Secrets** and reference them through the supported configuration.
## Configure transfers
Choose a static destination or provide routing instructions for a dynamic destination. A destination can be a phone number, SIP URI, or supported dynamic variable.
* A **cold transfer** connects the destination without an agent debrief.
* A **warm transfer** lets the AI provide a debrief to the next agent.
Choose SIP invite or SIP refer according to your provider support. For SIP invite, configure the displayed caller ID and transfer ring duration. Add custom SIP headers only when the receiving system requires them.
## Capture keypad input
Set the expected digit count, termination key, prompt, timeout, confirmation behavior, and variable that stores the result. Test slow entry, early termination, invalid digits, and timeout.
## MCP servers
An agent can connect to an MCP server and expose selected MCP tools. Configure the server URL, headers, query parameters, and timeout, then choose the tools the agent may call. A workspace-global MCP can be available across agents; an agent-specific MCP stays scoped to that agent.
Treat an MCP server like any other privileged integration: grant the smallest useful tool set and verify its authentication and failure behavior.
## Calendar connections
Calendar actions require a connected Cal.com or Calendly account. Manage connections under **Integrations** before adding calendar actions to an agent.
# Agent settings
Source: https://docs.persistence.dev/build/agent-settings
Configure call behavior, speech, transcription, data, and security.
Open an agent and select **Settings** to configure the behavior around its prompt or conversation flow. Agent settings save automatically while you edit the current draft.
## Call settings
* Maximum call duration
* End call after a period of silence
* Voicemail and answering-machine detection, with hang-up or leave-message behavior
* IVR detection and hang-up behavior
* Call recording, consent, and recording beep controls when available
* Keypad and digit handling
## Speech settings
* Voice and language
* Voice speed
* Interruption sensitivity
* Response eagerness
* Reminder-message frequency
* Background ambience and volume
* Voice volume and digit pronunciation
## Instructions and model behavior
Adjust the LLM temperature when you need more or less variation in responses. Persistence appends default guardrails to agent instructions unless you explicitly remove them.
Removing the default guardrails can weaken context boundaries, instruction compliance, topic restrictions, sensitive-data protection, action boundaries, fallback handling, and behavior consistency. Strengthen and test your custom instructions before removing them.
## Transcription settings
* Denoising
* Endpointing behavior
* Vocabulary specialization for domain-specific terms
Test changes with real examples from your callers. Faster endpointing can reduce latency but may cut off a caller who pauses mid-sentence.
## Dynamic variables
Define variables that personalize a prompt, greeting, tool request, or flow. Provide a default value for preview calls and for production calls where the caller-specific value is unavailable.
Use test values in the preview. Do not use production secrets as test variables.
See [Dynamic variables](/build/dynamic-variables) for supported sources and testing guidance.
## Data extraction
Configure extraction triggers for events such as **On Call Ended** or **On Call Transferred**. An extracted category can be text, yes/no, numeric, or a fixed known value.
## Security
Agent security controls include PII protection, anonymization, and redaction. Workspace-level [privacy settings](/accounts/privacy) can provide defaults, while an agent can apply the behavior appropriate for its workflow.
Configure recording consent, data handling, and PII behavior for the laws and policies that apply to your callers. Product controls do not replace legal review.
# Agents
Source: https://docs.persistence.dev/build/agents
Create, manage, publish, import, and restore AI voice agents.
An agent defines how Persistence handles a conversation. Choose the agent structure, configure its behavior, test the draft, and publish it when it is ready for live calls.
## Choose an agent structure
Use one instruction set for flexible conversations that do not require a fixed sequence.
Build a visual flow with explicit conversation, condition, action, transfer, and end nodes.
## Create an agent
In the dashboard, open **Agents** and select **Create Agent**.
Select **Single Prompt** or **Conversation Flow**.
Start from a template that matches the conversation you want to automate. Review the proposed configuration before creating the agent.
Use a name that identifies the workflow, describe its main goal, and optionally provide a public website whose content can help personalize the draft. Enable **Chat only** when the workflow should use text without audio processing.
## Drafts and live versions
Changes are made to a draft. Test that draft before you publish it. Publishing promotes the current configuration for live calls while preserving earlier versions in the version timeline.
You can inspect an earlier version and restore it into a new draft when you need to roll back a change. Superseded versions are read-only.
## Import and export
The **Agents** page supports importing a `.pa` agent package up to 2 MB. An agent can also be exported from its actions menu by selecting a version. Use import and export to move a supported agent configuration without recreating it manually.
## Share an agent preview
Save an agent version, select **Share**, and choose an expiry of 1, 3, 7, or 15 days. A generated link can be opened up to 20 times and is copied to your clipboard.
The recipient can try the shared version without receiving workspace access. Treat the link as access to an agent test: do not configure the shared version to expose secrets, production customer data, or privileged actions.
## Discover reusable agents
Use **Marketplace** to browse agents by job, industry, language, and outcome. Review an agent profile, listen to its sample conversation, inspect its capabilities and integrations, and configure a copy for your workspace.
Before deleting an agent, remove it from phone numbers and active or scheduled campaigns. Persistence blocks deletion while those assignments exist.
## Next steps
Set the voice, call behavior, transcription, data, and security controls.
Start a browser-based voice preview before publishing.
# Build with Composer
Source: https://docs.persistence.dev/build/composer
Create or modify an agent through the AI-assisted workspace.
Composer turns a written goal into an agent configuration. Use it to build a new AI voice agent, modify an existing agent, or explore a workflow before opening the full builder.
## Start a build
State the caller, call direction, goal, information the agent needs, actions it may take, and when it should transfer or end the call.
Attach an existing agent, knowledge base, or document when Composer should use that resource. You can also mention an agent or knowledge base in the message.
Confirm important choices such as structure, voice, and capabilities. Treat generated configuration as a draft that still needs review.
Talk to the generated agent, inspect it in the builder, correct any unsupported assumption, and publish only after simulated calls pass.
Composer keeps chat history so you can return to earlier work. Do not paste credentials or production customer data into a Composer message or attachment.
# Conversation flows
Source: https://docs.persistence.dev/build/conversation-flow
Build structured call logic with a visual flow.
Use a Conversation Flow when a call must follow explicit stages, branch on known conditions, or run actions in a controlled order.
## Flow nodes
| Node | Use it to |
| - | - |
| **Conversation** | Hold a multi-turn conversation for one stage of the call. |
| **Condition** | Route the call by comparing variables with one or more rules. |
| **Function** | Call a configured HTTP function and branch on its result. |
| **MCP** | Run a tool exposed by a configured MCP server. |
| **Extract** | Store text, number, boolean, or known-value data from the conversation. |
| **Transfer call** | Hand the call to a configured destination. |
| **End call** | End the conversation at a defined terminal point. |
## Build a flow
Open **Agents**, select **Create**, and choose **Conversation Flow**.
Use the canvas toolbar to add the nodes required for the workflow. Give each node a name that describes its responsibility.
Connect the start node to the first step, then define the condition or fallback that leads to each next node.
Open a Function, MCP, or Transfer call node to provide its configuration. Keep secret values in workspace secrets rather than plain text.
Test every branch, including the fallback path, before publishing.
The editor saves flow changes as you work. Wait for pending saves to finish before closing the page or starting a test.
## Condition operators
Conditions can compare variables with equality and numeric operators, text containment, or existence checks. Combine rules using **all** when every rule must match, or **any** when one matching rule is sufficient.
Always provide an else or fallback transition for values you did not anticipate.
## Design guidance
* Keep each conversation node focused on one goal.
* Extract a value before a condition depends on it.
* Give functions explicit success and failure transitions.
* Keep transfer and end nodes terminal unless the workflow intentionally continues.
* Test flows with missing, malformed, and unexpected variable values.
# Dynamic variables
Source: https://docs.persistence.dev/build/dynamic-variables
Personalize calls and carry structured values through prompts, flows, and actions.
Dynamic variables let one agent use call-specific values such as a caller name, account reference, campaign attribute, or action result.
## Variable sources
A value can come from:
* Defaults configured on the agent
* Test values entered for a preview
* Recipient metadata supplied for an outbound call or campaign
* An inbound webhook response
* An extraction or action result during the conversation
## Use variables safely
Give every required variable a default so the draft can be saved and previews remain predictable. Use a neutral fallback rather than a fake production value.
Reference variables only in fields that support them, such as instructions, greetings, action requests, and flow conditions. Keep credentials in [Secrets](/accounts/secrets), not dynamic variables.
## Test missing and malformed values
Run a preview with the expected value, an empty value, an unexpected value, and characters that need pronunciation. Confirm that the agent does not expose raw placeholders or take an unsafe branch.
# Knowledge bases
Source: https://docs.persistence.dev/build/knowledge-base
Create reusable knowledge collections and attach them to agents.
A knowledge base gives an agent information it can retrieve during a conversation. Use it for product information, policies, support material, or other content that should remain separate from the core prompt.
## Create a knowledge base
From the dashboard, open **Knowledge Base** and create a knowledge base with a clear name and description.
Upload PDF files up to 5 MB each. Wait until processing finishes before attaching the knowledge base to a production agent.
Open the agent's settings, select **Knowledge Base**, and add the ready knowledge base.
Ask questions that should be answered, should combine nearby information, and should return a fallback because the answer is absent.
## Keep retrieval reliable
Use **Retrieval Testing** to select a knowledge base, enter a representative query, adjust supported retrieval settings, and inspect the chunks the agent would receive.
* Keep each knowledge base focused on one domain.
* Remove obsolete or conflicting documents.
* Use descriptive headings and plain text in source documents.
* Put behavior rules in the agent instructions, not only in the knowledge documents.
* Re-test the agent after adding or deleting a document.
An agent can only use a knowledge base that has finished processing. The agent settings identify knowledge bases that are not ready.
Document processing moves through pending, extracting, chunking, embedding, and ready states. Replace a document when it reaches failed or upload failed.
Knowledge base names can contain up to 128 characters and descriptions up to 512 characters.
Deleting a knowledge base or a source document removes it from future retrieval. Review every agent that depends on that content before deleting it.
Create, list, inspect, and delete knowledge bases through the public API.
# Models and voice pipelines
Source: https://docs.persistence.dev/build/models-and-pipelines
Choose the language, models, and processing pipeline for an agent.
An agent can use a cascaded voice pipeline or a realtime model, depending on the models available in your workspace.
## Cascaded pipeline
A cascaded pipeline uses separate components for speech-to-text, language generation, and text-to-speech. It gives you direct control over the transcription model, LLM, and voice.
## Realtime pipeline
A realtime pipeline uses a realtime model for the conversation. Some configurations use realtime audio directly, while others pair a realtime model with a selected text-to-speech voice.
## Choose a configuration
Select the conversation language first, then choose compatible models and a voice. Review the model's supported language, context window, and specialization in the builder.
Use a representative simulated call to compare:
* Transcription accuracy for names, numbers, and domain terms
* Voice quality and pronunciation
* Response latency
* Interruption and endpointing behavior
* Action execution and structured output
Change one model or speech setting at a time so you can attribute the result.
# Single-prompt agents
Source: https://docs.persistence.dev/build/single-prompt
Define an agent's behavior with one structured instruction set.
A single-prompt agent uses one instruction set throughout the conversation. It works well when the caller can move between topics and the agent should decide the next response from context.
## Write the instructions
Open a single-prompt agent and edit **Instructions**. A useful prompt separates the agent's role, goal, information, conversation rules, and fallback behavior.
```text theme={null}
Role
You are Acme's returns assistant.
Goal
Answer questions about the returns policy and collect the order number.
Policy
- Unused items can be returned within 30 days of delivery.
- Refunds return to the original payment method.
Conversation rules
- Ask one question at a time.
- Keep responses concise and natural for a phone call.
- Confirm important numbers before continuing.
Fallback
If the prompt or connected knowledge does not contain the answer, say you do not know.
```
## Configure the first message
Choose whether the AI or the caller starts the conversation. For an AI-first call, configure a static greeting or instructions for a generated greeting. You can also control the pause before the greeting and whether the caller may interrupt it.
Use dynamic variables in the greeting or instructions when the value changes per call. Define a default value so previews and calls still behave predictably when a value is missing.
## Connect data and actions
* Attach a [knowledge base](/build/knowledge-base) for information that is too large or changes too often to place in the prompt.
* Add [actions](/build/actions) when the agent needs to end or transfer a call, call an API, capture keypad input, extract values, or use a calendar.
* Configure post-call extraction when you need structured results after the conversation.
## Test the boundaries
Test the intended path and at least these failure paths:
* The caller asks for information that is not available.
* A required dynamic variable is missing.
* A tool returns an error or times out.
* The caller interrupts or stays silent.
* The caller gives an ambiguous date, phone number, or identifier.
Change one prompt section at a time, repeat the same test, and compare the result before publishing.
# Voices
Source: https://docs.persistence.dev/build/voices
Browse, preview, organize, and create voices for agents.
The voice library contains text-to-speech and speech-to-speech voices available to your workspace. Preview a voice with the same kind of sentence your agent will use before assigning it.
## Find a voice
Open **Voices** to search and filter the library. Available filters can include provider, language, accent, gender, age, traits, and voice category.
The library can include voices from Cartesia, ElevenLabs, MiniMax, OpenAI, and custom sources. Availability depends on the current workspace configuration.
## Preview consistently
Enter a specimen script to hear the same text across candidate voices. Test names, dates, amounts, product terms, and phone numbers that occur in the real workflow.
When you select a voice for an agent, also configure its language and speaking speed. Use the browser preview to check pacing and interruption behavior over a complete conversation.
## Voice collections
Use **Collections** to group voices for a team, brand, language, or use case. Adding a voice to a collection does not change the voice itself.
You can copy a voice ID from the library for a supported integration. Deleting a collection unlinks its voices; it does not delete the underlying voices.
## Clone a voice
The **Custom voices** page supports creating a Cartesia voice from a clean recording.
Use WAV, MP3, FLAC, OGG, M4A, or WebM audio smaller than 10 MB. Record one speaker in a quiet environment.
Confirm that you have permission to clone and use the speaker's voice.
Name the voice, upload or record the clip, create the clone, and preview it before using it in an agent.
Only clone a voice when you have the speaker's authorization. Voice consent is a product requirement and may also be a legal requirement in your jurisdiction.
You can edit the local name and description of a cloned voice. Deleting a custom voice permanently removes it, so update any dependent agent first.
# API-triggered calls
Source: https://docs.persistence.dev/deploy/api-triggered-calls
Start outbound call batches with the Persistence API.
Use the public Calls API when your application needs to start outbound calls without creating a dashboard campaign.
An outbound batch identifies the caller ID, recipients, concurrency, and optional schedule. Recipient metadata becomes call-specific context for the agent. You can use the phone number's assigned outbound agent or provide an agent override supported by the request.
## Before you call the API
* Publish the agent version you intend to use.
* Configure and activate the caller phone number.
* Create an API key with the call permission required by the endpoint.
* Validate every destination and remove recipients covered by DND requirements.
* Choose a safe concurrency value for downstream actions and integrations.
The API accepts up to 1,000 recipients in one batch. Inspect rejected recipients in the response instead of assuming the complete batch was accepted.
Use the end-call endpoint only with the session identifier returned for the active call.
Review the batch-call and end-call contracts.
# Outbound campaigns
Source: https://docs.persistence.dev/deploy/campaigns
Configure, schedule, and control outbound calling campaigns.
Campaigns use an agent, phone number, and contact groups to place outbound calls.
## Create a campaign
Open **Campaigns**, select **New campaign**, and enter a campaign name. Select a phone number that has the intended outbound agent assigned.
Choose how many calls the campaign can make concurrently. Use a level your workflow and connected services can support.
Add at least one contact group. Include the DND groups that apply to the campaign.
Start immediately or choose a start date and time. For a scheduled window, set its start, end, and repeat days.
Review the reach analysis, then confirm the agent, phone number, included and excluded audiences, schedule, and concurrency before you start or schedule the campaign.
## Control a campaign
The campaign list shows its current state. Depending on that state, you can start, pause, resume, or cancel the campaign. A campaign can move through states including draft, scheduled, running, paused, completed, cancelled, failed, or stopped.
Open campaign details to review total contacts and call progress, including pending, queued, dialing, answered, and failed attempts.
Edit a campaign only when its current state allows configuration changes. Pausing stops new campaign work while preserving progress; cancelling ends the campaign lifecycle.
Confirm consent, calling hours, DND groups, and other requirements that apply to your calls before launch.
# Audiences and contacts
Source: https://docs.persistence.dev/deploy/contact-lists
Manage campaign audiences, individual contacts, and do-not-contact suppression lists.
Audiences define who a campaign may call. Contacts are the individual people or phone numbers in those audiences. Do-not-contact lists, also called DNC or DND groups, define numbers that must not receive calls.
## Create a group
Open **Audiences** or **Contacts**, start an upload, enter a name, and choose whether the file supplies callable contacts or suppression entries.
Download the template when you need the expected file shape. Upload one `.csv`, `.xlsx`, or `.xls` file up to 21 MB, or import contacts from a connected HubSpot or Salesforce account.
Review the valid, invalid, and duplicate number counts. Persistence excludes invalid and duplicate numbers when you save the group.
Save the processed group, then select it when you configure a campaign audience.
Use a DNC or DND suppression list for numbers that must not receive campaign calls. Review suppression coverage before every launch.
You can replace the uploaded list or edit the group name and type. Check campaigns that use the group before you delete it.
Open a group to review entries and their metadata. A saved group can be ready while individual numbers remain active or blocked.
# Inbound webhooks
Source: https://docs.persistence.dev/deploy/inbound-webhooks
Provide call-specific variables or reject an inbound call before the agent starts.
An inbound webhook lets your application make a decision when a configured phone number receives a call. The runtime invokes the endpoint before the agent conversation starts.
Use the webhook to return dynamic variables needed by the greeting, prompt, flow, or actions. Your endpoint can also reject the call when your application decides it should not proceed.
## Configure the endpoint
Open a phone number's inbound configuration, enter an HTTPS webhook URL, and use **Test** to inspect the response before enabling live traffic.
Design the endpoint to:
* Respond within the configured timeout
* Return dynamic variables as string-compatible values
* Avoid returning credentials or unnecessary personal data
* Handle retries without causing duplicate side effects
* Fail safely when the caller or account cannot be resolved
Keep authorization values in secrets or the supported phone configuration. Monitor webhook failures alongside the related conversation or observability session.
# Phone numbers
Source: https://docs.persistence.dev/deploy/phone-numbers
Buy or import a phone number and connect it to an agent.
Phone numbers connect published agents to inbound and outbound calls.
## Add a number
Open **Numbers** and select **Add number**. Choose the path that matches your phone setup:
Search available inventory and buy a number for the workspace.
Import numbers from a connected Twilio or Telnyx account.
Add a custom phone number and SIP configuration.
## Configure routing
Open a number to assign its inbound and outbound agents. Publish the agent version you want to use before routing live calls to it.
You can also configure supported controls for the number, including:
* Allowed inbound countries
* Allowed outbound countries
* SIP settings for a manually connected number
* An inbound webhook for events that need to reach your application
For custom SIP, configure the outbound termination URL, optional credentials, transport, and inbound trunk information supplied by your provider. Test the inbound webhook before saving it.
Verify the selected agent, phone number, and country restrictions before you enable production traffic.
## Remove a number
Unassign agents and confirm that no active workflow depends on the number before you remove it. Removing a number can stop inbound or outbound calls that use it.
You can deactivate a number temporarily and activate it again later. A deactivated number is unavailable for calls.
# Persistence documentation
Source: https://docs.persistence.dev/index
Put phone conversations on autopilot.
## Welcome to Persistence
Persistence is the platform for voice AI agents that handle phone calls the way a person would — and finish the task instead of passing it along.
Take one call workflow from prompt to live phone number.
How build, test, deploy, and performance fit together.
Choose a single prompt or visual conversation flow.
Connect phone numbers and launch outbound campaigns.
Investigate conversations, latency, tools, and errors.
## What Persistence does
Define an agent in a single prompt. Connect a knowledge base and define actions. Test with simulated calls before launch, then connect phone calls and review live performance.
Define the agent's behavior in one prompt, then connect the knowledge and actions it needs.
Run simulated calls across expected paths, edge cases, and accents.
Provision a number, use a SIP trunk, or trigger calls through the API.
Review containment, conversion, sentiment, and latency.
## What you can build
Answer from your knowledge base and escalate when needed.
Call leads in seconds, qualify them, push results onward.
Check availability, book, and reschedule on the call.
Run reminders and follow-ups at scale from a contact list.
# Calendar integrations
Source: https://docs.persistence.dev/integrations/calendars
Connect Cal.com or Calendly and give an agent selected booking actions.
Persistence supports Cal.com and Calendly connections for calendar actions.
## Connect a calendar
For Cal.com, use an API key. For Calendly, use a personal access token. Store reusable credentials in [Secrets](/accounts/secrets).
Open **Integrations**, choose the provider, name the account, and enter or reference its credential.
In the agent's calendar action, select the connection and event type.
Enable at least one of **Check availability**, **Book appointment**, **Cancel booking**, or **Reschedule booking**.
Describe when the agent should use the calendar and what it must confirm before making a change. Test time zones, unavailable slots, ambiguous dates, and provider errors.
# CRM integrations
Source: https://docs.persistence.dev/integrations/crm
Connect HubSpot or Salesforce for CRM tools and contact imports.
Persistence supports HubSpot and Salesforce connections.
Connected CRM accounts can provide agent tools and contact-group imports. Available tools can include lead, contact, case, deal, query, and task operations, depending on the provider.
## Import campaign contacts
Open **Integrations**, choose HubSpot or Salesforce, and complete the provider authorization.
Open **Contacts**, select **New contact group**, and choose the connected CRM as the import source.
Confirm the imported, valid, invalid, and duplicate counts before saving the group.
Grant only the CRM permissions needed by the workflow. Test create or update actions with non-production records before enabling them for live calls.
# Integrations
Source: https://docs.persistence.dev/integrations/overview
Connect calendar, CRM, and messaging services to Persistence.
Integrations let agents use approved external services and let workspaces import campaign contacts.
The catalog can show additional services as they become available to a workspace. Configure only integrations supported by your current workspace and release channel.
## Available integration types
| Integration | Use in Persistence |
| - | - |
| [Calendly](/integrations/calendars) | Check availability and manage bookings |
| [Cal.com](/integrations/calendars) | Check availability and manage bookings |
| [HubSpot](/integrations/crm) | Use CRM tools and import contacts |
| [Salesforce](/integrations/crm) | Use CRM tools and import contacts |
| [Slack](/integrations/slack) | Send messages to selected workspace channels |
## Connect an account
Choose the service you want to connect and start its connection flow.
Complete the provider's authorization or enter the credential requested by the connection form.
Choose only the accounts, calendars, or Slack channels that the workflow needs when those controls are available.
Add the related action to an agent or select the CRM while creating a contact group.
Treat provider credentials as secrets. Store reusable values in the workspace secret controls instead of placing them in prompts or documentation.
Test the connected action in a simulated call before publishing the agent.
Disconnecting an account makes its tools unavailable to agents immediately. Review dependent agents and contact-import workflows first.
# Slack integration
Source: https://docs.persistence.dev/integrations/slack
Connect Slack and restrict which channels an agent may use.
The Slack integration lets an agent send messages to approved channels.
## Connect Slack
Open **Integrations**, choose **Slack**, provide a unique account name, and complete the Bot OAuth connection.
Choose the public or private channels the bot may use. Do not approve channels unrelated to the workflow.
Make the connected **Send message** tool available only to agents that require it.
Run a simulated call and verify the destination, content, failure behavior, and absence of sensitive data.
Disconnecting the account immediately stops agents from using its tools. Review agent dependencies before disconnecting or removing channel access.
# Alerts and activity
Source: https://docs.persistence.dev/monitor/alerts
Monitor incidents and audit important workspace changes.
Alerts identify operational conditions that need attention. Activity records important workspace and system events so a team can understand what changed and who or what initiated it.
## Review an alert
Use severity, status, date, resource type, and saved filters to narrow the incident list. Open an incident to review the affected resource, start time, acknowledgement, resolution, and related activity.
Create alert rules only for conditions that have a clear owner and response. Snooze an alert when investigation is already in progress, and unsnooze it when notifications should resume.
## Audit activity
Use **Activity** to review events such as agent configuration changes, campaign starts or failures, integration changes, role changes, import failures, and usage or cost events. Pair an activity entry with the relevant agent version, campaign, conversation, or integration record when investigating.
An activity record explains that an event occurred. It does not replace provider logs, conversation details, or an incident-response record when deeper evidence is required.
# Analytics and observability
Source: https://docs.persistence.dev/monitor/analytics
Track outcomes, latency, errors, and tool performance across calls.
Analytics summarizes call activity and performance. Observability helps you isolate where time and errors occur inside a session.
## Review analytics
Use **Analytics** to track live calls, total calls, P50 and P90 duration, answer and pickup rates, transfer rate, average cost, P50 and P90 latency, call volume, dispositions, and duration distribution. Apply the available date and agent filters before comparing periods.
Pair aggregate metrics with conversation reviews. A trend shows where to investigate; the transcript and call details show what happened.
## Diagnose with observability
Open **Observability** to review:
* Voice-to-voice latency at the 95th percentile
* Greeting latency at the 95th percentile
* Tool success rate and error rate
* Voice-to-voice latency by component and model
* Session end-reason distribution
* Tool execution count, success rate, and duration
The sessions view lets you filter sessions, open a session, and inspect its greeting, interruptions, tools, errors, and turn waterfall.
## Improve safely
Choose a measurable target, change one agent component, test the draft, and publish a new version. Compare the same filters and time window after enough calls have completed.
# Conversations
Source: https://docs.persistence.dev/monitor/conversations
Inspect completed and live calls to understand agent behavior.
Use **Conversations** to investigate individual calls and find patterns that require an agent change.
## Review a call
Filter conversations by time range, agent, campaign, collection, tag, status, channel, end result, or user sentiment. Open a conversation to review its summary, call details, transcription, activity log, and recording when available.
Focus on:
* Whether the call reached its intended result
* The end reason and call duration
* What the caller said before a wrong or delayed response
* Which actions ran and whether they succeeded
* User sentiment and end-to-end latency
End results distinguish connected hangups, transfers, voicemail, IVR detection, no answer, and failures. Activity logs show events such as participants joining or leaving, transfers, voicemail detection, and call ending.
## Monitor active calls
Open **Live calls** to see calls that are currently in progress. Use live monitoring for operational awareness; use the completed conversation record for a full investigation after the call ends.
## Turn findings into changes
Group similar failures before changing an agent. Update one part of the draft—prompt, flow, knowledge, action, or speech setting—then run simulated calls and publish a new version.
Use [collections and exports](/monitor/exports-and-collections) when you need a repeatable review cohort or a filtered data extract.
# Exports and collections
Source: https://docs.persistence.dev/monitor/exports-and-collections
Organize conversation reviews and export filtered results.
Collections group related conversations for review. Exports let you take a filtered result set into an approved analysis workflow.
## Use collections
Create a collection with a descriptive name, then add or remove conversations from it. Use collections for a bounded review set such as a campaign cohort, escalation sample, or regression test.
Deleting a collection unlinks its conversations; it does not describe a deletion of the conversations themselves.
## Export conversations
Apply filters for time range, agent, campaign, collection, tag, status, channel, end result, or sentiment, then select **Export**. Persistence starts the export using the active filters.
Review exported data under your organization's storage, access, and retention requirements. Apply PII controls before sharing or moving call data.
# Platform concepts
Source: https://docs.persistence.dev/platform
How build, test, deploy, and performance fit together.
Persistence brings agent design, pre-launch simulation, phone connectivity, and live performance insights into one workflow.
## Build
Define the conversation, the knowledge the agent can use, and the actions it can take.
Design a structured conversation as a visual flow.
Define the agent behavior in one prompt.
Connect the information the agent should use during calls.
Define what the agent can do while handling a call.
## Test
Challenge the agent before it handles live phone calls.
Run call simulations before launch.
Exercise varied paths and accents so issues surface early.
## Deploy
Connect the agent to phone calls through the path that fits your setup.
Provision a number and activate the agent.
Use your SIP trunk for phone connectivity.
Trigger calls through an API.
Run outbound calling at scale.
## Improve performance
Use live call metrics and session details to decide what to refine next.
Track whether calls achieve the intended outcome.
Review caller sentiment and response latency.
Inspect transcripts, recordings, outcomes, and call details.
## API information
Review the API information included in the current public documentation.
# Quickstart
Source: https://docs.persistence.dev/quickstart
Build, test, publish, and improve your first AI voice agent in the Persistence dashboard.
Build a simple returns assistant, test it in your browser, and publish it from the Persistence dashboard. You can adapt the example to your own phone-call workflow.
**Estimated time:** 30 minutes
## Before you begin
* Get access to the [Persistence dashboard](https://dashboard.persistence.dev).
* Use a browser with microphone access for the web preview.
* Choose one call type and one result for your first agent.
This example answers questions about a fictional returns policy. It does not use external knowledge or actions, so you can test the core conversation first.
## Build the agent
In the dashboard, open **Agents** and select **Create Agent**. Choose **Single Prompt**, select a template and use case, then review the agent details.
Enter:
* **Agent name:** `Returns assistant`
* **Description:** `Answers questions about the Acme returns policy`
Complete the creation flow. The agent builder opens and marks the new agent as a draft.
Select the language and voice that fit your callers. Keep the default model for this first test.
Replace the content in **Instructions** with this single prompt:
```text theme={null}
You are Acme's returns assistant.
Goal
Answer callers' questions about the returns policy.
Policy
- Acme accepts unused items within 30 days of delivery.
- The caller needs the order number and the email used for the order.
- Refunds return to the original payment method.
Rules
- Keep each response under 30 words.
- Ask one question at a time.
- Use only the policy in this prompt.
- If the policy does not answer a question, say you do not know.
```
This prompt gives the agent one goal, the information it can use, and a fallback for questions it cannot answer.
Skip this step for the example, or extend your own agent:
* Open **Knowledge base** to add documents the agent can reference.
* Open **Functions** to add the actions your workflow needs.
Add only the knowledge and actions required for the call's intended result.
## Test the conversation
In **Preview agent**, select **Web**, then select **Start talking**. Allow microphone access when your browser asks.
Test the expected path:
> I received an unused item 10 days ago. Can I return it?
The agent should confirm that the item is within the 30-day return window and explain what information the caller needs.
Then test a question outside the supplied policy:
> Can I exchange the item at a retail store?
The agent should say that it does not know. It should not invent an exchange policy.
Run more simulated calls for your real workflow. Include edge cases and a range of accents. Update the prompt, knowledge, or actions when a test exposes a problem, then test again.
## Publish and deploy
When the agent handles the test calls as expected, select **Publish** in the agent builder.
Publishing makes the current agent configuration available for live calls. Connect it through the deployment path approved for your setup:
* Provision a phone number.
* Use a SIP trunk.
* Trigger calls through the API.
The controls available for these paths can differ by workspace. Confirm the destination number and agent before you route production calls.
## Improve the agent
After the agent handles calls, open **Conversations** and filter the results by agent. Review the call status, end result, end-to-end latency, and user sentiment.
Use these results to assess containment and conversion. Change one part of the prompt, knowledge, or actions at a time. Test the draft again before you publish the next version.
## Troubleshooting
### Create is unavailable
Select an agent type and complete both **Agent name** and **Description**.
### The web preview cannot hear you
Allow microphone access in your browser and confirm that the browser uses the correct input device. Restart the preview after you change the permission or device.
### The agent invents an answer
Add a direct fallback instruction, such as `If the provided information does not answer a question, say you do not know.` Add the missing information to the prompt or knowledge base only after you verify it.
### Your deployment path is not visible
Deployment options depend on your phone setup and workspace. Use the supported phone number, SIP trunk, or API-triggered path available to you.
## Next steps
See how build, test, deploy, and improve fit together.
Automate supported Persistence workflows.
# File and workflow limits
Source: https://docs.persistence.dev/reference/limits
Verified limits enforced by the dashboard and public API.
These limits are enforced by the current product interfaces or public API.
| Resource | Limit |
| - | - |
| Agent import package | One `.pa` file up to 2 MB |
| Knowledge base document | PDF only, up to 5 MB per file |
| Voice-cloning clip | WAV, MP3, FLAC, OGG, M4A, or WebM under 10 MB |
| Contact-group upload | One `.csv`, `.xlsx`, or `.xls` file up to 21 MB |
| API outbound batch | Up to 1,000 recipients |
| Shared agent link | Expires after 1, 3, 7, or 15 days; up to 20 opens |
| Knowledge base name | Up to 128 characters |
| Knowledge base description | Up to 512 characters |
| Agent API name | Up to 64 characters |
| Agent API description | Up to 512 characters |
| Workspace API keys | One active key at a time |
Limits can differ from provider quotas and workspace permissions. A campaign's concurrency cannot exceed the workspace concurrency available to it.
# Go-live checklist
Source: https://docs.persistence.dev/test/go-live-checklist
Verify an agent, its dependencies, and its deployment before production traffic.
## Agent
* The prompt or every flow branch has a clear goal, fallback, transfer, and ending.
* The intended version is published.
* Required dynamic variables have safe defaults.
* Knowledge bases are ready and contain current, non-conflicting information.
* Actions and MCP tools have the smallest required access and tested failure behavior.
* Secrets are stored in Secret Manager rather than prompts or variables.
## Conversation quality
* Web and phone previews pass the expected path and important failure paths.
* Names, dates, amounts, identifiers, and domain terms are pronounced and transcribed correctly.
* Silence, interruption, background noise, DTMF, voicemail, IVR, and transfers behave as intended.
* Maximum duration and end-call conditions prevent an unbounded call.
## Privacy and operations
* Recording, consent, PII, retention, and calling policies match your requirements.
* Phone numbers are active, ready, assigned to the correct agents, and restricted to intended countries.
* Inbound webhooks and external actions meet timeout and retry expectations.
* Campaign contacts are validated and applicable DND groups are included.
* Payment method, credit, and concurrency are ready for the expected traffic.
## Monitoring
* The team knows which conversations, outcomes, latency, tool errors, and end reasons to monitor.
* A rollback version and owner are identified.
* The first production cohort is small enough to review before traffic expands.
# Test by phone
Source: https://docs.persistence.dev/test/phone-preview
Run a telephony preview before assigning production traffic.
A phone preview lets you test the agent through the telephony path instead of the browser microphone.
## Start a test call
Open the agent preview, select the phone option, enter the destination requested by the preview, and start the call. Answer the incoming test call and exercise the same paths you use in web preview.
Test telephony-specific behavior:
* The configured greeting and opening pause
* Number and keypad pronunciation
* DTMF capture and termination keys
* Voicemail and answering-machine behavior
* IVR detection
* Cold and warm transfers
* Silence and maximum-duration endings
A valid payment method may be required for telephony previews. The preview uses live phone connectivity and can incur usage.
Use test phone numbers and non-sensitive data. Publish only after both the conversation logic and telephony behavior pass.
# Simulation suites
Source: https://docs.persistence.dev/test/simulation
Run repeatable conversation suites and release gates before deployment.
Simulation suites test agents across repeatable scenarios before deployment. Use them when a workflow needs more coverage than a single manual preview can provide.
## Build a useful suite
Create scenarios for the expected conversation, missing or malformed information, caller interruptions, tool failures, transfers, voicemail, silence, and policy boundaries. Select the agent version and test methods the suite should exercise.
## Review results
Use the suite pass rate and failed-scenario count to find regressions. Open a failed run, inspect the transcript and evaluation result, correct the prompt, flow, action, knowledge, or speech settings, and run the suite again.
Mark critical suites as release gates so a failing result is visible before deployment. A passing suite is evidence for the tested scenarios, not a guarantee that every production call will succeed.
Keep suites small enough to diagnose quickly, and separate critical release gates from broader exploratory coverage.
# Test in the web preview
Source: https://docs.persistence.dev/test/web-preview
Run simulated calls before you route live traffic to an agent.
Use the web preview to test a draft agent through your browser microphone or text chat. A simulated call lets you check the conversation without assigning a phone number.
## Start a simulated call
Open **Agents**, select an agent, and make the draft you want to test active in the builder.
In the preview, enter values for any dynamic variables the agent expects. Use test data only.
Select **Start talking** and allow microphone access when your browser asks. For a text-only test, select **Start chatting** instead.
Test the expected path, missing information, interruptions, silence, and requests that should invoke an action.
## What to verify
* The greeting matches the call direction and opening mode.
* The agent asks one clear question at a time.
* Knowledge answers stay grounded in the connected sources.
* Actions receive the required values and handle failures safely.
* Transfers and call endings happen only under the intended conditions.
* The agent responds correctly when a caller interrupts or pauses.
Change the prompt, flow, knowledge, or settings when a test fails. Start a new simulated call after each meaningful change.
Test with several speakers and audio environments. A successful happy-path call does not cover interruptions, background noise, or ambiguous answers.
## Before you publish
Confirm that the draft passes your expected path and important failure paths. Then publish the version and assign it to a deployment path.
# Troubleshooting
Source: https://docs.persistence.dev/troubleshooting/common-issues
Resolve common agent, preview, telephony, integration, and campaign issues.
## An agent will not publish
Check the required system prompt, language and models, voice, greeting, ambience, actions, extraction triggers, and dynamic-variable defaults. Wait for any pending autosave before publishing again.
## A knowledge base cannot be attached
Only a knowledge base in **Ready** state can be attached. Open it to find documents that are pending, processing, or failed. Replace a failed PDF and wait for processing to finish.
## A preview cannot start
Confirm microphone permission for a web preview. A valid payment method may be required for web and phone previews. Also verify that the draft has compatible language, model, and voice settings.
## A phone number cannot place calls
Confirm that the number is active and ready, has an outbound agent, allows the destination country, and has valid provider or SIP configuration. Check workspace credit or payment method when a paid operation fails.
## A campaign cannot start
Confirm that it has a name, an active phone number with an outbound agent, at least one contact group, a valid schedule, concurrency, and a payment method or credit. Review DND groups and excluded invalid contacts.
## An action or integration fails
Check the endpoint or provider connection, secret reference, selected permissions, timeout, required parameters, and response shape. For Slack, confirm the channel remains allowed. For calendars, refresh the event type and fields.
## Sign-in loops or expires
Return to the dashboard and start a fresh login. Reused links, old tabs, strict cookie settings, and expired passcodes can invalidate the login session.