flux2-klein-4b-q4 model (FLUX.2 klein 4B, 4-bit, Apache-2.0) on a capability-qualified,
attested provider node. The prompt is sealed to that node on your side, and the result is sealed
back to you, so the Grid never sees either in plaintext. See the content rules for what you can and cannot generate. To make images locally or serve them as a provider, see the Singularity Node desktop app.
At a glance
The quote is
max(0.002, ceil6(width * height / 1e6 * 4 * 0.0015)) in USD.
Request flow
Image generation uses three requests: reserve, submit, poll.POST /v1/images/reservesends metadata only. It returns a ready node, the node’s verified keys, a quote, and areservation_token.- The client verifies the node key binding, seals the prompt to the node, and sends
POST /v1/images/generationswith the token and the sealed envelope. The response is202with ajob_idand apoll_url. GET /v1/images/generations/<job_id>every 5 seconds untilstatusiscompleted. The sealed PNG is returned once, along with the node’s signature over the ciphertext. The client verifies the signature, then opens the result locally.
X-API-Key: x402c_...) or a session token
(Authorization: Bearer sgl_sess...).
1. Reserve
POST /v1/images/reserve (JSON body, 16 KiB cap).
model_revision, model_sha256, image_protocol),
and adds reservation_token, node_id, node_ed25519_pubkey, node_x25519_pubkey,
node_x25519_pubkey_sig, key_version, attestation_verified, and a quote object with
price_usd.
2. Seal and submit
Build this plaintext JSON with the keys in exactly this order:seed is null when you did not send one. prompt.bytes is the UTF-8 byte count, not the
character count.
Generate a fresh X25519 response keypair, then seal the plaintext to node_x25519_pubkey with
the x25519-xchacha20poly1305-hkdf-v2 algorithm. The ciphertext must decode to exactly
len(canonical JSON with data = "") + 4 * ceil(bytes / 3) + 40 bytes, or the orchestrator rejects
it. Use the SDK helper where available so the canonical form and sealing stay consistent.
POST /v1/images/generations (JSON body, 64 KiB cap) takes exactly two fields:
202:
estimated_seconds is a conservative upper bound. Typical jobs finish in about 60 to 75 seconds.
Credits are held at submit and settled only when the image is delivered. A failed job refunds the
hold.
3. Poll and open
GET /v1/images/generations/<job_id> returns status of queued, running, completed,
failed, or expired. Only the same account and the same API key that submitted the job can
read it; anything else returns 404.
When status is completed, the response includes sealed_result
(algorithm, encoding, ciphertext, ephemeral_public_key), result_envelope_signature,
node_id, and usage.cost_usd. Then:
- Check
node_idmatches the reserved node. - Verify
result_envelope_signaturewith the reservednode_ed25519_pubkeyoversgl-result-v1\n<job_id>\nimage\n<sha256 hex of the ciphertext string>. - Open the ciphertext with your response secret key and
ephemeral_public_key. - The plaintext is one JSON header line, a newline, then the PNG bytes. Check the header
(
protocol,request_id,job_id,model,model_revision,model_sha256,width,height,prompt_bytes,image.sha256,image.bytes) against what you sent, and check the PNG magic and dimensions.
expired.
Complete client
A minimal Node 20+ client for the whole flow. It uses only published packages (@noble/curves, @noble/ciphers, @noble/hashes, bs58). Save it as image-client.mjs, then run
SGL_API_KEY=x402c_... node image-client.mjs. It writes out.png.
HKDF-SHA256(x25519 shared secret, salt "sgl-e2e-v2-salt", info "sgl-e2e-v2-input")
and the output key uses info sgl-e2e-v2-output. The AAD binds the node key, your ephemeral key
and your response key, so a sealed prompt cannot be replayed against another key.
Errors
A failed job reports
failure_reason such as image_input_invalid or image_runtime_failed,
and the credit hold is refunded.