Reference

API reference

A REST API over HTTPS. JSON in, JSON out. Base URL https://api.polnor.net/api/v1. Every call is authenticated and scoped to a single workspace.

Conventions

Base URL & format

All endpoints live under https://api.polnor.net/api/v1. Request and response bodies are JSON; send Content-Type: application/json on writes. Timestamps are ISO-8601 UTC.

Pagination

List endpoints accept limit (default 50, max 200) and cursor. The response carries next_cursor when more rows exist.

GET /compute?limit=50&cursor=eyJpZCI6...

# → { "data": [ … ], "next_cursor": "eyJpZCI6…" }

Rate limits & quotas

Quota ceilings return 429 with the exact limit in the body, for example max_running_runs=10, current=10.

Errors

StatusMeaning
400Malformed request or invalid parameters.
401Missing or expired token.
403Authenticated but not permitted.
404Not found, or not in your workspace.
409Conflict (for example, resource already in that state).
429Quota exceeded.

Errors share one shape: a JSON object with a single error string.

Authentication

Exchange credentials for a bearer token and send it on every call. See Authentication for API keys and agent tokens.

POST/auth/login

Exchange email and password for a short-lived access token.

Request

curl -s https://api.polnor.net/api/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"you@acme.eu","password":"••••••"}'

200 OK

{
  "access_token": "eyJhbGciOi…",
  "token_type": "Bearer",
  "expires_in": 3600
}
POST/auth/refresh

Issue a fresh access token before the current one expires.

Compute

GPU and CPU instances provisioned on your own cloud. See the Compute guide.

GET/compute

List compute instances in the workspace.

200 OK

{ "data": [
  { "id": "cmp_8f21", "name": "training-a100",
    "flavor": "gpu.a100", "status": "running",
    "region": "GRA9", "auto_stop": "2h" }
] }
POST/compute

Create an instance. It is provisioned on the cloud provider registered for the workspace.

Body

FieldTypeNotes
namestringRequired. Unique in the workspace.
flavorstringRequired. e.g. gpu.a100, cpu.32.
auto_stopstring30m, 2h or never. Default 1h.
imagestringOptional. Pinned on first start.
curl -s https://api.polnor.net/api/v1/compute \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"training-a100","flavor":"gpu.a100","auto_stop":"2h"}'

201 Created

{ "id": "cmp_8f21", "status": "stopped" }
POST/compute/:id/start

Start a stopped instance. The image is persisted on first start for reproducible restarts.

POST/compute/:id/stop

Stop a running instance and release the underlying VM.

DELETE/compute/:id

Delete an instance. Returns 409 if it is still running.

SQL warehouses

On-demand DuckDB + Spark warehouses. See the SQL warehouses guide.

GET/sql/warehouses

List warehouses and their state (stopped, starting, running, stopping).

POST/sql/warehouses/:id/start

Provision the warehouse VM with DuckDB and Spark sidecars. Takes roughly three minutes to reach running.

POST/sql/execute

Run a query. Reads route to DuckDB, writes to Spark, automatically.

Request

curl -s https://api.polnor.net/api/v1/sql/execute \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"SELECT count(*) FROM acme.sales.orders",
       "warehouse_id":"wh_4a2b"}'

200 OK

{
  "columns": ["count"],
  "rows": [[1284902]],
  "engine": "duckdb",
  "elapsed_ms": 412,
  "lineage": { "read": ["acme.sales.orders"] }
}

Catalog

Iceberg namespaces and tables, via the Lakekeeper catalog. See the Lakehouse guide.

GET/databases

List databases (Iceberg namespaces) in the workspace.

GET/databases/:id/tables

List tables in a namespace, with row counts and current snapshot.

GET/databases/:id/schemas/:schema/tables/:table/schema

Return a table's column schema (name and Iceberg type).

{ "columns": [
  { "name": "id", "type": "long" },
  { "name": "amount", "type": "decimal(10,2)" }
] }

Jobs

Jobs run a command or a multi-task DAG. See the Jobs guide.

POST/jobs

Create a job. Pass tasks to declare a DAG, or omit it for a single command.

{
  "name": "daily-pipeline",
  "tasks": [
    { "key": "ingest", "command": "python ingest.py" },
    { "key": "transform", "command": "python tx.py",
      "depends_on": ["ingest"], "max_retries": 2, "timeout_seconds": 1800 }
  ]
}
PUT/jobs/:id

Update a job. tasks: null leaves the DAG intact; tasks: [] clears it. Editing never rewrites past runs.

POST/jobs/:id/run

Trigger a run. Subject to the max_running_runs quota.

{ "run_id": "run_4812", "status": "pending" }

Runs & tasks

GET/runs/:id

Run status and timing. Statuses: pending, running, success, failed, cancelled.

GET/runs/:id/tasks

Per-task rows for a run (empty for single-command jobs).

[ { "key": "ingest", "status": "success", "retry_count": 0 },
  { "key": "transform", "status": "running" } ]
GET/runs/:id/tasks/:key/logs

Logs for a single task, streamed and archived.

GET/runs/:id/lineage

Tables this run read and wrote, captured from each query. See Governance.

POST/runs/:id/cancel

Cancel a run. Pending and running tasks are cancelled; the agent SIGTERMs then SIGKILLs live processes.

Experiments & models

MLflow-compatible tracking. See Models & serving and the Python SDK.

POST/experiments/:id/runs/:run/metrics

Log a metric. Stored as the latest value and as a step history.

{ "key": "auc", "value": 0.934, "step": 4200 }
POST/experiments/:id/runs/:run/metrics/batch

Log many metrics in one call.

GET/experiments/:id/runs/:run/metrics/:key

Full step / value / timestamp history for a metric.

POST/experiments/:id/runs/:run/artifacts/presigned-url

Get a presigned URL to upload an artifact straight to your own S3.

GET/models/:id/endpoints

Serving endpoints backed by a model version.

Serving endpoints

GET/endpoints

List serving endpoints with status, model version, QPS and latency.

POST/endpoints

Create an endpoint from a model version. Subject to the max_endpoints quota.

{ "name": "churn-prod", "model": "churn-v3", "version": 7 }

Audit & lineage

GET/audit/analytics

Daily roll-ups of the audit log.

GET /audit/analytics?from=2026-06-01&to=2026-06-12&group_by=day,action

Billing

See the Billing guide and Pricing.

GET/settings/billing/invoices

List the current workspace's invoices (draft, sent, paid).

GET/settings/billing/usage?from=&to=

Usage and cost for a date range: provider cost, multiplier, and Polnor margin.

{ "data": [
  { "category": "compute_gpu", "provider_cost": 1842.50,
    "multiplier": 2.0, "total_cost": 1842.50 }
] }