Telnyx Email Domains Curl logo

Telnyx Email Domains Curl

Organization
team-telnyx
telnyx-email-domains-curl

Manage email sending domains, verify DNS records (SPF, DKIM, DMARC, MX), check domain health, and configure domain-level webhooks for delivery events.

Overview

Publisherteam-telnyx
Repositoryai
Skill nametelnyx-email-domains-curl
Stars
217
Forks
21
Bundled files
1
LicenseMIT
Links
  • Markdown instructions

    A SKILL.md file the model loads on demand, so it only costs tokens when a request actually matches.

  • Works with any LLM

    AI skills are plain Markdown, not provider-specific code, so this works with GPT, Claude, Gemini, Grok, or a local model.

  • 1 bundled files

    Scripts, templates, and references the model can read while it works. Files are read-only and never executed.

  • Open source

    Published by team-telnyx on GitHub. Read the source before you install it.

Installation

Install the Telnyx Email Domains Curl AI skill in TypingMind to use it with any LLM, or drop it into another agent that reads SKILL.md.

1

Install in TypingMind

TypingMind installs a skill straight from its GitHub folder — it reads SKILL.md, bundles the resource files, and stores the result locally.

  1. Open the app and go to Plugins → Skills.
  2. Choose "Install from GitHub".
  3. Paste the skill folder URL below and confirm.
  4. Enable the skill in any chat where you want it available.
Plugins → Skills → Add skill → From GitHub URL, then paste the folder URL and press Continue.
2

Install in another agent

Any agent that reads the Agent Skills format can use this skill — copy the folder into that agent's skills directory.

Claude Code — .claude/skills
git clone --depth 1 https://github.com/team-telnyx/ai.git /tmp/ai
mkdir -p .claude/skills
cp -r /tmp/ai/providers/claude/plugins/telnyx-email/skills/telnyx-email-domains-curl .claude/skills/telnyx-email-domains-curl
Restart Claude Code after copying so it picks up the new skill.

Use it in TypingMind

Enable Telnyx Email Domains Curl in any TypingMind chat and the model takes it from there. Its name and description sit in the system prompt, and the moment a request matches, the model loads the full instructions itself — you never invoke it by hand, and it costs no tokens until it is actually used.

The model loads Telnyx Email Domains Curl on its own as soon as a request matches it.

Works with any AI model

AI skills are plain Markdown instructions rather than provider-specific code, so Telnyx Email Domains Curl is not tied to the model it was written for. Install it once in TypingMind and use it with GPT-5, Claude, Gemini, Grok, DeepSeek, Mistral, Llama, or a local model you run yourself — all on your own API keys.

  • Loaded only when it is needed

    The system prompt carries just the name and description. The instructions are fetched on the first matching request, so an idle skill costs nothing.

  • Switch models mid-chat

    Because the skill is instructions rather than code, changing model does not break it — the next model reads the same SKILL.md.

Skill instructions

This is the SKILL.md content the model loads. Read it before installing — a skill is instructions your model will follow.

Telnyx Email Domains — curl

Installation

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

Setup

bash
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:

bash
-H "Authorization: Bearer $TELNYX_API_KEY"

Mutation requests with JSON also require:

bash
-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:

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

Common cases:

HTTPMeaningAction
400Invalid list query or malformed inputFix the query; do not retry unchanged.
401Missing or invalid API keyFix authentication.
403Shared domain is read-only (10008) or access is insufficientUse an owned custom domain or correct permissions.
404Domain or webhook not found (10001)Re-list resources and verify both IDs.
422Request validation or state transition failed (10015 and related codes)Inspect every error and source.pointer; correct the request or state.
429Rate limitHonor Retry-After when present and back off.
500Unexpected service errorRetry 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

ParameterTypeRequiredDescription
domainstringYesCustom domain name, for example example.com.
inbound_enabledbooleanNoEnable inbound routing; defaults to false.
dmarc_policyobject | nullNoAdvisory DMARC policy (p, pct, rua, sp).
trackingobjectNoDomain defaults for open, click, and unsubscribe tracking.
bash
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

ParameterTypeRequiredDescription
domain_idUUID path parameterYesDomain ID returned by the API.
bash
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

ParameterTypeRequiredDescription
domain_idUUID path parameterYesDomain whose current DNS records should be checked.
Request bodyNoThis operation has no request body.
bash
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

ParameterTypeRequiredDescription
idUUID path parameterYesDomain whose aggregate readiness should be checked.
bash
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 parameterTypeRequiredDescription
page[number]integerNoOffset page number.
page[size]integerNoPage size from 1 to 100.
sortenumNocreated_at, -created_at, domain, or -domain.
filter[type]enumNocustom, shared, or shared_inbound.
filter[usable_for_sending]booleanNoLimit results by sending readiness.
...See all list query parameters.
bash
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}

ParameterTypeRequiredDescription
idUUID path parameterYesDomain to retrieve.
bash
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}

ParameterTypeRequiredDescription
idUUID path parameterYesDomain to update.
inbound_enabledbooleanNoEnable or disable inbound routing.
dmarc_policyobject | nullNoChange the advisory DMARC policy.
trackingobjectNoChange 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.

bash
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}

ParameterTypeRequiredDescription
idUUID path parameterYesDomain to delete.
forceboolean query parameterFor verified domainsMust be true to delete a verified domain.
bash
# 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:

