Skip to content

Run HTTP, SDK and backend examples

JavaScript, Python, and curl examples for submitting tasks, tracking progress, and recovering interrupted requests.

Download the examples

Typed dependency-free TypeScript client

Equivalent JavaScript client

JavaScript workflow runner

Python workflow runner

curl request example

Installed request collection

These files are generated from the current registry. They are not a separately published npm or pip package. The JavaScript runner needs Node 22+ and waveform-client.mjs beside it. Python uses its standard library. Set WAVEFORM_ORIGIN and WAVEFORM_API_KEY privately. Scripts reject redirects and never retry a mutation automatically.

Prepare once, send once, then read

Save a request document containing an operation and its MCP/client input. Use real IDs/hashes returned by your workspace. For example:

{
  "operation": "generation_create",
  "input": {
    "body": {
      "prompt": "Create a focused homepage for my bicycle repair workshop. Use the facts in my brief and make requesting an appointment the main action."
    }
  }
}
node waveform-workflow.mjs prepare request.json intent.json
node waveform-workflow.mjs send intent.json
node waveform-workflow.mjs watch GENERATION_ID
node waveform-workflow.mjs download GENERATION_ID page.zip
# Same commands in Python:
python3 waveform-workflow.py prepare request.json intent.json
python3 waveform-workflow.py send intent.json
python3 waveform-workflow.py watch GENERATION_ID

prepare reads identity, generates a key where required, and writes a private intent file containing the origin, workspace, exact body and fingerprint. send records that an attempt began before making one mutation request. A successful receipt is saved. Re-running send reads that receipt; it does not submit again. If acceptance is unknown, inspect saved state first. recover sends only the exact saved keyed request. Never delete the intent merely to get a new key. A .lock file prevents concurrent sends; after a process crash, confirm no process is using that intent before removing only the stale lock. Keep the intent and its attempted state intact.

Use the same runner for design_edit, design_select, site_task_start or another installed bearer mutation by changing the request document for a new user action. New actions get new intent files. Payment/account management is excluded; complete it in the browser.

Read site jobs, releases and interrupted requests

read accepts a request document for any installed JSON GET operation. It sends one read and cannot submit work. Use it for site_task_get, site_build_get, site_release_options, generation_request_get, artifact_manifest and billing_receipt. The status/watch shorthand is only for generation jobs; use repeated bounded reads or MCP watch tools for other job kinds.

{
  "operation": "site_task_get",
  "input": {
    "params": {
      "id": "22222222-2222-4222-8222-222222222222"
    }
  }
}
node waveform-workflow.mjs read site-status.json
python3 waveform-workflow.py read site-status.json

Replace the example task id with the id returned by site_task_start. The runner prints the actual response; inspect state and attention findings before the next deliberate action.

Use raw HTTP with curl

For raw HTTP, send only the body JSON to the method/path listed in the reference. The quickstart shows the one keyed create request. After saving its returned id as WAVEFORM_GENERATION_ID, these requests only read that job and its eligible terminal ZIP. Do not use a generated-page hostname for API calls. Keep the Authorization header private and do not add redirect-following or automatic mutation-retry flags.

curl --fail-with-body --max-time 30 --header "Authorization: Bearer $WAVEFORM_API_KEY" "$WAVEFORM_ORIGIN/api/v1/generations/$WAVEFORM_GENERATION_ID"

# Only after the saved job reports a downloadable result:
curl --fail-with-body --max-time 30 --header "Authorization: Bearer $WAVEFORM_API_KEY" --output page.zip "$WAVEFORM_ORIGIN/api/v1/generations/$WAVEFORM_GENERATION_ID/download"

A 202 create response is saved work, not completion. A 402 rejects admission; a timeout or 5xx may leave acceptance uncertain. Save the original body/key and read authoritative state before any deliberate identical recovery. The workflow runners above automate that local record keeping without retrying mutations themselves.

Wait for results and reconnect

