# Organization API: Org Legacy Migration

> Every Organization API operation tagged Org Legacy Migration.

Source: https://www.coritan.com/docs/api/reference/organizations/org-legacy-migration/

Base URL: `https://api.coritan.com/api/v1`. Paths below are complete.

To try these requests in the browser, open the [interactive Organization API reference](https://api.coritan.com/docs/org).

## Operations

| Method | Path | Summary |
| --- | --- | --- |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/alerts`](#op-post-api-v1-orgs-org-slug-legacy-migration-alerts) | Money or a chargeback the previous platform will not settle for a moved account |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/availability`](#op-post-api-v1-orgs-org-slug-legacy-migration-availability) | Whether an email address or a username is already taken in the organization |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/exchange`](#op-post-api-v1-orgs-org-slug-legacy-migration-exchange) | Open a relayed sign-in code and return the session it holds |
| GET | [`/api/v1/orgs/{org_slug}/legacy-migration/go`](#op-get-api-v1-orgs-org-slug-legacy-migration-go) | Send the browser to the organization's storefront |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/redeem`](#op-post-api-v1-orgs-org-slug-legacy-migration-redeem) | Move an account from the previous website into the organization |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/relay-login`](#op-post-api-v1-orgs-org-slug-legacy-migration-relay-login) | A sign-in typed on the previous platform for an account that lives here |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/state`](#op-post-api-v1-orgs-org-slug-legacy-migration-state) | Whether the previous platform's move is open and its forum is frozen |
| POST | [`/api/v1/orgs/{org_slug}/legacy-migration/ticket`](#op-post-api-v1-orgs-org-slug-legacy-migration-ticket) | What moving an account from the previous website will do, before anything moves |

### Money or a chargeback the previous platform will not settle for a moved account {#op-post-api-v1-orgs-org-slug-legacy-migration-alerts}

`POST /api/v1/orgs/{org_slug}/legacy-migration/alerts`

Money or a chargeback the previous platform will not settle for a moved account.

Signed by the previous platform. ``late_money`` is a payment or deposit that
reached the old account after it moved; ``chargeback`` is a dispute on one
of its old charges. Nothing is credited or deducted: the alert is written
to the organization's audit log as ``customer.legacy_alert`` for staff to
settle. Answers 404 for a customer this organization does not have.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `ok` | boolean |

### Whether an email address or a username is already taken in the organization {#op-post-api-v1-orgs-org-slug-legacy-migration-availability}

`POST /api/v1/orgs/{org_slug}/legacy-migration/availability`

Whether an email address or a username is already taken in the organization.

Signed by the previous platform, which asks before it registers an account
or changes an address or a username, and refuses on ``true``. Emails and
usernames compare without regard to letter case, and names held by
``unclaimed`` placeholders count as taken. Answers 404 while the link is
off and 401 for a request that is not signed with the shared secret.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `email_taken` | boolean |
| `username_taken` | boolean |

### Open a relayed sign-in code and return the session it holds {#op-post-api-v1-orgs-org-slug-legacy-migration-exchange}

`POST /api/v1/orgs/{org_slug}/legacy-migration/exchange`

Open a relayed sign-in code and return the session it holds.

The storefront's ``/auth/callback`` sends the ``legacy_code`` from its URL
fragment. The answer has the shape ``POST /auth/login`` answers: a session,
or a two-factor step. A code opens for about a minute, and only for the
organization that sealed it; anything else answers 400.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `code` | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Send the browser to the organization's storefront {#op-get-api-v1-orgs-org-slug-legacy-migration-go}

`GET /api/v1/orgs/{org_slug}/legacy-migration/go`

Send the browser to the organization's storefront.

The previous platform links here instead of to a storefront hostname, so
the link keeps working when the storefront moves to another host. The
redirect goes to the storefront address Coritan has registered for the
organization: ``/migrate``, ``/auth/callback``, ``/login`` or
``/community``. A ticket or sign-in code rides in the URL fragment, which
the browser keeps across the redirect and never sends to a server.
Answers 404 when no storefront address is registered.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `org_slug` | path | string | yes |  |
| `to` | query | string, one of `migrate`, `callback`, `signin`, `community` | no | The storefront page to open: migrate, callback, signin or community. Default: `signin`. |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

### Move an account from the previous website into the organization {#op-post-api-v1-orgs-org-slug-legacy-migration-redeem}

`POST /api/v1/orgs/{org_slug}/legacy-migration/redeem`

Move an account from the previous website into the organization.

Send the ``ticket``, ``accept_terms: true`` and, if the person chose one,
the ``handle`` to use (3 to 20 letters, numbers or underscores). Without a
handle the move uses the one ``POST /legacy-migration/ticket`` proposed. For
``merge_sign_in``, send the existing account's bearer token too.

The previous website locks the old account and sends what moves: the
password, so the old password signs in here; the names; the forum profile;
the saved cards; and the balances, which become one wallet credit in USD.
A merge keeps the existing account's password, username and settings, and
takes the old account's forum threads. The answer holds the ``handle``,
whether the old account was ``merged`` into an existing one,
``credited_usd``, the number of ``cards`` saved, and a ``session`` (or a
two-factor step) in the shape ``POST /auth/login`` answers. Sending the
same ticket again answers the same result and credits nothing twice. The
repeat carries a session only for a ticket issued before the move, and
for ``merge_sign_in`` only with that account's bearer token; otherwise
``session`` is null and the person signs in.

Refusals answer with ``detail.code`` and ``detail.message``:
``terms_required`` and ``invalid_ticket`` (400); ``sign_in_required``
(401); ``handle_unavailable`` (409, with ``reason`` and ``suggestion``);
``not_eligible`` (409, with the ``blocking`` items the previous website
lists); ``already_moved``, ``email_blocked`` and ``limit_reached`` (409);
``old_site_unavailable`` and ``rate_unavailable`` (503), after which
nothing has moved and the same request can be sent again later. Answers
404 while the organization is not moving accounts.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `ticket` | string | yes |
| `accept_terms` | boolean | yes |
| `handle` | string or null | no |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `result` | string |
| `handle` | string |
| `merged` | boolean |
| `credited_usd` | string |
| `cards` | integer |
| `session` | Session or MfaStep or null |

### A sign-in typed on the previous platform for an account that lives here {#op-post-api-v1-orgs-org-slug-legacy-migration-relay-login}

`POST /api/v1/orgs/{org_slug}/legacy-migration/relay-login`

A sign-in typed on the previous platform for an account that lives here.

Signed by the previous platform. It sends either ``customer_id`` (an account
that moved) or ``login`` (an email address or username it does not know),
with the password and the person's ``client_ip``. The password is checked
the way ``POST /auth/login`` checks it, and two-factor authentication is
asked for in the same way. Failures count against the sign-in budget of
``client_ip`` and against the account.

``ok`` carries a ``go_url`` whose fragment holds a sealed sign-in code that
``POST /legacy-migration/exchange`` opens within a minute. ``invalid``
covers a wrong password and an unknown login alike. ``social_only`` names
an account with no password. ``rate_limited`` asks the person to wait.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `result` | string, one of `ok`, `invalid`, `social_only`, `rate_limited` |
| `go_url` | string or null |

### Whether the previous platform's move is open and its forum is frozen {#op-post-api-v1-orgs-org-slug-legacy-migration-state}

`POST /api/v1/orgs/{org_slug}/legacy-migration/state`

Whether the previous platform's move is open and its forum is frozen.

Signed by the previous platform, with an empty object as the body. It asks
every so often and keeps the answer for up to a minute. ``move_open`` opens
its migrate section and lets someone who signs in on the storefront with an
old account move it; ``forum_read_only`` makes its forum refuse new posts.
Coritan's staff set both. Unlike the other signed routes this one answers
while the link is off, with ``move_open: false``, so the previous platform
learns that the move closed. Answers 404 while no shared secret is set and
401 for a request that is not signed with it.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `move_open` | boolean |
| `forum_read_only` | boolean |

### What moving an account from the previous website will do, before anything moves {#op-post-api-v1-orgs-org-slug-legacy-migration-ticket}

`POST /api/v1/orgs/{org_slug}/legacy-migration/ticket`

What moving an account from the previous website will do, before anything moves.

The storefront's move page sends the ``ticket`` from the link the previous
website opened it with. The answer names the old account (``username``,
``email``, ``providers``) and says which case applies in ``account``:
``new``; ``placeholder`` when the account's forum threads are already here;
``merge_automatic`` when an account here has the same email address and
both sites verified it; ``merge_sign_in`` when an account here has it but
one site has not verified it, so the move needs that account's sign-in;
or ``blocked`` when the account here is banned, suspended or closed.

``handle`` proposes the username for a new account or a placeholder: the
old username when it fits the username rules and nobody here uses it,
else a free suggestion, with ``reason`` saying why the old one could not
be kept. A merge keeps the existing account's username, so ``handle.value``
is then null. ``terms_url`` and ``privacy_url`` link the organization's
terms of service and privacy policy. Nothing is locked or written.

Refusals answer with ``detail.code`` and ``detail.message``:
``invalid_ticket`` (400) for a ticket that is altered, of another kind or
expired, and ``already_moved`` (409) for an account that has already moved
here. Answers 404 while the organization is not moving accounts.

#### Parameters

| Name | In | Type | Required |
| --- | --- | --- | --- |
| `org_slug` | path | string | yes |

#### Request body

`application/json` (required)

| Field | Type | Required |
| --- | --- | --- |
| `ticket` | string | yes |

#### Responses

| Status | Meaning |
| --- | --- |
| `200` | Success. |
| `422` | The request is not valid. `detail` lists each problem. |

Fields of a `200` response:

| Field | Type |
| --- | --- |
| `username` | string |
| `email` | string |
| `providers` | array of string |
| `account` | string, one of `new`, `placeholder`, `merge_automatic`, `merge_sign_in`, `blocked` |
| `handle` | HandleVerdict |
| `handle.value` | string or null |
| `handle.available` | boolean |
| `handle.reason` | string or null |
| `terms_url` | string or null |
| `privacy_url` | string or null |
