# Migrate from API v1 to v2

API v2 keeps the existing messaging workflows and changes public record identifiers to UUIDs. It also enforces access to the selected templates, sender accounts and referenced records. V1 remains available for existing integrations. Migrate one supported workflow at a time.

Production base URLs:

- V1: `https://1confirmed.com/api/v1`
- V2: `https://1confirmed.com/api/v2`

Keep your deployment's host if you use another environment. Only change the API version for endpoints listed below.

## What changes

| Area | V1 | V2 | Migration action |
| --- | --- | --- | --- |
| Record `id` | Usually an integer | UUID string | Change client types, storage, validation and route builders to accept strings. |
| Relationship fields | Numeric keys | UUID strings in the same field names | Keep names such as `template_id` and `broadcast_id`; replace their values with the corresponding UUIDs. |
| Record URLs | For example, `/broadcasts/123` | `/broadcasts/{broadcast_uuid}` | Use the `id` returned by the v2 resource. Casting `123` to `"123"` does not convert it to a UUID. |
| Languages | Numeric `id` and `language_id` | Still numeric | Keep language IDs as integers. |
| Template sender response | `group_id` | `account_id` | Update reads of `/template/accounts`. Send with the returned `template_account_flow_id`, not `account_id`. |
| Sender/template access | Some v1 lookups include public resources | Templates must be attached to the user; sender accounts must be assigned to the user | Re-fetch choices using the same account/token that will send. |
| Missing or inaccessible references | Legacy endpoint behavior | Malformed, unknown or inaccessible UUID references return 404 | Check the identifier and account access; do not retry with a numeric ID. |
| Authentication | Bearer access tokens for protected account endpoints | Same Bearer-token mechanism | Preserve phone verification and role requirements. Login needs credentials; registration accepts a premium account API token or an admin-issued registration token. |
| Broadcast file download | `/broadcast/download/{id}` | `/broadcast/{broadcast_uuid}/download` | Change the path order as well as the identifier. |

V2 does **not** rename every `*_id` property to `*_uuid`. The field named `id` contains the public UUID; there is no guarantee of a separate `uuid` field. Internal numeric identifiers and unsupported identifier properties may be omitted from responses. Do not rely on undocumented response fields.

## Endpoints available in v2

The following account API paths are relative to `/api/v2`. A resource family does not imply that every HTTP method is implemented. The separate knowledge-search API uses collection-scoped authentication; it is not part of this account-token migration.

| Workflow | Supported methods and paths |
| --- | --- |
| Sign in / sign up | `POST /login`, `POST /register` |
| Account and lookups | `GET /user`, `GET /categories`, `GET /credits`, `GET /templates`, `GET /template/accounts` |
| Languages | `GET /languages`; identifiers remain numeric. Other language resource routes are registered but their controller actions are not implemented; do not use them. |
| Contacts | `GET /contacts`, `GET /filter/contacts/segments` |
| Opt-outs and confirmations | `GET /black-list`, `POST /black-list`, `GET /confirmations`, `GET /confirmation/listeners`, `POST /confirmation/listeners` |
| Single messages / complete broadcasts | `POST /messages`, `POST /send-broadcast` |
| Broadcast records | `GET /broadcasts`, `POST /broadcasts`, `GET /broadcasts/{broadcast}`, `PUT/PATCH /broadcasts/{broadcast}` |
| Broadcast wizard | `POST /broadcast/template`, `/broadcast/file`, `/broadcast/mapping`, `/broadcast/country`, `/broadcast/send` |
| Broadcast actions | `GET /broadcast/{broadcast}/download`, `GET /broadcast/{broadcast}/scheduled-jobs`, `POST /broadcast/{broadcast}/stop`, `POST /broadcast/{broadcast}/cancel-schedule` |
| Payments and login history | `GET /payments`, `POST /payments`, `GET /connections` |
| SMS | `POST /sms/send`, `GET /sms/cost`, `GET /sms`, `GET /sms/{smsMessage}` |
| Saved lists (Premium) | `GET/POST /saved-list`, `GET /saved-list/{savedList}`, `PUT/PATCH /saved-list/{savedList}`, `DELETE /saved-list/{savedList}`, `POST /saved-list/{savedList}/clone`, `POST /saved-lists/{savedList}/share` |
| Calendars | `GET/POST /calendars`, `GET/PUT/PATCH/DELETE /calendars/{calendar}` |
| Calendar children | `GET /calendars/{calendar}/cities`, `GET /cities/{city}/weekday-schedules`, `GET /weekday-schedules/{weekdaySchedule}/time-ranges`; `POST` on `/cities`, `/weekday-schedules`, `/time-ranges`; `GET/PUT/PATCH/DELETE` on each child resource's UUID path |

