Skip to main content
Every Causeloop client (customer) maps to one organization that owns one workspace. All provisioning happens inside a single database transaction via the onboard_client() PL/pgSQL function, which is idempotent with respect to duplicate slugs and emails.
This page is the operator runbook. If you are building a self-service onboarding flow, see the Onboarding tutorial for the end-user journey.
POST /v1/provisioning/clients provisions a complete client in one call and returns the initial API key (shown once) and an owner invite link. Authenticate with your platform provisioning key (separate from tenant API keys; configure its SHA-256 hash in CAUSELOOP_PROVISION_KEY_HASHES, generate with python scripts/gen_provision_key.py).
Valid plan values: free, starter, growth, enterprise. The endpoint is idempotent: re-calling with the same slug + owner returns the existing tenant (created:false, no secret); reuse an Idempotency-Key to safely retry and recover the original response. The underlying mechanism is the onboard_client() SQL function documented below. See the Provisioning API reference for the full request and response schema.

Prerequisites

Before you provision a client:
  1. The database schema, seed data, and onboard_client.sql functions have been loaded:
  2. DATABASE_URL connects as a role with sufficient privileges. onboard_client() inserts into organizations, workspaces, users, memberships, and audit_log. The schema owner or a role with INSERT on those tables is required.
  3. The org slug you plan to use is unique. The function rejects duplicate slugs with an error.

Quick start — one command

This is all you need. Everything else defaults automatically.

Parameters

What gets created

onboard_client() runs everything inside a single transaction. On success, it returns a JSON object with the new IDs:
Inside the transaction, the function:
  1. Creates an organizations row with the given slug, name, plan, and seats
  2. Creates a workspaces row linked to the organization
  3. Creates (or finds) a users row for the owner email
  4. Creates a memberships row linking the user to the workspace with the admin role
  5. Creates a default workspace_settings row
  6. Writes an audit_log entry (workspace.created) under the new workspace

Step-by-step — with full options

Run this from psql or any Postgres client connected as the schema owner:

Verification

After running onboard_client(), verify the tenant was created correctly:
You should see:
  • One organizations row with status = 'active'
  • One workspaces row with status = 'active'
  • One memberships row with role = 'admin'
  • One audit_log entry with action = 'workspace.created'

Adding the first teammates

Option A — invite by email

The invitation email is currently a stub in the development build. The invited user must accept via POST /v1/invitations/{id}/accept.

Option B — add directly

If you already have the user’s record:

Bulk onboarding

To provision many clients at once, wrap multiple calls in a script:
Where clients.csv has columns: name,slug,email,plan.

Offboarding a client

Suspend (reversible)

Suspending blocks all access to the workspace while retaining all data:
This sets organizations.status = 'suspended'. API requests from suspended workspace tokens receive a 403 Forbidden. To reinstate:

Purge (permanent, irreversible)

This deletes the organizations row. The ON DELETE CASCADE constraint propagates the deletion through:
  • workspaces
  • All tenant-scoped tables beneath the workspace (issues, patterns, memberships, connectors, audit_log, …)
offboard_client('slug', 'purge') is irreversible. All tenant data is permanently deleted. users rows are not deleted — users may belong to other organizations. Clean up user records separately if needed.Before purging, consider exporting the tenant’s data: POST /v1/gdpr/export-requests.

GDPR erasure of one person

To erase a single person’s data without removing the entire tenant, use the RTBF API:
See GDPR & data governance for the full RTBF workflow.

Troubleshooting