Using curl
The Sybilion API is plain HTTP/JSON. If you don't want a generated client — for shell scripts, prototypes, CI, or onboarding — these patterns get you the same coverage as the SDKs without any dependencies.
Setup
Export your API key once per shell:
export SYBILION_API_TOKEN="sk_ops_..."The base URL is https://api.sybilion.dev. To hit a non-production host, substitute the URL.
Need jq?
Most examples pipe to jq for readability. It's optional — the JSON works just as well in your code.
Authentication header
Every authenticated request takes a Bearer token:
curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
https://api.sybilion.dev/api/v1/me | jqA missing or invalid token returns 401 Unauthorized. There is no separate "verify token" endpoint — GET /api/v1/me is the canonical health check (it also tells you balance, tier, and trial state in one call).
See Authentication for the supported token types and how to get them.
Paginated lists
Listing endpoints (/usage, /jobs) share four query parameters:
| Param | Default | Notes |
|---|---|---|
page | 1 | 1-based. |
limit | 50 | Max 200 per page. |
sort | endpoint-specific | E.g. created_at, id. |
order | desc | asc or desc. |
The response wraps results in a pagination object:
curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
"https://api.sybilion.dev/api/v1/usage?page=1&limit=50&sort=created_at&order=desc" \
| jq '{total: .pagination.total, total_pages: .pagination.total_pages, first: .usage_events[0]}'To walk every page, increment page until you've seen pagination.total_pages pages.
Polling an async job
Forecasts return 202 with a job_id. Poll GET /api/v1/forecasts/:id until settled is true, then read status and artifacts. A simple loop with jq -e exits when settled:
JOB_ID="<paste job_id>"
API="https://api.sybilion.dev"
until curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
"$API/api/v1/forecasts/$JOB_ID" | jq -e '.settled == true' >/dev/null; do
sleep 2
done
curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
"$API/api/v1/forecasts/$JOB_ID" \
| jq '{status, eur_cents_final, artifacts: .artifacts | map(.name)}'Forecasts run for tens of seconds to a few minutes. Pick a poll interval (2–5 seconds is fine) and add a max-duration guard for production use.
Reading the error envelope
Every error response uses the same shape. For validation:
{
"error": "validation_failed",
"details": [{ "field": "horizon", "message": "horizon must be between 1 and 12" }]
}Validation is fail-fast — only the first offending field is reported per call. Other errors use a shorter shape:
{ "error": "insufficient credits" }Common patterns:
# Show only the error code on non-2xx, otherwise pretty-print the body.
RES=$(curl -sS -w "\n%{http_code}" \
-H "Authorization: Bearer $SYBILION_API_TOKEN" \
https://api.sybilion.dev/api/v1/forecasts \
-d @forecast_body.json)
BODY=$(printf '%s' "$RES" | sed '$d')
CODE=$(printf '%s' "$RES" | tail -n1)
if [ "$CODE" -ge 400 ]; then
printf 'HTTP %s — %s\n' "$CODE" "$(printf '%s' "$BODY" | jq -r '.error // .message // .')"
else
printf '%s' "$BODY" | jq
fiFull catalog of HTTP codes: Errors & limits.
Downloading artifacts
Forecast artifacts stream through the API at GET /api/v1/forecasts/:id/artifacts/:name — there are no direct storage URLs. Use -o to save:
JOB_ID="<paste job_id>"
for ART in forecast.json external_signals.json backtest_metrics.json; do
curl -sS -H "Authorization: Bearer $SYBILION_API_TOKEN" \
-o "$ART" \
"https://api.sybilion.dev/api/v1/forecasts/$JOB_ID/artifacts/$ART"
done
jq '.data.forecast_series | to_entries | .[0]' forecast.jsonArtifact responses can be large (up to 100 MiB per file). Use Range headers for partial reads — the API returns 206 when honoring a range. Full artifact contract: Artifact download.
Idempotent retries
For synchronous billed calls (e.g. POST /api/v1/drivers), pass a stable X-Request-ID header on each retry to deduplicate billing on success:
REQ_ID=$(uuidgen)
curl -sS -X POST https://api.sybilion.dev/api/v1/drivers \
-H "Authorization: Bearer $SYBILION_API_TOKEN" \
-H "Content-Type: application/json" \
-H "X-Request-ID: $REQ_ID" \
-d @drivers_body.jsonUseful flags
| Flag | Why |
|---|---|
-sS | Silent + show errors. Hides progress bars without hiding real failures. |
-w "\n%{http_code}\n" | Append the HTTP status to the output for scripted handling. |
-D - | Dump response headers to stdout (useful for inspecting Content-Type, Content-Length). |
--fail-with-body | Exit non-zero on 4xx / 5xx while still printing the body (curl 7.76+). |
-o file | Stream the body to disk (use for artifact downloads). |
-H "Accept-Encoding: gzip" | Lets the API gzip large list responses. |
See also
- Quickstart — end-to-end walkthrough.
- Feature pages with curl tabs: Forecasts · Drivers · Regions & categories · Account & usage
- Errors & limits · Authentication