Do not globally replace `/api/v1` throughout a project. Provider webhooks, Shopify login, password reset, credit sharing, integration routes and other v1-only endpoints do not automatically have v2 equivalents. Leave those on their supported version. Portal routes, such as the broadcast reschedule form, are browser-session routes and are not v2 API endpoints.

## Find the right UUIDs

1. Fetch numeric language IDs with `GET /api/v2/languages`, then fetch templates with `GET /api/v2/templates?language_id={language_id}&is_broadcast=0` (use `is_broadcast=1` for broadcast variable definitions). Use a template's returned `id` as `template_id`.
2. Fetch senders with `GET /api/v2/template/accounts?template_id={template_uuid}`. Select an authorized sender and retain its `template_account_flow_id`. Its `account_id` identifies the account, not the template/sender pairing.
3. When supplying `country_id`, use a Country record UUID, such as `country.id` in the sender response when applicable. It is not the numeric telephone calling code or an ISO country code. Omit optional country fields when they are not needed; never invent a UUID.
4. Re-fetch broadcasts, saved lists and calendars through their v2 list endpoints and follow pagination. Store the returned `id` values for subsequent calls. There is no public numeric-ID-to-UUID conversion endpoint in this contract. If matching existing records is ambiguous, obtain a verified mapping from the account owner instead of guessing from names.
5. Version cache keys and persisted references. Keep legacy numeric references separately until all workflows using them have migrated.

For single messages, identifier inputs include `template_id`, `template_account_flow_id` and optional `country_id`. For `/send-broadcast`, they additionally include optional `saved_list_id`, `calendar_id`, `follow_up_configuration.template_id` and `follow_up_configuration.calendar_id`. The follow-up object can arrive as nested JSON or a JSON-encoded multipart field.

Wizard steps use UUIDs in `broadcast_id`; the template step also uses `template_id`, and the country step can use `country_id` and `template_account_flow_id`. Contact filters use `broadcast_id`; template filters use `category_id`. Calendar creation relationships use `calendar_id`, `city_id` or `weekday_schedule_id` as appropriate.

Do not rewrite identifiers inside customer-defined `data` or `mapping` objects. An order ID, SKU, phone number, OTP or a customer's field called `id` is business data. Preserve its value and type. Credit amounts, hours, counts and pagination numbers also remain numeric.

## Before and after: single message

These payloads show the identifier change. Replace the example identifiers and template variables with values from your own account. Do not send both examples to a real recipient during migration.

V1, `POST /api/v1/messages`:

```json
{
  "name": "Order update",
  "template_id": 42,
  "template_account_flow_id": 73,
  "phone": "212600000000",
  "data": {"name": "Sam", "order_id": "000123"}
}
```

V2, `POST /api/v2/messages`:

```json
{
  "name": "Order update",
  "template_id": "018f16b6-7696-4ae8-8cf0-9d54bca0d981",
  "template_account_flow_id": "018f16b6-7698-4ae8-8cf0-9d54bca0d981",
  "phone": "212600000000",
  "data": {"name": "Sam", "order_id": "000123"}
}
```

Keep the existing headers:

```http
Authorization: Bearer YOUR_EXISTING_VALID_TOKEN
Accept: application/json
Content-Type: application/json
```

For multipart file uploads, let your HTTP client set the multipart boundary. Keep the endpoint's documented payload structure, scheduling fields and template-variable validation. V2 is not a change to the send workflow itself.

## Registration access and Turnstile

