SuperAPI AI Directory

telnyx-email-domains-curl

Office & productivity

View repository

Updated 10-16 04:31

About this skill

Telnyx Email Domains — curl

Installation

# curl is pre-installed on macOS, Linux, and Windows 10+.
# A JSON formatter such as `python3 -m json.tool` is optional.

Setup

export TELNYX_API_KEY="YOUR_API_KEY_HERE"
export TELNYX_API_BASE="https://api.telnyx.com/v2"

# Set these from API responses after creating or listing resources.
export EMAIL_DOMAIN_ID="123e4567-e89b-12d3-a456-426614174000"
export EMAIL_WEBHOOK_ID="123e4567-e89b-12d3-a456-426614174003"

Every request requires:

-H "Authorization: Bearer $TELNYX_API_KEY"

Mutation requests with JSON also require:

-H "Content-Type: application/json"

Use --fail-with-body --silent --show-error in automation so non-2xx responses fail the command without hiding the Telnyx error body.

Error Handling

Error responses use an errors array:

{
  "errors": [
    {
      "code": "10015",
      "title": "Validation Failed",
      "detail": "domain is invalid",
      "source": {"pointer": "/data/attributes/domain"}
    }
  ]
}

Common cases:

HTTP Meaning Action
400 Invalid list query or malformed input Fix the query; do not retry unchanged.
401 Missing or invalid API key Fix authentication.
403 Shared domain is read-only (10008) or access is insufficient Use an owned custom domain or correct permissions.
404 Domain or webhook not found (10001) Re-list resources and verify both IDs.
422 Request validation or state transition failed (10015 and related codes) Inspect every error and source.pointer; correct the request or state.
429 Rate limit Honor Retry-After when present and back off.
500 Unexpected service error Retry only safe reads or carefully reconciled mutations.

Do not retry a create blindly after a transport timeout; first list domains and check whether the resource was created. verify and GET operations are safe to repeat. Before retrying DELETE or PATCH, retrieve the current state. Use bounded exponential backoff with jitter for transient 429 and 5xx failures.

Important Notes

  • All 13 reachable operations use the Telnyx v2 REST API and Bearer authentication.
  • A custom domain is not ready merely because POST /v2/email_domains succeeds. Create it, retrieve its generated DNS records, publish those records, trigger verification, and check health until usable_for_sending is true.
  • Call GET /v2/email_domains/{domain_id}/dns_records to retrieve the exact DNS records you need to publish. The response includes the record type, host, value, and priority for each record.
  • The OpenAPI DNS-purpose enum includes ownership, spf, dkim, dmarc, and mx. SPF, DKIM, and DMARC are authentication-related purposes; MX supports inbound routing when required. Publish the exact API-returned values rather than constructing DNS records from examples.
  • Webhooks are configured at the domain level through POST /v2/email_domains/{domain_id}/webhooks, not per message.
  • Domain IDs and webhook IDs are UUIDs returned by the API, not domain names.

Operational Caveats

  • Shared versus custom domains: Telnyx-managed shared domains are pre-provisioned and readable/usable by accounts. Custom domains require customer DNS setup and verification. Non-owners cannot update, verify, or delete a shared domain; those attempts return 403 with code 10008.
  • DNS is API-generated: The API does not expose customer-facing create/update/delete operations for individual generated DNS records. Publish records at the authoritative DNS provider, then call the verify operation.
  • Tracking defaults live on the domain: open_tracking, click_tracking, and unsubscribe_tracking default to false, false, and true, respectively. A send may override these defaults without changing the domain.
  • Health is the readiness signal: Do not infer deliverability from one DNS record. Check the aggregate health response and the relevant usability boolean.
  • Verification reflects DNS propagation: A successful verify request means the check ran, not that every record passed. Wait and use bounded backoff before checking again; never tight-loop verification.
  • Verified deletion requires intent: Pass force=true to delete a verified custom domain. Delete returns 200 with the deleted domain, not 204.
  • Pagination differs by resource: Domain lists support offset or cursor pagination. Webhook lists support offset pagination only. Treat cursors as opaque and inspect the returned .meta shape.

