Docs · API
API keys & automation
Use a personal access token to call the SynthForge REST API from scripts, CI, or local tools without a browser session cookie.
1. Create a key
- Sign in at app.synthforge.io
- Open Settings → API keys
- Choose a short name (for example
ciorlaptop) and create the key - Copy the secret immediately. It is shown only once.
After that you only see a prefix like
sfk_live_ab12…
Production secrets look like sfk_live_…. Dev-environment keys use
sfk_dev_… against https://api-dev.synthforge.io.
2. Authenticate
Send the secret as a Bearer token on every request. Base URL for production:
https://api.synthforge.io export SF_API_KEY='sfk_live_…' # paste your secret
export API_BASE='https://api.synthforge.io'
curl -sS -H "Authorization: Bearer $SF_API_KEY" \
"$API_BASE/api/v1/users/me" | jq .
A successful response is your user profile JSON (email, quotas, etc.). A bad or revoked key returns
401.
3. curl: end-to-end generate
Minimal flow: create a schema → start a dataset job → poll status → download the ZIP (CSV, Parquet, SQL loaders, README, quality report).
export SF_API_KEY='sfk_live_…'
export API_BASE='https://api.synthforge.io'
# 1) Create a minimal schema (or use an existing schema id from the app)
SCHEMA_JSON='{
"name": "api-demo",
"schema_data": {
"tables": [
{
"name": "customers",
"columns": [
{ "name": "id", "field_type": "integer_sequence", "primary_key": true },
{ "name": "email", "field_type": "email" },
{ "name": "full_name", "field_type": "full_name" }
]
},
{
"name": "orders",
"columns": [
{ "name": "id", "field_type": "integer_sequence", "primary_key": true },
{
"name": "customer_id",
"field_type": "integer",
"foreign_key": { "table": "customers", "column": "id" }
},
{ "name": "amount", "field_type": "currency_amount" }
]
}
]
}
}'
SCHEMA_ID=$(curl -sS -X POST "$API_BASE/api/v1/schemas" \
-H "Authorization: Bearer $SF_API_KEY" \
-H "Content-Type: application/json" \
-d "$SCHEMA_JSON" | jq -r .id)
# 2) Start generation (flat formats stream out-of-core on the server)
DATASET_ID=$(curl -sS -X POST "$API_BASE/api/v1/datasets" \
-H "Authorization: Bearer $SF_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"schema_id\": \"$SCHEMA_ID\",
\"name\": \"api-demo-run\",
\"row_counts\": { \"customers\": 100, \"orders\": 400 },
\"formats\": [\"csv\", \"parquet\"],
\"seed\": 42
}" | jq -r .id)
# 3) Poll until completed / failed / cancelled
while true; do
STATUS=$(curl -sS -H "Authorization: Bearer $SF_API_KEY" \
"$API_BASE/api/v1/datasets/$DATASET_ID/status")
S=$(echo "$STATUS" | jq -r .status)
echo "status=$S"
case "$S" in completed|failed|cancelled) break ;; esac
sleep 2
done
# 4) Presigned download URL → ZIP bundle
URL=$(curl -sS -H "Authorization: Bearer $SF_API_KEY" \
"$API_BASE/api/v1/datasets/$DATASET_ID/download" | jq -r .url)
curl -sS -L -o dataset.zip "$URL"
echo "wrote dataset.zip"
Prefer schemas you already built in the visual editor? Skip step 1 and pass that schema’s UUID as
schema_id. List yours with
GET /api/v1/schemas.
4. Python
Same flow with the standard library-friendly requests package
(pip install requests):
import os
import time
import requests
API = os.environ.get("SF_API_BASE", "https://api.synthforge.io")
KEY = os.environ["SF_API_KEY"] # sfk_live_… or sfk_dev_…
H = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}
# Who am I?
me = requests.get(f"{API}/api/v1/users/me", headers=H, timeout=30)
me.raise_for_status()
print(me.json()["email"])
# Create schema
schema = {
"name": "py-demo",
"schema_data": {
"tables": [
{
"name": "events",
"columns": [
{"name": "id", "field_type": "integer_sequence", "primary_key": True},
{"name": "label", "field_type": "word"},
],
}
]
},
}
r = requests.post(f"{API}/api/v1/schemas", headers=H, json=schema, timeout=60)
r.raise_for_status()
schema_id = r.json()["id"]
# Generate
r = requests.post(
f"{API}/api/v1/datasets",
headers=H,
json={
"schema_id": schema_id,
"name": "py-demo-run",
"row_counts": {"events": 500},
"formats": ["csv"],
"seed": 7,
},
timeout=60,
)
r.raise_for_status()
dataset_id = r.json()["id"]
# Poll
while True:
st = requests.get(
f"{API}/api/v1/datasets/{dataset_id}/status", headers=H, timeout=30
).json()
print(st["status"], st.get("progress_pct"))
if st["status"] in ("completed", "failed", "cancelled"):
break
time.sleep(2)
if st["status"] != "completed":
raise SystemExit(st)
# Download ZIP
url = requests.get(
f"{API}/api/v1/datasets/{dataset_id}/download", headers=H, timeout=30
).json()["url"]
zip_bytes = requests.get(url, timeout=120).content
open("dataset.zip", "wb").write(zip_bytes)
print("wrote dataset.zip", len(zip_bytes), "bytes")
5. CLI (synthforge)
The synthforge CLI (alias sf) wraps the same API.
It is available for early use (not on public npm yet). You can always inject a Settings-minted key via
SF_API_KEY without synthforge login.
# CLI early access. Easiest path: set SF_API_KEY from Settings.
# Option A: login (mints a key named "cli" and stores it locally)
export SF_PASSWORD='your-password'
synthforge login --email you@example.com
# Option B: use a key you created in Settings
export SF_API_KEY='sfk_live_…'
export SF_API_BASE='https://api.synthforge.io' # optional; production is the default
synthforge whoami
synthforge schemas list
# AI-forge a schema, then generate + download
SCHEMA_ID=$(synthforge schemas forge -d "customers and orders with FK" --name demo | tail -1)
synthforge generate --schema "$SCHEMA_ID" \
--rows customers=50,orders=200 \
--format csv --seed 42 -o demo.zip 6. TypeScript SDK
@synthforgeio/sdk is a thin typed client for schemas, AI schema jobs, and datasets.
Early access only for now (not on public npm yet).
// Workspace package @synthforgeio/sdk (not published to npm in v1)
import { SynthForge, SynthForgeError } from '@synthforgeio/sdk';
const sf = new SynthForge({
apiKey: process.env.SF_API_KEY!, // sfk_…
// baseUrl: 'https://api-dev.synthforge.io',
});
const { items } = await sf.schemas.list({ limit: 20 });
const schema = await sf.schemas.create({
name: 'orders',
schema_data: {
tables: [
{
name: 'orders',
columns: [
{ name: 'id', field_type: 'uuid', primary_key: true },
{ name: 'label', field_type: 'word' },
],
},
],
},
});
const dataset = await sf.datasets.create({
schema_id: schema.id,
name: 'demo',
row_counts: { orders: 100 },
formats: ['csv'],
seed: 42,
});
const status = await sf.datasets.wait(dataset.id);
if (status.status === 'completed') {
const { url } = await sf.datasets.getDownloadUrl(dataset.id);
// fetch(url) → ZIP
} Useful endpoints
| Method | Path | Notes |
|---|---|---|
| GET | /api/v1/users/me | Account + quota snapshot |
| GET / POST | /api/v1/schemas | List or create schemas |
| POST | /api/v1/datasets | Start generation (row_counts, formats, seed, locale…) |
| GET | /api/v1/datasets/:id/status | Poll until completed / failed / cancelled |
| GET | /api/v1/datasets/:id/download | JSON with presigned url for the ZIP |
| POST | /api/v1/datasets/:id/cancel | Cooperative cancel of an in-flight job |
| GET | /openapi.json | Full OpenAPI document (no auth) |
Machine-readable catalog: https://api.synthforge.io/openapi.json
Security notes
- Treat keys like passwords. Prefer environment variables or a secret manager. Never commit them.
- Store CI secrets as
SF_API_KEY(and optionalSF_API_BASE). - Revoke compromised keys in Settings; rotation is create-new then revoke-old (or re-run
synthforge loginwith the same key name). - API-key auth cannot create more keys (session required for key management).
- Keys inherit your account quotas (rows, storage, concurrency). Very large jobs may return
413if they exceed plan limits, especially nested JSON formats.