Views API
Query named field projections with role-based access control.
Views provide named column projections that limit which fields are returned in API responses. Each view can have its own access control, and all security pillars (firewall, masking) still apply.
Endpoint
GET /api/v1/{resource}/views/{view-name}Example
Given this definition:
export default defineTable(customers, {
views: {
summary: {
fields: ['id', 'name', 'status'],
access: { roles: ['owner', 'admin', 'member'] },
},
full: {
fields: ['id', 'name', 'email', 'status', 'ssn', 'internalNotes'],
access: { roles: ['owner', 'admin'] },
},
},
// ...
});Request
curl /api/v1/customers/views/summary \
-H "Authorization: Bearer <token>"Response
{
"data": [
{ "id": "cust_001", "name": "Acme Corp", "status": "active" },
{ "id": "cust_002", "name": "Widget Inc", "status": "pending" }
],
"view": "summary",
"fields": ["id", "name", "status"],
"pagination": {
"limit": 50,
"offset": 0,
"count": 2
}
}Only the fields specified in the view definition are returned. Requesting the full view with a member role returns 403.
Query Parameters
Views support the same query parameters as the list endpoint:
| Parameter | Description | Default |
|---|---|---|
limit | Number of records to return (1–100) | 50 |
offset | Number of records to skip | 0 |
sort | Field to sort by | createdAt |
order | Sort direction (asc or desc) | desc |
{field} | Filter by exact value | — |
{field}.gt | Greater than | — |
{field}.gte | Greater than or equal | — |
{field}.lt | Less than | — |
{field}.lte | Less than or equal | — |
{field}.ne | Not equal | — |
{field}.like | Pattern match (SQL LIKE) | — |
{field}.in | Match any value in comma-separated list | — |
Examples
# Paginated with sorting
GET /api/v1/customers/views/summary?limit=10&offset=0&sort=name&order=asc
# With filters
GET /api/v1/customers/views/summary?status=active&name.like=%25Corp%25
# Combined
GET /api/v1/customers/views/summary?status.in=active,pending&sort=name&order=asc&limit=25Security
All security pillars apply to view endpoints:
- Authentication — Required (401 if missing)
- Firewall — Organization/user isolation applied to all results. Only records the user owns or has access to are returned.
- Access — Per-view role check. Each view can require different roles.
- Masking — Applied to all returned fields. If a masked field is in the view's field list, the masking rules still apply based on the user's role.
Access Control Per View
Different views can require different permission levels:
views: {
// Available to all org members
summary: {
fields: ['id', 'name', 'status'],
access: { roles: ['owner', 'admin', 'member'] },
},
// Admin-only view with sensitive data
full: {
fields: ['id', 'name', 'email', 'ssn', 'internalNotes'],
access: { roles: ['owner', 'admin'] },
},
}A member requesting the full view receives:
{
"error": "Insufficient permissions",
"layer": "access",
"code": "ACCESS_ROLE_REQUIRED",
"details": { "required": ["admin"], "current": ["member"] }
}Masking in Views
Masking is applied after field projection. If your masking config hides ssn from non-admins:
masking: {
ssn: { type: 'ssn', show: { roles: ['admin'] } },
}A member requesting a view that includes ssn will see the masked value (e.g., *****1234), while an admin sees the full value.
See Also
- Defining Views — How to configure views in defineTable
- Query Parameters — Full query parameter reference
- Access Control — Role-based access configuration