Cloud API
The HTTP API behind patcharc share: authentication, upload sessions, capsules, shares, AI connections, and billing, with what is live in 0.2.0.
validated against patcharc 0.2.0 · 2026-08-22
Base URL https://api.patcharc.dev. Authenticate with Authorization: Bearer <token> where the token is the refresh token from ~/.patcharc/credentials.json. Errors are JSON: {"error": "<code>", "message": "<text>"}. CORS allows any origin.
$ TOKEN=$(jq -r .refresh_token ~/.patcharc/credentials.json)
$ curl -s https://api.patcharc.dev/healthz
{"ok":true,"version":"0.2.0"}
Authentication
| Method | Path | Notes |
|---|---|---|
| POST | /v1/auth/device | Start a device flow: {label, platform} → {device_code, user_code, verification_url, expires_at, poll_interval} |
| POST | /v1/auth/device/token | Poll with {device_code}; authorization_pending, access_denied, expired_token until approved |
| POST | /v1/auth/refresh | {refresh_token} → rotated pair; the old token is revoked |
| DELETE | /v1/auth/devices/:id | Revoke a device and its tokens |
| GET | /v1/me | The current user |
| GET | /v1/accounts | Accounts the user belongs to |
Capsules
| Method | Path | Notes |
|---|---|---|
| POST | /v1/upload-sessions | {arc_id, size, sha256}; max 200 MB → {upload_id, upload_url, expires_at} |
| PUT | /v1/upload-sessions/:id/put | Raw capsule body; rejected unless its SHA-256 matches the declared hash |
| POST | /v1/upload-sessions/:id/complete | {sha256, size}; starts verification → {capsule_id, status: "verifying"} |
| GET | /v1/capsules/:id/status | {status, progress[], share_slug?}; statuses uploaded, verifying, published, failed_terminal |
| GET | /v1/capsules/:id/review | The published review record (409 until published) |
| POST | /v1/capsules/:id/reprocess | Re-run verification |
| DELETE | /v1/capsules/:id | Delete the capsule, derived data, and shares |
Upload sessions expire after 30 minutes.
Shares
| Method | Path | Notes |
|---|---|---|
| POST | /v1/capsules/:id/shares | {visibility, expires_at?} → {share_id, slug, share_url, expires_at}; public requires the capsule to be published |
| GET | /v1/shares/:id | Share record |
| PATCH | /v1/shares/:id | {visibility?, expires_at?}; expires_at: null clears expiry |
| DELETE | /v1/shares/:id | Revoke; the link answers 410 |
| POST | /v1/shares/:id/rotate | New slug; the old one stops resolving |
| GET | /a/:slug | The public ArcLink page (on patcharc.dev, not the API host) |
See Sharing and ArcLinks for visibility semantics.
AI and BYOK
| Method | Path | Notes |
|---|---|---|
| POST | /v1/ai/connections | {name, provider, mode: "cloud_relay", api_key, base_url?}; the key is envelope-encrypted and never returned |
| GET | /v1/ai/connections | Metadata only |
| POST | /v1/ai/connections/:id/test | Broker-side decrypt and provider reachability check |
| DELETE | /v1/ai/connections/:id | Revoke |
| GET | /v1/ai/models, /v1/ai/routes | Available managed models and logical routes |
| GET | /v1/ai/wallet, /v1/ai/usage | Credits and 30-day usage |
| POST | /v1/ai/jobs | Reserve credits and enqueue a summary job (orchestrator is a stub in 0.2.0) |
Billing
| Method | Path | Notes |
|---|---|---|
| GET | /v1/billing/plans | Public; the four plans |
| GET | /v1/billing/subscription | {subscription, stripe_enabled: false} |
| POST | /v1/billing/checkout, /v1/billing/portal | Return mock URLs while Stripe is disabled |
Rate limits
30 requests per minute on /v1/auth/*, 300 per minute elsewhere, keyed by user, then account, then IP. A 429 response carries retry-after.
Not available
Repository integrations (GitHub App, GitLab), organisation and member management, and webhooks other than Stripe's are not implemented in 0.2.0.