# Migration Guide



This guide walks through migrating an existing v1 integration to the v2 API. v2
is not backwards compatible, but most changes are mechanical — a new base path,
camelCase fields, and a consistent response envelope — with a few flows (user
creation, authentication) split into clearer, dedicated endpoints. v1 keeps
working while you migrate, up to the sunset date below.

## Deprecation timeline [#deprecation-timeline]

The v1 API is deprecated as of **July 24, 2026** and sunset on
**August 21, 2026**. It keeps working between those dates but receives no further
updates or fixes. On August 21 it shuts down and stops accepting requests, so
you must be fully migrated to v2 by then.

| Date                | Milestone                                                                                                                    |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **July 24, 2026**   | **Deprecated.** v2 becomes the required API for all integrations. v1 keeps working but receives no further updates or fixes. |
| **August 21, 2026** | **Sunset.** v1 shuts down and stops accepting requests. All integrations must be on v2 by this date.                         |

<Callout type="warn" title="Sunset date">
  v1 will be sunset on **August 21, 2026**. All integrations must be on v2 by
  then. If you need more time, [reach out](/v2/support) before the sunset date
  to request an extension and we'll work with you.
</Callout>

## What changed at a glance [#what-changed-at-a-glance]

* **Versioned base path** — every endpoint now lives under `/v2`.
* **Consistent response envelope** — successful responses are wrapped in
  `{ "success": true, "data": ... }`; errors return
  `{ "success": false, "errors": [...] }`.
* **camelCase everywhere** — request and response fields use camelCase
  (`first_name` → `firstName`, `address1` → `addressLine1`, `postal` →
  `postalCode`).
* **RESTful, resource-based endpoints** — verb-style endpoints
  (`/generateApiLink`, `/loginCodeSend`) are replaced with resources
  (`/users`, `/auth/login-codes`).
* **Separated authentication** — integrator requests use `x-api-key`; requests
  made on behalf of an end user now use a short-lived JWT
  (`Authorization: Bearer <token>`).

## Base URL [#base-url]

```diff
- https://api.paytrie.com/<endpoint>
+ https://api.paytrie.com/v2/<endpoint>
```

## Response envelope [#response-envelope]

v1 returned the payload (or an ad-hoc `{ status, message }` object) directly. v2
always wraps the payload so success and errors are predictable.

```json title="v1 response"
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "email": "john.doe@example.com"
}
```

```json title="v2 response"
{
  "success": true,
  "data": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "john.doe@example.com"
  }
}
```

```json title="v2 error"
{
  "success": false,
  "errors": [{ "field": "email", "message": "Invalid email" }]
}
```

<Callout type="info">
  Update your client to read the payload from `response.data` and to check
  `response.success` (or the HTTP status) for errors.
</Callout>

## Endpoint mapping [#endpoint-mapping]

| v1 endpoint                    | v2 endpoint                                             |
| ------------------------------ | ------------------------------------------------------- |
| `POST /loginCodeSend`          | `POST /v2/auth/login-codes`                             |
| `POST /loginCodeVerify`        | `POST /v2/auth/login-codes/verify`                      |
| `POST /generateApiLink`        | `POST /v2/users` + `GET /v2/users/{userId}/kyc-url`     |
| `GET /apiFindUser`             | `GET /v2/users?email={email}`                           |
| `POST /sumsubImportUser`       | `PUT /v2/users/{userId}/kyc`                            |
| `GET /priceQuote`              | `GET /v2/quotes`                                        |
| `GET /transaction`             | `GET /v2/transactions` + `GET /v2/transactions/{txId}`  |
| `POST /transaction`            | `POST /v2/transactions`                                 |
| `GET, PATCH /webhooks`         | `GET, PUT, DELETE /v2/webhook-configurations`           |
| `POST /webhook-signing-secret` | `POST /v2/webhook-configurations/signing-secret/rotate` |

New in v2 with no v1 equivalent: `GET /v2/limits`, `GET /v2/users/me/requirements`,
and `PUT /v2/transactions/{txId}/cancel`.

## Migration examples [#migration-examples]

### Request a login code [#request-a-login-code]

```bash title="v1"
curl -X POST "https://api.paytrie.com/loginCodeSend" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com" }'
```

```bash title="v2"
curl -X POST "https://api.paytrie.com/v2/auth/login-codes" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com" }'
```

Then exchange the code for a JWT:

```bash title="v2"
curl -X POST "https://api.paytrie.com/v2/auth/login-codes/verify" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com", "code": "1234" }'
```

