Learn how to integrate custom domains into your SaaS application
The external API supports completely optional custom domain fields. You can create tenants with minimal data and progressively add subdomains and custom domains as needed:
Domain Events:
Tenant Events:
Create tenants for your multi-tenant SaaS
Add custom domains to your project via API
Verify domain ownership with DNS or HTTP challenge
Receive webhooks for domain status changes
const axios = require('axios');
// For External SaaS Integration
const client = axios.create({
baseURL: 'https://api.domainly.dev/external/api',
headers: {
'X-API-Key': 'dom_your_api_key_here',
'Content-Type': 'application/json'
}
});// Create a tenant (automatic project context from API key)
const tenant = await client.post('/tenants', {
name: 'Acme Corporation',
createSubdomain: true,
subdomainName: 'acme',
metadata: { plan: 'premium', industry: 'technology' }
});
console.log('Tenant created:', tenant.data);// Create a subdomain (automatic project context from API key)
const subdomain = await client.post('/subdomains', {
subdomain: 'store',
tenantId: tenant.data.id,
description: 'E-commerce store subdomain'
});
console.log('Subdomain created:', subdomain.data);// Create custom domain (automatic project context from API key)
const response = await client.post('/domains', {
customDomain: 'app.customer.com',
subdomain: 'customer-subdomain',
verificationMethod: 'cname',
tenantId: tenant.data.id
});
console.log('Domain created:', response.data);// List all domains (automatic project context from API key)
const response = await client.get('/domains');
console.log('Domains:', response.data.data);Complete API reference for all endpoints
/external/api/tenantsList all tenants for your project (automatic project context from API key)
{
"success": true,
"data": [
{
"id": "tenant-456",
"name": "Shopify Store",
"status": "ACTIVE",
"domainCount": 2,
"createdAt": "2024-01-15T12:00:00Z"
}
]
}/external/api/tenantsCreate a new tenant for your multi-tenant SaaS application
{
"name": "Acme Corporation",
"createSubdomain": true,
"subdomainName": "acme",
"metadata": {
"plan": "premium",
"industry": "technology"
}
}{
"success": true,
"data": {
"id": "tenant-456",
"name": "Shopify Store",
"status": "ACTIVE",
"metadata": {
"plan": "premium",
"features": ["custom_domain"]
},
"createdAt": "2024-01-15T12:00:00Z"
}
}/api/tenants/me/dataGet data for the current tenant based on domain resolution
{
"success": true,
"data": {
"id": "tenant-456",
"name": "Shopify Store",
"status": "ACTIVE",
"project": {
"id": "project-123",
"name": "My SaaS App",
"domain": "myapp.com"
},
"domains": [
{
"id": "domain-789",
"customDomain": "shop.customer.com",
"subdomain": "shop.myapp.com",
"status": "ACTIVE"
}
],
"metadata": {
"plan": "premium",
"features": ["custom_domain"]
}
}
}/external/api/subdomainsCreate a new subdomain for your project (automatic project context from API key)
{
"subdomain": "shop",
"tenantId": "tenant-456",
"description": "Main store subdomain"
}{
"success": true,
"data": {
"id": "subdomain-789",
"projectId": "project-123",
"subdomain": "shop",
"description": "Main store subdomain",
"tenantId": "tenant-456",
"tenant": {
"id": "tenant-456",
"name": "Shopify Store",
"identifier": "shop"
},
"domainCount": 0,
"createdAt": "2024-01-15T12:00:00Z"
}
}/external/api/subdomains/check-availabilityCheck if a subdomain is available for your project (automatic project context from API key)
{
"success": true,
"data": {
"available": true,
"subdomain": "shop",
"reason": null
}
}/external/api/domainsList all domains for your project (automatic project context from API key)
/external/api/domainsCreate a custom domain for your project (automatic project context from API key)
{
"customDomain": "app.customer.com",
"subdomain": "customer-subdomain",
"verificationMethod": "cname",
"tenantId": "tenant-456"
}{
"success": true,
"data": {
"id": "dom_123",
"projectId": "proj_123",
"subdomainId": "subdomain-789",
"customDomain": "shop.customer.com",
"subdomain": "shop",
"status": "PENDING_VERIFICATION",
"verificationMethod": "cname",
"verificationToken": "verify_abc123",
"sslStatus": "PENDING",
"dnsRecords": [
{
"type": "CNAME",
"name": "shop.customer.com",
"value": "your-project-id.domainly.dev"
}
],
"subdomainRef": {
"id": "subdomain-789",
"subdomain": "shop",
"description": "Main store subdomain",
"tenant": {
"id": "tenant-456",
"name": "Shopify Store",
"identifier": "shop"
}
}
}
}/external/api/webhooks/logsGet webhook delivery logs for your project (automatic project context from API key)
limitNumber of logs (default: 50)offsetOffset for pagination (default: 0){
"success": true,
"data": [
{
"id": "webhook_123",
"type": "DOMAIN_VERIFIED",
"status": "DELIVERED",
"attempts": 1,
"createdAt": "2024-01-15T10:30:00Z"
}
]
}Learn about webhook events and how to handle them
{
"event": "tenant.created",
"timestamp": "2024-01-15T10:30:00Z",
"data": {
"tenantId": "tenant-456",
"name": "Shopify Store",
"identifier": "shop",
"status": "ACTIVE",
"metadata": {
"plan": "premium"
}
}
}Common error responses and their meanings