API Reference

Quick Start

https://api.domainly.dev/external/api
Use this for SaaS integration with automatic project context
Use your API key in the X-API-Key header for SaaS integration:
X-API-Key: dom_your_api_key_here
API key provides automatic project context - no need to pass projectId

Getting Started

Learn how to integrate custom domains into your SaaS application

SaaS Integration Overview

🚀 Quick Setup

  • • Get API key from dashboard
  • • Use external SaaS API endpoints
  • • Automatic project context
  • • No manual project ID needed

🔧 Integration Flow

  • • Create tenant for each customer
  • • Add custom domain
  • • Verify domain ownership
  • • Receive webhook notifications

📋 Optional Custom Domain Fields

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:

  • • Flexible tenant creation - Only name is required, everything else is optional
  • • Progressive enhancement - Add subdomains/domains after tenant creation
  • • One subdomain + one custom domain per tenant constraint
  • • Intelligent availability checking with automatic suggestions

Webhook Configuration

Webhook Events

Domain Events:

  • • domain.verified
  • • domain.failed
  • • ssl.provisioned
  • • ssl.expired

Tenant Events:

  • • tenant.created
  • • tenant.updated
  • • subdomain.created
  • • subdomain.deleted

Rate Limits & Best Practices

Rate Limits

  • • General: 1000/hour
  • • Tenants: 100/hour
  • • Domains: 20/hour
  • • DNS checks: 50/hour

Error Handling

  • • Implement retry logic
  • • Handle 429 rate limits
  • • Validate input data
  • • Log API responses

Security

  • • Store API keys securely
  • • Use HTTPS only
  • • Verify webhook signatures
  • • Rotate keys periodically

1. Create Tenant

Create tenants for your multi-tenant SaaS

2. Add Domain

Add custom domains to your project via API

3. Verify Ownership

Verify domain ownership with DNS or HTTP challenge

4. Get Notifications

Receive webhooks for domain status changes

Code Examples

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);

API Endpoints

Complete API reference for all endpoints

GET
/external/api/tenants
API Key

List all tenants for your project (automatic project context from API key)

No Parameters Required

Project context automatically injected from API key

Response

{  
  "success": true,
  "data": [
    {
      "id": "tenant-456",
      "name": "Shopify Store",
      "status": "ACTIVE",
      "domainCount": 2,
      "createdAt": "2024-01-15T12:00:00Z"
    }
  ]
}
POST
/external/api/tenants
API Key

Create a new tenant for your multi-tenant SaaS application

Request Body

{
  "name": "Acme Corporation",
  "createSubdomain": true,
  "subdomainName": "acme",
  "metadata": {
    "plan": "premium",
    "industry": "technology"
  }
}

Response

{
  "success": true,
  "data": {
    "id": "tenant-456",
    "name": "Shopify Store",
    "status": "ACTIVE",
    "metadata": {
      "plan": "premium",
      "features": ["custom_domain"]
    },
    "createdAt": "2024-01-15T12:00:00Z"
  }
}
GET
/api/tenants/me/data
API Key

Get data for the current tenant based on domain resolution

Response

{
  "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"]
    }
  }
}
POST
/external/api/subdomains
API Key

Create a new subdomain for your project (automatic project context from API key)

Request Body

{
  "subdomain": "shop",
  "tenantId": "tenant-456",
  "description": "Main store subdomain"
}

Response

{
  "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"
  }
}
GET
/external/api/subdomains/check-availability
API Key

Check if a subdomain is available for your project (automatic project context from API key)

Response

{
  "success": true,
  "data": {
    "available": true,
    "subdomain": "shop",
    "reason": null
  }
}
GET
/external/api/domains
API Key

List all domains for your project (automatic project context from API key)

No Parameters Required

Project context automatically injected from API key
POST
/external/api/domains
API Key

Create a custom domain for your project (automatic project context from API key)

Request Body

{
  "customDomain": "app.customer.com",
  "subdomain": "customer-subdomain",
  "verificationMethod": "cname",
  "tenantId": "tenant-456"
}

Response

{
  "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"
      }
    }
  }
}
GET
/external/api/webhooks/logs
API Key

Get webhook delivery logs for your project (automatic project context from API key)

Query Parameters

limitNumber of logs (default: 50)
offsetOffset for pagination (default: 0)

Response

{
  "success": true,
  "data": [
    {
      "id": "webhook_123",
      "type": "DOMAIN_VERIFIED",
      "status": "DELIVERED",
      "attempts": 1,
      "createdAt": "2024-01-15T10:30:00Z"
    }
  ]
}

Webhook Events

Learn about webhook events and how to handle them

Event Types

tenant.created
New tenant created
POST
tenant.updated
Tenant updated
POST
domain.added
Domain added to project
POST
domain.verified
Domain ownership verified
POST
ssl.issued
SSL certificate issued
POST

Webhook Payload

{
  "event": "tenant.created",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "tenantId": "tenant-456",
    "name": "Shopify Store",
    "identifier": "shop",
    "status": "ACTIVE",
    "metadata": {
      "plan": "premium"
    }
  }
}

Error Codes

Common error responses and their meanings

400 Bad Request
Invalid request parameters
400
401 Unauthorized
Invalid API key or token
401
403 Forbidden
Insufficient permissions
403
404 Not Found
Resource not found
404
429 Too Many Requests
Rate limit exceeded
429
500 Internal Server Error
Server error
500