Protocol Reference
Summary
The 2Wee protocol is the JSON contract between client and server. This page is the authoritative reference for the wire format. For detailed explanations of each structure, see the linked pages.
Transport
All communication is synchronous HTTPS request/response. The client makes GET or POST requests. The server returns JSON.
| Action | Method | Content-Type |
|---|---|---|
| Fetch any screen | GET | → application/json (ScreenContract) |
| Save changes | POST | application/json (SaveChangeset) → ScreenContract |
| Delete record | POST | application/json (DeleteRequest) → ScreenContract |
| Execute action | POST | application/json (ActionRequest) → ActionResponse |
| Authenticate | POST | application/json (AuthRequest) → AuthResponse |
| Validate field | GET | → application/json (ValidateResponse) |
Only GET and POST are used. No PUT, PATCH, or DELETE. This is a screen rendering protocol, not a REST API.
No WebSocket, no persistent connections, no heartbeats.
Authentication
JWT Bearer tokens in the Authorization header:
Authorization: Bearer <jwt_token>If the server returns 401 Unauthorized, the client redirects to the login screen. See Authentication for the full login flow.
URL architecture
The client takes a base URL (e.g., http://2wee.test/terminal) and uses it for two entry points:
{base_url}/menu/main{base_url}/auth/login
All other paths come from the server as absolute paths (from the host root). The client resolves them by prepending only the scheme and host. See Routes for URL patterns and examples.
Response types
ScreenContract
Every server response to a screen request is a ScreenContract. See Screen Types for the full field reference.
json
{
"layout": "Card",
"title": "Customer Card - 10000",
"screen_id": "customer_card",
"sections": [],
"lines": null,
"menu": null,
"status": null,
"work_date": "10-03-2026",
"locale": {},
"ui_strings": null,
"auth_action": null,
"user_display_name": "Erik Y.",
"actions": {
"save": "/screen/customer_card/10000/save",
"delete": "/screen/customer_card/10000/delete",
"create": "/screen/customer_card/new"
},
"lines_overlay_pct": 50,
"screen_actions": []
}Layout types: Card, List, HeaderLines, Grid, Menu.
ValidateResponse
Returned by the blur validation endpoint. See Lookups for details.
json
{
"valid": true,
"autofill": {
"city": "Tórshavn"
},
"error": null
}| Property | Type | Purpose |
|---|---|---|
valid | bool | Whether the value exists in the related table |
autofill | map | Field values to write to the card (only when valid) |
error | string | Error message (only when invalid) |
AuthResponse
Returned by the login endpoint. See Authentication for details.
json
{
"success": true,
"token": "eyJ...",
"error": null,
"screen": {}
}| Property | Type | Purpose |
|---|---|---|
success | bool | Whether authentication succeeded |
token | string | JWT token (only on success) |
error | string | Error message (only on failure) |
screen | ScreenContract | Initial screen (only on success) |
Client → Server payloads
SaveChangeset (Ctrl+S)
Posted to the actions.save URL. See Saving for details.
json
{
"screen_id": "customer_card",
"record_id": "10000",
"changes": {
"name": "Acme Corporation",
"post_code": "100"
},
"action": null,
"lines": []
}| Property | Type | Purpose |
|---|---|---|
screen_id | string | Echoed from ScreenContract.screen_id |
record_id | string | Record identifier |
changes | map | Changed field values (field_id → value) |
action | string | Optional action hint (e.g., null for saves) |
lines | string[][] | Grid line data for HeaderLines and Grid screens |
For HeaderLines and Grid screens, lines contains the full grid data. Each inner array is one row, with values ordered by column definition. See HeaderLines and Grids for details.
DeleteRequest (Ctrl+D)
Posted to the actions.delete URL. See Deleting for details.
json
{
"screen_id": "customer_card",
"record_id": "10000"
}The path parameter is authoritative — the server identifies the record from the URL path.
ActionRequest (Ctrl+A)
Posted to the action's endpoint URL. See Screen Actions for details.
json
{
"action_id": "send_email",
"screen_title": "Sales Order - SO-1001",
"record_id": "SO-1001",
"fields": {
"to": "ap@cannongroup.example",
"subject": "Sales Order SO-1001"
}
}| Property | Type | Purpose |
|---|---|---|
action_id | string | Action identifier (from ActionDef) |
screen_title | string | Human-readable screen title |
record_id | string | From ScreenContract.record_id, or null if empty |
fields | object | Form field values (empty for Simple and Confirm kinds) |
The server returns an ActionResponse:
json
{
"success": true,
"message": "Email sent to ap@cannongroup.example.",
"screen": null,
"error": null
}| Property | Type | Purpose |
|---|---|---|
success | bool | Whether the action succeeded |
message | string | Success message (shown in result modal) |
screen | ScreenContract | Updated screen (replaces current if provided) |
error | string | Error message (shown in result modal) |
redirect_url | string | Navigate to this screen after dismissing the result modal |
push_url | string | Push a new screen onto navigation history (without a modal) |
AuthRequest
Posted to the auth_action URL. See Authentication for details.
json
{
"fields": {
"username": "admin",
"password": "admin"
}
}Backwards compatibility
The 2Wee protocol follows an additive-only evolution model — the same model the web uses.
What this means in practice:
- New field types, new optional properties, new layout kinds may be added at any time
- Servers that don't send new optional fields get the documented default — nothing breaks
- Clients that don't yet understand a new property ignore it — nothing breaks
- Old clients work against new servers; old servers work against new clients
What will never happen after 1.0:
- Removing a field or property
- Renaming a field or property
- Changing the meaning of an existing field
- Making an optional field required
This is the actual compatibility contract. There is no on-wire version number — the design makes mismatches structurally unlikely rather than just detectable. If a true breaking change is ever required, it will be introduced via a new URL namespace (e.g., /v2/) so old and new implementations can coexist.
Detailed references
| Topic | Page |
|---|---|
| ScreenContract fields, layout types | Screen Types |
| Sections and fields | Cards, Field types |
| Tables (TableSpec), columns, rows | Lists |
| Menus (MenuSpec) | Menus |
| Route patterns, query parameters | Routes |
| Full-screen editable grids | Grids |
| Lookup endpoints, autofill, validation | Lookups |
| Screen actions, ActionRequest/Response | Screen Actions |
| Localization, UI strings | Localization |