Migrations API
Migrations API
Create and track migrations over REST. All endpoints require a bearer token
(see Authentication) and Accept: application/json.
Migrate via API only (end-to-end)
No dashboard needed — you can run a full migration with just the API. The whole flow is:
pre-flight → create → (pay, if PAYG) → poll → done. Here's a complete, copy-paste script:
#!/usr/bin/env bash
set -euo pipefail
BASE=https://dev.dbmigratepro.com
TOKEN="YOUR_TOKEN" # Settings → API Tokens (see Authentication)
SRC="mysql://user:pass@source-host:3306/app"
DST="postgresql://user:pass@target-host:5432/app"
auth=(-H "Authorization: Bearer $TOKEN" -H "Accept: application/json" -H "Content-Type: application/json")
# 1. Pre-flight: confirm both databases are reachable, measure the source, preview the price.
curl -s -X POST "$BASE/api/migrations/preflight" "${auth[@]}" \
-d "{\"source_url\":\"$SRC\",\"target_url\":\"$DST\"}" | jq '{ready, estimate, free_eligible}'
# 2. Create the migration.
resp=$(curl -s -X POST "$BASE/api/migrations" "${auth[@]}" \
-d "{\"source_url\":\"$SRC\",\"target_url\":\"$DST\"}")
id=$(echo "$resp" | jq -r '.migration.id')
checkout=$(echo "$resp" | jq -r '.checkout_url // empty')
# 3. Pay if required. PAYG returns a checkout_url that a human authorizes in a browser (a hold —
# captured only on success, never on failure). Pro and first-migration-free runs start
# immediately with NO checkout_url, so those are fully headless.
[ -n "$checkout" ] && echo "Authorize the hold: $checkout"
# 4. Poll until the run finishes.
while :; do
status=$(curl -s "$BASE/api/migrations/$id" "${auth[@]}" | jq -r '.status')
echo "status: $status"
case "$status" in completed|failed) break;; esac
sleep 3
done
# 5. (Optional) Read the timeline.
curl -s "$BASE/api/migrations/$id/logs" "${auth[@]}" | jq -r '.data[].message'
Fully headless? Yes for Pro and your first-migration-free run (no payment step). A
pay-as-you-go run needs the one-time Stripe hold authorized in a browser — after that the
whole thing is API-driven.
The rest of this page is the reference for each step.
Create a migration
curl -X POST https://dev.dbmigratepro.com/api/migrations \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-d '{
"source_url": "mysql://user:pass@source-host:3306/app",
"target_url": "postgresql://user:pass@target-host:5432/app"
}'
Fields:
| Field |
Required |
Description |
source_url |
yes |
Connection URL of the database to migrate from (MySQL or PostgreSQL). |
target_url |
yes |
Connection URL of the database to migrate to. |
estimate_id |
no |
ID of a prior price quote, to tie the run to a shown estimate. |
The engine auto-detects whether this is a same-engine transfer or a cross-engine
conversion from the two URLs — you don't pick.
Response
-
Pay-as-you-go: the migration is created as awaiting_payment and the response
includes a checkout_url. Send the user there to authorize payment; the migration
starts automatically once the hold is placed. You're only charged on success.
{
"message": "Payment required to start migration",
"migration": { "id": "0191e5c2-6a4b-71f2-b3c9-2d1e4f8a9c07", "status": "awaiting_payment", "...": "..." },
"amount": 8.42,
"checkout_url": "https://checkout.stripe.com/..."
}
-
Pro subscriber: it starts immediately, no per-migration charge:
{
"message": "Migration started — included in your Pro plan",
"migration": { "id": "0191e5c2-6a4b-71f2-b3c9-2d1e4f8a9c07", "status": "pending" },
"covered_by_plan": true
}
-
First migration free (non-Pro, source under 1 GB): your first successful migration is on us —
it starts immediately with no hold and no checkout_url:
{
"message": "Migration started — your first migration is on us (under 1 GB)",
"migration": { "id": "0191e5c2-6a4b-71f2-b3c9-2d1e4f8a9c07", "status": "pending" },
"covered_by_plan": true,
"free": true
}
Detect the case in code: if the response has a checkout_url, authorize it; otherwise the run has
already started (Pro or free).
The migration id is an opaque string (a UUID) — capture it from the create response and pass it
back verbatim; don't assume it's numeric.
Check migration status
curl https://dev.dbmigratepro.com/api/migrations/0191e5c2-6a4b-71f2-b3c9-2d1e4f8a9c07 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
Key status values you'll see:
| Status |
Meaning |
awaiting_payment |
Created; waiting for the payment hold to be authorized. |
pending / in_progress |
Queued or actively running. |
completed |
Done — schema, data, indexes and foreign keys applied; row counts verified. |
failed |
Stopped and failed closed. Not charged. Inspect logs and retry. |
Other endpoints
| Method & path |
Purpose |
GET /api/migrations |
List your migrations. |
GET /api/migrations/{id} |
Get one migration. |
GET /api/migrations/{id}/logs |
Fetch the migration's log timeline. |
POST /api/migrations/{id}/checkout |
(Re)start Stripe Checkout for one that's awaiting payment. |
POST /api/migrations/{id}/retry |
Re-queue a failed migration. |
DELETE /api/migrations/{id} |
Delete a migration. |
Polling for completion
Poll GET /api/migrations/{id} until status is completed or failed. A typical loop
waits a few seconds between checks. Migrations of small databases finish in seconds;
larger ones scale with size.