Tenant Management

Manage tenants in your Approved Contact account. Tenants represent organizations or business units that can have their own phone numbers, settings, and webhook configurations. This is essential for multi-tenant applications or managing multiple customer accounts.

What is a Tenant? A tenant is an isolated organizational unit within your Approved Contact account. Each tenant has its own phone numbers, message history, contacts, and settings. Perfect for SaaS applications serving multiple customers or enterprises managing multiple business units.

Creating Tenants

Create a new tenant with custom settings, webhook configuration, and domain assignment. Tenants are automatically assigned an owner based on your authentication credentials.

Example: Create a Tenant

curl -X POST https://api.approvedcontact.com/api/v1/tenants \
  -u "your-email@example.com:your-password" \
  -H "Content-Type: application/json" \
  -d '{
    "tenantId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "domain": "customer.example.com",
    "settings": {
      "webhookPrimaryUri": "https://customer.example.com/webhooks/messages",
      "webhookSecondaryUri": "https://backup.example.com/webhooks/messages",
      "webhookSecret": "your-secure-secret-key"
    }
  }'
import requests
import base64
import uuid

credentials = base64.b64encode(b'your-email@example.com:your-password').decode()

response = requests.post(
    'https://api.approvedcontact.com/api/v1/tenants',
    headers={'Authorization': f'Basic {credentials}'},
    json={
        'tenantId': str(uuid.uuid4()),  # Optional - auto-generated if not provided
        'domain': 'customer.example.com',
        'settings': {
            'webhookPrimaryUri': 'https://customer.example.com/webhooks/messages',
            'webhookSecondaryUri': 'https://backup.example.com/webhooks/messages',
            'webhookSecret': 'your-secure-secret-key'
        }
    }
)

tenant = response.json()
print(f"Created tenant: {tenant['tenantId']}")
var client = new HttpClient();
var credentials = Convert.ToBase64String(
    Encoding.ASCII.GetBytes("your-email@example.com:your-password"));
client.DefaultRequestHeaders.Authorization = 
    new AuthenticationHeaderValue("Basic", credentials);

var request = new
{
    tenantId = Guid.NewGuid().ToString(),  // Optional
    domain = "customer.example.com",
    settings = new
    {
        webhookPrimaryUri = "https://customer.example.com/webhooks/messages",
        webhookSecondaryUri = "https://backup.example.com/webhooks/messages",
        webhookSecret = "your-secure-secret-key"
    }
};

var response = await client.PostAsJsonAsync(
    "https://api.approvedcontact.com/api/v1/tenants",
    request
);

var tenant = await response.Content.ReadFromJsonAsync();
Console.WriteLine($"Created tenant: {tenant.TenantId}");
const axios = require('axios');
const { v4: uuidv4 } = require('uuid');

const credentials = Buffer.from('your-email@example.com:your-password').toString('base64');

axios.post(
    'https://api.approvedcontact.com/api/v1/tenants',
    {
        tenantId: uuidv4(),  // Optional
        domain: 'customer.example.com',
        settings: {
            webhookPrimaryUri: 'https://customer.example.com/webhooks/messages',
            webhookSecondaryUri: 'https://backup.example.com/webhooks/messages',
            webhookSecret: 'your-secure-secret-key'
        }
    },
    {
        headers: { 'Authorization': `Basic ${credentials}` }
    }
)
.then(response => {
    console.log(`Created tenant: ${response.data.tenantId}`);
});

Create Request Parameters

Parameter Type Required Description
tenantId GUID No Tenant ID (auto-generated if not provided)
domain string No Custom domain for this tenant
settings object No Tenant settings including webhooks
Owner Assignment: The owner and billableOwner fields are automatically set based on your authentication credentials and cannot be specified in the request. This ensures proper billing and access control.

Listing Tenants

Retrieve all tenants associated with your owner account or get details about a specific tenant.

List All Tenants

curl -X GET https://api.approvedcontact.com/api/v1/tenants \
  -u "your-email@example.com:your-password"

Get Specific Tenant

curl -X GET https://api.approvedcontact.com/api/v1/tenants/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
  -u "your-email@example.com:your-password"

Response Example

{
  "tenantId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "owner": "owner@approvedcontact.com",
  "billableOwner": "billing@approvedcontact.com",
  "domain": "customer.example.com",
  "createdDate": "2025-01-11T10:30:00Z",
  "settings": {
    "webhookPrimaryUri": "https://customer.example.com/webhooks/messages",
    "webhookSecondaryUri": "https://backup.example.com/webhooks/messages",
    "webhookSecret": "***hidden***"
  }
}

Updating Tenants

Update tenant settings, including webhook configuration, custom domains, and other preferences. The owner and billable owner cannot be changed after creation.

Update Tenant Settings

curl -X PUT https://api.approvedcontact.com/api/v1/tenants/3fa85f64-5717-4562-b3fc-2c963f66afa6 \
  -u "your-email@example.com:your-password" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "new-domain.example.com",
    "settings": {
      "webhookPrimaryUri": "https://new-webhook.example.com/messages",
      "webhookSecret": "new-secure-secret"
    }
  }'

Updatable Fields

Field Type Description
domain string Custom domain for the tenant
settings object All tenant settings (see webhook section)
Immutable Fields: The owner and billableOwner fields cannot be changed after tenant creation. Contact support if you need to transfer tenant ownership.

Webhook Configuration

Configure webhooks at the tenant level to receive notifications for all messages and order status updates for that tenant's phone numbers.

Webhook Settings

{
  "settings": {
    "webhookPrimaryUri": "https://your-app.com/webhooks/messages",
    "webhookSecondaryUri": "https://backup-app.com/webhooks/messages",
    "webhookSecret": "your-webhook-secret-key",
    "webhookBasicAuthUsername": "webhook-user",
    "webhookBasicAuthPassword": "webhook-pass"
  }
}

Webhook Configuration Options

Field Description
webhookPrimaryUri Primary webhook endpoint URL
webhookSecondaryUri Fallback webhook endpoint (optional)
webhookSecret Secret key for HMAC signature verification
webhookBasicAuthUsername Username for HTTP Basic Authentication (optional)
webhookBasicAuthPassword Password for HTTP Basic Authentication (optional)
Security Best Practice: Always configure both a webhook secret for signature verification AND Basic Authentication for defense in depth. See the Webhooks Guide for signature verification examples.

Best Practices

Tenant Organization

Webhook Configuration

Multi-Tenant Architecture

# Example: SaaS application tenant provisioning
class TenantProvisioner:
    def provision_customer(self, customer_id, customer_domain):
        # Create tenant
        tenant = api.create_tenant({
            'tenantId': str(uuid.uuid4()),
            'domain': customer_domain,
            'settings': {
                'webhookPrimaryUri': f'https://api.yourapp.com/webhooks/{customer_id}',
                'webhookSecret': generate_secure_secret()
            }
        })
        
        # Provision phone numbers for tenant
        numbers = api.provision_numbers({
            'tenantId': tenant['tenantId'],
            'phoneNumbers': get_available_numbers(area_code=customer_area_code)
        })
        
        return {
            'tenant': tenant,
            'numbers': numbers
        }

Monitoring

Pro Tip: Store the tenant ID in your application's customer database. Use it as a foreign key for all Approved Contact API operations related to that customer, ensuring proper data isolation and billing.

Next Steps