Reference Use Rules

Do not invent request fields, DNS values, event names, response fields, or status enums.

Core Tasks

Provision and verify a custom domain

1. Create a domain

POST /v2/email_domains

Parameter Type Required Description
domain string Yes Custom domain name, for example example.com.
inbound_enabled boolean No Enable inbound routing; defaults to false.
dmarc_policy object | null No Advisory DMARC policy (p, pct, rua, sp).
tracking object No Domain defaults for open, click, and unsubscribe tracking.
curl --fail-with-body --silent --show-error \
  -X POST \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "domain": "example.com",
    "inbound_enabled": true,
    "dmarc_policy": {
      "p": "none",
      "pct": 100,
      "rua": "mailto:dmarc@example.com"
    },
    "tracking": {
      "open_tracking": true,
      "click_tracking": true,
      "unsubscribe_tracking": true
    }
  }' \
  "$TELNYX_API_BASE/email_domains"

Expected status: 201. Save .data.id as EMAIL_DOMAIN_ID. Do not send until .data.usable_for_sending is true.

2. Retrieve the required DNS records

GET /v2/email_domains/{domain_id}/dns_records

Parameter Type Required Description
domain_id UUID path parameter Yes Domain ID returned by the API.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/dns_records"

Each item in .data[] includes purpose, record_type, host, value, priority, required, status, and possibly actual_value. Publish every required record exactly as returned. Use the response to decide which records are required for this domain's sending and inbound configuration.

3. Trigger DNS verification

POST /v2/email_domains/{domain_id}/verify

Parameter Type Required Description
domain_id UUID path parameter Yes Domain whose current DNS records should be checked.
Request body — No This operation has no request body.
curl --fail-with-body --silent --show-error \
  -X POST \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/verify"

Expected status: 200. Inspect .data.verification and each .data.dns_records[].status. A 200 means the check ran; it does not guarantee that every record verified.

4. Check domain health

GET /v2/email_domains/{id}/health

Parameter Type Required Description
id UUID path parameter Yes Domain whose aggregate readiness should be checked.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/health"

Read .data.status, .data.usable_for_sending, .data.usable_for_inbound, .data.verification, and .data.checked_at. DMARC may be missing_optional without blocking sending; use each record's required flag and the health booleans rather than treating every non-verified value as fatal.

List domains

GET /v2/email_domains

Query parameter Type Required Description
page[number] integer No Offset page number.
page[size] integer No Page size from 1 to 100.
sort enum No created_at, -created_at, domain, or -domain.
filter[type] enum No custom, shared, or shared_inbound.
filter[usable_for_sending] boolean No Limit results by sending readiness.
... See all list query parameters.
curl --fail-with-body --silent --show-error --get \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  --data-urlencode "page[number]=1" \
  --data-urlencode "page[size]=25" \
  --data-urlencode "sort=-created_at" \
  --data-urlencode "filter[type]=custom" \
  --data-urlencode "filter[usable_for_sending]=true" \
  "$TELNYX_API_BASE/email_domains"

Supported filters also include status, partial case-insensitive domain, profile_id, and usable_for_inbound. Domain lists support offset pagination and cursor pagination; inspect the returned .meta shape.

Retrieve a domain

GET /v2/email_domains/{id}

Parameter Type Required Description
id UUID path parameter Yes Domain to retrieve.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID"

Expected status: 200. The response includes DNS, DKIM, inbound, DMARC, tracking, usability, timestamps, and optional reputation information.

Update a domain

PATCH /v2/email_domains/{id}

Parameter Type Required Description
id UUID path parameter Yes Domain to update.
inbound_enabled boolean No Enable or disable inbound routing.
dmarc_policy object | null No Change the advisory DMARC policy.
tracking object No Change domain tracking defaults.

