# Switchboard — v1

## Available Sections

Use `?section=<slug>` to fetch detailed docs for a single resource group.
Use `?section=overview` for authentication, filtering, and error handling reference.

### `account`
Verify your API credentials and view your account's organization and permissions.
Endpoints: `GET /v1/whoami`

### `broadcasts`
Text messages sent to an audience (from a Phone List or Saved Search). List, create (Beta), send (Beta), schedule (Beta), preview (Beta), and export broadcasts, as well as view and export individual messages.
Endpoints: `GET /v1/broadcasts`, `POST /v1/broadcasts`, `POST /v1/broadcasts/export`, `GET /v1/broadcasts/{broadcast_id}`, `POST /v1/broadcasts/{broadcast_id}/send`, `POST /v1/broadcasts/{broadcast_id}/schedule`, `POST /v1/broadcasts/{broadcast_id}/unschedule`, `GET /v1/broadcasts/{broadcast_id}/preview`, `GET /v1/broadcasts/{broadcast_id}/phone_messages`, `POST /v1/broadcasts/{broadcast_id}/phone_messages/export`

### `email-blasts`
Email messages sent to an audience (from an Email List or Saved Search). View email blasts, list their individual messages, and export blast data or message-level details.
Endpoints: `GET /v1/email_blasts`, `POST /v1/email_blasts/export`, `GET /v1/email_blasts/{blast_id}`, `GET /v1/email_blasts/{blast_id}/email_messages`, `POST /v1/email_blasts/{blast_id}/email_messages/export`

### `email-lists`
Named collections of emails, typically created by uploading a CSV file. Email lists can be used as audiences for email blasts. Create lists from CSV, view list details, manage labels, and export list members.
Endpoints: `POST /v1/email_lists`, `GET /v1/email_lists`, `GET /v1/email_lists/{email_list_id}`, `POST /v1/email_lists/{email_list_id}/export`, `POST /v1/email_lists/{email_list_id}/update_labels`

### `emails`
Individual email addresses in your organization. Each email has associated metadata (name, location, labels). List, create, update labels, and export emails.
Endpoints: `GET /v1/emails`, `POST /v1/emails`, `POST /v1/emails/update_labels`, `POST /v1/emails/export`, `POST /v1/emails/export_unsubscribes`

### `inbox`
Inbound text messages received by your organization. Export inbox messages with optional filtering by reply status.
Endpoints: `POST /v1/inbox/export`

### `jobs`
Asynchronous operations such as CSV exports and list processing. When you trigger an export or create a list from CSV, a job is created. Poll the job endpoint to check status (PROCESSING → COMPLETED/ERROR) and retrieve result URLs.
Endpoints: `GET /v1/jobs`, `GET /v1/jobs/{job_id}`

### `labels`
Tags for organizing and segmenting phones and emails. Labels can be attached to phones or emails individually or in bulk. Create, list, view, and rename labels.
Endpoints: `GET /v1/labels`, `POST /v1/labels`, `GET /v1/labels/{label_id}`, `PATCH /v1/labels/{label_id}`

### `phone-lists`
Named collections of phones, typically created by uploading a CSV file. Phone lists can be used as broadcast audiences. Create lists from CSV, view list details, manage labels, and export list members.
Endpoints: `POST /v1/phone_lists`, `GET /v1/phone_lists`, `GET /v1/phone_lists/{phone_list_id}`, `POST /v1/phone_lists/{phone_list_id}/export`, `POST /v1/phone_lists/{phone_list_id}/update_labels`

### `phones`
Individual phone numbers in your organization. Each phone has associated metadata (name, location, carrier, opt-in status, labels). List, create, update labels, export phones, and export opt-outs.
Endpoints: `GET /v1/phones`, `POST /v1/phones`, `GET /v1/phones/{phone_number}`, `GET /v1/phones/{phone_number}/messages`, `POST /v1/phones/{phone_number}/messages`, `POST /v1/phones/update_labels`, `POST /v1/phones/export`, `POST /v1/phones/export_opt_outs`

