Sources & imports

Registering a source connection and running an import job against it — the pipeline that turns a real RDS Postgres database into a golden snapshot version. See Goldens and imports for the CLI-level walkthrough, including where the source's actual credentials go (straight into the data-plane cluster, never through this API).

All routes on this page are admin-gated, except listing sources.

POST /v1/sources — register a source connection

Auth: admin.

Request body

Field Type Required Notes
kind string yes "rds" or "s3" (only "rds" is importable today — see below).
config object yes Kind-specific connection metadata, e.g. {"host": "...", "dbname": "...", "username": "..."}. Endpoint metadata only — no password.
scoped_creds_ref string no The name of the Kubernetes Secret in the data-plane cluster holding the actual credentials (e.g. adjoint-src-app). The password itself never transits this API.
$ curl -s https://api.stagdb.com/v1/sources -X POST -H "Authorization: Bearer $TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{"kind":"rds","config":{"host":"prod-replica.abcdef.us-east-1.rds.amazonaws.com","dbname":"app","username":"adjoint_ro"},"scoped_creds_ref":"adjoint-src-app"}'

Response 201 Created

{"id": "3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b", "kind": "rds", "status": "registered"}
Status When
400 kind is neither "rds" nor "s3" — wire body is the generic {"error": "invalid input"}.
403 Caller is not an admin.

GET /v1/sources — list source connections

Auth: bearer (any authenticated member can list; only admins can create or start imports against them).

$ curl -s https://api.stagdb.com/v1/sources -H "Authorization: Bearer $TOKEN"

Response 200 OK

{
  "sources": [
    {
      "id": "3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b",
      "kind": "rds",
      "status": "registered",
      "config": {"host": "prod-replica.abcdef.us-east-1.rds.amazonaws.com", "dbname": "app", "username": "adjoint_ro"},
      "scoped_creds_ref": "adjoint-src-app"
    }
  ]
}

No credential values ever appear here — config is endpoint metadata, and scoped_creds_ref is only the Secret's name.

Status When
401 Missing/invalid/expired bearer token.

POST /v1/imports — start an import

Auth: admin.

Request body

Field Type Required Notes
source_id string yes A source connection UUID (from GET /v1/sources).
golden string yes The golden lineage name to build the next version of (created on first use).
pg_major integer no Must be >= 13 if set. Must match the source's actual Postgres major version.
$ curl -s https://api.stagdb.com/v1/imports -X POST -H "Authorization: Bearer $TOKEN" \
    -H 'Content-Type: application/json' \
    -d '{"source_id":"3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b","golden":"prod-pg16","pg_major":16}'

Response 202 Accepted — the import runs asynchronously in the data plane.

{
  "id": "5b9d7c31-2e4f-4a6b-8c0d-1e2f3a4b5c6d",
  "source_id": "3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b",
  "golden": "prod-pg16",
  "version": 3,
  "phase": "Pending",
  "message": "",
  "size_bytes": 0,
  "pg_major": 16,
  "created_at": "2026-07-19T21:03:12Z",
  "finished_at": null
}

phase progresses PendingProbingProvisioningImportingSnapshottingRegisteringCleaningSucceeded/Failed. version is reserved at request time — the version number this import will register once it succeeds; existing clones of older versions are unaffected while it runs.

Status When
400 golden empty; pg_major set but < 13; the source's kind isn't "rds" (only RDS is importable); the source's config is missing host/dbname; or the source has no scoped_creds_ref set. Wire body for all of these is the generic {"error": "invalid input"} — except a malformed source_id, which gets its own {"error": "bad source_id"}.
403 Caller is not an admin.
404 No such source connection.
409 The target golden exists but its substrate isn't "postgres"; an import for this exact golden is already running; or a concurrent request just reserved the same version (rare — retry). Wire body for all three is the generic {"error": "conflict"} — they are not distinguishable from the body. The fourth 409, no registered cluster, is the one you can tell apart: {"error": "org has no registered cluster"}.
— (503/504 not applicable) An import with no registered cluster returns the distinct 409 above, not 503 — imports need a cluster to run the ephemeral probe/dump Postgres, checked up front.

GET /v1/imports — list import jobs

Auth: admin.

$ curl -s https://api.stagdb.com/v1/imports -H "Authorization: Bearer $TOKEN"

Response 200 OK

{"imports": [ /* job objects, same shape as the POST response above */ ]}
Status When
403 Caller is not an admin.

GET /v1/imports/{id} — get one import job

Auth: admin.

$ curl -s https://api.stagdb.com/v1/imports/5b9d7c31-2e4f-4a6b-8c0d-1e2f3a4b5c6d -H "Authorization: Bearer $TOKEN"

Response 200 OK — a single job object. Once phase is Succeeded, size_bytes and finished_at are populated; on Failed, message carries the failure reason.

{
  "id": "5b9d7c31-2e4f-4a6b-8c0d-1e2f3a4b5c6d",
  "source_id": "3e6f0a2b-7c8d-4e1f-9a2b-3c4d5e6f7a8b",
  "golden": "prod-pg16",
  "version": 3,
  "phase": "Succeeded",
  "message": "",
  "size_bytes": 45097156608,
  "pg_major": 16,
  "created_at": "2026-07-19T21:03:12Z",
  "finished_at": "2026-07-19T21:09:53Z"
}
Status When
400 {id} not a valid UUID.
403 Caller is not an admin.
404 No such import job in this org.

Next