`POST /api/v1/register` and `POST /api/v2/register` accept two types of Bearer token:

- **Active premium account:** send your normal API access token from Login. No separate registration token is required.
- **Non-premium account:** an administrator must issue a dedicated registration token from your backend user profile and give it to you. Send that token instead. You cannot generate it yourself, and approval alone does not make your normal API token valid for registration.

Both paths require an active, phone-verified account. Premium eligibility is checked on every request, so an expired subscription stops registration with a normal API token. A dedicated registration token additionally requires current admin approval; it only creates accounts and cannot access other account APIs. Admin-issued tokens are shown once, stored as hashes, expire after 90 days and can be replaced by an administrator or revoked. Replacement immediately invalidates the previous dedicated token. The **Registration API** portal page explains which token to use.

Remove `turnstile_token` from API login and registration payloads. The portal's interactive login and registration retain their challenge protection. API login needs only the documented credentials and any required two-factor code; it does **not** need a registration token.

API login allows 1 attempt per second, 5 per minute and 20 per 15 minutes per client IP. Successful, failed and invalid attempts count. These limits are shared across v1, v2 and Shopify login, regardless of the submitted email. Simultaneous requests cannot reserve the same allowance. A `429` response includes `Retry-After` in seconds; wait before retrying and reuse a valid API access token for other operations instead of logging in before every call.

Registration attempts are limited to 5 per minute and 100 per day per owner, shared across v1/v2, normal premium API tokens and replacement dedicated tokens. Existing per-IP credential limits also apply. Missing, invalid, expired, revoked or ineligible tokens return `401`; limits return `429` with `Retry-After`. Keep the token out of URLs and browser code. Newly created users still need to verify their phone before using protected APIs.

An existing server integration should use its existing account and normal Bearer token for other operations. Registration is not a prerequisite to each API call.

## Responses and error handling

Keep endpoint-specific response handling. Common responses wrap the result in `success`, `data` and `message`; resource collections and authentication responses have their own documented nesting. V2 changes identifiers inside these responses, not every response into a single new schema.

- Treat record identifiers as opaque strings. Remove integer casts, numeric validators, arithmetic and number-only URL patterns for those fields.
- Preserve numeric language IDs and pagination values.
- Handle 401, verification/role failures, 404, 422 validation errors and 429 rate limits. A reference-related 404 can mean the current account cannot use the selected resource.
- A sender flow must belong to the selected template and an account assigned to the authenticated user. An old public v1 sender choice may no longer be offered in v2.
- Keep secrets in server configuration. Avoid logging tokens or sending them in URLs.

## Checklist for an AI-assisted migration

Give the coding assistant this page or its Markdown version together with the current integration's API client and tests.

1. Inventory every v1 method/path, authentication flow, stored record ID, request schema and response parser. Classify each endpoint against the support table above.
2. Preserve v1-only endpoints and provider webhook URLs. Do not invent v2 replacements.
3. Add explicit v2 client types for UUID-bearing fields; keep `language_id` numeric. Update `group_id` reads from template sender responses to `account_id`.
4. Re-fetch authorized resource choices. Create a verified migration mapping for existing stored references. Do not derive UUIDs from integers or silently select a similarly named resource.
5. Update the supported request paths and only the identifier fields defined by each endpoint. Preserve business data, template variables, file contents, phone numbers and scheduling behavior.
6. Update response fixtures to the actual v2 shape. Test UUIDs in URLs, query strings, JSON, multipart fields and nested follow-up configuration.
7. Test a valid authorized request, numeric-ID rejection, unknown/foreign UUID rejection, invalid template/sender pairing, language-ID compatibility and validation errors. Test list pagination before switching stored references.
8. Use a controlled test recipient for one send. Never replay both versions of a real broadcast to compare them. Confirm message results and credit behavior before enabling the migrated workflow.
9. Roll out per workflow and keep an explicit rollback plan using the retained v1 references. Remove legacy storage only after all consumers have migrated.

The [v1 reference](/developers/api?version=v1) and [v2 reference](/developers/api?version=v2) use the same layout, with version-specific identifiers, access notes and examples. Use the version switch to keep the same endpoint selected.
