Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Manage email sending domains, verify DNS records (SPF, DKIM, DMARC, MX), check domain health, and configure domain-level webhooks for delivery events.
SkillScore100/100
Test results 100
3/3 safety checks passed
36%100%of test cases passed +64 pts
Passed 22 of 22 test cases with the skill, and 8 of 22 without it.
14 fixed8 passed either way0 still failing0 broke
One test taskI created a custom domain in Telnyx (ID: 333e4444-e89b-12d3-a456-426614174000) by mistake. It is still in unverified status. What curl command should I run to delete it? Do I need force=true?
Adds every file the skill has, pinned so you can update it. No account needed.
pip install "decimalai>=0.15"
decimalai skills add team-telnyx-telnyx-email-domains-curl
claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"The same install from Python, for a notebook or a setup script.
pip install "decimalai>=0.15"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
print("Added. Start Claude Code with the command below.")claude --plugin-dir "$(git rev-parse --show-toplevel 2>/dev/null || pwd)/.agents"Type these in a Claude Code session. No account or API key. It writes the skill and any files it bundles, and asks first when its safety rating isn't Passed.
/plugin marketplace add decimal-labs/decimalai-claude-plugins
/plugin install decimalai@decimalai/decimalai:install team-telnyx-telnyx-email-domains-curlThe plugin needs python3 and curl on your machine.
No Python or account. Claude Code picks it up in its next session.
curl -fsSL --create-dirs -o .claude/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md https://app.decimal.ai/s/team-telnyx-telnyx-email-domains-curl/SKILL.md.claude/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"
decimalai skills add team-telnyx-telnyx-email-domains-curlimport asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[claude-agent-sdk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from claude_agent_sdk import ClaudeAgentOptions
from decimalai.claude_agent_sdk import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
async def main():
question = "Hello!"
async with support.run(question) as run: # one user message, one run
async for message in run.query(options=ClaudeAgentOptions(max_turns=6)):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())Prefer its own loader? ClaudeAgentOptions(plugins=[skills_plugin()], skills="all") reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdimport asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
options = ClaudeAgentOptions(system_prompt=f"You are a helpful agent.\n\n{skill}", max_turns=6)
async def main():
async for message in query(prompt="Hello!", options=options):
print(message)
# In a notebook or async code: await main()
asyncio.run(main())This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai-agents]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from agents import Agent, Runner
from decimalai.openai_agents import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
name=support.name,
instructions=support.instructions, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")Using SandboxAgent? capabilities=[Shell(), decimalai.openai_agents.sandbox_skills()] points its own loader at the same folder.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from agents import Agent, Runner
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = Agent(name="support", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await Runner.run(agent, "Hello!")
result = Runner.run_sync(agent, "Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"
decimalai skills add team-telnyx-telnyx-email-domains-curlimport json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[openai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import json
from openai import OpenAI
from decimalai.openai import agent_config
client = OpenAI()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your tools, as Chat Completions takes them, and what answers each.
TOOLS = [{"type": "function", "function": {
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
# run.system is your prompt, then the skill list.
messages = [{"role": "system", "content": run.system}, run.message]
while True:
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=messages,
tools=[*TOOLS, *run.tools], # your tools, then load_skill
).choices[0].message
messages.append(reply)
if not reply.tool_calls:
break
for call in reply.tool_calls:
# load_skill is answered by the run; your own tools by FUNCTIONS.
function = FUNCTIONS.get(call.function.name)
messages.append(run.tool_result(call) or {
"role": "tool", "tool_call_id": call.id,
"content": function(**json.loads(call.function.arguments)) if function
else f"There is no tool named {call.function.name!r}.",
})
print(reply.content)
# The Responses API takes run.response_tools instead of run.tools.No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from openai import OpenAI
client = OpenAI()
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
reply = client.chat.completions.create(
model="gpt-5.4-mini",
messages=[
{"role": "system", "content": f"You are a helpful agent.\n\n{skill}"},
{"role": "user", "content": "Hello!"},
],
).choices[0].messageThis gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"
decimalai skills add team-telnyx-telnyx-email-domains-curlimport anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[anthropic]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import anthropic
from decimalai.anthropic import agent_config
client = anthropic.Anthropic()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
question = "Hello!"
with support.run(question) as run: # one user message, one run
answer = client.beta.messages.tool_runner(
model="claude-haiku-5-5",
max_tokens=4096,
system=run.system, # your prompt, then the skill list
tools=[*run.tools], # your tools, then load_skill
messages=[{"role": "user", "content": question}],
).until_done()No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
import anthropic
client = anthropic.Anthropic()
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
reply = client.messages.create(
model="claude-haiku-5-5",
max_tokens=4096,
system=f"You are a helpful agent.\n\n{skill}",
messages=[{"role": "user", "content": "Hello!"}],
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[google-genai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from google import genai
from google.genai import types
from decimalai.google_genai import agent_config
client = genai.Client()
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
def lookup_order(order_id: str) -> str:
return f"Order {order_id} shipped yesterday."
# Your functions, as declarations for the model, and what answers each.
TOOLS = [{"function_declarations": [{
"name": "lookup_order",
"description": "Look up the status of an order.",
"parameters_json_schema": {"type": "object", "properties": {"order_id": {"type": "string"}},
"required": ["order_id"]},
}]}]
FUNCTIONS = {"lookup_order": lookup_order}
question = "Where is order A1001?"
with support.run(question) as run: # one user message, one run
config = types.GenerateContentConfig(
system_instruction=run.system, # your prompt, then the skill list
tools=[*TOOLS, *run.tool_params], # your functions, then load_skill
)
contents = [{"role": "user", "parts": [{"text": run.message}]}]
while True:
response = client.models.generate_content(
model="gemini-3.5-flash", contents=contents, config=config,
)
if not response.function_calls:
break
contents.append(response.candidates[0].content)
parts = []
for call in response.function_calls:
# load_skill is answered by the run; your own functions by FUNCTIONS.
# A loop of your own rather than automatic function calling, which
# raises KeyError when the model asks for a function you did not pass.
function = FUNCTIONS.get(call.name)
parts.append(run.tool_result(call) or {"function_response": {
"name": call.name, "id": call.id,
"response": {"result": function(**(call.args or {})) if function
else f"There is no function named {call.name!r}."},
}})
contents.append({"role": "user", "parts": parts})
print(response.text)No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from google import genai
from google.genai import types
client = genai.Client()
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
response = client.models.generate_content(
model="gemini-3.5-flash",
contents="Hello!",
config=types.GenerateContentConfig(system_instruction=f"You are a helpful agent.\n\n{skill}"),
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openai
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[langchain]" langchain-openaifrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from langchain.agents import create_agent
from decimalai.langchain import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = create_agent(
"openai:gpt-5.4-mini",
tools=[], # your tools; the middleware adds load_skill
middleware=[support.middleware], # your prompt, the skill list and load_skill
)
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from langchain.agents import create_agent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = create_agent("openai:gpt-5.4-mini", tools=[], system_prompt=f"You are a helpful agent.\n\n{skill}")
result = agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"
decimalai skills add team-telnyx-telnyx-email-domains-curlimport decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()The same install from Python, for a notebook or a setup script. CrewAI's own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" "crewai>=1.15.27"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.crewai
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=decimalai.crewai.skills(), # the installed folder
tools=decimalai.crewai.skill_tools(), # reads a skill's files, runs its scripts
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()No DecimalAI package. CrewAI's own loader reads the folder, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from crewai import Agent, Crew, Task
agent = Agent(
role="Support", goal="Help the customer", backstory="A support agent.",
llm=llm, # your own CrewAI LLM
skills=[Path(".agents/skills")],
)
task = Task(description="Hello!", expected_output="an answer", agent=agent)
Crew(agents=[agent], tasks=[task]).kickoff()This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[adk]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.adk import DecimalAIPlugin, agent_config
from google.adk.agents import LlmAgent
from google.adk.apps import App
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = LlmAgent(
name="support", # ADK needs a Python identifier
model="gemini-3.5-flash",
instruction=support.instruction, # your prompt, then the skill list
tools=[*support.tools], # your tools, then load_skill
)
# DecimalAIPlugin makes each invocation of runners built from this App one trace.
app = App(name="support", root_agent=agent, plugins=[DecimalAIPlugin()])Prefer ADK's own loader? SkillToolset(skills=decimalai.adk.skills(), ...) reads the same folder. Use one or the other: a skill delivered both ways reaches the prompt twice.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from google.adk.agents import LlmAgent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = LlmAgent(
name="support",
model="gemini-3.5-flash",
instruction=lambda context: f"You are a helpful agent.\n\n{skill}",
)This gets SKILL.md only. The skill's 1 other file is not included.
agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
The same install from Python, for a notebook or a setup script. agent_config() hands your agent the skill. With no DecimalAI key it reads your project's files and sends nothing. Needs SDK 0.27 or newer.
pip install "decimalai[pydantic-ai]"from decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from pydantic_ai import Agent
from decimalai.pydantic_ai import agent_config
# With no DECIMAL_API_KEY this reads the skills your project lists, from disk.
support = agent_config("support", fallback="You are a helpful agent.")
agent = Agent(
"openai:gpt-4o-mini",
name=support.name,
tools=[], # your tools; the capability adds load_skill
capabilities=[support], # your prompt, the skill list and load_skill
)
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")On the Pydantic AI harness, decimalai.pydantic_ai_harness.skills(project) uses its own loader instead.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from pydantic_ai import Agent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = Agent("openai:gpt-4o-mini", instructions=f"You are a helpful agent.\n\n{skill}")
# In a notebook or async code: result = await agent.run("Hello!")
result = agent.run_sync("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagents
decimalai skills add team-telnyx-telnyx-email-domains-curlimport decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
The same install from Python, for a notebook or a setup script. Deep Agents' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" deepagentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import decimalai.deepagents
from deepagents import create_deep_agent
agent = create_deep_agent(model=model, **decimalai.deepagents.skills())
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})The default backend reads files but has no shell. To run a skill's scripts, pass skills(backend=LocalShellBackend(...)).
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from deepagents import create_deep_agent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = create_deep_agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent.invoke({"messages": [{"role": "user", "content": "Hello!"}]})This gets SKILL.md only. The skill's 1 other file is not included.
Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-framework
decimalai skills add team-telnyx-telnyx-email-domains-curlimport asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
The same install from Python, for a notebook or a setup script. Its own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" agent-frameworkfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
import asyncio
from agent_framework import Agent
from decimalai.agent_framework import skills
agent = Agent(client=client, instructions="You are a helpful agent.", context_providers=[skills()])
asyncio.run(agent.run("Hello!"))It caches skills by default, so restart the process after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdimport asyncio
from pathlib import Path
from agent_framework import Agent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = Agent(client=client, instructions=f"You are a helpful agent.\n\n{skill}")
asyncio.run(agent.run("Hello!"))This gets SKILL.md only. The skill's 1 other file is not included.
Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agents
decimalai skills add team-telnyx-telnyx-email-domains-curlfrom decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
The same install from Python, for a notebook or a setup script. Strands' own skill loader reads the installed folder. No DecimalAI account needed.
pip install "decimalai>=0.16" strands-agentsfrom decimalai import skillpkg
# Writes .agents/skills and .decimal/skills.toml. Safe to run twice.
result = skillpkg.add("team-telnyx-telnyx-email-domains-curl")
if result.exit_code:
raise SystemExit(result.problems)
from decimalai.strands import skills
from strands import Agent
from strands.vended_tools import file_editor, shell
agent = Agent(
model=model, # always pass one: the default is Amazon Bedrock
system_prompt="You are a helpful agent.",
tools=[file_editor, shell],
plugins=[skills()],
)
agent("Hello!")Strands loads an agent's skills once, so build the agent again after decimalai skills update.
No DecimalAI package. The whole skill goes in every prompt, and nothing pins or updates it.
.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdfrom pathlib import Path
from strands import Agent
skill = Path(".agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md").read_text()
agent = Agent(model=model, system_prompt=f"You are a helpful agent.\n\n{skill}")
agent("Hello!")This gets SKILL.md only. The skill's 1 other file is not included.
Adds every file the skill has, pinned so you can update it. Cursor, Copilot, Cline and Warp read this folder by themselves.
pip install "decimalai>=0.15"
decimalai skills add team-telnyx-telnyx-email-domains-curlNo Python or account. Cursor, Copilot, Cline and Warp read this folder by themselves.
curl -fsSL --create-dirs -o .agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.md https://app.decimal.ai/s/team-telnyx-telnyx-email-domains-curl/SKILL.md.agents/skills/team-telnyx-telnyx-email-domains-curl/SKILL.mdThis gets SKILL.md only. The skill's 1 other file is not included.
Give its text to your model as instructions. No account or package needed.
This gets SKILL.md only. The skill's 1 other file is not included.
Raw files: /s/team-telnyx-telnyx-email-domains-curl/SKILL.md · /s/team-telnyx-telnyx-email-domains-curl.json
Fetch the file and give its text to your model as instructions. No account or package needed.
curl -fsSL https://app.decimal.ai/s/team-telnyx-telnyx-email-domains-curl/SKILL.mdcurl -fsSL https://app.decimal.ai/s/team-telnyx-telnyx-email-domains-curl.jsonThis gets SKILL.md only. The skill's 1 other file is not included.
You don't need a DecimalAI account.
Saved prompts and skills, pinned versions, and traces of this skill in your runs. DecimalAI does not run your agent.
Claude Code reads files from your project, so DecimalAI config does not apply there.
On Claude Agent SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI Agents: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On OpenAI SDK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Anthropic: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Gemini API: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On LangChain: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On CrewAI: set DECIMAL_API_KEY and add decimalai.init(crewai=True) to record runs and skill use. The skill version stays in your repo.
On Google ADK: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Pydantic AI: save the skill to an agent here, set DECIMAL_API_KEY, and the same code uses it with no command to run. Changes you save reach the next run with no redeploy.
On Deep Agents: set DECIMAL_API_KEY and add decimalai.init(langchain=True) to record runs and skill use. The skill version stays in your repo.
On Microsoft Agent Framework: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
On Strands: set DECIMAL_API_KEY and add decimalai.init(otel=True, agent_name="support") to record runs and skill use. The skill version stays in your repo.
Editors read files from your project, so DecimalAI config does not apply there.
Anywhere else: record a use with decimalai.log_skill_activation() inside a trace.
# curl is pre-installed on macOS, Linux, and Windows 10+.
# A JSON formatter such as `python3 -m json.tool` is optional.
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 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.
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.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.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.POST /v2/email_domains/{domain_id}/webhooks, not per message.403 with code 10008.open_tracking, click_tracking,
and unsubscribe_tracking default to false, false, and true,
respectively. A send may override these defaults without changing the domain.force=true to delete a verified
custom domain. Delete returns 200 with the deleted domain, not 204..meta shape.Do not invent request fields, DNS values, event names, response fields, or status enums.
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:[email protected]"
},
"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.
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.
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.
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.
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.
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.
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 /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 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.
Telnyx signs webhook deliveries with Ed25519 and sends the
telnyx-signature-ed25519 and telnyx-timestamp headers. Follow this order for
every delivery:
telnyx-timestamp and reject requests outside a 5-minute timestamp
tolerance to limit replay attacks.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.2xx response within 10 seconds. Keep
slow downstream processing outside the request path.Telnyx retries on timeout or non-2xx. Keep your endpoint idempotent.
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.
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.
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.
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.
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 /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.
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.
Published skills whose descriptions closely match this one, with their headline benchmark lift.
Skills that do similar work, with their headline benchmark lift.
From the same source and nearby in the catalogue.