The two-level model
Every GetSigned resource is scoped by two IDs:
| ID | What it represents | Where it comes from |
|---|
app_id | Your API client (your SaaS product) | Derived from your client_id — set automatically |
tenant_id | A customer within your product | You supply this on every request |
What is a tenant?
A tenant is any unit of ownership within your platform. Depending on your product:
- For a healthcare SaaS: a clinic or practice (
tenant_id = "clinic-001")
- For a legal platform: a law firm (
tenant_id = "firm-greenwood")
- For an HR tool: a company (
tenant_id = "company-acme")
You decide what a tenant is. GetSigned doesn’t validate or resolve tenant IDs — it just uses
them to scope all data storage and retrieval. Data from Tenant A is never visible to Tenant B,
even through the same API credentials.
Setting tenant_id
Pass tenantId on every envelope creation request:
curl -X POST https://api.getsigned.ca/v1/envelopes \
-H "Authorization: Bearer $TOKEN" \
-d '{
"tenantId": "acme-corp",
"subject": "NDA",
...
}'
If you’re sending envelopes for a single organization (your own), use a fixed tenantId.
Listing envelopes for a tenant
All list endpoints are filtered by the token’s app_id. To further filter by tenant:
curl "https://api.getsigned.ca/v1/envelopes?tenantId=acme-corp" \
-H "Authorization: Bearer $TOKEN"
This returns only envelopes for acme-corp. Your API credentials cannot access envelopes
belonging to another app’s tenants — the isolation is enforced at the database level.
Data isolation guarantee
GetSigned enforces multi-tenant isolation at two levels:
- Application level — your API token can only access records where
app_id matches your
registered application. No cross-app leakage.
- Tenant level —
GET /v1/envelopes?tenantId=X only returns records matching both your
app_id AND tenantId=X. Omitting tenantId returns all your tenants’ data, scoped to your app.
If your SaaS serves multiple customers and each customer should only see their own documents,
always pass tenantId in your API calls and always filter by tenantId in your own
data layer. Do not rely on a UI filter alone.
One set of credentials, many tenants
You don’t need a separate GetSigned application per tenant. One client_id / client_secret pair
serves all your tenants. tenantId is just a tag — it costs nothing to create a new one.
This means:
- No per-customer credential management
- No per-customer onboarding in GetSigned
- Billing is at the application level (across all your tenants)
Webhook routing
Webhooks fire to your configured endpoint for all events across all tenants. The payload always
includes tenantId, so you can route events to the right customer in your system:
{
"event": "envelope.completed",
"data": {
"envelopeId": "env_01HX...",
"tenantId": "acme-corp",
...
}
}