API reference

The Pawpado API is a REST API that uses JSON for both requests and responses. It's the same API the portal and SDKs use; if you want to integrate Pawpado directly without an SDK, this page covers everything you need to authenticate and call it.

Base URL

https://pawpado.com

All API endpoints live under /api/v1/. There is no separate api. subdomain — the portal and the API are served from the same origin.

If you're pointing at a different deployment (staging, local), override the base URL via PAWPADO_BASE_URL in the SDKs or CLI.

Authentication

Every authenticated request carries a Huudis-issued bearer token in the Authorization header:

Authorization: Bearer <huudis-access-token>

That's it. No HMAC signing, no signature header, no timestamp window. Pawpado validates the JWT, reads sub as your huudisUserId, and scopes the response to your account.

Tokens are issued by Huudis at sign-in. The three ways to obtain one:

Audience How to get a token
Browser session Automatic — sign in to pawpado.com and the cookie carries it.
Server-side script pawpado auth login then read ~/.pawpado/credentials, or copy from Settings → Tokens.
Long-running integration Pair an access token with its refresh token. The SDKs handle rotation when you pass Session instead of apiKey.

Access tokens expire after 1 hour. Refresh tokens are good until revoked but rotate on every use — see Auth overview for the rotation rules.

If you call an endpoint with an expired or missing token, you get:

{ "error": "UNAUTHENTICATED", "message": "Missing or invalid bearer token" }

with HTTP 401.

Endpoints at a glance

The API surface is small — one user, one session, one wallet:

Sessions

Method Path Purpose
POST /api/v1/sessions/start Provision and start an instance.
POST /api/v1/sessions/stop Stop the running instance.
GET /api/v1/sessions/poll Current state + readiness.
POST /api/v1/sessions/pair Mint a four-digit Moonlight pairing PIN.
GET /api/v1/sessions/connect Tailnet IP + port for the streaming server.
POST /api/v1/sessions/tailscale-key Generate an ephemeral Tailscale auth key.

Credits

Method Path Purpose
GET /api/v1/credits/me Current balance, currency, storage usage.
POST /api/v1/credits/topup Create a Plugipay top-up checkout session.

Billing

Method Path Purpose
GET /api/v1/billing/storage Current storage tier and billing period.

Settings

Method Path Purpose
GET /api/v1/settings Read preferences.
PATCH /api/v1/settings Update preferences (partial).

Account

Method Path Purpose
GET /api/v1/session Current Huudis identity + cookie expiry.
DELETE /api/v1/account/delete Schedule account + EBS deletion (30-day grace).

Health

Method Path Purpose
GET /api/v1/health Liveness probe. No auth required.

Response shape

Most successful responses are flat JSON of the resource itself, not wrapped in an envelope. For example, GET /api/v1/sessions/poll:

{
  "state": "running",
  "instanceId": "i-0a1b2c3d4e5f6g7h8",
  "publicIp": "13.214.x.x",
  "tailnetIp": "100.64.x.x",
  "startedAt": "2026-05-12T10:42:00Z",
  "ready": true,
  "message": null
}

Errors share a consistent shape:

{
  "error": "INSUFFICIENT_CREDITS",
  "message": "Balance is below the 15-minute minimum to start a session"
}

HTTP status codes follow REST norms: 200 on success, 204 on success with no body, 400 for client errors, 401 for missing/invalid auth, 404 for missing resources, 409 for state conflicts (e.g. starting a session when one is already running), 429 for rate limits, 5xx for server errors.

Error catalog

The errors you're most likely to hit:

Code Means
UNAUTHENTICATED Missing or invalid bearer token.
INSUFFICIENT_CREDITS Balance too low to start a session.
SESSION_ALREADY_RUNNING Calling start while a session is active.
SESSION_NOT_RUNNING Calling stop / pair / connect with no session.
NOT_READY Calling pair before ready === true.
AWS_CAPACITY Jakarta region out of capacity. Transient.
VALIDATION_ERROR Bad request body. The message field names the offending field.
RATE_LIMITED Too many requests. Retry after the Retry-After header value.

Rate limits

Default per-account limits:

Endpoint class Limit
Read (GET) 60 req/min
Write (POST, PATCH, DELETE) 20 req/min
sessions/poll 30 req/min — polling is expected; we tolerate it.

Limits are returned in response headers:

  • X-RateLimit-Limit — the bucket size.
  • X-RateLimit-Remaining — how many requests left in the window.
  • X-RateLimit-Reset — epoch seconds when the bucket refills.

On 429, you'll see a Retry-After header in seconds.

Webhooks (none, yet)

Pawpado doesn't publish webhooks today. Top-ups are settled by Plugipay's webhooks coming inbound to Pawpado — if you want to be notified of credit changes, poll GET /api/v1/credits/me.

If your integration needs push notifications for session state changes or low-balance alerts, email support@forjio.com — we may publish them based on demand.

OpenAPI

A machine-readable OpenAPI 3.0 spec is at pawpado.com/openapi.json. Use it with Postman, openapi-generator, or any other OpenAPI tooling to build clients in languages we don't ship SDKs for.

Next