REST · JSON · v1

API reference

Base URL https://webora.web.id/api/v1. All responses are JSON; list endpoints are paginated with data, links and meta.

Authentication

Create a key in Studio → Developers → API keys. Keys carry abilities: read and/or write. The API requires a plan with API access.

Authenticated request
curl https://webora.web.id/api/v1/me \
  -H "Authorization: Bearer YOUR_KEY" \
  -H "Accept: application/json"

Rate limits & errors

Authenticated calls are limited per site by plan (X-RateLimit-Limit / X-RateLimit-Remaining headers). Public endpoints allow 120 requests/min per IP. Every request is logged and visible in Studio → API logs.

401Missing or invalid key
402Feature not in your plan
403Key lacks the “write” ability
404Not found (or belongs to another site)
422Validation failed — see errors{}
429Too many requests

Public (no key)

Read-only endpoints for headless front-ends and the generated mobile app. Rate-limited per IP. {site} is the site slug.

GET /public/{site} Site profile, theme, contact & social links
GET /public/{site}/app-config Remote config for the Flutter app (tabs, colors, features)
GET /public/{site}/pages Published pages
GET /public/{site}/pages/{slug} One page incl. rendered HTML
GET /public/{site}/posts Blog posts (?category=, ?q=, ?per_page=)
GET /public/{site}/posts/{slug} One post
GET /public/{site}/products Products (?category=, ?q=, ?featured=1)
GET /public/{site}/products/{slug} One product
GET /public/{site}/categories Blog & product categories
POST /public/{site}/orders Place an order (customer_name, customer_phone, shipping_address, payment_method, items[product_id, qty, variant])
POST /public/{site}/forms/{id} Submit a form — body: {"fields": {"name": "…"}} (field names from GET /forms)

Authenticated — read

Send your key as a Bearer token. Keys are created in Studio → Developers → API keys.

GET /me The site that owns the key, plan and rate limit
GET /pages All pages incl. drafts
GET /pages/{id} One page with its JSON element tree
GET /posts All posts
GET /posts/{id} One post
GET /products All products
GET /products/{id} One product
GET /orders Orders (?status=pending)
GET /orders/{id} One order
GET /forms Forms
GET /forms/{id}/submissions Form submissions
GET /media Media library

Authenticated — write (key needs the “write” ability)

Create, update and delete content. Every change fires the matching webhook.

POST /pages Create a page (title, slug, content[])
PUT /pages/{id} Update a page draft
POST /pages/{id}/publish Publish the draft
DELETE /pages/{id} Delete a page
POST /posts Create a post
PUT /posts/{id} Update a post
DELETE /posts/{id} Delete a post
POST /products Create a product
PUT /products/{id} Update a product (e.g. stock from your POS)
DELETE /products/{id} Delete a product
PATCH /orders/{id} Update order status / payment status
POST /media Upload a file (multipart “file”)

Webhooks

Add endpoints in Studio → Developers → Webhooks. Events: order.created, order.updated, form.submitted, post.published, page.published, product.updated. Failed deliveries retry 3× (10s, 60s, 5m).

POST https://your-endpoint.example
X-Webora-Event: order.created
X-Webora-Timestamp: 1767225600
X-Webora-Signature: sha256=<HMAC-SHA256 of "{timestamp}.{raw body}" with your signing secret>

{ "event": "order.created", "site": "kopisenja", "sent_at": "…", "data": { … } }

// Verify (PHP)
$ts = $_SERVER['HTTP_X_WEBORA_TIMESTAMP'];
hash_equals('sha256='.hash_hmac('sha256', $ts.'.'.$rawBody, $secret), $_SERVER['HTTP_X_WEBORA_SIGNATURE']);