---
title: Templates
path: tutorials/templates
status: published
---

# Templates

Templates are reusable record sets that you can apply to new or existing zones. Use them to bootstrap common patterns — mail records (MX + SPF + DKIM + DMARC), Google Workspace setup, load-balanced web frontends — without copy-pasting records each time.

**Base path:** `/api/v1/templates/`
**Required permission:** `records:create` on the target zone

## When to use templates

- **Standard mail configuration** applied to every new customer zone.
- **Per-provider setups** (Google Workspace, Microsoft 365, Cloudflare front-end) where the record list is well-known.
- **Internal zone scaffolding** — organizations with strict naming conventions.
- **Onboarding automation** — your provisioning pipeline applies a template immediately after validation.

## List templates

```bash
curl https://scaidns.scailabs.ai/api/v1/templates/ \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

System templates (shipped with the platform) appear alongside custom templates you create. Filter by `?template_type=system` or `?template_type=custom` if needed.

## Template anatomy

A template is a JSON document describing:

- A list of **records** with placeholders for variables.
- A list of **variables** that must be provided at apply time.

Example — a minimal mail template:

```json
{
  "name": "google-workspace-mail",
  "description": "MX, SPF, and DMARC for Google Workspace",
  "records": [
    {"name": "@", "type": "MX", "content": "1 aspmx.l.google.com.", "ttl": 3600},
    {"name": "@", "type": "MX", "content": "5 alt1.aspmx.l.google.com.", "ttl": 3600},
    {"name": "@", "type": "TXT", "content": "\"v=spf1 include:_spf.google.com -all\"", "ttl": 3600},
    {"name": "_dmarc", "type": "TXT", "content": "\"v=DMARC1; p=quarantine; rua=mailto:${dmarc_contact}\"", "ttl": 3600}
  ],
  "variables": [
    {"name": "dmarc_contact", "description": "Email address for DMARC reports", "required": true}
  ]
}
```

Variables use `${variable_name}` syntax in the content field. The template engine substitutes values at apply time.

### Built-in variables

Some variables are always available:

| Variable | Value |
|----------|-------|
| `${domain}` | The zone apex name (e.g., `example.com`) |
| `${subdomain}` | The subdomain portion if creating on a subdomain zone |
| `${tenant_slug}` | The tenant's slug |
| `${tenant_name}` | The tenant's display name |

Retrieve the full list from `GET /api/v1/templates/variables`.

## Create a template

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/templates/ \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "basic-web",
    "description": "Web apex with www CNAME",
    "records": [
      {"name": "@",   "type": "A",     "content": "${web_ip}", "ttl": 300},
      {"name": "www", "type": "CNAME", "content": "${domain}.", "ttl": 300}
    ],
    "variables": [
      {"name": "web_ip", "description": "Public IP of the web server", "required": true}
    ]
  }'
```

Custom templates are scoped to your tenant. Other tenants don't see them.

## Preview before applying

See what records a template would create without making any changes:

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/templates/$TEMPLATE_ID/preview/$DOMAIN_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"variables": {"web_ip": "192.0.2.10"}}'
```

Returns the fully-substituted record list:

```json
{
  "records": [
    {"name": "example.com", "type": "A", "content": "192.0.2.10", "ttl": 300},
    {"name": "www.example.com", "type": "CNAME", "content": "example.com.", "ttl": 300}
  ]
}
```

## Apply a template

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/templates/ \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "template_id": "tpl_abc123",
    "domain_id": "d_xyz789",
    "variables": {"web_ip": "192.0.2.10"}
  }'
```

```python
resp = httpx.post(
    "https://scaidns.scailabs.ai/api/v1/templates/",
    headers={"X-API-Key": os.environ["SCAIDNS_API_KEY"]},
    json={
        "template_id": TEMPLATE_ID,
        "domain_id": DOMAIN_ID,
        "variables": {"web_ip": "192.0.2.10"},
    },
)
result = resp.json()
print(f"Created: {len(result['created_records'])}, skipped: {len(result['skipped_records'])}")
```

```typescript
const resp = await fetch("https://scaidns.scailabs.ai/api/v1/templates/", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.SCAIDNS_API_KEY!,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    template_id: templateId,
    domain_id: domainId,
    variables: { web_ip: "192.0.2.10" },
  }),
});
const result = await resp.json();
```

### Conflict handling

If a record already exists with the same name/type/content, it's skipped rather than duplicated. The response distinguishes created records from skipped ones:

```json
{
  "created_records": [...],
  "skipped_records": [
    {"name": "example.com", "type": "A", "reason": "already exists"}
  ]
}
```

To overwrite, delete the conflicting records first, then apply the template.

## Required variables

Check what a template needs before you apply it:

```bash
curl https://scaidns.scailabs.ai/api/v1/templates/$TEMPLATE_ID/required-variables \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

Useful when building UIs or pipelines that apply templates dynamically.

## Apply at zone creation

You can apply a template as part of the domain creation call:

```bash
curl -X POST https://scaidns.scailabs.ai/api/v1/domains/ \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "customer42.example.com",
    "domain_type": "primary",
    "template_id": "tpl_standard_customer",
    "template_variables": {"web_ip": "192.0.2.42"}
  }'
```

Template application is deferred until the zone completes validation — records are created on transition to `active`.

## Update and delete

```bash
# Update metadata / records / variables
curl -X PATCH https://scaidns.scailabs.ai/api/v1/templates/$TEMPLATE_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"description": "Updated copy"}'

# Delete a custom template
curl -X DELETE https://scaidns.scailabs.ai/api/v1/templates/$TEMPLATE_ID \
  -H "X-API-Key: $SCAIDNS_API_KEY"
```

System templates are read-only — you can't edit or delete them.

## What's next

- [Managing Records](./managing-records.md) — work with records directly.
- [Templates reference](../reference/templates.md) — full endpoint details.