watch polls generation_get every three seconds and stops on a terminal state or after five minutes. Expiry stops this local wait, not the job. status reads once; cancel explicitly calls generation_cancel. For site tasks use site_task_get/watch; for batches use site_build_get/watch, then inspect each child generation. MCP watches wait at most 20 seconds and return a cursor. Pass that cursor on the next watch so unchanged state does not cause a busy loop.

{
  "id": "11111111-1111-4111-8111-111111111111",
  "cursor": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "waitMs": 20000
}

The server also exposes SSE for generation and proposal jobs at /api/v1/generations/{id}/events and /api/v1/site-jobs/{id}/events. Streams are bounded and reauthorize. Reconnect to current saved truth; Last-Event-ID is not replay assurance. An abort or process exit never substitutes for the cancel operation.

Use the downloadable client directly

import {WaveformClient} from './waveform-client.js';
const waveform = new WaveformClient(process.env.WAVEFORM_ORIGIN!,
  () => ({Authorization: 'Bearer ' + process.env.WAVEFORM_API_KEY}));
const identity = await waveform.call('identity_get', {});
// Persist this exact input and key before this single mutation.
const input = {body: {prompt: 'Create a clear homepage for the bicycle workshop described in my verified brief.'}, idempotencyKey: crypto.randomUUID()};
const job = await waveform.call('generation_create', input);
const current = await waveform.call('generation_get', {params: {id: job.id}});
console.log(identity.workspaceId, current.state);

Compile waveform-client.ts with your project’s TypeScript settings; the .js import above targets that compiled file. For plain JavaScript import waveform-client.mjs. The library returns server shapes directly; binary operations return Response. MCP tools wrap JSON as structuredContent.data. Do not parse monetary decimal strings through floating-point arithmetic.

Find a generation after an interrupted submission

If the response was lost before you saved the generation ID, use generation_request_get with the original persisted request key. This read returns {generation: ...} or {generation: null} in the authenticated workspace and never submits work. Null means no committed result is currently visible: an earlier in-flight request may still commit. Preserve its exact key/body and do not substitute a new key. If the underlying task was cancelled or retired in your system, keep looking up or cancelling existing work; do not replay a create request.

generation_request_get · MCP / client input

{
  "params": {
    "requestKey": "example-create-page-001"
  }
}

Verify a downloaded page before importing it

Read artifact_manifest after a source revision is ready or needs_review. A stopped build with finalizableSourceHash can be recovered with generation_finalize using that hash; it creates a final child without new AI calls or credits. It returns version, generationId, pageId, state, sourceHash, referenceHash, qualityPass, and sorted entries with path, byteSize, sha256 and contentType. Download the same revision through download_read. The inventory and ZIP use the same export builder. Match every extracted file and reject extra, missing, duplicate or unsafe paths; enforce byte limits before extraction. Verify each file digest and the source hash. ZIP container bytes are not a stable identity because archive metadata may differ.

artifact_manifest · MCP / client input

{
  "params": {
    "id": "11111111-1111-4111-8111-111111111111"
  }
}

The final:true field identifies a completed source export, including historical needs_review results. qualityPass remains an honest quality signal, not a publication gate. Verify artifact identity and your integration requirements before importing. Keep scripts as data until served on an isolated page origin with a restrictive CSP; never execute generated JavaScript on your backend or studio origin. Publication needs pages:publish authority, either captured with autoPublish:true or used in an explicit publication command.

Recover interrupted backend jobs

  • Persist intent before network I/O: workspace, operation, body, key and the returned job id.
  • Retry only an identical keyed request after uncertain transport; never fan out fresh keys to overcome a timeout.
  • Read 402 as actual plan/balance admission failure. Do not silently purchase credits or invent a maximum.
  • Read 409 as stale version or conflicting idempotency evidence; reconcile authoritative state.
  • Observe 429/503 with bounded backoff for read requests; leave mutations for explicit same-intent recovery.
  • Finish an automation run at a defined deadline and record the last saved job state for its next run.
  • When webhook_create is listed in the API reference, an owner or admin can subscribe a receiver to signed generation, publication and form-submission events. Use bounded read/watch or SSE when no receiver is configured. Read current authorized state after an event; delivery can be duplicated or arrive out of order.

Set up signed event webhooks