The domain name and type are not mutable. Include at least one field to change. Updating the DMARC policy rebuilds the recommended DMARC record and resets its verification to pending, so retrieve the new DNS records, publish the returned value, and verify again.

curl --fail-with-body --silent --show-error \
  -X PATCH \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "inbound_enabled": true,
    "tracking": {
      "open_tracking": false,
      "click_tracking": true,
      "unsubscribe_tracking": true
    }
  }' \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID"

Expected status: 200. A non-owner cannot mutate a shared domain (403, code 10008).

Delete a domain

DELETE /v2/email_domains/{id}

Parameter Type Required Description
id UUID path parameter Yes Domain to delete.
force boolean query parameter For verified domains Must be true to delete a verified domain.
# For a pending or unverified custom domain:
curl --fail-with-body --silent --show-error \
  -X DELETE \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID"

# For a verified custom domain, explicitly confirm deletion:
curl --fail-with-body --silent --show-error --get \
  -X DELETE \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  --data-urlencode "force=true" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID"

Expected status: 200 with the deleted domain in .data. A non-owner cannot delete a shared domain.

Webhooks

Webhooks are configured at the domain level through POST /v2/email_domains/{domain_id}/webhooks, not per message. A subscription contains a delivery URL and a non-empty explicit event allowlist.

Verify and process webhook deliveries

Telnyx signs webhook deliveries with Ed25519 and sends the telnyx-signature-ed25519 and telnyx-timestamp headers. Follow this order for every delivery:

  1. Read and retain the request's raw body bytes. Do not parse JSON first; changing whitespace or serialization before verification invalidates the signed body.
  2. Read telnyx-timestamp and reject requests outside a 5-minute timestamp tolerance to limit replay attacks.
  3. Verify telnyx-signature-ed25519 against the timestamp and raw body with your Telnyx Ed25519 public key. Use the official Telnyx verifier for your runtime where available. Reject the request before parsing or processing if signature verification fails.
  4. Parse the verified body, extract its event ID, and atomically record that ID. If the event ID was already processed, return a success response without repeating side effects.
  5. Persist or enqueue work, then return a 2xx response within 10 seconds. Keep slow downstream processing outside the request path.

Telnyx retries on timeout or non-2xx. Keep your endpoint idempotent.

Webhook events

The current OpenAPI EmailWebhookEvent enum contains these exact subscribable event types:

Category Event types
Outbound lifecycle email.scheduled, email.sandbox, email.queued, email.sending, email.sent, email.delivered, email.deferred, email.bounced, email.failed
Engagement email.complained, email.opened, email.clicked, email.unsubscribed
Inbound email.received
Domain lifecycle email_domain.created, email_domain.verified, email_domain.degraded, email_domain.suspended, email_domain.deleted

Use exact case and punctuation. The create request requires at least one event; there is no implicit all-events subscription. PATCH replaces the event list, so include the complete desired allowlist.

List webhooks

GET /v2/email_domains/{domain_id}/webhooks

Query parameter Type Required Description
domain_id UUID path parameter Yes Parent domain.
page[number] integer No Offset page number; defaults to 1.
page[size] integer No Page size from 1 to 100; defaults to 25.
sort enum No created_at or -created_at.
curl --fail-with-body --silent --show-error --get \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  --data-urlencode "page[number]=1" \
  --data-urlencode "page[size]=25" \
  --data-urlencode "sort=-created_at" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/webhooks"

Expected status: 200 with .data[] and .meta. Webhook lists use offset pagination only.

Create a webhook

POST /v2/email_domains/{domain_id}/webhooks

