Control which services a workspace runs.
Each service (Auth, Mail, Waitlist, Social, Trawl) is activated per workspace. New workspaces start with every service enabled; disable the ones you don't use. Endpoints of a disabled service return 403 SERVICE_NOT_ENABLED before any data leaks.
1
Why activation is per-workspace
- Scoping — each of your workspaces (production, dev, per-client) runs only the services it actually needs.
- Defence in depth — a misconfigured key shouldn't accidentally hit a service the workspace never wanted. The
SERVICE_NOT_ENABLEDcheck runs before any service-specific logic.
Today a new workspace is created with all five services enabled, so the console shows every product immediately — disabling is how you narrow the surface.
2
Enable a service
From the console (Workspace → Services, then Enable / Disable on the service row) or API:
# Enable (or re-enable) Mail
curl -X POST https://api.platform-auth.productcraft.co/v1/workspaces/acme/services/mail \
-H 'authorization: Bearer <token-or-pak>' \
-H 'content-type: application/json' \
-d '{}'
# → 201, the full service state row:
{
"workspace_id": "<workspace-uuid>",
"service": "mail",
"enabled": true,
"enabled_at": "2026-07-28T14:20:46.083Z",
"enabled_by": "<account-uuid>",
"disabled_at": null,
"disabled_by": null,
"settings": {}
}Requires the workspace.service.enable permission. Valid service names are auth, mail, waitlist, social, trawl — anything else is a 400 SERVICE_UNKNOWN.
3
Per-service settings
Each activation row carries a free-form settings JSON blob whose shape is up to the service. Update it via PATCH /v1/workspaces/:slug/services/:service/settings — the request body is the settings object itself (no wrapper) and replaces the blob entirely:
curl -X PATCH https://api.platform-auth.productcraft.co/v1/workspaces/acme/services/mail/settings \
-H 'authorization: Bearer <token-or-pak>' \
-H 'content-type: application/json' \
-d '{ "default_sender": "noreply@acme.com" }'
# → 200, the updated service state row (settings included)Requires workspace.service.enable. Patching a service that was never activated on the workspace returns 404 SERVICE_NOT_ACTIVATED.
4
Disable
curl -X DELETE https://api.platform-auth.productcraft.co/v1/workspaces/acme/services/mail \
-H 'authorization: Bearer <token-or-pak>'
# → 204. Disabling a service that isn't enabled → 409 SERVICE_NOT_ENABLED.Requires workspace.service.disable. Disable doesn't delete data — domains, templates, messages, settings are all preserved. Subsequent calls to the service's endpoints return 403 SERVICE_NOT_ENABLED. Re-enabling restores access (allow up to a minute for downstream permission caches to refresh). For permanent removal, delete the workspace (Chapter 1).
5
List active services
curl https://api.platform-auth.productcraft.co/v1/workspaces/acme/services \
-H 'authorization: Bearer <token-or-pak>'{
"data": [
{ "workspace_id": "...", "service": "auth", "enabled": true,
"enabled_at": "...", "enabled_by": "...",
"disabled_at": null, "disabled_by": null, "settings": {} },
{ "workspace_id": "...", "service": "mail", "enabled": true, ... },
{ "workspace_id": "...", "service": "social", "enabled": true, ... },
{ "workspace_id": "...", "service": "trawl", "enabled": true, ... },
{ "workspace_id": "...", "service": "waitlist", "enabled": false,
"disabled_at": "...", "disabled_by": "...", ... }
]
}Requires workspace.service.read. A disabled service keeps its row with enabled: false and disabled_at set.
6
The SERVICE_NOT_ENABLED guard in practice
Useful for SDKs and customer support — what error to expect when a service hasn't been turned on.
Workspace-scoped endpoints on a service check activation before anything else. With the service disabled you get:
HTTP/1.1 403 Forbidden
{
"statusCode": 403,
"message": "mail is not enabled on this workspace",
"code": "SERVICE_NOT_ENABLED"
}This 403 isn't a permission failure. Your role and policies are fine — activation is a structural prerequisite, not an authz outcome. Re-enable the service and the same call succeeds.