CategoryEvent types
Outbound lifecycleemail.scheduled, email.sandbox, email.queued, email.sending, email.sent, email.delivered, email.deferred, email.bounced, email.failed
Engagementemail.complained, email.opened, email.clicked, email.unsubscribed
Inboundemail.received
Domain lifecycleemail_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 parameterTypeRequiredDescription
domain_idUUID path parameterYesParent domain.
page[number]integerNoOffset page number; defaults to 1.
page[size]integerNoPage size from 1 to 100; defaults to 25.
sortenumNocreated_at or -created_at.
bash
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

ParameterTypeRequiredDescription
domain_idUUID path parameterYesParent domain.
urlURI stringYesWebhook delivery destination.
eventsarray of EmailWebhookEventYesNon-empty exact event allowlist.
bash
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}

ParameterTypeRequiredDescription
domain_idUUID path parameterYesParent domain.
idUUID path parameterYesWebhook to retrieve.
bash
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}

ParameterTypeRequiredDescription
domain_idUUID path parameterYesParent domain.
idUUID path parameterYesWebhook to update.
urlURI stringNoNew delivery destination.
eventsarray of EmailWebhookEventNoReplacement non-empty event allowlist.

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

bash
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}

ParameterTypeRequiredDescription
domain_idUUID path parameterYesParent domain.
idUUID path parameterYesWebhook to delete.
bash
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.

#OperationOperation IDEndpointRequired params
1List domainslistEmailDomainsGET /v2/email_domainsNone
2Create a domaincreateEmailDomainPOST /v2/email_domainsdomain
3Retrieve a domaingetEmailDomainGET /v2/email_domains/{id}id
4Update a domainupdateEmailDomainPATCH /v2/email_domains/{id}id; include at least one update field
5Delete a domaindeleteEmailDomainDELETE /v2/email_domains/{id}id; force=true for a verified domain
6Get domain healthgetEmailDomainHealthGET /v2/email_domains/{id}/healthid
7List generated DNS recordslistEmailDomainDnsRecordsGET /v2/email_domains/{domain_id}/dns_recordsdomain_id
8Verify current DNSverifyEmailDomainDnsRecordsPOST /v2/email_domains/{domain_id}/verifydomain_id
9List domain webhookslistEmailDomainWebhooksGET /v2/email_domains/{domain_id}/webhooksdomain_id
10Create a domain webhookcreateEmailDomainWebhookPOST /v2/email_domains/{domain_id}/webhooksdomain_id, url, events
11Retrieve a domain webhookgetEmailDomainWebhookGET /v2/email_domains/{domain_id}/webhooks/{id}domain_id, id
12Update a domain webhookupdateEmailDomainWebhookPATCH /v2/email_domains/{domain_id}/webhooks/{id}domain_id, id; include url, events, or both
13Delete a domain webhookdeleteEmailDomainWebhookDELETE /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.

Bundled files

The model reads these on demand while the skill is loaded. They are exposed as readable files and are never executed.

Frequently asked questions

What does the Telnyx Email Domains Curl AI skill do?

Manage email sending domains, verify DNS records (SPF, DKIM, DMARC, MX), check domain health, and configure domain-level webhooks for delivery events.

Why use Telnyx Email Domains Curl on TypingMind?

Because you install it once and use it with any model. Telnyx Email Domains Curl is plain Markdown rather than provider-specific code, so the same skill runs on GPT-5, Claude, Gemini, Grok, or a local model — and you can switch model mid-chat without it breaking. TypingMind runs on your own API keys, so you pay providers directly instead of a per-seat subscription, and your skills and chats stay in your own storage.

How do I install Telnyx Email Domains Curl in TypingMind?

Open Plugins → Skills → Install from GitHub in TypingMind and paste https://github.com/team-telnyx/ai/tree/main/providers/claude/plugins/telnyx-email/skills/telnyx-email-domains-curl. TypingMind reads its SKILL.md and bundles its files and installs it as a skill you can enable per chat.

Which AI models can use Telnyx Email Domains Curl?

Any model you connect in TypingMind. AI skills are plain Markdown instructions rather than provider-specific code, so GPT, Claude, Gemini, Grok, and local models can all load this skill when a request matches it.

How many AI models can I use with Telnyx Email Domains Curl?

As many as you like. As long as a model supports skills, you can use Telnyx Email Domains Curl with it — GPT, Claude, Gemini, Grok, DeepSeek, Mistral, Llama and more — all on TypingMind with your own API keys.

Is the Telnyx Email Domains Curl AI skill free?

Yes. It is published on GitHub by team-telnyx under the MIT license. You only pay your own AI provider for the tokens you use.

What are AI skills?

An AI skill is a reusable instruction bundle that teaches an AI model how to do one specific task. It follows the open Agent Skills format: a SKILL.md file with a name and description, plus any scripts, templates or reference files the model may need. The model reads the instructions only when your request matches the skill, so an installed skill costs nothing until it is used.

How are AI skills different from plugins or MCP servers?

A plugin or MCP server gives a model new tools to call — code that runs somewhere and returns a result. An AI skill gives the model knowledge and process instead: how to approach a task, which steps to follow, what good output looks like. Skills are plain Markdown, so they need no server, no API key and no runtime, and they work with any model.

View all

Set up your own AI workspace now

Get notified about new features and future giveaways by subscribing to our newsletter 👇