Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,16 @@ ANTHROPIC_API_KEY=

# Required for TestIntegration_OpenAIInference
OPENAI_API_KEY=

# ── MPP credit-card payments (Stripe) ──────────────────────────────────────
# Seller-side credit-card settlement via the Machine Payments Protocol (MPP).
# Requires a Stripe account with "Machine payments" enabled. See the
# "Credit-card payments (MPP)" section of README.md.
#
# Consumed by the x402-verifier (sourced from the x402-secrets Secret in the
# `x402` namespace) to authorize/capture Stripe PaymentIntents for card offers.
STRIPE_SECRET_KEY=
# Your Stripe "machine payments" network id, advertised in the 402 challenge so
# card clients can mint a Shared Payment Token. Default for
# `obol sell http --pay-with card --stripe-network-id`.
STRIPE_NETWORK_ID=
12 changes: 12 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,18 @@ Caveats:

**Auto-configuration**: `obol stack up` → `autoConfigureLLM()` detects host Ollama models, patches LiteLLM config. `obolup.sh` → `check_agent_model_api_key()` reads `~/.openclaw/openclaw.json`, resolves API key from `ANTHROPIC_API_KEY` / `CLAUDE_CODE_OAUTH_TOKEN` (Anthropic) or `OPENAI_API_KEY` (OpenAI), exports for downstream.

**BYOK cloud providers** (easiest getting-started path) — provider knowledge is a single registry in `internal/model/model.go` (`knownProviders` / `ProviderInfo` with `Mode`/`BaseURL`/`Default`/`SignupURL`/`Free`); adding a provider is one row, no per-provider switch. Built-in: `anthropic`, `openai`, `ollama` (native/local) + OpenAI-compatible aggregators `venice`, `openrouter`, `nvidia`, `gmi`, `novita`, `huggingface` (`Mode=openai-compatible` → `model_list` entry `openai/<id>` + explicit `api_base` + key from the provider's env var; no wildcard). When `--model` is omitted, setup uses the registry `Default` or lists the live `GET <base>/v1/models` (TTY picker / non-TTY error naming real ids). `--free` seeds only the curated free-tier model snapshot (OpenRouter).

Two front doors share one engine (`setupCloudProvider` in `cmd/obol/model.go`):
- `obol buy inference <provider>` — friendly onboarding: opens the provider's `SignupURL` in the browser (`openBrowser`, hermes-style), takes the key (`--api-key` → env var → prompt), wires LiteLLM + syncs agents. `obol buy inference` with a URL/no-arg is still the **x402 crypto-paid seller** path — dispatch keys on whether the positional arg matches a registry provider id.
- `obol model setup <provider> --api-key <key>` — the scriptable, no-browser equivalent. Unlisted endpoints still use `obol model setup custom`.

```bash
obol buy inference venice # opens venice key page, prompts, wires up
obol buy inference openrouter --free # seeds curated free models
obol model setup venice --api-key $VENICE_API_KEY # scriptable / CI
```

**External OpenAI-compatible LLM** (vLLM / sglang / mlx-lm / remote GPU) — canonical user flow, no ConfigMap surgery:

```bash
Expand Down
10 changes: 10 additions & 0 deletions Dockerfile.x402-escrow
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM golang:1.25-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /x402-escrow ./cmd/x402-escrow

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /x402-escrow /x402-escrow
ENTRYPOINT ["/x402-escrow"]
54 changes: 54 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,60 @@ obol openclaw skills remove <name> # remove via openclaw CLI in pod

Skills are delivered via host-path PVC injection — no ConfigMap size limits, works before pod readiness, and survives pod restarts.

## Credit-card payments (MPP)

Alongside the default x402 on-chain (stablecoin) payment path, sellers can accept
**credit-card** payments via the [Machine Payments Protocol](https://mpp.dev) (MPP,
the Stripe + Tempo HTTP-402 standard). A card offer is gated on the same
`/services/<name>/*` route as a crypto offer — the payment method is selected per
offer.

```bash
# Expose an upstream as a card-paid endpoint (Stripe stripe.charge).
obol sell http my-api \
--pay-with card \
--stripe-account acct_1A2b3C4d \ # Stripe destination account (card analog of --pay-to)
--stripe-network-id stripenet_...\ # Stripe "machine payments" network id (or STRIPE_NETWORK_ID)
--card-currency usd \
--upstream my-svc --port 8080 --price 0.01
```

How it works:

- The offer advertises a `card` option in its `402` challenge (amount in the
currency's **minor units** — cents for `usd`, whole yen for `jpy`, etc.).
- A card-capable buyer presents a Stripe **Shared Payment Token** (`spt_…`) in the
`X-PAYMENT` header.
- The verifier **authorizes** a manual-capture Stripe PaymentIntent before serving,
proxies to the upstream, then **captures** only after a successful (`<400`)
response — a failed upstream **cancels** the hold, so a buyer is never charged for
nothing. Each SPT is single-use (replay-guarded).

### Requirements & configuration

- A **Stripe account with "Machine payments" enabled** (a gated Stripe feature).
- `STRIPE_SECRET_KEY` — used by the `x402-verifier` to authorize/capture
PaymentIntents. It is read from the `x402-secrets` Secret in the `x402` namespace;
populate it before taking card payments:

```bash
kubectl -n x402 patch secret x402-secrets --type merge \
-p '{"stringData":{"STRIPE_SECRET_KEY":"sk_live_..."}}'
kubectl -n x402 rollout restart deploy/x402-verifier
```

- `STRIPE_NETWORK_ID` — your Stripe "machine payments" network id, advertised in the
402 challenge so clients can mint an SPT. It is a host/CLI value (default for
`--stripe-network-id`); add both to your `.env` from `.env.example`.

> **Note on scope.** Card offers are not ERC-8004 registered (no on-chain identity).
> The Stripe key is currently a single cluster-wide value in `x402-secrets`; a
> per-offer/per-namespace Secret is the production direction but is gated on widening
> the verifier's deliberately `resourceName`-scoped Secret RBAC. The SPT replay guard
> is per-pod (the verifier runs single-replica). The SPT is passed as the top-level
> Stripe form field `shared_payment_granted_token` per the `cp0x-org/mppx` reference —
> validate against your live Stripe account before relying on it in production.

## Public Access (Cloudflare Tunnel)

Expose your stack to the internet via Cloudflare Tunnel:
Expand Down
Loading