---
title: "Link a GitHub source repository"
method: POST
path: "/v1/projects/{project_id}/source:link"
---

# Link a GitHub source repository

`POST /v1/projects/{project_id}/source:link`

## Request

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

Uses the workspace GitHub connection to admit a source-link operation without another browser authorization or a build. The caller must have current sources:link permission and the connected installation must cover the repository. If the workspace is not connected, run github connect first; if repository access is missing, update the installation through its settings URL. Repeat identical arguments and key after uncertainty.

## Path parameters

- `project_id` string, required

## Headers

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

## Request body

- LinkProjectSourceRequest
  - `repository_owner` string, required
  - `repository_name` string, required

## 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)