### Create a user [#create-a-user]

User creation and KYC are now two steps: create the user, then request a KYC URL.

```bash title="v1"
curl -X POST "https://api.paytrie.com/generateApiLink" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "John",
    "last_name": "Doe",
    "email": "john.doe@example.com",
    "phone": "4165551234",
    "dob": "1990-01-15",
    "address1": "123 Main Street",
    "address2": "Suite 100",
    "city": "Toronto",
    "province": "on",
    "postal": "M5V1A1",
    "occupation": "Software Engineer",
    "pep": false,
    "tpd": false
  }'
```

```bash title="v2"
curl -X POST "https://api.paytrie.com/v2/users" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "john.doe@example.com",
    "firstName": "John",
    "lastName": "Doe",
    "dob": "1990-01-15",
    "phone": "4165551234",
    "addressLine1": "123 Main Street",
    "addressLine2": "Suite 100",
    "city": "Toronto",
    "province": "on",
    "postalCode": "M5V1A1",
    "occupation": "Software Engineer",
    "pep": false,
    "tpd": false
  }'
```

Then generate the KYC link with the returned `id`:

```bash title="v2"
curl -X GET "https://api.paytrie.com/v2/users/{userId}/kyc-url" \
  -H "x-api-key: your-api-key"
```

See [Customer Onboarding](/v2/customer-onboarding) for the full onboarding flow.

### Fetch a price quote [#fetch-a-price-quote]

```bash title="v1"
curl -X GET "https://api.paytrie.com/priceQuote?leftSideLabel=CAD&leftSideValue=100&rightSideLabel=USDC-ETH" \
  -H "x-api-key: your-api-key"
```

```bash title="v2"
curl -X GET "https://api.paytrie.com/v2/quotes?leftSideLabel=CAD&leftSideValue=100&rightSideLabel=USDC-ETH" \
  -H "x-api-key: your-api-key"
```

The v2 quote response is enveloped and adds a `quoteId` (pass it to
`POST /v2/transactions` to lock in the rate) plus a fee `breakdown`.

### Create a transaction [#create-a-transaction]

The v2 body drops the client-supplied `ethCost` and `gasId` fields — pricing is
derived server-side from the `quoteId`.

```bash title="v1"
curl -X POST "https://api.paytrie.com/transaction" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "leftSideLabel": "CAD",
    "leftSideValue": 1000,
    "rightSideLabel": "USDC-ETH",
    "wallet": "0x05a238198541d076B4fc74254Cd426A8C8e84D32",
    "ethCost": 3440.64,
    "gasId": 2,
    "quoteId": 1
  }'
```

```bash title="v2"
curl -X POST "https://api.paytrie.com/v2/transactions" \
  -H "x-api-key: your-api-key" \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "leftSideLabel": "CAD",
    "leftSideValue": 1000,
    "rightSideLabel": "USDC-ETH",
    "wallet": "0x05a238198541d076B4fc74254Cd426A8C8e84D32",
    "quoteId": 1
  }'
```

### Migrate webhooks [#migrate-webhooks]

You can adopt v2 webhooks without interrupting your existing v1 integration. Registering a v2 webhook does **not** disable v1, so both fire in parallel while you migrate. Move over before the [sunset date](#deprecation-timeline), then turn off v1 yourself:

1. Register your v2 webhook URL with `PUT /v2/webhook-configurations`.
2. Confirm v2 events are arriving at your endpoint.
3. Once you're confident, turn off v1 yourself.

To turn off v1, you don't need a new endpoint — use the existing v1 [`PATCH /webhooks`](/docs/webhooks#update-webhook-configuration) call and set every enabled flag to `false`:

```bash title="Disable v1 webhooks"
curl -X PATCH "https://api.paytrie.com/webhooks" \
  -H "x-api-key: your-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "verifiedEmailEnabled": false,
    "transactionInitiatedEnabled": false,
    "transactionCompleteEnabled": false,
    "transactionStatusUpdateEnabled": false
  }'
```

See [Webhooks](/v2/webhooks) for the full v2 webhook setup, payload schemas, and signature verification.

## Next steps [#next-steps]

<Card title="v2 API Reference" href="/v2/api-reference" icon="arrow-right-left">
  Browse the full list of v2 endpoints, parameters, and response schemas
</Card>

<Card title="Need help migrating?" href="/v2/support" icon="life-buoy">
  Reach out and we'll help you plan the migration
</Card>
