Beta documentation. This is an early preview — content is still in active development. Feedback helps shape the final release. Share your thoughts or join the discussion.

REST API Overview

```

On this page

Base URL

https://api.wapka.org/v1

All requests to the REST API use this base URL. The site is determined from your authentication token — you do not pass a site ID in the URL.

Authentication

Every /v1/* endpoint requires authentication. Choose one method:

Bearer JWT (recommended)

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

Obtain a JWT via Authentication. The token contains your site ID, user ID, permission level, and scopes. It is cryptographically signed and valid for 24 hours.

API Key

Authorization: wpk_live_xxxxxxxxxxxxxxxx

API keys are prefixed with wpk_. Create and manage them via POST /v1/api-keys. Use API keys for external integrations and server-to-server calls where JWT refresh is impractical.

JWT structure

A decoded Wapka JWT contains these claims:

Claim Description
iss Issuer — always wapka-api
sub Subject — site:{site_id}
site_id Your site's numeric ID
user_id Authenticated user's ID (0 for guest tokens)
level Permission level (0–10)
persona Role label — public, user, moderator, admin, superadmin
scope * for full access, public:read for guest tokens
iat Issued-at timestamp
exp Expiration timestamp

Permission levels (personas)

Level Persona Capabilities
0 public Read public fields only
1–5 user Read/write own content
6–7 moderator Edit/delete content below own level
8–9 admin Full CRUD, manage users
10 superadmin Everything including API keys and firewall

Response format

Every API response is JSON and follows one of three envelopes:

Collection response

{
  "data": [ ... ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "totalItems": 142,
    "totalPages": 8,
    "hasNext": true,
    "hasPrev": false
  },
  "meta": {
    "requestId": "req_a1b2c3",
    "timestamp": "2026-05-23T12:00:00Z"
  }
}

Single resource response

{
  "data": { ... },
  "meta": {
    "requestId": "req_a1b2c3",
    "timestamp": "2026-05-23T12:00:00Z"
  }
}

Error response

{
  "error": {
    "code": "not_found",
    "message": "Resource not found",
    "details": null
  },
  "meta": {
    "requestId": "req_a1b2c3",
    "timestamp": "2026-05-23T12:00:00Z"
  }
}

Error codes

HTTP Code Meaning
400 invalid_request Bad request — check your parameters
400 invalid_site Site context is missing or invalid
401 unauthorized Missing or invalid credentials
401 expired Token has expired — get a new one
403 forbidden Insufficient permission level
403 jwt_disabled JWT auth is disabled for this site
404 not_found Resource does not exist
422 validation_error Input failed validation
429 rate_limited Too many requests — slow down
500 internal_error Something went wrong on the server

Pagination

All list endpoints (GET /v1/users, GET /v1/posts, etc.) support pagination via query parameters:

Parameter Default Description
page 1 Page number (1-based)
limit 20 Items per page (max 100)

The response includes a pagination object so you know if there are more pages.

Rate limiting

The API enforces per-IP rate limits. When you exceed the limit, you receive a 429 response with error.code = "rate_limited". Implement exponential backoff in your client.

Sorting

List endpoints accept a sort parameter. Use a field name to sort ascending, or prefix with - to sort descending:

GET /v1/posts?sort=-created_at   # newest first
GET /v1/users?sort=username       # alphabetical

Lua API wrapper

The same REST API is available inside your Lua scripts via the api global. No authentication headers needed — the current request context is used automatically.

local users = api.users:list({ page = 1, limit = 10 })
local post  = api.posts:get(42)

Next: Authentication — how to obtain tokens and manage API keys.

Next Authentication