Parameter Type Required Description
domain_id UUID path parameter Yes Parent domain.
url URI string Yes Webhook delivery destination.
events array of EmailWebhookEvent Yes Non-empty exact event allowlist.
curl --fail-with-body --silent --show-error \
  -X POST \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/webhooks/email",
    "events": [
      "email.queued",
      "email.sent",
      "email.delivered",
      "email.bounced",
      "email.failed",
      "email.received",
      "email_domain.verified"
    ]
  }' \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/webhooks"

Expected status: 201. Save .data.id as EMAIL_WEBHOOK_ID.

Retrieve a webhook

GET /v2/email_domains/{domain_id}/webhooks/{id}

Parameter Type Required Description
domain_id UUID path parameter Yes Parent domain.
id UUID path parameter Yes Webhook to retrieve.
curl --fail-with-body --silent --show-error \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/webhooks/$EMAIL_WEBHOOK_ID"

Expected status: 200. Confirm .data.domain_id matches the domain in the path.

Update a webhook

PATCH /v2/email_domains/{domain_id}/webhooks/{id}

Parameter Type Required Description
domain_id UUID path parameter Yes Parent domain.
id UUID path parameter Yes Webhook to update.
url URI string No New delivery destination.
events array of EmailWebhookEvent No Replacement non-empty event allowlist.

The request may update url, events, or both. domain_id is bound at creation and cannot be changed.

curl --fail-with-body --silent --show-error \
  -X PATCH \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "events": [
      "email.sent",
      "email.delivered",
      "email.bounced",
      "email.complained",
      "email.opened",
      "email.clicked",
      "email.unsubscribed"
    ]
  }' \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/webhooks/$EMAIL_WEBHOOK_ID"

Expected status: 200. Verify the returned .data.events contains the complete desired allowlist.

Delete a webhook

DELETE /v2/email_domains/{domain_id}/webhooks/{id}

Parameter Type Required Description
domain_id UUID path parameter Yes Parent domain.
id UUID path parameter Yes Webhook to delete.
curl --fail-with-body --silent --show-error \
  -X DELETE \
  -H "Authorization: Bearer $TELNYX_API_KEY" \
  "$TELNYX_API_BASE/email_domains/$EMAIL_DOMAIN_ID/webhooks/$EMAIL_WEBHOOK_ID"

Expected status: 200 with the deleted webhook in .data, not 204.

Additional Operations

All 13 reachable operations are indexed below. Use the inline core tasks first; for exhaustive optional parameters and response schemas, read references/api-details.md.

# Operation Operation ID Endpoint Required params
1 List domains listEmailDomains GET /v2/email_domains None
2 Create a domain createEmailDomain POST /v2/email_domains domain
3 Retrieve a domain getEmailDomain GET /v2/email_domains/{id} id
4 Update a domain updateEmailDomain PATCH /v2/email_domains/{id} id; include at least one update field
5 Delete a domain deleteEmailDomain DELETE /v2/email_domains/{id} id; force=true for a verified domain
6 Get domain health getEmailDomainHealth GET /v2/email_domains/{id}/health id
7 List generated DNS records listEmailDomainDnsRecords GET /v2/email_domains/{domain_id}/dns_records domain_id
8 Verify current DNS verifyEmailDomainDnsRecords POST /v2/email_domains/{domain_id}/verify domain_id
9 List domain webhooks listEmailDomainWebhooks GET /v2/email_domains/{domain_id}/webhooks domain_id
10 Create a domain webhook createEmailDomainWebhook POST /v2/email_domains/{domain_id}/webhooks domain_id, url, events
11 Retrieve a domain webhook getEmailDomainWebhook GET /v2/email_domains/{domain_id}/webhooks/{id} domain_id, id
12 Update a domain webhook updateEmailDomainWebhook PATCH /v2/email_domains/{domain_id}/webhooks/{id} domain_id, id; include url, events, or both
13 Delete a domain webhook deleteEmailDomainWebhook DELETE /v2/email_domains/{domain_id}/webhooks/{id} domain_id, id

Before using lower-frequency optional parameters or branching on response fields, read the list-query section, the request schemas, and the response schemas.