### `saved-searches`
Reusable dynamic queries over phones and emails. Define search criteria to select a set of phones or emails, then use the saved search as a broadcast audience or export its results.
Endpoints: `GET /v1/saved_searches`, `POST /v1/saved_searches`, `GET /v1/saved_searches/{saved_search_id}`, `POST /v1/saved_searches/{saved_search_id}/convert_to_list`, `POST /v1/saved_searches/{saved_search_id}/refresh`, `POST /v1/saved_searches/{saved_search_id}/export`

### `sql-mirror-datasets`
BigQuery datasets that mirror your organization's Switchboard data for SQL-based analytics. List your organization's SQL mirror datasets.
Endpoints: `GET /v1/sql_mirror_datasets`

### `uploaded-media`
Images and media files for use in broadcasts (Beta). Upload media from a URL for attachment to broadcast messages.
Endpoints: `GET /v1/uploaded_media`, `POST /v1/uploaded_media`


## Common Response Fields

All endpoints return these fields in every response:

- `errors`: array of objects


## Quick Start

Get up and running in three steps:

**1. Get your credentials** — Visit [Organization Settings](https://oneswitchboard.com/organization/settings?tab=api) or [Account Settings](https://oneswitchboard.com/account?tab=api) and generate API credentials. You'll receive an **Account ID** and **Secret Key**. Save the Secret Key securely — it cannot be retrieved again.

**2. Verify your credentials** — Call the `whoami` endpoint to confirm everything works:

```bash
curl -u YOUR_ACCOUNT_ID:YOUR_SECRET_KEY https://api.oneswitchboard.com/v1/whoami
```

A successful response returns your organization name and roles.

**3. Make your first data request** — List your phones:

```bash
curl -u YOUR_ACCOUNT_ID:YOUR_SECRET_KEY https://api.oneswitchboard.com/v1/phones
```

From here, explore the endpoints below to manage phones and emails, send broadcasts, run exports, and more.

## Key Concepts

Here are the core resources you'll work with:

- **Phones** — Individual phone numbers in your organization, with metadata like name, location, carrier, opt-in status, and labels.
- **Emails** — Individual email addresses in your organization, with metadata like name, location, and labels.
- **Broadcasts** — Text messages sent to an audience (from a Phone List or Saved Search). Create a broadcast, set a message and audience, then send or schedule it.
- **Email Blasts** — Email messages sent to an audience (from an Email List or Saved Search). The email equivalent of Broadcasts.
- **Phone Lists / Email Lists** — Named collections of phones or emails, typically created by uploading a CSV file. Used as audiences for broadcasts and email blasts.
- **Labels** — Tags you attach to phones and emails for segmentation and organization (e.g., "VIP", "Donor", "Volunteer").
- **Saved Searches** — Reusable dynamic queries that define a set of phones or emails matching specific criteria. Can be used as broadcast audiences or exported.
- **Jobs** — Asynchronous operations (exports, list processing). Many operations return a job URL you poll for results.
- **Uploaded Media** — Images and media files that can be attached to broadcasts (Beta).

## Feedback and Support

Switchboard's API is currently in Beta. For any feedback or questions, please email developers@oneswitchboard.com.

For a history of API changes, see the [API Changelog](https://swtch.help/api-changelog).

## Authentication

In order to access the API, you'll need to set up credentials within Switchboard.

There are two places to create API credentials:

- **Organization API Credentials** — Visit [Organization Settings](https://oneswitchboard.com/organization/settings?tab=api) to create a key scoped to a single organization.
- **Account API Credentials** — Visit [Account Settings](https://oneswitchboard.com/account?tab=api) to create a key with access to one or more organizations.

You will receive an Account ID and a Secret Key. Note that you will not be able to access the
Secret Key again, so be sure to save it somewhere secure.

This API uses HTTP Basic Authentication. When making requests, you must pass in that Account ID and
Secret Key as the Basic Auth username and password, respectively.

## Multi-Organization Keys

API keys can be granted access to multiple organizations. This is useful if you manage several organizations and want to use a single credential across them.

**Reading data** — List endpoints automatically return results from all organizations your key can access. Use the `organization_id` filter to narrow results to a specific organization (see [Filtering](#section/Filtering)).

**Creating resources** — When making a create/POST request with a multi-organization key, you must include the `organization_id` field in the request body to specify which organization the resource belongs to. Single-organization keys do not require this field.

**Checking your access** — Call `GET /v1/whoami` to see which organizations your key can access and what roles it has in each.

## Rate Limiting

Requests are rate limited to 300 requests per minute. Please reach out to us if this limit is a
problem for your use-cases.
If you need more data in bulk, you can use the export endpoints below to generate CSV exports,
which you can then download from the provided URL.

## Response Structure

Responses all follow this format:

```json
{ data: {}, errors: [] }
```

where `data` is the contents of a successful message and `errors` is the
content of a failed message. `data` will be `null` on error, and `errors` will
be an empty array on success.

There may be more than one error, each containing a `code` indicating a machine-readable
error code as well as a short `title` and longer `description` of the error in human terms.
Where applicable, `field_name` will be included to indicate which input field caused the error.

## Paginated Endpoints

APIs like `/v1/broadcasts` are paginated. You'll receive 20
entries and, if there are more entries after them, you'll get a URL in the
`next_page` field.

To get the next group of entries, run an HTTP GET request against that URL.
You'll keep getting `next_page` fields until there are no more entries, in which
case `next_page` will be `null`.

Page sizes are 20 entries per page. Page sizes are not adjustable. If you cannot
retrieve all your entries because of page and rate limiting restrictions, we recommend
using the [export endpoints](https://api.oneswitchboard.com/v1/docs#section/Export-Endpoints) instead.

## Export Endpoints

When you run an export, you start a Job that runs asynchronously on Switchboard's servers.
The response will return immediately and the data will contain a `job_url`.

Example:
```json
{
    "data": {
        "job_url": "https://..."
    },
    "errors": []
}
```

You can then poll this URL using an HTTP GET request periodically to check on the status of
the export. When the export is ready, the status will be `COMPLETED`, and you will get a
`result_url` that you can download.

```json
{
  "data": {
    "status": "COMPLETED",
    "result_url": "https://..."
  },
  "errors": []
}
```

The result URL is a signed S3 URL, and only available for five minutes from time of request.
New URLs can be generated by re-requesting the status of the Job.

### Polling Recommendations

We recommend polling the job URL with exponential backoff:

- **First poll**: after 5 seconds
- **Subsequent polls**: double the interval each time (10s, 20s, 40s) up to a maximum of 60 seconds
- **Typical completion time**: most exports finish within 1–2 minutes; large exports may take up to 10 minutes

Job statuses progress as follows: `PROCESSING` → `COMPLETED` or `ERROR`.

## DateTimes
All date times will be strings in ISO 8601 format yyyy-mm-ddThh:mm:ss±hhmm

## Filtering

Some list endpoints support filtering using via a `filter=` query param and a query syntax that allows you to narrow down results based on field values. The filter parameter accepts expressions that combine field comparisons with logical operators.

The specific fields available for filtering vary by endpoint and are documented in each endpoint's description.

**Important**: Filter expressions must be URL-encoded when included in query parameters, especially when they contain spaces, special characters, quotes, or operators.

### Basic Syntax

Filter expressions use the format `field operator value`, where:

- **field**: The name of the field to filter on
- **operator**: A comparison operator (see below)
- **value**: The value to compare against, enclosed in quotes for strings

### Operators

- `=` - equals
- `!=` - not equals
- `>` - greater than
- `<` - less than
- `>=` - greater than or equal
- `<=` - less than or equal
- `:` - contains (for text fields)

### Logical Operators

- `AND` - both conditions must be true
- `OR` - either condition can be true
- `NOT` - negates the following condition

### Examples

The following examples show filter expressions before URL encoding for clarity. Note: available filter fields vary by endpoint — check each endpoint's documentation for its supported fields.

```
// Filter by exact title match
?filter=title="My Broadcast"

// Filter by date range (after 2023-01-01)
?filter=created_at>"2023-01-01"

// Filter where time is not present
?filter=started_at=null

// Combine text search with date filter
?filter=name:"keyword" AND created_at<"2023-12-31"

// Exclude drafts
?filter=NOT status="draft"

// Complex query with grouping and multiple conditions
?filter=(title:"urgent" OR title:"important") AND created_at>"2023-01-01"

// Filter to a specific organization (for multi-organization keys)
?filter=organization_id="org_01jt0r4xhcefqs0rfkh906p7z0"

// Filter to one of several organizations (for multi-organization keys)
?filter=organization_id="org_01jt0r4xhcefqs0rfkh906p7z0" OR organization_id="org_01jv8k2m3npqr5st6uwx7yz9ab"
```

### URL Encoding

When making actual requests, these filter expressions must be URL-encoded. For example:

```
// Before encoding
?filter=title="My Broadcast"

// After URL encoding
?filter=title%3D%22My%20Broadcast%22

// Before encoding
?filter=(title:"urgent" OR title:"important") AND created_at>"2023-01-01"

// After URL encoding
?filter=%28title%3A%22urgent%22%20OR%20title%3A%22important%22%29%20AND%20created_at%3E%222023-01-01%22

// Before encoding
?filter=organization_id="org_01jt0r4xhcefqs0rfkh906p7z0" OR organization_id="org_01jv8k2m3npqr5st6uwx7yz9ab"

// After URL encoding
?filter=organization_id%3D%22org_01jt0r4xhcefqs0rfkh906p7z0%22%20OR%20organization_id%3D%22org_01jv8k2m3npqr5st6uwx7yz9ab%22
```

Most HTTP clients and libraries handle URL encoding automatically, but be sure to encode manually if constructing URLs by hand.

### Grouping

Use parentheses to group conditions and control operator precedence.

### Global Search

Some endpoints also support global search terms (without specifying a field) that will search across multiple relevant fields. For example: `"urgent message"` instead of `title:"urgent message"`.

### Filtering by Organization

Most list endpoints support filtering by `organization_id` to scope results to a specific organization. This is particularly useful with multi-organization keys, where results span all accessible organizations by default.

## Beta Headers

Some endpoints are in beta and require opt-in via the `switchboard-beta` header. Beta features
are experimental and may have breaking changes without notice.

To access beta endpoints, include the header in your requests:

```http
switchboard-beta: broadcasts-2025-01-07
```

To use multiple beta features in a single request, separate them with commas:

```http
switchboard-beta: feature1,feature2
```

Endpoints that require beta opt-in will return a `403 Forbidden` error with code `beta_feature_required`
if the appropriate header is not provided. If an invalid beta feature name is provided, you'll receive
a `400 Bad Request` error with code `beta_invalid_feature`.

Currently available beta features:
- `broadcasts-2025-01-07` - Create, send, and preview broadcasts via API

## Error Handling

All error responses follow this structure:

```json
{
  "data": null,
  "errors": [
    {
      "code": "bad_request",
      "title": "Invalid Request",
      "description": "The request was malformed or contained invalid parameters.",
      "field_name": "phone_number"
    }
  ]
}
```

There may be more than one error in the `errors` array. Each error contains:

- **`code`** — Machine-readable error code (see table below)
- **`title`** — Short human-readable summary
- **`description`** — Detailed explanation of what went wrong
- **`field_name`** — (optional) The specific input field that caused the error

### Error Codes

| Code | HTTP Status | Meaning |
|------|-------------|---------|
| `bad_request` | 400 | Invalid arguments or malformed request body |
| `unauthenticated` | 401 | Missing or invalid API credentials |
| `unauthorized` | 403 | Valid credentials but insufficient permissions for this action |
| `route_not_found` | 404 | The URL path does not match any API endpoint |
| `object_not_found` | 404 | The requested resource does not exist or you lack access |
| `beta_feature_required` | 403 | Endpoint requires a `switchboard-beta` header |
| `beta_invalid_feature` | 400 | The beta feature name in the header is not recognized |
| `internal_server_error` | 500 | Unexpected server error — contact support if persistent |

### Common Scenarios

- **401 Unauthenticated** — Double-check your Account ID and Secret Key. Ensure you're using HTTP Basic Auth, not Bearer tokens.
- **404 Object Not Found** — The ID may be wrong, or the resource belongs to a different organization. Verify the ID prefix matches the resource type (e.g., `bc_` for broadcasts, `lb_` for labels).
- **400 with `field_name`** — A specific input field failed validation. Check the `field_name` and `description` for details.
- **429 Rate Limited** — You've exceeded 300 requests/minute. Wait briefly and retry, or use export endpoints for bulk data.


