On this page
§.Public API & SDK

REST API overview

Base URL, authentication, response envelope, pagination, rate limits, and edge caching for the public `/api/v1` surface.

Updated 2026-04-25 · By Jon Lasley

The public REST API at /api/v1 is the read-only surface for fetching prompts, versions, and resolved content from outside the web app. It runs on the same domain as the workbench, isn't gated by session cookies, and is exempt from CSRF (the Bearer header is the authenticator). Everything you can read in the editor you can fetch through /api/v1 with a key issued from Account settings.

Quickstart
Issue a key from /settings → API keys, then curl -H "Authorization: Bearer pa_live_…" https://promptassay.ai/api/v1/prompts. The full endpoint surface is at Endpoint reference. The TypeScript SDK at TypeScript SDK wraps every call with typed responses.

Base URL

https://promptassay.ai/api/v1
All endpoints are absolute paths under this prefix. The SDK defaults to this base; override via the `baseUrl` option only for self-hosted deployments.

Authentication

Every request carries a Bearer API key in the Authorization header. Keys are issued from your account settings and scoped to your active workspace at call time. See Creating and managing API keys for the issuing flow.

curl -H "Authorization: Bearer pa_live_..." \
  https://promptassay.ai/api/v1/prompts

Key format

Keys are formatted pa_live_ followed by 64 hex characters, generated from 32 random bytes. We store only a SHA-256 hash; the plaintext is shown exactly once at creation. The UI shows a pa_live_<first-4>...<last-4> summary so you can identify a key in the listing without exposing it. Treat any key that doesn't start with pa_live_ as invalid.

Rejection cases

Every authentication failure returns HTTP 401 with one of the messages below. The status is always 401 to avoid leaking whether a key exists; the message tells you (and your support team) what to fix:

  • Missing or malformed Authorization header · the header isn't Bearer <key>.
  • Invalid API key format · the token after Bearer doesn't start with pa_live_.
  • Invalid API key · the SHA-256 hash doesn't match any active key.
  • API key has been revoked · the key was deactivated.
  • API key owner must reset password · the user who created the key is in a forced-reset state.
  • API key has no organization assigned · legacy key shape; reissue a new one.

Response envelope

Success responses always wrap data in a top-level data field and add meta only on paginated list endpoints:

{
  "data": [ /* resource or array of resources */ ],
  "meta": {
    "page": 1,
    "per_page": 20,
    "total": 142
  }
}
Success envelope. List endpoints include `meta`; single-resource endpoints omit it.

Error responses share a single shape and the code is a stable UPPER_SNAKE_CASE identifier you can switch on:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Prompt not found"
  }
}

Pagination

List endpoints accept page (1-indexed, default 1) and per_page (default 20, max 100). meta.total is the count of resources visible to the calling key, so it's the workspace-scoped total · not a global count and not affected by the page slice. Pages beyond meta.total / per_page return an empty data array, not an error.

Rate limits

Two layers protect the API. Both are window-counted per minute and both will return 429 RATE_LIMITED with a Retry-After: <seconds> header when exceeded.

LayerLimitBucketWhen you'll hit it
Per-key100 requests / minuteOne bucket per API keySpiky workload from a single deployment.
Global circuit breaker500 requests / minuteOne bucket per Vercel processBurst across the whole tenant. Rare on normal traffic.
Distributed rate limiting
By default each Vercel function instance counts independently. In our production deploy, both buckets route through a shared Postgres-backed counter so multi-region deploys share state. The shared counter fails open · a transient infrastructure issue won't block legitimate traffic.

Edge caching

Successful 2xx responses ship with Cache-Control: public, s-maxage=30, SWR=300 so Vercel's edge layer can serve repeated reads of the same prompt for 30 seconds without a function invocation, with up to 5 minutes of stale-while-revalidate.

Vary: Authorization keeps cache per-key
Every cached 2xx response carries Vary: Authorization, so the edge keeps a separate cache entry per Bearer token. One workspace's freshly-rotated prompt never serves to a different key, even if the path matches. 4xx and 5xx responses are never cached.

Tier gating

HTTPCodeTrigger
402DISPUTEDWorkspace has an active chargeback dispute.
402PAST_DUESubscription is past-due or over-limit.
403API_NOT_ALLOWEDWorkspace is on Free tier; the public API requires Solo or higher.

Free-tier keys can be issued and inspected, but every call returns 403 API_NOT_ALLOWED until the workspace upgrades. There's no soft preview · the gate fires before the database is touched.

Limits

  • Per-key rate limit: 100 req/min.
  • Global rate limit: 500 req/min per process.
  • Pagination: per_page default 20, max 100.
  • Cache TTL: s-maxage=30, SWR=300 on 2xx.
  • Tier: Solo or higher.
Read-only API
Every /api/v1 endpoint is a GET. There are no mutation endpoints in this release · no creating prompts, no editing content, no triggering LLM calls. If you need to write back, do it from the workbench. Mutation surface is on the roadmap; let support know what shape you'd want.