Platform guides
03 · Service activation

Turn on the services you need.

Each service (Auth, Mail, Waitlist, Social) is opt-in per workspace. Until you activate, every endpoint on that service returns 403 SERVICE_NOT_ENABLED before any data leaks.


1

Why activation is per-workspace

Two reasons:

  • Billing isolation — services charge per workspace based on usage. Activating Mail for one of your workspaces (production) without activating it for another (dev) keeps the bill clean.
  • Defence in depth — a misconfigured key shouldn't accidentally hit a service the workspace never wanted. The SERVICE_NOT_ENABLED guard runs before any service-specific logic, so a caller can't enumerate a non-activated surface.

2

Enable a service

From the console (Settings → Services → flip the toggle) or API:

POST /v1/workspaces/:slug/services/:service
# Enable Mail
curl -X POST https://api.platform-auth.productcraft.co/v1/workspaces/acme/services/mail \
  -H 'authorization: Bearer <cookie-or-pak>' \
  -H 'content-type: application/json' \
  -d '{
    "settings": {
      "from_address": "noreply@acme.com",
      "notifications_via_envoi": true
    }
  }'

workspace.service.enable permission required. Enabling a service for the first time fires the service's initial provisioning — e.g. Auth doesn't need much, Mail may seed default templates if the workspace has none.


3

Service-specific settings

Each service exposes its own settings shape:

# Mail
{
  "from_address":            "noreply@acme.com",
  "notifications_via_envoi": true,   # used by Auth verify/reset
  "default_brand":           { "logo_url": "...", "accent_color": "#..." }
}

# Auth
{
  "default_signup_role":     "member",
  "session_ttl_seconds":     3600,
  "refresh_ttl_seconds":     2592000   # 30 days
}

# Waitlist
{
  "default_capacity":        500,
  "default_captcha_provider": "recaptcha"   # or "hcaptcha" | "turnstile" | null
}

# Social
{
  "default_visibility":      "public",
  "moderation_required":     false
}

Update via PATCH /v1/workspaces/:slug/services/:service/settings. Settings update doesn't fire provisioning a second time; it's just metadata.


4

Disable

DELETE /v1/workspaces/:slug/services/:service
curl -X DELETE https://api.platform-auth.productcraft.co/v1/workspaces/acme/services/mail \
  -H 'authorization: Bearer <cookie-or-pak>'

Disable doesn't delete data. Domains, templates, messages, suppression list — all preserved. Subsequent calls to the service's endpoints just return 403 SERVICE_NOT_ENABLED. Re-enabling immediately restores access.

For permanent removal, delete the workspace (Chapter 1) or open a customer-support ticket for service-scoped purges.


5

List active services

GET /v1/workspaces/:slug/services
curl https://api.platform-auth.productcraft.co/v1/workspaces/acme/services \
  -H 'authorization: Bearer <cookie-or-pak>'
{
  "services": [
    { "service": "auth",     "enabled": true,  "enabled_at": "..." },
    { "service": "mail",     "enabled": true,  "enabled_at": "..." },
    { "service": "waitlist", "enabled": false },
    { "service": "social",   "enabled": false }
  ]
}

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.

Every service-specific endpoint runs this check first:

HTTP/1.1 403 Forbidden
{
  "statusCode": 403,
  "code":       "SERVICE_NOT_ENABLED",
  "service":    "mail",
  "message":    "Service 'mail' is not enabled on this workspace.",
  "remediation": "Owner: enable via console → Settings → Services."
}

This 403 isn't a permission failure — even a PAK with full mail.* permission gets 403 if the service isn't enabled. Activation is a structural prerequisite, not an authz outcome.