# Client API: Object Storage: Migrations

> The 7 Client API operations for migrations.

Source: https://www.coritan.com/docs/api/reference/client/object-storage/object-storage-migrations/

Part of [Object Storage](/docs/api/reference/client/object-storage/).

## Operations

| Method | Path | Summary |
| --- | --- | --- |
| GET | [`/api/v1/client/object-storage/{service_id}/migrations`](#op-get-api-v1-client-object-storage-service-id-migrations) | List migrations |
| POST | [`/api/v1/client/object-storage/{service_id}/migrations`](#op-post-api-v1-client-object-storage-service-id-migrations) | Start copying objects from another provider into one of the service's buckets |
| POST | [`/api/v1/client/object-storage/{service_id}/migrations/preflight`](#op-post-api-v1-client-object-storage-service-id-migrations-preflight) | Check migration source |
| GET | [`/api/v1/client/object-storage/{service_id}/migrations/{migration_id}`](#op-get-api-v1-client-object-storage-service-id-migrations-migration-id) | One migration, as the list writes it |
| POST | [`/api/v1/client/object-storage/{service_id}/migrations/{migration_id}/cancel`](#op-post-api-v1-client-object-storage-service-id-migrations-migration-id-cancel) | Stop a queued or running migration and delete its source keys |
| GET | [`/api/v1/client/object-storage/{service_id}/migrations/{migration_id}/failures`](#op-get-api-v1-client-object-storage-service-id-migrations-migration-id-failures) | List migration failures |
| POST | [`/api/v1/client/object-storage/{service_id}/migrations/{migration_id}/retry`](#op-post-api-v1-client-object-storage-service-id-migrations-migration-id-retry) | Retry migration |

### List migrations {#op-get-api-v1-client-object-storage-service-id-migrations}

`GET /api/v1/client/object-storage/{service_id}/migrations`

The service's migrations, newest first, with the provider presets a
new one can use and the limits.

Each item has its ``status`` (``queued``, ``running``, ``done``,
``failed`` or ``cancelled``), the source (``provider``, ``endpoint``,
``region``, ``source_bucket``, ``source_prefix`` and the last four
characters of its access key as ``access_key_hint``), the destination
(``bucket_id``, ``bucket_name``, ``dest_prefix``, ``overwrite``) and its
progress: ``objects_listed``, ``objects_copied``, ``objects_skipped``
(already in the destination), ``objects_failed``, ``bytes_copied`` and
``last_key``, the last source key it reached. ``listed_all`` turns true
once the whole source has been listed, so ``objects_listed`` is the
total from then on. A ``done`` migration with ``objects_failed`` above
zero finished with failures, and ``can_retry`` says whether a retry has
anything to do; ``failures_dropped`` counts the failed objects beyond
the last 1000 we keep. ``error`` says why one ``failed``.

``providers`` lists each preset's ``endpoint`` (with ``{region}``, or
null when you give the endpoint) and whether it needs a region.
``limits.running_max`` is how many may be queued or running at once.

Answers 404 for a service that is not this account's Object Storage.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |
| `limit` | query | integer | no | How many migrations to list, newest first Default: `50`. |

#### Responses

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

### Start copying objects from another provider into one of the service's buckets {#op-post-api-v1-client-object-storage-service-id-migrations}

`POST /api/v1/client/object-storage/{service_id}/migrations`

Start copying objects from another provider into one of the
service's buckets. We check the source first, as the preflight does, and
the copy starts within a minute. It runs in the background until every
object under the prefix is copied; the migration's ``status`` and counts
show how far it got.

Each object keeps its ``Content-Type``, ``Cache-Control``,
``Content-Disposition``, ``Content-Encoding``, ``Content-Language`` and
user metadata. The destination key is ``dest_prefix`` followed by the
source key. We keep the keys encrypted while the migration runs and
delete them when it ends. Copies are free; the storage they take is
billed as storage.

Answers the migration as ``GET`` writes it. Answers 404 for a service or
bucket that is not this account's, 409 when the service is not active or
already has 3 migrations queued or running, 422 or 502 as the preflight
does, and 429 after 30 migration changes in an hour.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | yes | Where the objects are now: aws (Amazon S3), r2 (Cloudflare R2), gcs (Google Cloud Storage), b2 (Backblaze B2), wasabi, digitalocean (DigitalOcean Spaces) or other |
| `endpoint` | string or null | no | The source's S3 endpoint, such as https://s3.example.com. HTTPS only. Required for r2 and other; the other providers' endpoints are built from the region |
| `region` | string or null | no | The source bucket's region, such as us-east-1. Required for aws, b2, wasabi and digitalocean; r2 and gcs use auto, and other defaults to us-east-1 |
| `source_bucket` | string | yes | The bucket to copy from, at the source |
| `source_prefix` | string | no | Copy only the keys that start with this. Empty copies the bucket |
| `access_key_id` | string | yes | An access key ID at the source that can list and read the bucket |
| `secret_access_key` | string | yes | Its secret access key. We keep it encrypted until the migration ends |
| `bucket_id` | integer | yes | The destination: one of this service's buckets |
| `dest_prefix` | string | no | Put in front of every key in the destination. Empty keeps the keys as they are |
| `overwrite` | boolean | no | When false, an object the destination already holds with the same size and ETag is skipped. When true, every object is copied again |

#### Responses

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

### Check migration source {#op-post-api-v1-client-object-storage-service-id-migrations-preflight}

`POST /api/v1/client/object-storage/{service_id}/migrations/preflight`

Check a source before a migration starts: we list the bucket (under
the prefix) with the key and read the first object's headers. Nothing is
copied and nothing is stored.

Answers ``{"ok": true, "endpoint", "region", "bucket", "prefix",
"sample", "more"}``: ``sample`` is up to five of the objects found, and
``more`` is true when there are others. Answers 422 with the reason
when the source refuses the key, has no such bucket, is in another
region, or the endpoint is not a public HTTPS endpoint; 502 when the
source cannot be reached or answers with an error of its own; 404 for a
service that is not this account's Object Storage; 429 after 30 checks in
ten minutes.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `provider` | string | yes | Where the objects are now: aws (Amazon S3), r2 (Cloudflare R2), gcs (Google Cloud Storage), b2 (Backblaze B2), wasabi, digitalocean (DigitalOcean Spaces) or other |
| `endpoint` | string or null | no | The source's S3 endpoint, such as https://s3.example.com. HTTPS only. Required for r2 and other; the other providers' endpoints are built from the region |
| `region` | string or null | no | The source bucket's region, such as us-east-1. Required for aws, b2, wasabi and digitalocean; r2 and gcs use auto, and other defaults to us-east-1 |
| `source_bucket` | string | yes | The bucket to copy from, at the source |
| `source_prefix` | string | no | Copy only the keys that start with this. Empty copies the bucket |
| `access_key_id` | string | yes | An access key ID at the source that can list and read the bucket |
| `secret_access_key` | string | yes | Its secret access key. We keep it encrypted until the migration ends |

#### Responses

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

### One migration, as the list writes it {#op-get-api-v1-client-object-storage-service-id-migrations-migration-id}

`GET /api/v1/client/object-storage/{service_id}/migrations/{migration_id}`

One migration, as the list writes it. Answers 404 for a service or a
migration that is not this account's.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |
| `migration_id` | path | integer | yes | The migration's id, from the list |

#### Responses

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

### Stop a queued or running migration and delete its source keys {#op-post-api-v1-client-object-storage-service-id-migrations-migration-id-cancel}

`POST /api/v1/client/object-storage/{service_id}/migrations/{migration_id}/cancel`

Stop a queued or running migration and delete its source keys.
Objects it already copied stay in the bucket, and a large object it was
copying part by part is discarded. Works whatever the service's status,
so a suspended service can still stop one.

Answers the migration, now ``cancelled``. Answers 404 for a migration
that is not this account's, 409 when it has already ended, and 429 after
30 migration changes in an hour.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |
| `migration_id` | path | integer | yes | The migration's id, from the list |

#### Responses

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

### List migration failures {#op-get-api-v1-client-object-storage-service-id-migrations-migration-id-failures}

`GET /api/v1/client/object-storage/{service_id}/migrations/{migration_id}/failures`

The objects a migration could not copy, most recent first: each
one's ``key``, ``size`` (null when the source did not say), the
``error``, how many ``attempts`` were made, and ``retry_pending`` while
a retry has yet to reach it. We keep the last 1000 (``kept_max``);
``total`` is how many are kept now.

Answers 404 for a migration that is not this account's.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |
| `migration_id` | path | integer | yes | The migration's id, from the list |
| `limit` | query | integer | no | How many failed objects to list, most recent first Default: `100`. |
| `offset` | query | integer | no | How many to skip, for the next page Default: `0`. |

#### Responses

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

### Retry migration {#op-post-api-v1-client-object-storage-service-id-migrations-migration-id-retry}

`POST /api/v1/client/object-storage/{service_id}/migrations/{migration_id}/retry`

Try a migration again: first the objects it could not copy, then the
rest of the source from where it stopped. We delete the source keys
when a migration ends, so send them again; we check them as the
preflight does.

For a migration that failed, or one that is ``done`` with failures. When
more objects failed than the last 1000 we keep, the retry walks the
whole source again and skips what the bucket already holds.

Answers the migration, ``queued`` again. Answers 404 for a migration
that is not this account's, 409 when the service is not active, when it
has nothing to try again or when 3 migrations are already queued or
running, 422 or 502 as the preflight does, and 429 after 30 migration
changes in an hour.

Authentication: an access token, sent as `Authorization: Bearer <token>`.

#### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `service_id` | path | integer | yes | The Object Storage service's id |
| `migration_id` | path | integer | yes | The migration's id, from the list |

#### Request body

`application/json` (required)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `access_key_id` | string | yes | The source access key ID. We delete keys when a migration ends |
| `secret_access_key` | string | yes | Its secret access key |

#### Responses

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