> ## Documentation Index
> Fetch the complete documentation index at: https://docs.b3iq.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Private Jobs

B3IQ-native async encrypted private-job APIs and the active private_transport privacy boundary.

Private jobs are B3IQ-native async APIs, not hosted OpenAI chat. They are used
for encrypted private transport workflows against a fully enrolled machine on
your own account. `node_id` is required, and a customer-token caller who
targets a machine they don't own gets a 403 `Node not owned`.

**Privacy wording matters**

Current private jobs are private from the B3IQ control plane, gateway, hosted
  playground, router accounting, billing exports, and sanitized diagnostic payloads.
  They are not yet a claim that prompts and outputs are hidden from the node
  operator.

## Create a direct private job

Seal the request first with the private-transport helper. Send only the
encrypted request envelope to B3IQ.
Use `B3IQ_GATEWAY_BASE_URL=https://b3iq.org/v1/api` for the public hosted
gateway facade. `B3IQ_PRIVATE_NODE_ID` must be a fully enrolled machine on
your own account. Jobs have no per-request B3IQ charge, like other requests served
by machines you own.

```javascript
import { readFileSync } from "node:fs";

const baseURL = process.env.B3IQ_GATEWAY_BASE_URL;
const customerID = process.env.B3IQ_CUSTOMER_ID;
const nodeID = process.env.B3IQ_PRIVATE_NODE_ID;
const customerToken = readFileSync(process.env.B3IQ_CUSTOMER_TOKEN_FILE, "utf8").trim();
const encryptedRequest = JSON.parse(readFileSync(process.env.B3IQ_ENCRYPTED_REQUEST_FILE, "utf8"));

const response = await fetch(`${baseURL}/private-inference/jobs`, {
  method: "POST",
  headers: {
    "content-type": "application/json",
    "x-b3iq-customer-id": customerID,
    "x-b3iq-customer-token": customerToken
  },
  body: JSON.stringify({
    job_id: process.env.B3IQ_PRIVATE_JOB_ID,
    node_id: nodeID,
    model_id: "qwen3-8b",
    encrypted_request: encryptedRequest
  })
});

console.log(await response.json());
```

## Envelope contract

Accepted `b3iq-private-transport-v1` request envelope fields:

| Field | Purpose |
| --- | --- |
| ` version ` | Envelope version marker |
| ` key_id ` | Node transport key identifier |
| ` algorithm ` | Encryption algorithm |
| ` client_public_key_x25519 ` | Client public key for X25519 key exchange |
| ` nonce ` | Encryption nonce |
| ` ciphertext ` | Encrypted request payload |
| ` aad_hash ` | Optional associated-data hash |

Extra request fields are rejected before dispatch so plaintext cannot be
smuggled into D1 under `encrypted_request`.

## Job lifecycle

**Client verifies policy**

For current private transport, the client selects an enrolled node and
    transport key. Future verified-confidential jobs also verify TEE attestation
    before encryption.
  **Client seals payload**

The plaintext request is encrypted to the node transport key and bound with
    associated data such as `b3iq-private-inference:<job_id>`.
  **Control plane queues ciphertext**

B3IQ stores authorized job state, ciphertext envelopes and redacted
    operating metadata. It does not store the plaintext prompt or output.
  **Node claims and executes**

The host agent receives the encrypted job through command polling, decrypts,
    executes against local runtime, and returns an encrypted result envelope.
  **Receipt records**

The result can include a signed receipt hash, recorded as public-safe
    evidence. Private jobs on your own machines are free. Nothing is billed
    or paid out.

## Read job state

```text
GET /v1/api/private-inference/jobs/{job_id}
```

The response returns job status and encrypted result fields. It must not return
plaintext request or response bodies.

## Async completion (webhook)

A create request can include an optional `webhook_url`. When set, B3IQ posts a
notification to that URL once the job reaches a terminal state, so you do not have
to poll. The job-state response then carries a `webhook` object reporting delivery
progress (it is `null` when no webhook was requested):

| Field | Purpose |
| --- | --- |
| ` webhook.url ` | The callback URL the job was created with |
| ` webhook.status ` | Delivery state of the completion callback |
| ` webhook.attempts ` | Number of delivery attempts made |
| ` webhook.last_error ` | Error from the most recent failed attempt |
| ` webhook.next_attempt_at ` | When the next retry is due |
| ` webhook.last_attempt_at ` | Timestamp of the most recent attempt |
| ` webhook.delivered_at ` | Timestamp of successful delivery, when delivered |

## Privacy classes

| Class | Status | Meaning |
| --- | --- | --- |
| ` private_transport ` | Active | Client encrypts to node transport key. Protects content from B3IQ services and public surfaces, not from the node operator. |
| ` verified_confidential_cpu ` | Planned | Requires verified TEE attestation, transport key binding, freshness policy, and receipt evidence. |
| ` verified_confidential_gpu ` | Later | Requires practical confidential GPU hardware, drivers, and attestation tooling. |

See [Privacy boundary](/protocol/privacy) for the full privacy boundary.