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 Pending → Probing → Provisioning → Importing →
Snapshotting → Registering → Cleaning → Succeeded/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. |