How it Works Documentation Quick Start PAPI — Pages & Assets MAPI — Dynamic Data Integrations SAPI — Sessions & Forms MCP Server Tools Deploy Dashboard

SAPI Documentation

Add visitor sessions, form handling, and temporary data storage to your AI-built websites. No login required — sessions are anonymous and cookie-based.

ℹ️ How SAPI Works SAPI powers the visitor-facing side of your website. Visitors get a session automatically, can store data (like a shopping cart), and submit forms. Form submissions can trigger server-side actions like sending emails via the Integration API (IAPI). All with built-in CSRF protection.

Overview

SAPI provides four capabilities for visitor interactions:

Feature Prefix Description
Sessions /sapi/project/{id}/session Anonymous cookie-based sessions with CSRF tokens
Data Store /sapi/project/{id}/data Key-value storage per session (cart, preferences, state)
Form Config /sapi/project/{id}/forms Define forms and their server-side actions (owner only)
Form Submit /sapi/project/{id}/form/submit Anonymous form submission with CSRF validation

How It Works

Session Lifecycle

When a visitor loads your website, a JavaScript snippet calls the session endpoint. The server creates a session in Redis with a 1-hour TTL, sets an httpOnly cookie, and returns a CSRF token. The session extends automatically when data is written (up to 24 hours max).

Authentication Model

SAPI uses two different authentication models:

Who Auth Method Endpoints
Visitors (anonymous) Session cookie (wss_) + CSRF token Session, Data Store, Form Submit
Owners (you / AI) Bearer token (wps_ or wpa_) Form Configuration
⚠️ CSRF Required on All Writes All POST, PUT, and DELETE requests from visitors require a valid CSRF token. Send it as X-CSRF-Token header or _csrf in the request body.

Sessions

GET /sapi/project/{project_id}/session

Start a new session or resume an existing one. Returns a session cookie and CSRF token.

Response

{
    "success": true,
    "data": {
        "session_id": "wss_a1b2c3d4e5f6...",
        "csrf_token": "f7e8d9c0b1a2...",
        "expires_in": 3600,
        "is_new": true
    }
}

Response Headers

Set-Cookie: wss_session=wss_a1b2c3d4...; HttpOnly; Secure; SameSite=Lax; Path=/sapi/project/{project_id}/; Max-Age=3600
ℹ️ Session TTL New sessions expire after 1 hour. Writing data extends the TTL to 4 hours. Maximum session lifetime is 24 hours. When is_new is false, an existing session was resumed.
DELETE /sapi/project/{project_id}/session

Destroy the current session. Clears all session data and the cookie.

Requires: session cookie.

GET /sapi/project/{project_id}/csrf/refresh

Generate a new CSRF token. Invalidates the previous token.

Requires: session cookie.

Response

{
    "success": true,
    "data": {
        "csrf_token": "new_token_here...",
        "expires_in": 3600
    }
}

Data Store

Store key-value data per visitor session. Ideal for shopping carts, user preferences, wizard state, and other temporary data. All data is stored in Redis and expires with the session.

GET /sapi/project/{project_id}/data

Get all stored key-value data for the current session.

Requires: session cookie.

Response

{
    "success": true,
    "data": {
        "cart_items": [{ "product_id": 42, "quantity": 2 }],
        "cart_total": 29.98
    }
}
GET /sapi/project/{project_id}/data/{key}

Get a specific key from the session data store.

Requires: session cookie.

POST /sapi/project/{project_id}/data

Set multiple keys at once. Existing keys are overwritten.

Requires: session cookie + CSRF token.

Request Body

{
    "cart_items": [{ "product_id": 42, "quantity": 2 }],
    "cart_total": 29.98
}

Response

{
    "success": true,
    "data": {
        "keys_updated": ["cart_items", "cart_total"],
        "session_expires_in": 14400
    }
}
PUT /sapi/project/{project_id}/data/{key}

Set or update a single key in the session data store.

Requires: session cookie + CSRF token.

DELETE /sapi/project/{project_id}/data/{key}

Delete a key from the session data store.

Requires: session cookie + CSRF token.

Forms

Forms have two sides: configuration (you, the owner) and submission (your visitors). You define which forms exist, what fields they require, and what action the server takes when a form is submitted. Visitors only see the form name and send their field values.

Form Configuration (Authenticated)

These endpoints require a Bearer token (wps_ or wpa_). Use them directly or through MCP tools (configure_form, list_forms, remove_form).

POST /sapi/project/{project_id}/forms/configure

Create or update a form definition. Defines required fields, the server-side action, and rate limiting.

Requires: Bearer token.

Request Body

Field Type Required Description
form_name string Yes Unique name for this form (e.g., "contact", "newsletter")
required_fields array Yes Fields the visitor must submit (e.g., ["name", "email", "message"])
action object No Server-side action to execute on submit (see below). Defaults to type: "none".
max_submits_per_session integer No Max submissions per visitor session. Default: 3.

Action Types

