---
title: "Move a project to a chosen address"
method: PUT
path: "/v1/projects/{project_id}/handle"
---

# Move a project to a chosen address

`PUT /v1/projects/{project_id}/handle`

## Request

- Base URL: `https://app.ohmyho.st`
- URL: `https://app.ohmyho.st/v1/projects/{project_id}/handle`
- Auth: HTTP bearer

Starts a durable operation that re-publishes the project's Dev and Prod gateways at the chosen address and stores it only once both serve it. The previous address stops answering and returns to the pool for any project to claim. Ask GET /v1/project-handles/{handle} first; a taken, unusable or unchanged address is refused before any gateway moves, and a project with an operation in flight is refused until it finishes.

## Path parameters

- `project_id` string, required

## Headers

- `X-Request-Id` string
- `Idempotency-Key` string, required
- `If-Match` string, required

## Request body

- object
  - `handle` string, required: One to five lowercase words of letters and digits.

## Response `202`

The mutation was accepted for asynchronous processing.

- Operation: Durable record returned for an accepted asynchronous mutation. Optional reconciliation is a current observation for queued/running work, separate from immutable terminal state. A completed reconciliation attempt alone does not mean the operation succeeded.
  - `blocking_operation_id` string
  - `deployment_id` string
  - `id` string, required
  - `state` 'queued' | 'running' | 'succeeded' | 'failed' | 'cancelled', required
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `result` object
  - `error` OperationFailure
    - `code` 'operation_failed' | 'operation_abandoned' | 'authorization_changed' | 'source_commit_conflict' | 'source_snapshot_invalid' | 'source_upload_expired' | 'recovery_dispatch_failed' | 'recovery_job_failed' | 'recovery_input_expired' | 'recovery_database_unavailable' | 'recovery_checksum_mismatch' | 'recovery_scope_unavailable' | 'recovery_archive_too_large' | 'build_not_started' | 'build_failed' | 'database_write_rejected' | 'database_write_unavailable' | 'database_write_outcome_unknown' | 'database_compute_failed' | 'database_compute_plan_changed' | 'database_compute_rejected' | 'database_migration_failed' | 'insufficient_organization_credits' | 'paid_plan_required' | 'runtime_candidate_failed' | 'runtime_candidate_rejected' | 'storage_jurisdiction_conflict' | 'provider_state_absent' | 'auto_deploy_plan_rejected' | 'promotion_source_stale' | 'promotion_target_stale', required
    - `message` string, required
    - `retryable` false, required: A terminal operation cannot be retried in place; follow suggested_action.
    - `suggested_action` string, required
    - `detail` string: Present only on auto_deploy_plan_rejected when planning the pushed commit returned a typed refusal. It is the same fixed catalog sentence that the planning 409 problem returns as detail, naming the file, the rule and the required change.
  - `progress` OperationDeploymentProgress: Current deployment dependency observation, separate from immutable operation history. Poll the same operation; mail readiness does not mean application activation.
    - `build_completed_at` string, date-time: Actual successful build completion time when this operation ran a build; omitted for reused artifacts without a current build.
    - `phase` 'queued' | 'building' | 'publishing' | 'waiting_for_mail' | 'mail_status_unavailable', required
    - `project_id` string, required
    - `deployment_id` string, required
    - `observed_at` string, date-time, required
    - `next_poll_after_seconds` 60, required
    - `suggested_action` string, required
  - `reconciliation` OperationReconciliation
    - `state` 'required' | 'pending', required
    - `attempt_id` string, required
    - `observed_at` string, date-time, required
    - `suggested_action` string, required

## Other responses

- `400`: The request failed.
- `401`: The request failed.
- `403`: The request failed.
- `404`: The resource does not exist or is not visible to the authenticated principal.
- `409`: The idempotency key was already used with a different canonical request.
- `429`: The request failed.
- `503`: The request failed.

---

[API](https://skmtc.dev/ohmyho/apis/ohmyho-st-api.md) · [All operations](https://skmtc.dev/ohmyho/apis/ohmyho-st-api/llms.txt) · [OpenAPI document](https://skmtc.dev/ohmyho/apis/ohmyho-st-api/revisions/d069888c0017?raw)
