diff --git a/docs/payment-provider.md b/docs/payment-provider.md
new file mode 100644
index 0000000..f580dad
--- /dev/null
+++ b/docs/payment-provider.md
@@ -0,0 +1,192 @@
+---
+title: "Payment Provider"
+description: "Operate the network's payment infrastructure: use a hosted signer, run your own, or run the full clearinghouse suite for auth, metering, and billing."
+---
+
+> **Source doc — Tier 2 (Payment Provider role).** Written to split into the official Mintlify docs as a new operator role beside Orchestrator / Gateway / Delegator. The consume side (running a job, attaching a key) lives in **[Run a job on the network](./run-a-job.md)**.
+>
+> **Status legend:** *Shipped* — in go-livepeer today. *In build* — designed, not yet shipped (`livepeer/clearinghouse` is a scaffold; items marked *in build* are placeholders to finalize at build time).
+
+## Payments on Livepeer
+
+Livepeer is a decentralized network: every job is paid by sending the orchestrator a **probabilistic-micropayment (PM) ticket** that settles on-chain in ETH. A **signer** holds the wallet and mints those tickets behind a plain HTTP endpoint — so your app pays with just a URL and a header, no wallet or crypto in your code.
+
+Because the signer is a **separate node**, a local SDK can run jobs and pay orchestrators directly — no gateway in the path. Anything beyond raw payment — identity, balances, currency, billing — is added by a **clearinghouse** that sits *beside* the signer, never inside it. So there are two components, and you can stop at the first:
+
+- **Remote signer** — mints the PM tickets that pay orchestrators. *(Shipped.)*
+- **Clearinghouse** — the optional accounting layer on top: identity, balances, a spending gate, metering, funding. *(In build.)*
+
+## Choose how you pay
+
+By how much you want to operate yourself:
+
+| Path | You run | Use when |
+|---|---|---|
+| **[Use a hosted signer](#use-a-hosted-signer)** | nothing | you just want a key — someone else runs the infrastructure |
+| **[Run a remote signer](#run-a-remote-signer)** | a signer node | you pay for *your own* jobs from a trusted network — no accounts needed |
+| **[Run the clearinghouse suite](#run-the-clearinghouse-suite)** | signer + accounting | you serve *other* customers: identity, balances, metering, billing |
+
+## Use a hosted signer
+
+A hosted signer is a **managed clearinghouse** — someone else runs the signer, the accounting, and the funding rails, and gives you a key. Crucially, they bill you in **fiat** (cards, credits, dollars), so you never touch crypto, hold a wallet, or manage ETH. For your app it's the [signer step in Run a job](./run-a-job.md#4-pay-for-the-job-the-signer-step): sign up, top up, and pass `signer_url` + `signer_headers`.
+
+[PymtHouse](https://pymthouse.com) is a community-hosted option — billing, identity, payments, a UI, multi-cloud deploy — already onboarding apps, and more will follow. Each clearinghouse run *for the network* is an SPE governance proposal built on the same lean core described below.
+
+## Run a remote signer
+
+The signer is a standalone go-livepeer node (`-remoteSigner`) that holds the Ethereum key and signs PM tickets on demand, keeping the key out of the untrusted media path. It is **stateless**: it mints tickets, optionally asks a webhook "ok?", and tracks no customers or balances.
+
+```mermaid
+sequenceDiagram
+ participant G as Gateway / SDK
+ participant S as Remote signer
+ participant O as Orchestrator
+ G->>S: POST /sign-orchestrator-info
+ S-->>G: address, signature
+ G->>O: GetOrchestratorInfo(address, sig)
+ O-->>G: OrchestratorInfo (TicketParams, price)
+ loop per payment
+ G->>S: POST /generate-live-payment (OrchestratorInfo + signed state)
+ Note over S: mint PM ticket batch (ETH)
optional auth webhook → allow / deny
emit create_signed_ticket
+ S-->>G: payment, segCreds, new signed state
+ G->>O: POST /payment
+ end
+```
+
+**Run it right next to your app.** With no webhook configured (`-remoteSignerWebhookUrl` unset), a signer is a complete, self-contained way to pay for *your own* jobs — put it on the same private network as the SDK that requests jobs and you need no clearinghouse, no auth, no gate:
+
+```bash
+livepeer -remoteSigner -network arbitrum-one-mainnet -ethUrl \
+ -ethKeystorePath -maxPricePerUnit -httpAddr 0.0.0.0:8935
+```
+
+Every `/generate-live-payment` request is then allowed and signed from the signer's own wallet. The only guardrails are pricing caps and a hard ≤100 tickets-per-request cap — there is **no per-caller auth, spend cap, or rate limit**. So:
+
+- **Safe for self-use** — your app and your signer in one trust domain, paying for your jobs. No attach key, no gate.
+- **Never expose it** — anyone who can reach it can drain your wallet. Keep it internal behind infrastructure controls; being stateless, run it redundantly behind round-robin DNS.
+
+The moment you want *others* to call it, point it at a webhook — that's the clearinghouse.
+
+Key properties:
+
+- **Needs an on-chain network** (ETH connectivity to manage tickets). Your SDK stays offchain — it only needs the signer URL and a header.
+- **Stateless via a signed state blob.** Each response returns a blob the caller stores and sends back next time; the signer signs and verifies it, so no shared DB is needed.
+- **Pricing is enforced on the signer** (`-maxPricePerUnit`, max ticket EV).
+- **Key custody.** For production, delegate signing to the [`external-signer`](https://github.com/livepeer/external-signer) sidecar (Web3Signer → Turnkey / Fireblocks / Privy / Dfns) so the key never leaves your custody provider: `livepeer -remoteSigner -ethExternalSigner http://127.0.0.1:8550`.
+
+## Run the clearinghouse suite
+
+The clearinghouse **suite** is our payment logic packaged to run inside *your* app or infrastructure — so you can serve *other* customers without building accounting from scratch. It turns "mint a ticket" into "draw down this customer's balance," and integrates with established auth, metering, billing, and fiat-payment systems rather than reinventing them. It runs on an **unmodified** signer, plugging into three touchpoints the signer already exposes. *(In build.)*
+
+| Touchpoint | Direction | Purpose |
+|---|---|---|
+| **Auth webhook** (`-remoteSignerWebhookUrl`) | signer → clearinghouse | the gate — allow/deny per payment |
+| **Request headers** (`-remoteSignerHeaders`) | gateway → signer → webhook | customer identity (e.g. an API key) |
+| **`create_signed_ticket` events** | signer → bus (Kafka) | usage metering (fee in wei, pixels, `num_tickets`, `manifest_id`) |
+
+It is built on **ports & adapters** — a stable interface (*port*) with swappable implementations (*adapter*) — so you integrate proven tools instead of hand-rolling auth, metering, or billing:
+
+| Concern | Port | Available (v1) | Planned (drop-in) |
+|---|---|---|---|
+| Identity | `IdentityResolver` | API key | OIDC / OAuth |
+| Metering + billing | `Ledger` | OpenMeter | Lago, Kill Bill |
+| Funding | `FundingRail` | Grants (operator-issued) | Stripe, USDC, x402 |
+
+```mermaid
+flowchart LR
+ GW[Gateway / SDK
API key header] --> SIG[Remote signer
mint PM tickets → ETH]
+ SIG -- gate webhook --> CORE
+ SIG -- usage events --> CORE
+ subgraph CORE[clearinghouse · lean core]
+ GATE[gate · allow/deny]
+ METER[usage ingest · metering]
+ KEYS[keys + admin/grant]
+ end
+ IDP[Identity adapter] -. resolve .-> CORE
+ CORE --> LEDGER[(Ledger adapter · OpenMeter)]
+ ONRAMP[Funding · grants → Stripe / USDC / x402] --> LEDGER
+```
+
+The core does two things:
+
+- **Gate** — answer the signer's auth webhook: resolve the customer from the header, check their balance, allow or deny. A rejection means no usable payment, so it's a **pre-spend** gate.
+- **Meter** — consume `create_signed_ticket` events and draw the balance down. **Idempotent** (dedupe on `request_id`/`sequence_number`) and **gap-tolerant** (reconstruct missed events — exactly-once delivery isn't guaranteed).
+
+Keep **usage** and **balance** as separate ledgers with an explicit reconciliation step. Bill on minted-ticket EV (the signer reports fees in wei); use the wallet's on-chain ETH spend only as a later *aggregate* cross-check, not a per-customer match (PM is probabilistic).
+
+**Funding starts with grants** — an operator issues a customer a trial budget, the operator's wallet carries the ETH cost; real on-ramps (Stripe / USDC / x402) plug in later behind the `FundingRail` port. **Auth** is a personal API key for v1; OIDC/OAuth comes later via the `IdentityResolver` adapter.
+
+```bash
+docker compose up # in build: signer + clearinghouse + OpenMeter
+```
+
+**Acceptance loop:** grant → run a job → balance draws down → signing hard-stops at $0.
+
+**Design principles:** minimal first · never fork the signer (external, stable contract) · ports & adapters · delegate accounting to a proven engine · accounting first, on-ramps later · no auth platform in the core.
+
+> **In build:** concrete API-key/grant/admin endpoints, config keys, and the compose file land here once `livepeer/clearinghouse` ships them.
+
+---
+
+## Reference
+
+### Signer flags (go-livepeer)
+
+| Flag | Mode | Purpose |
+|---|---|---|
+| `-remoteSigner` | signer | run the remote signer service (requires an on-chain network) |
+| `-remoteSignerUrl` | gateway | URL of the signer to attach to |
+| `-remoteSignerHeaders` | gateway | headers sent gateway → signer, e.g. `header:val,header2:val2` (identity channel) |
+| `-remoteSignerWebhookUrl` | signer | auth-webhook URL called during `/generate-live-payment` (the gate) |
+| `-remoteSignerWebhookHeaders` | signer | headers sent on webhook requests |
+| `-remoteDiscovery` | signer | enable orchestrator discovery via `/discover-orchestrators` |
+| `-maxPricePerUnit` | signer | reject orchestrator prices above this (returns 481) |
+| `-ethExternalSigner` | signer | delegate ETH signing to a Web3Signer sidecar (`external-signer`) |
+
+### Endpoints & status codes
+
+`POST /sign-orchestrator-info` · `POST /generate-live-payment` · `POST /sign-byoc-job` · `GET /discover-orchestrators`
+
+`480` refresh session · `481` price exceeded · `482` no tickets needed.
+
+### Auth webhook contract
+
+Fired after the payment state is updated but **just before it is signed** — a rejection means no usable payment, making it a pre-spend gate.
+
+```json
+// request (signer → webhook)
+{ "Headers": { "Authorization": ["Bearer "] },
+ "State": { "...": "RemotePaymentState — StateID, PMSessionID, OrchestratorAddress, Balance, ..." } }
+
+// response (webhook → signer)
+{ "Status": 200, "Reason": "", "Expiry": 1718630400 }
+```
+
+- `Status` — HTTP status returned to the caller; non-200 denies the payment.
+- `Reason` — message when denied.
+- `Expiry` — Unix seconds to cache this allow decision (signer skips the webhook while `AuthExpiry > now`); `0` = no caching.
+
+### `create_signed_ticket` Kafka event
+
+| Field | Meaning |
+|---|---|
+| `session_id`, `session_status` | opaque state ID; `new` / `continuing` |
+| `pipeline` | e.g. `live-video-to-video` |
+| `request_id` | per-request UUID (dedupe key) |
+| `orch_address`, `orch_url` | orchestrator ETH address + service URL |
+| `manifest_id`, `pm_session_id` | stream + PM session identifiers |
+| `current_time(_unix)`, `previous_time(_unix)` | timing for usage measurement |
+| `billable_secs`, `pixels` | usage measured |
+| `computed_fee`, `cost_per_pixel`, `session_balance` | fee (wei), price ratio, balance after update |
+| `sequence_number`, `num_tickets` | request count; tickets minted |
+
+---
+
+## Appendix: source material
+
+- Vision: *Improve App Payment Experience* (Notion); Payments Clearinghouse / Livepeer: Weir.
+- Signer code: `server/remote_signer.go`, `core/accounting.go`, `cmd/livepeer/starter/flags.go`; `doc/remote-signer.md`.
+- Custody sidecar: [`livepeer/external-signer`](https://github.com/livepeer/external-signer).
+- SDK: [`livepeer/livepeer-python-gateway`](https://github.com/livepeer/livepeer-python-gateway).
+- Community hosted clearinghouse: [`eliteprox/pymthouse`](https://github.com/eliteprox/pymthouse).
+- Forum: [Livepeer Payment Clearinghouse](https://forum.livepeer.org/t/livepeer-payment-clearinghouse/3264).
diff --git a/docs/run-a-job.md b/docs/run-a-job.md
new file mode 100644
index 0000000..64add3f
--- /dev/null
+++ b/docs/run-a-job.md
@@ -0,0 +1,145 @@
+---
+title: "Run a job on the network"
+description: "Find an app on the network, call it through the SDK, and point it at a signer to pay — no wallet, no crypto in your app."
+---
+
+> **Developer docs source — Tier 1.** Illustrative walkthrough of the target developer experience. Code reflects the current [`livepeer-python-gateway`](https://github.com/livepeer/livepeer-python-gateway) SDK; names may still change.
+
+Three moves: **find** an app, **call** it through the SDK, point it at a **signer** to pay. Your media flows straight to the orchestrator; the payment layer never sees it — it's just a URL and a key.
+
+## 1. Find an app to run
+
+An *app* is a container that runs on the network — a realtime video pipeline, an LLM, an image model, or anything you bring yourself. Orchestrators host your container and pass traffic straight through over **HTTP, SSE, WebSocket, or trickle** (Livepeer's segment-based transport for realtime media), so you can lift an app off your old compute provider with little change: the orchestrator pulls your image and runs it on its GPUs.
+
+The runtime is in **beta** — there's no self-serve onboarding yet, so to put *your own* app on the network you [contact the team](#bring-your-own-app). You can already run the **open-source example apps** live today. Find them two ways:
+
+- **Dashboard** — [livepeer.org/dashboard](https://livepeer.org/dashboard), a small hosted app for trying the network.
+- **Discovery endpoint** — [`GET /v1/discovery/capabilities`](https://discovery-service-production-8955.up.railway.app/docs#tag/discovery/GET/v1/discovery/capabilities) lists the available apps and models.
+
+Each app has an **app id** (e.g. `livepeer-sample/hello-world`) — that's all the SDK needs to route to it.
+
+## 2. Install the SDK
+
+Not on PyPI yet — install from the `ja/live-runner` branch:
+
+```bash
+pip install "git+https://github.com/livepeer/livepeer-python-gateway@ja/live-runner"
+```
+
+## 3. Run a job
+
+`reserve_session` handles discovery and orchestrator selection from an app id — the same call for every app. What you do *after* it depends on the app's transport. Start with `hello-world`, a plain HTTP request/response app:
+
+```python
+from livepeer_gateway.selection import reserve_session
+from livepeer_gateway.live_runner import call_runner, stop_runner_session
+
+SIGNER_URL, SIGNER_HEADERS = "https://api.pymthouse.com", {"Authorization": "Bearer sk_live_..."} # see §4
+
+session = await reserve_session(
+ discovery_url="https://localhost:8935/discovery",
+ app="livepeer-sample/hello-world",
+ signer_url=SIGNER_URL, signer_headers=SIGNER_HEADERS,
+)
+result = await call_runner(
+ runner_url=session.app_url.rstrip("/") + "/hello",
+ payload={"name": "livepeer"},
+ signer_url=SIGNER_URL, signer_headers=SIGNER_HEADERS,
+)
+print(result.data) # {'message': 'Hello, livepeer!'}
+await stop_runner_session(session)
+```
+
+The other example apps keep the same `reserve_session` and swap the transport:
+
+| Example | Transport | App id |
+| --- | --- | --- |
+| [`hello-world`](https://github.com/livepeer/live-runner-example-apps/tree/main/hello-world) | HTTP request/response | `livepeer-sample/hello-world` |
+| [`vllm`](https://github.com/livepeer/live-runner-example-apps/tree/main/vllm) | SSE (token streaming) | `vllm/qwen2.5-0.5b-instruct` |
+| [`echo`](https://github.com/livepeer/live-runner-example-apps/tree/main/echo) | trickle (realtime video) | `livepeer-sample/echo` |
+| [`streaming-asr`](https://github.com/livepeer/live-runner-example-apps/tree/main/streaming-asr) | WebSocket (speech-to-text) | `whisper/base.en` |
+
+### SSE — streaming tokens (`vllm`)
+
+`vllm` serves an OpenAI-compatible API, so you use the **stock `openai` client** with zero Livepeer code. Payment lives in a small local [`gateway.py`](https://github.com/livepeer/live-runner-example-apps/blob/main/vllm/gateway.py) that does discovery + the ticket handshake for you (forwarding the runner's `text/event-stream` straight through with `call_runner(..., stream=True)`) — point it at your signer once (see §4):
+
+```bash
+uv run gateway.py --signer https://api.pymthouse.com # OpenAI endpoint on http://localhost:8080/v1
+```
+
+Your client is then plain OpenAI against that `base_url`:
+
+```python
+from openai import OpenAI
+
+client = OpenAI(base_url="http://localhost:8080/v1", api_key="unused") # gateway handles discovery + payment
+stream = client.chat.completions.create(
+ model="Qwen/Qwen2.5-0.5B-Instruct",
+ messages=[{"role": "user", "content": "write a haiku about GPUs"}],
+ stream=True,
+)
+for chunk in stream:
+ print(chunk.choices[0].delta.content or "", end="", flush=True) # tokens arrive as generated
+```
+
+### Trickle — realtime video (`echo`)
+
+POST to the app's endpoint to open its trickle `in`/`out` channels, then publish frames to `in` and read transformed frames from `out`, keeping the long-lived session funded in the background:
+
+```python
+from livepeer_gateway.http import post_json
+from livepeer_gateway.media_publish import MediaPublish
+from livepeer_gateway.media_output import MediaOutput
+
+session = await reserve_session(discovery_url="https://localhost:8935/discovery",
+ app="livepeer-sample/echo",
+ signer_url=SIGNER_URL, signer_headers=SIGNER_HEADERS)
+session.start_payments() # tops up the session balance while it stays open
+
+channels = await post_json(session.app_url.rstrip("/") + "/echo", {"radius": 75}) # → {"in": ..., "out": ...}
+publisher = MediaPublish(channels["in"]) # publish your frames here
+async with MediaOutput(channels["out"], on_bytes=write): # read transformed frames back
+ ... # pump frames — see the echo client
+await session.aclose() # stops payments + releases the session
+```
+
+### WebSocket — speech-to-text (`streaming-asr`)
+
+`open_websocket` opens the orchestrator-proxied socket from a reserved session and keeps it funded — stream audio up, get transcripts back on the same socket:
+
+```python
+from livepeer_gateway.live_runner import open_websocket
+
+session = await reserve_session(discovery_url="https://localhost:8935/discovery",
+ app="whisper/base.en",
+ signer_url=SIGNER_URL, signer_headers=SIGNER_HEADERS)
+async with open_websocket(session, "/transcribe") as ws: # SDK does the wss upgrade + session payments
+ await ws.send_bytes(pcm_16khz_mono) # stream 16 kHz mono PCM up (your audio bytes)
+ await ws.send_str("eos") # signal end of audio
+ async for msg in ws: # transcripts stream back
+ print(msg.json()) # {"text": "...", "final": false|true}
+```
+
+## 4. Pay for the job — the signer step
+
+Livepeer is a **decentralized network**: jobs are paid by sending the orchestrator a probabilistic-micropayment ticket that settles on-chain in ETH. Rather than hold a hot wallet in your app, you point it at a **signer** that mints tickets for you — and a **clearinghouse** can sit on top to handle accounts and billing in plain dollars. `signer_url` + `signer_headers` is the *only* payment config your app needs — no wallet, no crypto in your code.
+
+**Fastest path: a community-hosted signer.** [PymtHouse](https://pymthouse.com) hosts the signer and accounting — sign up, get a key, drop it in:
+
+```python
+SIGNER_URL = "https://api.pymthouse.com"
+SIGNER_KEY = "sk_live_..."
+```
+
+It meters usage and bills your account; when the balance runs out, jobs stop. Switching providers is just a different URL and key.
+
+**Run it yourself?** The [Payment Provider](./payment-provider.md) docs cover the whole stack:
+
+- **[Run a remote signer](./payment-provider.md#run-a-remote-signer)** — mint your own tickets for your own jobs, no accounts.
+- **[Run the clearinghouse suite](./payment-provider.md#run-the-clearinghouse-suite)** — the accounting layer on top, to give customers a balance and bill them.
+
+The clearinghouse is a **suite**: a lean core with swappable ports, so you plug in established solutions instead of rolling your own — [OpenMeter](https://openmeter.io) for metering/billing, OAuth/OIDC for auth, Stripe / USDC for funding.
+
+## Bring your own app
+
+Start from [`live-runner-example-apps`](https://github.com/livepeer/live-runner-example-apps) — each example runs locally with `docker compose` against a local orchestrator, so you can build and test your app end to end on your own GPUs **for free**: offchain, omit the signer entirely (`reserve_session(discovery_url="https://localhost:8935/discovery", app=...)`) — it's only needed to pay real orchestrators on the network. Once it's running locally and you want it live, reach out at [partnerships@livepeer.foundation](mailto:partnerships@livepeer.foundation) and we'll onboard it.