Backbone LabDocs
Get started

Quickstart

This guide runs one listing photo through the pipeline — perspective correction, signature tone, a dramatic sky — first with an SDK, then with raw curl so you can see every request on the wire.

Get an API key

Request a key for your workspace, then export it. Keys start with sk- and ride the X-API-Key header (the SDKs read BKBNLAB_API_KEY from the environment).

export BKBNLAB_API_KEY=sk-...

With an SDK

The SDKs hide the upload dance and the realtime plumbing: upload, order, wait, save. wait() follows the order live over a single multiplexed WebSocket and falls back to polling on restrictive networks.

npm install @bkbnlab/api

The Python (bkbnlab) and Kotlin (ai.bkbnlab:api-kotlin) clients share the same surface; their packages are being published.

import { BkbnClient } from '@bkbnlab/api'

const bkbn = new BkbnClient()            // reads BKBNLAB_API_KEY

const photo = await bkbn.upload('living-room.jpg')

const order = await bkbn.order({
  inputs: [photo],
  perspective: true,
  tonecraft: true,
  sky: 'dramatic',
})

const result = await order.wait({
  onProgress: (p) => console.log(p.stage, p.percent),
})
await result.save('enhanced.jpg')

The same, on the wire

Four steps with plain curl. Every JSON response is wrapped in a data envelope; errors come back as { "error": { "status", "reason" } }.

Step 1: Upload your image

Uploads are presigned: declare the file to get an assetId and a one-time uploadUrl, PUT the bytes there (they never transit the API), then confirm.

CREATE=$(curl -s -X POST https://api.bkbn.ai/v1/assets \
  -H "X-API-Key: $BKBNLAB_API_KEY" -H "Content-Type: application/json" \
  -d '{"filename": "living-room.jpg", "contentType": "image/jpeg"}')
ASSET_ID=$(echo "$CREATE" | jq -r .data.assetId)

curl -s -X PUT --upload-file living-room.jpg -H "Content-Type: image/jpeg" \
  "$(echo "$CREATE" | jq -r .data.uploadUrl)"

curl -s -X POST https://api.bkbn.ai/v1/assets/$ASSET_ID/uploaded \
  -H "X-API-Key: $BKBNLAB_API_KEY"

Ingest then normalizes the file. Poll until the asset is ready:

until [ "$(curl -s https://api.bkbn.ai/v1/assets/$ASSET_ID/status \
  -H "X-API-Key: $BKBNLAB_API_KEY" | jq -r .data.status)" = "ready" ]; do sleep 1; done

Step 2: Submit the order

One endpoint for every feature: POST /v1/orders. inputs takes 1-5 asset ids — the exposure brackets of one scene; HDR merge is automatic when there is more than one. The other fields are the feature options.

ORDER_ID=$(curl -s -X POST https://api.bkbn.ai/v1/orders \
  -H "X-API-Key: $BKBNLAB_API_KEY" -H "Content-Type: application/json" \
  -d '{
    "inputs": ["'$ASSET_ID'"],
    "perspective": true,
    "tonecraft": true,
    "sky": true, "sky_style": "dramatic"
  }' | jq -r .data.orderId)

Step 3: Follow it live

The order streams its lifecycle over SSE: a snapshot on connect, then progress events, then completed or failed — at which point the stream closes on its own.

curl -sN https://api.bkbn.ai/v1/orders/$ORDER_ID/events \
  -H "X-API-Key: $BKBNLAB_API_KEY"

Polling works too: GET /v1/orders/$ORDER_ID returns the same summary (status, progress, an ETA estimate while running).

Step 4: Download the result

OUTPUT_ID=$(curl -s https://api.bkbn.ai/v1/orders/$ORDER_ID \
  -H "X-API-Key: $BKBNLAB_API_KEY" | jq -r .data.outputAssetId)

curl -o enhanced.jpg https://api.bkbn.ai/v1/assets/$OUTPUT_ID

Next steps