Type Description Required Fields
"none" Store submission only, no server-side action
"iapi" Execute an integration proxy call (e.g., send email via Resend) service, endpoint, input_template

Example: Contact Form with Email

{
    "form_name": "contact",
    "required_fields": ["name", "email", "message"],
    "action": {
        "type": "iapi",
        "service": "resend",
        "endpoint": "send-email",
        "input_template": {
            "to": "you@example.com",
            "subject": "Contact from {{fields.name}}",
            "html": "From: {{fields.name}} ({{fields.email}})<br>{{fields.message}}"
        }
    },
    "max_submits_per_session": 3
}
ℹ️ Template Variables Use {{fields.name}} to insert visitor-submitted values into the action template. The server merges the template before executing the action.
GET /sapi/project/{project_id}/forms

List all configured forms for this project.

Requires: Bearer token.

GET /sapi/project/{project_id}/forms/{form_name}

Get a specific form configuration.

Requires: Bearer token.

DELETE /sapi/project/{project_id}/forms/{form_name}

Delete a form configuration.

Requires: Bearer token.

Form Submission (Anonymous)

This endpoint is called by visitors on your website. The form must be pre-configured by the owner.

POST /sapi/project/{project_id}/form/submit

Submit a form. Validates required fields, checks submission limits, and executes the configured action.

Requires: session cookie + CSRF token.

Request Body

Field Type Required Description
form_name string Yes Name of the configured form
fields object Yes Field values as key-value pairs

Example Request

{
    "form_name": "contact",
    "fields": {
        "name": "Jan Jansen",
        "email": "jan@example.nl",
        "message": "I have a question about your service."
    }
}

Response (with IAPI action)

{
    "success": true,
    "data": {
        "form_accepted": true,
        "submits_remaining": 2,
        "action_result": {
            "status": "completed",
            "service": "resend",
            "endpoint": "send-email"
        }
    }
}
⚠️ IAPI Actions Require Vault Credentials If the form action uses type: "iapi", the corresponding API key must be stored in the Vault (VAPI) first. Otherwise the submit will return an error.

Security

CSRF Protection

SAPI uses the Double Submit Cookie pattern. The session cookie is httpOnly (not accessible from JavaScript), but the CSRF token is returned in the API response. Your JavaScript must include the token on every write request.

How to Send the CSRF Token

Method How
HTTP Header X-CSRF-Token: your_csrf_token
Request Body "_csrf": "your_csrf_token"

CORS

SAPI validates the Origin header against your project's domain. Requests from unauthorized origins are rejected. Subdomains of websitepublisher.ai are allowed automatically.

Rate Limiting

Endpoint Group Limit
Session start/resume 30 requests/minute
Data read/write 60 requests/minute
Form submission 10 requests/minute

Anti-Abuse

Maximum 5 concurrent sessions per IP address per project. Excessive session creation triggers automatic rate limiting.

Error Handling

All errors return a consistent format:

{
    "success": false,
    "error": {
        "message": "Description of the error",
        "code": 403
    }
}

HTTP Status Codes

Code Meaning
200 Success
400 Bad Request — invalid input
401 Unauthorized — invalid Bearer token (form config endpoints)
403 Forbidden — missing or invalid CSRF token, or CORS origin rejected
404 Not Found — form not configured, key not found
422 Validation Error — missing required fields
429 Rate Limited — too many requests or max submissions reached
500 Server Error

Complete Example

Here's the full flow for adding a contact form to your website:

# 1. Configure the form (as owner, via API or MCP tool)
curl -X POST "https://api.websitepublisher.ai/sapi/project/{project_id}/forms/configure" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "form_name": "contact",
    "required_fields": ["name", "email", "message"],
    "action": {
        "type": "iapi",
        "service": "resend",
        "endpoint": "send-email",
        "input_template": {
            "to": "you@example.com",
            "subject": "Contact from {{fields.name}}",
            "html": "From: {{fields.name}} ({{fields.email}})<br>{{fields.message}}"
        }
    }
  }'

# 2. Visitor starts a session (from your website JavaScript)
curl -c cookies.txt "https://api.websitepublisher.ai/sapi/project/{project_id}/session"
# → Returns: csrf_token in response body + wss_session cookie

# 3. Visitor submits the form
curl -b cookies.txt -X POST "https://api.websitepublisher.ai/sapi/project/{project_id}/form/submit" \
  -H "Content-Type: application/json" \
  -H "X-CSRF-Token: {csrf_token_from_step_2}" \
  -d '{
    "form_name": "contact",
    "fields": {
        "name": "Jan Jansen",
        "email": "jan@example.nl",
        "message": "Great website!"
    }
  }'
# → Email sent via Resend integration

# 4. Verify form config
curl "https://api.websitepublisher.ai/sapi/project/{project_id}/forms" \
  -H "Authorization: Bearer YOUR_TOKEN"
ℹ️ Prerequisite: Vault Credentials For IAPI actions to work, store the service API key in the Vault first: POST /vapi/project/{id}/secrets with the Resend API key. See Vault documentation.

Powered by WebSumo