# Telnyx Fundamentals: Development — Full Documentation > Complete page content for Development (Fundamentals section) of the Telnyx developer docs (https://developers.telnyx.com). > This file: https://developers.telnyx.com/docs/development/llms-txt-full · Root index: https://developers.telnyx.com/llms.txt ### Overview > Source: https://developers.telnyx.com/docs/development.md ## Build with confidence From authentication utilities to multi-platform SDKs, this section mirrors the hands-on developer resources from our classic docs so you can build, test, and ship with Telnyx even faster. ## What you’ll find here Learn how to create and secure API keys, handle webhooks, and stay within rate limits across every Telnyx service. Dig into API fundamentals → Official SDKs for Node.js, Python, PHP, Java, Ruby, and Go to simplify backend integrations and speed up prototyping. Browse SDKs → Build voice and video experiences with JavaScript, React, iOS, and Android SDKs plus detailed class references. Explore WebRTC → Troubleshoot with call detail records, WebRTC debugging steps, and logging best practices. Start debugging → Step-by-step playbooks for migrating messaging, Call Control, and Twilio workloads onto Telnyx. Plan your migration → ## Working on AI agents? Spin up local or remote MCP servers so your AI assistants can query Telnyx APIs securely—check out the [MCP quickstarts](/docs/development/mcp/local-mcp). ## Need product-specific guides? Looking for AI, Voice, or Messaging docs? Explore our product tabs above. --- ## Account setup ### Create Account > Source: https://developers.telnyx.com/docs/account-setup/create-account.md Before you can start using any Telnyx services, you'll need to create an account to access our APIs and Mission Control Portal. ## Account creation steps Navigate to [telnyx.com/sign-up](https://telnyx.com/sign-up) to start the signup process. Enter your contact information, company details, and a secure password. This ensures Telnyx can verify who you are. Look for the confirmation email and click the verification link so we know you're the owner of the address you used. Access the [Mission Control Portal](https://portal.telnyx.com) with your new credentials to finish onboarding and explore your dashboard. New accounts come with free testing credits so you can explore the platform before adding payment methods. ## Need help? If you encounter any issues during account creation: - Review the [Account Setup FAQ](https://support.telnyx.com) - Contact our support team through the Mission Control Portal - Join the [Telnyx Slack community](https://joinslack.telnyx.com) for developer support --- ### Account Signup > Source: https://developers.telnyx.com/docs/account-setup/signup.md Every signup attempt is subjected to a battery of trust and safety checks. Among them, in no particular order, are the following: - Domain age - Domain reputation - Host reputation - IP reputation - Signup origin - reCAPTCHA verification An attempt will be unsuccessful if **any** of the above fails. Some attempts may also be subjected to additional requirements, including: - Successfully validating a legitimate mobile number - Successfully passing Know Your Customer (KYC) documentation verification Telnyx constantly adjusts the logic, sequence, and thresholds to combat signup abuse and fraudulent usage of the platform. --- ### Account Levels Overview > Source: https://developers.telnyx.com/docs/account-setup/levels-and-capabilities.md A successful signup may be placed in one of the following frameworks (**but never both**): - Level 1 / Level 2 account framework - Pretrial-Trial-Paid-Verified-Enterprise (PTPVE) framework An account is in the Level 1 / Level 2 framework when the [verification page](https://portal.telnyx.com/#/account/my-account/verifications) exists in the user's Mission Control Portal account. The remainder of this account setup section is only relevant to an account in the PTPVE framework. An account is in the PTPVE framework when the [Account Levels page](https://portal.telnyx.com/#/account/account-levels) exists in the user’s Mission Control Portal account. The level of an account is an organizational attribute. If the account is a paid account, all organization members have the privileges and limits of a paid account. For a holistic understanding of privileges and limits at each account level, consult the corresponding pages in this section, together with the following tables: - V2 APIs - S3 Compatible Storage APIs --- ### Pretrial Account > Source: https://developers.telnyx.com/docs/account-setup/levels-and-capabilities/pretrial.md ## Testing credit **USD $25** in AI credits is provided. ## Access - Full access to AI Suite (AI Assistant, Inference, Cloud Storage) except otherwise specified below. - Telnyx reserves the right to modify limitations without notification. ## Numbers ### Number searching - Full number display limited to **USA local numbers** only. - All other numbers will be shown redacted (e.g., +49351xxxxxxx). - No access to other APIs or features in this category. ### Number reservation - No access to APIs or features in this category. ### Number ordering - Limited to **1 USA local number** per **pretrial account lifetime**. - No access to global numbers. - No port out is allowed on this number. - This number will be reclaimed within 30 days of purchase if the account has not upgraded. - No access to other APIs or features in this category. ### Number porting - No access to APIs or features in this category. ### Bundles - No access to APIs or features in this category. ## Messaging - Limited to **1 messaging profile** at any one time. - **Outbound:** Limited to long code sending, destination limited to verified number, and capped at **10 messages a day**. - **Inbound:** Limited to receiving from the verified number. - No access to other APIs or features in this category. ## Verify - No access to APIs or features in this category. ## Voice ### General limits - Limited to **1 TeXML Application** at any one time. - Limited to **1 outbound voice profile** at any one time. - **Outbound** limited to dialing only the verified phone number. - **Inbound** limited to receiving from the verified phone number. - Limited to **2 concurrent outbound calls**. - Limited to a maximum of **10 minutes per call**. ### Programmable Voice - All machine-generated voices are prepended with: "_This is an automated call generated on the Telnyx platform, please report any abuse to fraud@telnyx.com_". - This applies to: - `/v2/calls` - `/v2/calls/:call_control_id/actions/transfer` - `/v2/calls/:call_control_id/actions/gather_using_audio` - `/v2/calls/:call_control_id/actions/gather_using_speak` - `/v2/calls/:call_control_id/actions/playback_start` - `/v2/calls/:call_control_id/actions/speak` - `/v2/calls/:call_control_id/actions/gather_using_ai` - `/v2/calls/:call_control_id/actions/ai_assistant_start` - TeXML verb `Play` - TeXML verb `Say` - TeXML verb `AIGather` - Limited to a maximum of **10 outbound calls a day**. ### Call Control Applications - No access to APIs or features in this category. ### Microsoft Operator Connect - No access to APIs or features in this category. ### Microsoft Direct Routing - No access to APIs or features in this category. ### Zoom Phone Provider Exchange - No access to APIs or features in this category. ## LRN / Number Lookup - No access to APIs or features in this category. ## Cloud Storage - Limited to non-public policy or ACL on buckets or objects. - Limited to **5 minutes of TTL** on pre-signed URLs. - Limited to the documented free tier of used capacity across all buckets and regions. ## Wireless - No access to APIs or features in this category. ## Account features ### Organizations and sub-users - No access to APIs or features in this category. ### ManagED Accounts - No access to APIs or features in this category. ### Payment methods - No access to APIs or features in this category. Credit is not required — AI credits are provided. ### Billing groups - No access to APIs or features in this category. ### API keys - Limited to **1 API key** at any one time. - No access to other APIs or features in this category. ### DDoS mitigation - No access to APIs or features in this category. --- ### Trial Account > Source: https://developers.telnyx.com/docs/account-setup/levels-and-capabilities/trial.md ## Testing credit **USD $5** in testing credit is provided. ## Access - Full access except otherwise specified below. - Telnyx reserves the right to modify limitations without notification. ## Numbers ### Verified numbers - Limited to **1 verified number** at any one time. - Limited to **10 changes** per **trial account lifetime**. - Limited to **15 delivery attempts** regardless of conversion outcome per **trial account lifetime**. ### Number searching - Full number display limited to **local numbers** of the account's country of origin. - All other numbers will be shown redacted (e.g., +49351xxxxxxx). - No access to other APIs or features in this category. ### Number reservation - No access to APIs or features in this category. ### Number ordering - Limited to **1 local number** of the account's country of origin per **trial account lifetime**. - Successful number activation is subject to inventory availability, sufficient account balance, and local jurisdiction documentation rules. - This number will be reclaimed within 30 days of purchase if the account has not upgraded. - No port out is allowed on this number. - No access to other APIs or features in this category. ### Number porting - Limited to **50 portability check attempts** per **trial account lifetime**. - No access to other APIs or features in this category. - Users do not have proprietary rights to their trial telephone number, and Telnyx reserves the right to make reasonable changes to them with reasonable notice. Users cannot port out their trial number. ### Bundles - No access to APIs or features in this category. ## Messaging - Limited to **1 messaging profile** at any one time. - **Outbound:** Limited to long code sending, destination limited to verified number, and capped at **100 messages a day**. - **Inbound:** Limited to receiving from the verified number. - No access to other APIs or features in this category. ## Verify - Limited to **1 verified profile** at any one time. - Only SMS is allowed. - Destination limited to verified number. - Limited to a max of **50 verifications a day**. - No access to other APIs or features in this category. ## Voice ### General limits - Limited to **1 instance per connection type** at any one time. - Limited to **1 outbound voice profile** at any one time. - **Outbound** limited to dialing only the verified phone number. - **Inbound** limited to receiving from the verified phone number. - Limited to **2 concurrent outbound calls** across all connection instances. - Limited to a maximum of **10 minutes per call**. ### Programmable Voice - All machine-generated voices are prepended with: “_This is an automated call generated on the Telnyx platform, please report any abuse to fraud@telnyx.com_”. - This applies to: - `/v2/calls` - `/v2/calls/:call_control_id/actions/transfer` - `/v2/calls/:call_control_id/actions/gather_using_audio` - `/v2/calls/:call_control_id/actions/gather_using_speak` - `/v2/calls/:call_control_id/actions/playback_start` - `/v2/calls/:call_control_id/actions/speak` - `/v2/calls/:call_control_id/actions/gather_using_ai` - `/v2/calls/:call_control_id/actions/ai_assistant_start` - TeXML verb `Play` - TeXML verb `Say` - TeXML verb `AIGather` - Limited to a maximum of **100 outbound calls a day**. - Limited to **10 outbound calls per hour**. ### Microsoft Operator Connect - No access to APIs or features in this category. ### Microsoft Direct Routing - No access to APIs or features in this category. ### Zoom Phone Provider Exchange - No access to APIs or features in this category. ## LRN / Number Lookup - No access to APIs or features in this category. ## Cloud Storage - Limited to non-public policy or ACL on buckets or objects. - Limited to **5 minutes of TTL** on pre-signed URLs. - Limited to the documented free tier of used capacity across all buckets and regions. ## Wireless - No access to physical SIM registration. - No access to eSIM purchase. ## Account features ### Organizations and sub-users - No access to APIs or features in this category. ### ManagED Accounts - No access to APIs or features in this category. ### Payment methods - Limited to credit cards. ### Billing groups - No access to APIs or features in this category. ### API keys - Limited to **1 API key** at any one time. - No access to other APIs or features in this category. ### DDoS mitigation - No access to APIs or features in this category. --- ### Using Your Trial Account > Source: https://developers.telnyx.com/docs/account-setup/using-trial-account.md Follow this process to make the most of your trial credit and stay within trial limitations. A [verified number](https://portal.telnyx.com/#/numbers/verified-numbers) is essential to test Voice and Messaging. Use a mobile phone number that you control. Keep in mind that trial accounts have limits on delivery attempts and the number of changes allowed. Once the allowance is depleted, [upgrade your account](/docs/account-setup/account-upgrade). Search results show only local (to the signup origin) numbers in full +E164; other results appear partially redacted. A successful purchase depends on inventory availability, sufficient account balance, and local jurisdiction [documentation rules](https://portal.telnyx.com/#/numbers/requirements). Only **one** phone number order is allowed during the trial, regardless of the outcome. Use one of the following tutorials to place calls: - [SIP Trunking](https://developers.telnyx.com/docs/voice/sip-trunking/get-started) - [Programmable Voice](https://developers.telnyx.com/docs/voice/programmable-voice/get-started) - [TeXML](https://developers.telnyx.com/docs/voice/programmable-voice/texml-setup) Regardless of how the call is created, the destination is limited to the verified phone number from Step 1, and inbound calls must also originate from that number. Check [trial voice limits](/docs/account-setup/levels-and-capabilities/trial). Use the [Send Message](https://developers.telnyx.com/docs/messaging/messages/send-message) tutorial to send SMS. Outbound messages must target the verified phone number you configured, and inbound messages must also originate from that number. Check [trial messaging limits](/docs/account-setup/levels-and-capabilities/trial). --- ### Paid Account > Source: https://developers.telnyx.com/docs/account-setup/levels-and-capabilities/paid.md ## Access - Full access except otherwise specified below. - Telnyx reserves the right to modify limitations without notification. ## Numbers ### Number searching - No access to number blocks. ### Number ordering - Limited to local numbers whose country code matches the account's country of origin. ### Number porting - No access to LRN migration. ## Messaging - No access to 10DLC. - No access to Toll-Free verification. - No access to hosted messaging. ## Voice ### General limits - Limited set of outbound destination country codes. - Limited to **5 concurrent outbound calls** across all connection types. ### Programmable Voice - All machine-generated voices are prepended with: “_This is an automated call generated on the Telnyx platform, please report any abuse to fraud@telnyx.com_”. - This applies to: - `/v2/calls` - `/v2/calls/:call_control_id/actions/transfer` - `/v2/calls/:call_control_id/actions/gather_using_audio` - `/v2/calls/:call_control_id/actions/gather_using_speak` - `/v2/calls/:call_control_id/actions/playback_start` - `/v2/calls/:call_control_id/actions/speak` - `/v2/calls/:call_control_id/actions/gather_using_ai` - `/v2/calls/:call_control_id/actions/ai_assistant_start` - TeXML verb `Play` - TeXML verb `Say` - TeXML verb `AIGather` - Limited to a maximum of **100 outbound calls a day**. - Limited to **10 outbound calls per hour**. ## Cloud Storage - Limited to non-public policy or ACL on buckets or objects. - Limited to **5 minutes of TTL** on pre-signed URLs. ## Account features ### ManagED Accounts - No access to APIs or features in this category. ### Payment methods - Credit card - PayPal ### DDoS mitigation - No access to APIs or features in this category. --- ### Verified Account > Source: https://developers.telnyx.com/docs/account-setup/levels-and-capabilities/verified.md ## Access - Full access except otherwise specified below. - Telnyx reserves the right to modify limitations without notification. ## Numbers ### Number searching - No access to number blocks. ### Number ordering - No access to number blocks. ### Number porting - No access to LRN migration. ## Account features ### ManagED Accounts - No access to APIs or features in this category. ### Payment methods - Credit card - PayPal - BTC ### DDoS mitigation - No access to APIs or features in this category. Qualification by the Telnyx sales team is required to upgrade your account to the enterprise level to gain access to the above features. [Contact Telnyx](https://telnyx.com/contact-us) to start the process. --- ### Account Upgrade > Source: https://developers.telnyx.com/docs/account-setup/account-upgrade.md | Criteria to meet | Pretrial | Trial | Paid | Verified | | --- | :---: | :---: | :---: | :---: | | Verified email | X | X | X | X | | Passed fraud review (LinkedIn/GitHub verification or AI agent eval) | | X | X | X | | Verified mobile number | | | X | X | | Made a payment with CC/Debit Card | | | X | X | | Enabled 2FA for the account | | | X | X | | Provided Service Address | | | X | X | | Successfully passed KYC | | | | X | | Successfully passed AI agent eval | | | | X | Identify the desired account level and complete **all** [required actions](https://portal.telnyx.com/#/account/account-levels). For enterprise upgrades, qualification by the Telnyx sales team is required. [Contact Telnyx](https://telnyx.com/contact-us) to begin the process. --- ### Data Locality > Source: https://developers.telnyx.com/docs/account-setup/data-locality.md Data Locality lets you choose the geographic region where your Telnyx data is stored at rest. --- ## Available regions | Region | Location | Default | |:-------|:---------|:--------| | US | United States | Yes | | EU | Germany | No | | APAC | Australia | No | | Middle East | UAE | No | --- ## Covered data types Data locality applies to the following data stored at rest: - Call Detail Records (CDRs) - Message Detail Records (MDRs) - Conference records - Forking CDRs - Media Storage (recordings) - Premium AMD - Speech-to-Text - Verify - Video - WhatsApp - Wireless --- ## Selecting a region 1. Log in to the [Mission Control Portal](https://portal.telnyx.com). 2. Go to **Account settings** > **Profile**. 3. Scroll to **Data Storage Location** and select a country from the dropdown. 4. Click **Save Location**. This setting can only be changed once and cannot be undone. After you save, Telnyx migrates your data to the new location. Some features may become temporarily unavailable during migration — the process can take a few minutes to several hours depending on your data size. All existing accounts default to the US. If you do not change the setting, your data remains in the US. --- ## API fundamentals ### Overview > Source: https://developers.telnyx.com/docs/development/api-fundamentals.md Telnyx REST APIs use the `https://api.telnyx.com/v2` base URL, JSON request and response bodies, and Bearer API-key authentication unless an endpoint reference states otherwise. Cloud Storage S3 operations, WebRTC clients, WebSocket APIs, and webhook deliveries use product-specific protocols. Follow the linked product documentation instead of applying the REST conventions on this page universally. ## Start here Complete these steps before configuring a product integration. Create, store, rotate, and revoke server-side credentials. Validate authentication with a safe `GET /balance` request. Inspect canonical endpoint contracts and language samples. ## Build the integration Send Bearer credentials and separate REST authentication from product-specific protocols. Select methods, encode JSON, and interpret success and error envelopes. Traverse collections using only the query parameters declared by each endpoint. Diagnose authentication, authorization, validation, throttling, and service failures. Respect response headers and retry only when the operation is safe. Verify signatures, acknowledge promptly, and process duplicate deliveries idempotently. ## Reference and tools - [Parameters and field names](/docs/development/api-fundamentals/data-standards/parameters-fields) - [API versions and deprecations](/docs/development/api-fundamentals/api-versions) - [General and product-specific error codes](/docs/development/api-fundamentals/api-errors) - [Server-side SDKs](/docs/development/sdk) - [Telnyx CLI](/docs/development/cli) - [Agent-readable API documentation](/docs/development/agent-readable-documentation) - [Other Telnyx interfaces and retired HTTP APIs](/docs/development/api-fundamentals/legacy-apis) --- ### Create API keys > Source: https://developers.telnyx.com/docs/development/api-fundamentals/create-api-keys.md Create API keys in Mission Control Portal. An API key authenticates server-side REST API requests for the associated Telnyx account. ## Create a key 1. Open [API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys) and sign in. 2. Select **Create API Key**. 3. Add a descriptive label that identifies the environment and application. 4. Under **Expiration**, select **No Expiration** or **Set Expiration Date**. 5. Create the key. 6. Copy the value immediately. **The key value is displayed once** Store the new value before leaving the creation dialog. If the value is lost, create a replacement key. Do not send the key in email, tickets, or chat. ## Store the key Use a secret manager for deployed applications. For local development, export a protected environment variable: ```bash export TELNYX_API_KEY="..." ``` - Keep `.env` and local secret files out of Git. - Restrict secret-manager access to required application runtimes and operators. - Redact `Authorization` headers from application and proxy logs. - Use separate keys for development, staging, and production. ## Validate a key ```bash curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: Bearer $TELNYX_API_KEY" \ --header "Accept: application/json" ``` Continue with [Make the first API request](/docs/development/api-fundamentals/first-api-request) for the response contract and failure handling. ## Rotate a key For a key with an expiration date, deploy a replacement before the date shown in the **Expires** column in Mission Control Portal. 1. Create and store a replacement key. 2. Deploy the replacement to every runtime that uses the old key. 3. Confirm a read-only authenticated request succeeds from the updated runtime. 4. Revoke the old key from [API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys). 5. Monitor authentication failures for workloads that still reference the old value. Revoke a key immediately after suspected exposure. Rotation does not remove leaked values from repository history or logs; remove or redact those copies separately. ## Use SDKs or CLI Current constructors, installation commands, and first requests are maintained in the [server-side SDK guides](/docs/development/sdk). CLI authentication is documented in the [Telnyx CLI guide](/docs/development/cli/getting-started/authentication). --- ### Make the first request > Source: https://developers.telnyx.com/docs/development/api-fundamentals/first-api-request.md Use the account balance endpoint as the initial authentication check. `GET /balance` is read-only and requires no product resource or provisioning step. ## Before starting - Create a key from [API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys). See [Create and manage API keys](/docs/development/api-fundamentals/create-api-keys) for storage and rotation guidance. - Install `curl` on macOS or Linux, or use PowerShell on Windows. - Keep the key in a server-side environment variable. Never embed it in browser or mobile code. ## Send the request ```bash export TELNYX_API_KEY="..." curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: Bearer $TELNYX_API_KEY" \ --header "Accept: application/json" ``` ```powershell $Env:TELNYX_API_KEY = "..." $headers = @{ Authorization = "Bearer $Env:TELNYX_API_KEY" Accept = "application/json" } Invoke-RestMethod ` -Method Get ` -Uri "https://api.telnyx.com/v2/balance" ` -Headers $headers ``` **Request failed?** Start with [API troubleshooting](/docs/development/api-fundamentals/troubleshooting), then check [authentication](/docs/development/api-fundamentals/authentication) and the [API error catalog](/docs/development/api-fundamentals/api-errors). A successful response has a `data` object containing the current balance, pending amount, credit limit, available credit, and ISO 4217 currency identifier: ```json { "data": { "record_type": "balance", "pending": "10.00", "balance": "300.00", "credit_limit": "100.00", "available_credit": "400.00", "currency": "USD" } } ``` The values above are illustrative. Treat monetary values as decimal strings rather than binary floating-point numbers. ## Interpret failures - `401 Unauthorized`: The `Authorization` header is absent or the key is invalid. - `403 Forbidden`: The credential or account cannot access balance information. - `422 Unprocessable Entity`: The request reached the endpoint but could not be processed. - `503 Service Unavailable`: The service is temporarily unavailable. Apply the [retry guidance](/docs/development/api-fundamentals/reliability/command-retries). See [API troubleshooting](/docs/development/api-fundamentals/troubleshooting) for a diagnostic sequence and [API error codes](/docs/development/api-fundamentals/api-errors) for Telnyx-specific error bodies. ## Continue - [Open the balance API reference](/api-reference/billing/get-user-balance-details) - [Select a server-side SDK](/docs/development/sdk) - [Install the Telnyx CLI](/docs/development/cli/getting-started/install) - [Review request and response handling](/docs/development/api-fundamentals/request-response) --- ### Authentication > Source: https://developers.telnyx.com/docs/development/api-fundamentals/authentication.md Telnyx REST API operations declare Bearer authentication in their API reference. Send the API key in the `Authorization` request header: ```http Authorization: Bearer ``` Create and manage server-side credentials from [API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys). ## REST API request Store the key in a server-side environment variable and reference it from the HTTP client: ```bash export TELNYX_API_KEY="..." curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: Bearer $TELNYX_API_KEY" \ --header "Accept: application/json" ``` Do not place Telnyx API keys in browser JavaScript, mobile applications, public repositories, URLs, logs, or support messages. ## SDK authentication Current server-side SDKs read `TELNYX_API_KEY` from the environment or accept it when constructing a client. Use the generated SDK guides for the current constructor and service method: - [TypeScript and Node.js](/docs/development/sdk/node) - [Python](/docs/development/sdk/python) - [Go](/docs/development/sdk/golang) - [Java](/docs/development/sdk/java) - [Ruby](/docs/development/sdk/ruby) - [PHP](/docs/development/sdk/php) ## Credential lifecycle 1. Create separate keys for development, staging, and production. 2. Store keys in a secret manager or protected environment configuration. 3. For a key with an expiration date, deploy a replacement before it expires. 4. Create a replacement key before rotating an active integration. 5. Deploy the replacement and confirm a read-only request succeeds. 6. Revoke the old key from [API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys). 7. Revoke any key exposed in source control, logs, client code, or chat immediately. See [API error codes](/docs/development/api-fundamentals/api-errors) and [troubleshooting](/docs/development/api-fundamentals/troubleshooting) for revoked, forbidden, and invalid credential failures. ## Product-specific authentication Do not reuse the REST Bearer pattern where a product defines another protocol: - **Cloud Storage S3 operations:** Use the S3-compatible credentials and AWS Signature Version 4 described by [Cloud Storage API endpoints](/docs/cloud-storage/api-endpoints). - **WebRTC clients:** Mint short-lived client tokens on a trusted server; do not expose a Telnyx API key to the client. - **WebSocket APIs:** Follow the authentication message or connection fields documented by that specific WebSocket API. - **Webhook deliveries:** When a product documents Telnyx Ed25519 signing, verify the signature with the account public key. Follow another validation scheme when the selected product defines one. See [Webhook fundamentals](/docs/development/api-fundamentals/webhooks/receiving-webhooks). ## Related - [Create and manage API keys](/docs/development/api-fundamentals/create-api-keys) - [Open API Keys in Mission Control Portal](https://portal.telnyx.com/#/app/api-keys) - [Make the first API request](/docs/development/api-fundamentals/first-api-request) - [Account levels and capabilities](/docs/account-setup/levels-and-capabilities) --- ### Requests and responses > Source: https://developers.telnyx.com/docs/development/api-fundamentals/request-response.md The Telnyx REST API base URL is `https://api.telnyx.com/v2`. Use the API reference as the contract for each operation. It defines the supported method, path, authentication, query parameters, request media type, response schema, and status codes. ## Construct a request A typical JSON request contains: ```http POST /v2/ HTTP/1.1 Host: api.telnyx.com Authorization: Bearer Accept: application/json Content-Type: application/json {...} ``` - Send `Authorization: Bearer ` when the operation declares Bearer authentication. - Send `Accept: application/json` for JSON REST responses. - Send `Content-Type: application/json` only when a body is present and the operation accepts JSON. - Do not set multipart or form media types unless the endpoint reference declares them. ## Select the HTTP method - `GET` retrieves a resource or collection without requesting a state change. - `POST` creates a resource or invokes an action. - `PATCH` updates fields on an existing resource. - `DELETE` removes a resource. Never infer that a path supports a method. Use the operation shown in the API reference. ## Read successful responses Many REST operations return a top-level `data` member. A single-resource response commonly uses an object: ```json { "data": { "id": "resource_id", "record_type": "resource_type" } } ``` Collection operations commonly use a `data` array and can include pagination metadata: ```json { "data": [], "meta": { "page_number": 1, "page_size": 20, "total_pages": 1, "total_results": 0 } } ``` The endpoint schema is authoritative. Do not assume every operation returns `data`, `meta`, or JSON. Common success statuses include `200 OK`, `201 Created`, `202 Accepted`, and `204 No Content`. Read the operation reference before deciding whether to parse a body or poll an asynchronous resource. ## Read error responses General REST failures commonly return an `errors` array: ```json { "errors": [ { "code": "10004", "title": "Missing required parameter", "detail": "A required parameter was missing.", "source": { "pointer": "/data/attributes/example" } } ] } ``` Use all available fields: - `code`: Stable Telnyx error identifier when supplied. - `title`: Short error classification. - `detail`: Request-specific explanation. - `source.pointer`: JSON Pointer to the invalid request member. - `source.parameter`: Invalid query parameter. - `meta`: Additional product-specific context. See [API error codes](/docs/development/api-fundamentals/api-errors). Product APIs can define additional errors and envelopes, so inspect the operation reference before implementing a parser. ## Handle status codes - `400` or `422`: Correct the request; do not retry unchanged input. - `401`: Restore a valid credential and Bearer header. - `403`: Check account access, resource ownership, verification, and product prerequisites. - `404`: Verify the path and resource identifier. - `409`: Reconcile current resource state before retrying. - `429`: Respect rate-limit guidance and delay the next attempt. - `5xx`: Treat as potentially transient, subject to operation safety and the [retry guidance](/docs/development/api-fundamentals/reliability/command-retries). ## Protocol boundaries These conventions describe Telnyx REST operations. S3-compatible Cloud Storage, WebRTC, WebSocket APIs, and webhook deliveries have separate protocol contracts in their product documentation. ## Related - [Pagination, filtering, and sorting](/docs/development/api-fundamentals/pagination-filtering-sorting) - [Rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting) - [API troubleshooting](/docs/development/api-fundamentals/troubleshooting) - [API reference](/api-reference) --- ### Pagination and filtering > Source: https://developers.telnyx.com/docs/development/api-fundamentals/pagination-filtering-sorting.md Collection operations declare their supported query parameters in the API reference. Do not assume that every endpoint implements the same pagination, filtering, or sorting fields. ## Page-based pagination Endpoints using page-based pagination commonly accept `page[number]` and `page[size]`: ```http GET /v2/phone_numbers?page[number]=3&page[size]=20 ``` Page numbering is 1-based. Omitting `page[number]` requests the first page. Endpoint references define default and maximum page sizes. A paginated response can include: ```json { "data": [], "meta": { "page_number": 3, "page_size": 20, "total_pages": 13, "total_results": 246 } } ``` When `total_pages` is present, continue until `page_number` reaches it. Otherwise, follow the endpoint's documented links, cursors, or termination condition. Do not hard-code a global maximum page size. ## Filtering Filter syntax is endpoint-specific. An endpoint can expose scalar filters: ```http GET /v2/phone_numbers?filter[tag]=production ``` An endpoint can also declare repeated or array filters: ```http GET /v2/phone_numbers?filter[country_iso_alpha2][]=US&filter[country_iso_alpha2][]=CA ``` Use only filter names and operators documented for the selected operation. ## Sorting Endpoints that support sorting declare a `sort` parameter and allowed fields. A leading `-` commonly selects descending order: ```http GET /v2/connections?sort=connection_name GET /v2/connections?sort=-created_at ``` Some operations support multiple sort fields. Follow the exact format shown in that operation's reference. ## Encode query parameters Square brackets are part of the parameter name. HTTP clients normally percent-encode them automatically. When constructing a URL manually, preserve the equivalent encoded form: ```text page%5Bnumber%5D=3&page%5Bsize%5D=20 ``` ## Operational guidance - Preserve a stable sort where supported so records are not skipped or repeated as a collection changes. - Bound concurrent page requests to remain within endpoint rate limits. - Restart pagination when filters or sorting change. - Treat pagination metadata as response data rather than predicting totals locally. See [Parameters and field names](/docs/development/api-fundamentals/data-standards/parameters-fields) and [Rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting). --- ### API error catalog > Source: https://developers.telnyx.com/docs/development/api-fundamentals/api-errors.md Use the code returned in an API error response to locate its title and detail below. The legacy General API catalog includes shared request, authentication, and validation errors together with some product-context entries; do not assume that every code applies to every endpoint. Product-specific delivery, protocol, SDK, and provider errors are maintained in their product references and combined with this table in the unified catalog. - [Unified machine-readable error catalog](/data/api-errors.json): normalized entries with product scope, source provenance, and authored remediation metadata. - [Catalog source registry](/data/error-catalog-sources.json): versioned inventory of the maintained public tables included by the generator. ## Product-specific references - [10DLC troubleshooting](/docs/messaging/10dlc/troubleshooting) - [Call Control webhook errors](/docs/voice/programmable-voice/voice-api-webhooks) - [Edge Compute Stateful Actor errors](/docs/edge-compute/stateful-actors/api-reference/errors) - [Email API errors](/docs/messaging/email/error-codes) - [Messaging delivery errors](/docs/messaging/messages/error-codes) - [SIP response codes](/docs/voice/sip-trunking/troubleshooting/response-codes) - [Speech-to-Text WebSocket errors](/docs/voice/stt/websocket-streaming/errors) - [Text-to-Speech WebSocket errors](/docs/voice/tts/websocket-streaming/errors) - [Toll-Free Verification troubleshooting](/docs/messaging/toll-free-verification/troubleshooting) - [Voice Design Lab errors](/docs/voice/voice-design-lab/clone-voice/errors) - [WebRTC JavaScript SDK error handling](/docs/development/webrtc/js-sdk/how-to/error-handling) - [WhatsApp template errors](/docs/messaging/whatsapp/manage-templates) - [Wireless API errors](/docs/iot-sim/api-errors) ## General API catalog entries Search this page with the browser's find command (`Command+F` on macOS or `Ctrl+F` on Windows and Linux) to locate an exact error code or phrase. For product scope, remediation, and source provenance, use the unified machine-readable catalog linked above. | Code | Title | Detail | | --- | --- | --- | | 10001 | Inactive phone number | The phone number is inactive. | | 10002 | Invalid phone number | The phone number is invalid. | | 10003 | Invalid URL | The URL provided was invalid, malformed, or too long. URLs can be a maximum of 2000 characters. | | 10004 | Missing required parameter | A required parameter was missing. | | 10005 | Resource not found | The requested resource or URL could not be found. | | 10006 | Invalid ID | The resource ID provided was invalid. | | 10007 | Unexpected error | An unexpected error occurred. | | 10008 | Request timeout | The request timed out. | | 10009 | Authentication failed | The required authentication headers were either invalid or not included in the request. | | 10010 | Authorization failed | You do not have permission to perform the requested action on the specified resource or resources. | | 10011 | Too many requests | You have exceeded the maximum number of allowed requests. | | 10012 | Duplicate resource | Resource is a duplicate. | | 10013 | Missing association | One of the associated fields does not exist. | | 10014 | Unsupported Media Type | The request failed because the server does not support the media type. | | 10015 | Bad Request | The request failed because it was not well-formed. | | 10016 | Phone number must be in +E.164 format | The specified phone number parameter must be in +E.164 format. | | 10017 | Associated resource does not exist | The requested parameter is invalid as the associated resource does not exist. | | 10018 | Invalid sort direction | The 'sort_direction' parameter must have a value of either 'asc' or 'desc'. | | 10019 | Invalid email address | The 'email' parameter is not a valid email address. | | 10020 | Invalid resource type | The requested parameter must be of type 'string' | | 10021 | Resource in use | The resource can not be removed as it is still in use. | | 10022 | One or more invalid IDs | One or more of the IDs provided were invalid. | | 10023 | Invalid JSON | The supplied JSON is invalid. | | 10024 | Unsupported Content-Type | Must encode request as 'application/x-www-form-urlencoded' or 'application/json' | | 10025 | String length out of range | The string length provided for the indicated field was outside the allowed range. The field must be between {min} and {max} characters long, but was {actual}. | | 10026 | Invalid parameter type | The parameter must be of type {expected_type}, but received type {received_type} | | 10027 | Unprocessable Entity | The server understood the syntax of the request but was unable to process the instructions. | | 10028 | Character encoding error | The request body was not able to be decoded. | | 10029 | Expected JSON Content-Type | Must encode request as 'application/json' | | 10030 | Method not allowed | The URL is valid, but the method is not allowed. | | 10031 | Invalid request filter | The request filter filter[{filter}] is invalid. | | 10032 | Invalid enumerated value | The value must be one of {enumerated_values} | | 10033 | Value outside of range | The value is outside of allowed range {min_allow} to {max_allow} | | 10034 | Expected URL-encoded form Content-Type | Must encode request as 'application/x-www-form-urlencoded' | | 10035 | Resource locked | The resource has been locked. Contact Telnyx support. | | 10036 | Resource is being processed | This resource is in ongoing processing and it can't be interacted with. Please, wait for its operation to finish and retry later. | | 10037 | Service unavailable | Service is unavailable. | | 10038 | Feature not permitted | This feature is not permitted at this account level. Refer to https://telnyx.com/upgrade. | | 10039 | Feature limited | A limit for this feature has been reached at this account level. See https://telnyx.com/upgrade for options. | | 10700 | Invalid caller data | The CNAM caller data provided is invalid. | | 20000 | Invalid resource groups | The resource groups provided are invalid. | | 20001 | Invalid API Key secret | The secret provided is invalid. | | 20002 | API Key revoked | The API Key provided is not active. | | 20003 | API Key forbidden | The API Key provided is forbidden. | | 20004 | Invalid permission groups | The permission groups provided are invalid. | | 20005 | Invalid user | The user provided is invalid. | | 20006 | Expired access token | The access token provided is expired. | | 20007 | Invalid permission groups | The permission groups provided must be a subset of the API Key's. | | 20008 | Invalid API Key | The API Key provided is invalid. | | 20009 | Invalid user | The user provided does not exist. | | 20010 | Invalid invitation | The invitation provided does not exist. | | 20011 | API Key in use | The API Key can not be revoked while assigned to a portal user. | | 20012 | Account inactive | The request cannot be fulfilled because your account has been deactivated. It may be out of funds. | | 20013 | Account blocked | Your account has been blocked. Please contact Telnyx support. | | 20014 | Account unverified | You have not completed the verifications required to perform this action. Check the 'verifications' tab under 'account' on the portal for more information. | | 20015 | Feature not enabled | The {feature} feature is not enabled on your account. | | 20016 | Account not level 1 verified | Level 1 account verification is required to perform this action. Check the 'verifications' tab under 'account' on the portal for more information. | | 20017 | Account not level 2 verified | Level 2 account verification is required to perform this action. Check the 'verifications' tab under 'account' on the portal for more information. | | 20100 | Insufficient Funds | You do not have enough funds to perform this action. | | 20200 | Invalid address | The address provided is invalid. | | 20201 | Invalid country code | The country code provided is invalid. | | 20202 | Invalid locality | The locality provided is invalid. | | 20203 | Invalid neighborhood | The neighborhood provided is invalid. | | 20204 | Invalid administrative area | The administrative area provided is invalid. | | 20205 | Invalid postal code | The postal code provided is invalid. | | 20206 | Invalid borough | The borough provided is invalid. | | 20207 | Invalid street address | The street address provided is invalid. | | 20208 | Invalid street address house number | The street address house number provided is invalid. | | 20209 | Invalid extended address | The extended address provided is invalid. | | 40001 | Not routable | The destination number is either a landline or a non-routable wireless number. | | 40002 | Blocked as spam - temporary | The message was flagged by a SPAM filter and was not delivered. This is a temporary condition. | | 40003 | Blocked as spam - permanent | The message was flagged by a SPAM filter and was not delivered. The originating phone number is permanently blocked. | | 40004 | Rejected by destination | The recipient server is rejecting the message for an unknown reason. | | 40005 | Message expired during transmission | The message expired before it could be fully delivered to the recipient. | | 40006 | Recipient server unavailable | The recipient server is unavailable or not responding. | | 40007 | Loop detected | Infinite loop detected. | | 40008 | Undeliverable | The recipient carrier did not accept the message. | | 40009 | Invalid message body | The message body was invalid. | | 40010 | Not 10DLC registered | The sending number is not 10DLC-registered but is required to be by the carrier. | | 40011 | Too many requests | Exceeded upstream rate limit. As a result the message was flagged by a SPAM filter and was not delivered. This is a temporary condition. | | 40012 | Invalid messaging destination number | The destination phone number was deemed invalid by the carrier. | | 40013 | Invalid messaging source number | The source phone number was deemed invalid by the carrier. | | 40014 | Message expired in queue | The message was not sent by Telnyx because its validity period expired. | | 40015 | Blocked as spam - internal | The message was flagged by an internal Telnyx SPAM filter. | | 40016 | T-Mobile 10DLC Sending Limit Reached | You have exceeded T-Mobile's allotted throughput limits for the campaign associated to this phone number | | 40017 | AT&T 10DLC Spam Message Rejected | AT&T has rejected your message for spam on the 10DLC route | | 40018 | AT&T 10DLC Sending Limit Reached | You have exceeded AT&T's allotted throughput limits for the campaign associated to this phone number | | 40019 | AT&T 10DLC Invalid Tag Data | AT&T has rejected your message because the tagging information is incorrect | | 40020 | Blocked as potentially artificial inflation of traffic | Sending of 2FA traffic has been blocked for 24 hours. | | 40100 | Number not messaging enabled. | The number is not currently messaging enabled. | | 40150 | Toll free number not in registry | Messaging cannot be enabled for this number because the number is not in the voice registry. | | 40151 | Message enablement pending with other provider | Messaging is in the process of being enabled with another messaging provider. | | 40152 | Invalid OSR parameter | One of the parameters sent to the OSR was missing or invalid. | | 40153 | Cannot access OSR | Telnyx is not authorized to access the OSR. | | 40154 | Unauthorized NNID | Telnyx is not authorized to use this NNID. | | 40155 | LOA required | An LOA is required to text message enable this number. | | 40156 | Unauthorized property name/value | Telnyx is not authorized to provision this property name or property value. | | 40157 | Temporarily blocked | Telnyx is temporarily unable to make changes to the OSR. | | 40158 | Delete failed | The record was not found or the NNID was invalid so it could not be deleted. | | 40159 | Unknown OSR error | An error occurred while updating the OSR. | | 40300 | Blocked due to STOP message | Messages cannot be sent from {src} to {dst} due to an existing block rule. | | 40301 | Unsupported message type for the 'to' address | Sending messages from {src} to {dst} is currently unsupported. | | 40302 | Message too large | The SMS message would be divided into {parts} parts. The maximum is {max_parts}. | | 40303 | Message not found | The message with ID {id} was not found. | | 40304 | Invalid combination of message content arguments | The message must contain exclusively 'body' for SMS, or 'subject' and/or 'media_urls' for MMS | | 40305 | Invalid 'from' address | The 'from' address should be string containing a valid phone number or alphanumeric sender ID associated with the sending messaging profile. | | 40306 | Alpha sender not configured | The messaging profile doesn't have an associated alphanumeric sender ID. | | 40307 | Alpha sender mismatch | The specified alphanumeric sender ID {provided_sender} does not match the one configured on the profile {expected_sender} | | 40308 | Invalid 'from' address for MMS | MMS can only be sent from US long code numbers and MMS-configured short codes | | 40309 | Invalid destination region | The region {region} for the destination {dst} is not included in the messaging profile's whitelisted destinations. | | 40310 | Invalid 'to' address | The 'to' address should be a single valid number. | | 40311 | Invalid messaging profile secret | The provided X-Profile-Secret header was invalid. | | 40312 | Messaging profile is disabled | The specified messaging profile {id} is disabled. | | 40313 | Missing messaging profile secret | The X-Profile-Secret header is missing. | | 40314 | Messaging disabled on account | Messaging has been disabled on your account. Contact Telnyx support. | | 40315 | Unhealthy 'from' address | Sending number {src} (with success rate {success} and spam rejection rate {spam}) did not pass the health check. | | 40316 | No content provided for message | The message has no content. Either 'text' and/or 'media_urls' must be provided in the request. | | 40317 | Invalid MMS content | MMS can only contain up to 10 items (URLs provided) and the total size must be less than 1 MB. | | 40318 | Message queue full | Message queue is full. Wait before resending. | | 40319 | Incompatible message type for the 'to' address | Sending messages from {src} to {dst} is not possible. | | 40320 | Temporarily unusable 'from' address | The sending number {src} is in a temporarily unusable or pending state. | | 40321 | No usable numbers on messaging profile | Number Pool is not enabled, or it is unable to select a usable number on the messaging profile. | | 40322 | Blocked due to content | Message contains invalid content. | | 40323 | Messaging activation failed | Could not enable messaging on the number. | | 40324 | Messaging product type change failed | Could not change product types for the number. | | 40325 | Invalid alphanumeric sender ID | The specified alphanumeric sender ID value is invalid. | | 40326 | Cannot assign alphanumeric sender ID | The alphanumeric sender ID could not be assigned to the messaging profile. | | 40327 | Invalid Domain | The domain provided is not listed as a valid domain to be used with URL Shortener | | 40328 | SMS exceeds recommended size | The SMS message would be divided into {parts} parts. Messages over {max_parts} should be sent by MMS or by adding auto_detect=False. | | 40329 | Tollfree number is not verified | Try verifying the number if you haven't already; otherwise double check that verification succeeded. | | 40330 | Tollfree number is not provisioned | This TFN is not yet fully provisioned for messaging. | | 40331 | Missing whitelisted destinations | Messaging profile is missing whitelisted destinations. | | 40332 | Brand cannot be deleted | Brand cannot be deleted due to an associated active campaign. | | 40333 | Messaging profile spend limit reached | Request refused because this would incur cost above the spend limit configured on the messaging profile. | | 41000 | WhatsApp Error | {code} - {title} | | 50000 | VRF still deployed | The VRF can not be removed as it is still deployed to one or more sites | | 50001 | VRF not deployed | The VRF is not deployed at this site | | 50002 | VRF already deployed | The VRF is already deployed at this site | | 50003 | Invalid IP address | This is not a valid IP address | | 50004 | Private IP address not permitted | Private IP addresses are not permitted | | 50005 | Invalid CIDR block | This is not a valid CIDR block | | 50006 | Private CIDR block not permitted | Private CIDR blocks are not permitted | | 50007 | CIDR block too large | CIDR blocks are limited to /{prefixlen} and higher | | 50008 | Can not delete IP from source | Can not delete IP from source {source} | | 55001 | Credential expired, can not create token. | The credential used to create the token has expired. | | 65001 | Invalid Room ID | The provided room_id was not valid. | | 70000 | Consumption reached data limit | The consumption reached the defined data limit. Please, update the SIM card group data limit. | | 70001 | There aren't enough available SIM cards | Insufficient inventory to satisfy order request. | | 70002 | Invalid data format | The provided data attribute was invalid. | | 70003 | Mobile operators' preferences priorities are out of sequence | The mobile operators' preferences priorities should be in an ascending order starting by 0. | | 70004 | OTA update in progress | SIM card network preferences can't be defined when a previous OTA update is still in progress. | | 70005 | Could not delete SIM card group | The SIM card group associated with the provided ID can not be deleted because there are SIM cards associated with the SIM card group. | | 70006 | Could not delete default SIM card group | The SIM card group associated with the provided ID can not be deleted because it is the default SIM card group on your account. | | 70007 | SIM card doesn't have a SIM card group | A SIM card cannot be enabled unless it's associated with a SIM card group. | | 70008 | Public IPs are unavailable at this time | There aren't any public IPs available at this time. Please contact Telnyx support for more information. | | 75000 | Webhook delivery error | The webhook was not successful | | 75001 | Could not resolve name | Unable to resolve the webhook URL domain name | | 75002 | Could not connect to host | Could not connect to the webhook host | | 75003 | Certificate misconfiguration | Webhook host certificate could not be verified | | 75004 | Expired certificate | The webhook host certificate has expired | | 75005 | Certificate name mismatch | The domain name on the certificate does not match the domain in the URL | | 75006 | Untrusted certificate root | The certificate is not signed by a trusted authority | | 75299 | Webhook host returned a non-200 HTTP 2XX | The server returned an HTTP 2XX code, but was not the expected HTTP 200 | | 75300 | Webhook host returned HTTP 3XX | The server returned an HTTP 3XX redirect | | 75400 | Webhook host returned HTTP 400 | The server returned an HTTP 400 | | 75404 | Webhook host returned HTTP 404 | The server returned an HTTP 404 | | 75499 | Webhook host returned HTTP 4XX | The server returned an HTTP 4XX error | | 75500 | Webhook host returned HTTP 500 | The server returned an HTTP 500 | | 75599 | Webhook host returned HTTP 5XX | The server returned an HTTP 5XX error | | 80000 | Wrong account | One or more numbers you are attempting to port do not belong to the specified account. | | 80001 | Inactive number | One or more numbers you are attempting to port are not active on the account. Only active numbers may be ported. | | 80002 | Wrong provider | Telnyx is not the service provider for one or more of the numbers you are attempting to port. | | 80003 | Pending order | One or more numbers are already part of another port request. | | 80004 | Invalid desired due date | The desired due date is not within the allowable window. Please review the porting guidelines. | | 80005 | Invalid passcode or pin | The passcode or PIN provided does not match what has been assigned to the number. | | 80006 | Invalid PON | The Purchase Order Number (PON) provided is invalid. It must be between 3 and 20 characters and may not contain special characters. | | 80007 | FOC expired | The firm order committment has expired since the number was not ported on the agreed upon due date. | | 80008 | Missing LOA | A valid LOA (Letter of Authorization) is required to port numbers. | | 80009 | Illegible LOA | The LOA (Letter of Authorization) provided was illegible or unable to be viewed. | | 80010 | Expired LOA | The LOA (Letter of Authorization) provided has expired and is no longer valid. | | 80011 | Invalid SPID | The service provider ID (SPID) provided was not recognized. | | 80012 | Unsuported carrier | The functionality requested is not supported with the specified carrier. | | 80013 | Invalid country | Automated porting is only supported in the US and Canada. | | 80014 | Service address mismatch | The service address provided does not match the address on the account. | | 80015 | Stranded phone numbers | The BTN/ATN on the account is being ported out which would leave stranded any remaining phone numbers. | | 80016 | No CSR data available | A CSR could not be retrieved because the data submitted did not match closely enough with the data on file with the carrier. | | 80017 | Invalid service provider type | The 'service_provider_type' parameter must be one of either 'Telnyx' or 'Peerless'. | | 80018 | Invalid FOC date | The 'foc_date' parameter must be an ISO8601 datetime selected from the available FOC dates. | | 80019 | Invalid service provider ID | The 'service_provider_id' parameter must be the ID of an existing service provider. | | 80020 | Invalid subscription status | The 'subscription_status' parameter is required and must have a value of 'pending', 'concurred', 'timer_expired', 'conflict', 'activated', 'cancel_pending', 'cancelled', 'disconnect_pending', 'disconnected' or 'failed' | | 80021 | Invalid porting option | The 'porting_option' parameter is required and must have a value of 'full' or 'partial'. | | 80022 | Invalid document type | The 'document_type' parameter must have value of 'loa', 'csr', 'invoice' or 'other'. | | 80023 | Invalid value for rate centers | The 'rate_centers' parameter must be a list of valid rate centers. | | 80024 | Record could not be deleted | The sub_request could not be deleted as it has associated phone_numbers. | | 80100 | Subscription version not created | The new service provider did not create an NPAC subscription version. | | 80101 | Subscription version does not match | The new service provider created an NPAC subscription version that does not match the record Telnyx created. | | 80200 | Duplicate phone numbers found | Duplicate phone numbers were found in the request. | | 80201 | Phone number limit exceeded | Too many phone numbers were specified for an LSR preorder. | | 80400 | Invalid credentials | The Port PS account credentials were invalid. | | 80401 | Too many phone numbers | There is a maximum of 1000 lookups per request. | | 85000 | Must search phone number via search API first | You must search for the number through our API before attempting to purchase. | | 85001 | Phone numbers not available | The numbers you are trying to order are no longer available for purchase. | | 85002 | Phone numbers update not allowed on this order | You are trying to update a number that is not in this order. | | 85003 | Regulatory requirements already satisfied | Regulatory requirements cannot be updated once all have been satisfied. | | 85004 | Invalid connection id provided | The connection id provided is invalid. | | 85005 | Invalid messaging profile id provided | The messaging profile id provided is invalid. | | 85006 | The phone number is already reserved | The phone number {number} is already reserved. | | 85007 | Reservation limit exceeded | You have too many active phone number reservations. | | 85008 | Reservation extension limit exceeded | The reservation has reached its limit of allowed extensions. | | 90000 | Invalid value for format | Format must be of type 'string' with a value of either 'mp3' or 'wav'. | | 90001 | Invalid value for channels | Channels must be a 'string' with a value of either 'single' or 'dual'. | | 90002 | Invalid value for timeout | The 'timeout' parameter must be an 'integer' with a minimum and a maximum value accepted by command | | 90003 | Invalid value for inter_digit_timeout | The 'inter_digit_timeout' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 120000. | | 90004 | Invalid value for min | The 'min' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90005 | Invalid value for max | The 'max' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90006 | Invalid value for tries | The 'tries' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90007 | Invalid value for terminating_digit | The 'terminating_digit' parameter must be a 'string' with a value of 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, #, or '' for no terminating digit. | | 90008 | Invalid value for valid_digits | The 'valid_digits' parameter must be a 'string' with a value of 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, *, or #. | | 90009 | Invalid value for loop | The 'loop' parameter must either be 'infinity' or an 'integer' with a minimum value of 1 and a maximum value of 100. | | 90010 | Invalid value for payload | The 'payload' parameter should contain between 1 and 5000 characters. | | 90011 | Invalid value for payload_type | The 'payload_type' parameter must be of type 'string' with a value of either text or ssml. | | 90012 | Invalid value for voice | The 'voice' parameter must be 'female' or 'male' when using the en-US language. | | 90013 | Invalid value for language | The 'language' parameter must be of type 'string' with a value of either de-DE, en-AU, en-GB, en-US, es-ES, fr-CA, fr-FR, it-IT, ja-JP, ko-KR, nl-NL, pt-BR, sv-SE or tr-TR. | | 90014 | Invalid value for digits | The 'digits' parameter must be a 'string' made of a combination of either 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, w, W, * or #. | | 90015 | Invalid Call Control ID | The provided call_control_id was not valid. | | 90016 | Invalid value for stop | The 'stop' parameter must be a 'string' with a value of 'all', 'current' or 'overlay'. | | 90017 | Invalid value for client_state | The 'client_state' parameter must be a valid base64 string. | | 90018 | Call has already ended | This call is no longer active and can't receive commands. | | 90019 | Conference has already ended | This conference is no longer active and can't receive commands. | | 90020 | Call recording triggered before audio started | Call recording cannot be started until audio has commenced on the call. | | 90021 | Invalid value for duration | The 'duration' parameter must be an 'integer' with a minimum value of 100 and a maximum value of 500. | | 90022 | Invalid value for minimum_digits | The 'minimum_digits' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90023 | Invalid value for maximum_digits | The 'maximum_digits' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90024 | Invalid value for maximum_tries | The 'maximum_tries' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 128. | | 90025 | Invalid value for timeout_millis | The 'timeout_millis' parameter must be an 'integer' with a minimum and a maximum value accepted by command | | 90026 | Invalid value for inter_digit_timeout_millis | The 'inter_digit_timeout_millis' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 120000. | | 90027 | Invalid value for duration_millis | The 'duration_millis' parameter must be an 'integer' with a minimum value of 100 and a maximum value of 500. | | 90028 | Invalid value for timeout_secs | The 'timeout_secs' parameter must be an 'integer' with a minimum and a maximum value accepted by command | | 90029 | Invalid value for time_limit_secs | The 'time_limit_secs' parameter must be an 'integer' with a minimum value of 60 and a maximum value of 14,000. | | 90030 | Invalid value for service_level | The 'service_level' parameter must be of type 'string' with a value of either 'basic' or 'premium'. | | 90031 | Call is not currently forked | Can't stop forking, because the call isn't currently forked. | | 90032 | Too many conference participants | The participant is unable to join because the maximum number of participants ({num}) has been reached. | | 90033 | Conference has no active participants | This conference does not have any active participants. | | 90034 | Call has not been answered yet | This call can't receive this command because it has not been answered yet. | | 90035 | Call not in queue | This call can't receive this command because it has not been put in any queue yet. | | 90036 | Queue full | The queue is full and can't accept more calls. | | 90037 | Queue max_size cannot be modified | Queue exists and max_size cannot be modified. | | 90038 | Call already in queue | Call can't be added to a queue it's already in. | | 90040 | Downloading audio file failed | Provided audio file couldn't be downloaded due to a timeout. | | 90041 | User termination channels limit exceeded | The limit of simultaneous termination channels configured to your user has been reached. | | 90042 | Outbound voice profile channels limit exceeded | The limit of simultaneous channels configured to the outbound voice profile associated to this connection has been reached. | | 90043 | Connection outbound channels limit exceeded | The limit of simultaneous outbound channels configured to this call control connection has been reached. | | 90044 | Conference join not allowed | Participant must not join the same conference twice. | | 90045 | Media Streaming is used. | This command can't be issued when media streaming is used. | | 90046 | Media Streaming Failed. | The media streaming failed to start. | | 90048 | Media Streaming is not used. | This command can only be issued when media streaming is used. | | 90049 | Invalid value for record_timeout_secs | The 'record_timeout_secs' parameter must be an 'integer' with a minimum value of 0. | | 90053 | Call recording triggered with 'timeout_secs' while transcribing | Call recording can not be started with 'timeout_secs' while the call is being transcribed. | | 90054 | Call Transcription is already in progress | Call Transcription can not be started more than once. | | 90055 | Call transcription can not be stopped | Call transcription can not be stopped while there is a recording with 'timeout_secs' in progress. | | 90056 | Invalid value for initial_timeout_millis | The 'initial_timeout_millis' parameter must be an 'integer' with a minimum value of 1 and a maximum value of 120000. | | 90057 | Invalid call control event type for webhook_urls | The webhook_urls json keys must be valid call control event types. | | 90058 | Invalid conference_id | The conference does not exist. | | 90059 | Invalid value for recording_track | The 'recording_track' parameter must be a 'string' with a value of either 'inbound', 'outbound' or 'both'. | | 90080 | Cannot issue a command on fax in the current state. | This command can only be issued when a fax is in either queued, media.processed or sending state. | | 90081 | Cannot issue command for inbound fax. | This command can only be issued for outbound fax. | | 90100 | Notification key is invalid | The notification key provided is invalid. | | 90101 | Notification context is invalid | The required notification context was either invalid or not included in the request. | | 90102 | Command is invalid | Call answer command cannot be issued for outbound calls. | | 100001 | Invalid Dialogflow API | The value should be either 'es' or 'cx' | --- ### Rate limiting > Source: https://developers.telnyx.com/docs/development/api-fundamentals/reliability/rate-limiting.md Most `api.telnyx.com` endpoints enforce rate limits. Limits and scopes can differ by product and operation and can change as service capacity changes. Treat response headers and product documentation as authoritative rather than hard-coding a global request rate. ## Rate-limit headers When present, these headers describe the current request window: | Header | Meaning | | --- | --- | | `x-ratelimit-limit` | Applicable request limit for the current window. | | `x-ratelimit-remaining` | Requests remaining in the current window. | | `x-ratelimit-reset` | Reset timing signal. The representation and interpretation are product-specific. | | `retry-after` | Delay before another attempt, when supplied. | Header availability and semantics can vary by endpoint. A missing header is not evidence that an endpoint has no limit. Follow the selected product's documentation before interpreting `x-ratelimit-reset` as either a duration or a timestamp. ## 429 response A throttled REST request returns HTTP `429 Too Many Requests`: ```json { "errors": [ { "code": "10011", "title": "Too many requests", "detail": "You have exceeded the maximum number of allowed requests." } ] } ``` ## Recover safely 1. Stop issuing requests in the affected scope. 2. Honor `Retry-After` when present; otherwise use the documented reset signal or bounded exponential backoff with jitter. 3. Retry only when the original operation is safe to repeat. 4. Reduce concurrency and cache safe read results where appropriate. 5. Bound attempts and total elapsed retry time. Do not distribute traffic across API keys to bypass a product limit. Contact [Telnyx Support](https://support.telnyx.com) when normal operation consistently exceeds documented capacity. ## Product-specific limits - [Messaging API rate limits](/docs/messaging/messages/rate-limiting) - [10DLC rate limits](/docs/messaging/10dlc/10dlc-rate-limits) Other products publish limits in their product guides or endpoint descriptions. Do not infer Messaging limits for Voice, Storage, Wireless, or other APIs. ## Related - [Retries and reliability](/docs/development/api-fundamentals/reliability/command-retries) - [API error codes](/docs/development/api-fundamentals/api-errors) - [API troubleshooting](/docs/development/api-fundamentals/troubleshooting) --- ### Retries and reliability > Source: https://developers.telnyx.com/docs/development/api-fundamentals/reliability/command-retries.md A failed connection or timed-out response does not prove that Telnyx failed to process the request. Retry decisions must account for the method, operation semantics, response status, and any product-specific idempotency mechanism. ## Classify the operation - **Read-only requests:** `GET` operations are normally safe to retry when no response was received or a retryable status was returned. - **Idempotent mutations:** Retry only when the endpoint contract or an idempotency mechanism makes repeated execution safe. - **Non-idempotent actions:** Do not automatically retry a timed-out `POST` that can place a call, send a message, purchase a resource, or perform another side effect. First reconcile the resource or action state. Consult the endpoint reference and product guide for supported idempotency fields such as `command_id` or an idempotency key. Do not invent or send an idempotency header that the endpoint does not declare. ## Decide by failure class - `400`, `401`, `403`, `404`, and `422`: Correct the request, credential, access, or resource state. Do not retry unchanged input. - `409`: Reconcile current state and follow endpoint-specific conflict guidance. - `429`: Delay according to the rate-limit response and retry within a bounded policy. - `500`, `502`, `503`, and `504`: Retry only when the operation is safe to repeat. - Connection reset or timeout before a response: Treat the outcome as unknown for mutating operations. ## Apply bounded exponential backoff Use exponential backoff with jitter: ```text next_delay = random(0, min(max_delay, base_delay × 2^attempt)) ``` Set the maximum attempts, delay per attempt, total elapsed time, and request timeout explicitly. Values depend on the product and operation latency contract. There is no universal Telnyx timeout or retry count. ## Preserve observability Record the endpoint and method, HTTP status and Telnyx error code, request or correlation identifier, product resource identifier, attempt number, delay, and supported idempotency identifier. Do not log credentials or sensitive payloads. ## Use SDK defaults deliberately Server-side SDKs expose retry and timeout controls. Review the language-specific [SDK guides](/docs/development/sdk) before overriding defaults. Application retries and SDK retries can multiply each other; keep one bounded retry budget for the complete operation. ## Related - [Rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting) - [Requests and responses](/docs/development/api-fundamentals/request-response) - [API troubleshooting](/docs/development/api-fundamentals/troubleshooting) --- ### Webhook fundamentals > Source: https://developers.telnyx.com/docs/development/api-fundamentals/webhooks/receiving-webhooks.md Telnyx products send HTTP callbacks when asynchronous events occur. Event schemas, retry schedules, failover behavior, and configuration fields are product-specific. Use this page for the common handling contract, then follow the selected product's webhook reference. ## Delivery contract 1. Preserve the raw request body and request headers. 2. When the selected product documents Ed25519 signing, preserve `telnyx-timestamp` and `telnyx-signature-ed25519`, verify the signature before trusting the event, and reject signatures outside the application's replay window. 3. Record the event identifier and product correlation identifiers. 4. Queue the accepted event and return the product's required success status promptly. 5. Process the event asynchronously and idempotently. Do not depend on single delivery or delivery order. Events can be concurrent, duplicated, delayed, or delivered out of order. Reconcile state using `occurred_at` and product resource identifiers where available. ## Configure the endpoint Configure the primary webhook URL in the corresponding product application or profile. Configure a failover URL when the product supports one. Use an HTTPS endpoint with a valid certificate for production integrations. For local testing, expose a local handler with the [ngrok setup guide](/docs/development/development-tools/ngrok-setup). Do not send production payloads containing sensitive data to public request-inspection services. ## Verify an Ed25519 signature Products that document Telnyx Ed25519 signing use the account's key pair. The public key is available in [Mission Control Portal](https://portal.telnyx.com/#/api-keys/public-key). Follow another signing or validation scheme when the selected product defines one. Verification requires the exact body bytes received by the server. Do not parse and reserialize JSON before verification. Current server-side SDKs provide maintained verification helpers: - [Node.js webhook verification](/docs/development/sdk/node/webhooks) - [Python webhook verification](/docs/development/sdk/python/webhooks) - [Go webhook verification](/docs/development/sdk/golang/webhooks) - [Java webhook verification](/docs/development/sdk/java/webhooks) - [Ruby webhook verification](/docs/development/sdk/ruby/webhooks) - [PHP webhook verification](/docs/development/sdk/php/webhooks) The helpers accept the raw payload and request headers, verify the signature against `TELNYX_PUBLIC_KEY`, and return a parsed event. Treat a verification exception as an invalid or malformed delivery. Parsing helpers whose names include `unsafe` do not verify the signature. Use them only after independent verification or in isolated tests. ## Understand the event envelope Many V2 JSON callbacks use a `data` event envelope: ```json { "data": { "record_type": "event", "event_type": "message.finalized", "id": "4ef8c3a6-4195-4389-b3a6-38e3cb9eb4ae", "occurred_at": "2026-08-19T12:00:00.000Z", "payload": {} }, "meta": { "attempt": 1, "delivered_to": "https://example.com/webhooks/telnyx" } } ``` The envelope is not universal. TeXML callbacks can be form-encoded, and product families can define different fields. Use the [machine-readable webhook event catalog](/data/webhook-events.json) for the exact media type, source specification, and payload schema. ## Acknowledge promptly For event-notification webhooks, follow the selected product's acknowledgment contract after validation and durable queueing. Many products accept any `2xx`. Some products require `200`. Use `200` when the product documentation does not specify another successful status. Telnyx does not use the response body to process ordinary event notifications. TeXML instruction requests and other product-specific callback protocols can use the HTTP response body; follow the relevant product documentation. Avoid database transactions, external API calls, media downloads, and other long-running work before acknowledgment. ## Handle retries and duplicates A delivery can be repeated when an acknowledgment is lost even if the first attempt completed. Use the event `id` as a deduplication key when supplied. Make downstream state changes conditional so replaying the event has no additional effect. Product-specific policies determine retry timing, timeout, and failover destinations. Do not implement one assumed schedule for every Telnyx webhook. ## Preserve observability Record the event identifier and type, `occurred_at`, delivery attempt when present, product resource identifiers, verification result, and queue and processing outcome. Do not log signing keys, full sensitive payloads, or authentication credentials. ## Product references - [Messaging webhooks](/docs/messaging/messages/receiving-webhooks) - [Call Control webhooks](/docs/voice/programmable-voice/voice-api-webhooks) - [Webhook event catalog](/data/webhook-events.json) --- ### Parameters and fields > Source: https://developers.telnyx.com/docs/development/api-fundamentals/data-standards/parameters-fields.md Telnyx V2 REST operations share common naming and value conventions. The selected endpoint's API reference remains authoritative when its schema defines a different format, enum, range, or requirement. ## Data types ### Booleans JSON Boolean values are `true` and `false`, not `1`, `0`, `"true"`, or `"false"`. ### Date-times Date-time fields commonly use UTC ISO 8601 values: ```text YYYY-MM-DDThh:mm:ss.fffZ ``` Endpoint schemas can accept additional ISO 8601 timezone and precision variants. Preserve timezone information when converting values and do not interpret an absent offset as local time unless the endpoint explicitly defines that behavior. ### Times without a date Time-only fields commonly use UTC with millisecond precision: ```text hh:mm:ss.fffZ ``` ### Durations Duration field names include the unit when the endpoint uses a numeric value, for example `retry_timeout_secs` or `retry_timeout_millis`. Confirm the exact field and unit in the endpoint schema. ### Time zones Fields named `timezone` use an IANA Time Zone Database area name when declared by the endpoint, for example `Europe/Berlin` or `America/Chicago`. ## Naming conventions ### Field and enum names JSON field names and string enum values commonly use `snake_case`. Preserve the spelling and case declared by the schema. ### Country codes Fields named `country_code` commonly use uppercase ISO 3166-1 alpha-2 values, for example `DE` or `US`. ### Phone numbers Telephone-number fields commonly use E.164 format, including the leading `+`, for example: ```json { "phone_number": "+18005550199", "country_calling_code": "1", "country_code": "US" } ``` Some protocol-specific fields also accept SIP URIs, alphanumeric sender IDs, short codes, or other identifiers. Follow the endpoint schema rather than applying E.164 universally. ### Addresses Address objects commonly use these fields: ```json { "street_address": "311 W Superior St", "extended_address": "Suite 504", "locality": "Chicago", "administrative_area": "IL", "country_code": "US", "postal_code": "60654" } ``` Required fields and validation vary by country and operation. ## HTTP date headers Date-time values in standard HTTP headers follow the IMF-fixdate format defined by [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110#name-date-time-formats), for example: ```text Sun, 06 Nov 1994 08:49:37 GMT ``` ## Collection query parameters See [Pagination, filtering, and sorting](/docs/development/api-fundamentals/pagination-filtering-sorting). Only use collection parameters declared by the selected endpoint. --- ### Versions and deprecations > Source: https://developers.telnyx.com/docs/development/api-fundamentals/api-versions.md The current Telnyx REST API base URL includes the major version: ```text https://api.telnyx.com/v2 ``` The `/v2` prefix identifies the API family. It does not imply that every product or operation has the same release lifecycle. ## Source of truth Use these sources in order: 1. The current [API reference](/api-reference) for available operations and schemas. 2. Product guides for provisioning, lifecycle, and migration requirements. 3. [Telnyx release notes](https://telnyx.com/release-notes) or migration guides linked from the affected product documentation. 4. The [consolidated OpenAPI specification](https://raw.githubusercontent.com/team-telnyx/openapi/master/openapi/spec3.json) for machine-readable REST contracts. ## Track API changes [Telnyx release notes](https://telnyx.com/release-notes) cover updates across all Telnyx products and services; they are not an API-only deprecation log. Filter the release notes by product, then confirm request and response contracts in the affected product guide and API reference. - Subscribe by email from the release notes page. - Subscribe to the [release notes RSS feed](https://telnyx.com/rss.xml) for automated update monitoring. - Subscribe to [Telnyx Status](https://status.telnyx.com) for service incidents and scheduled maintenance. Status notifications describe operational availability, not API lifecycle changes. ## Deprecation handling When a page or operation is marked deprecated: 1. Identify the documented replacement. 2. Compare request and response schemas rather than changing only the URL. 3. Update error handling, webhook consumers, and SDK method calls affected by the migration. 4. Test against the replacement before removing the old integration. 5. Complete migration before the announced retirement date. Do not begin a new integration with a deprecated or legacy endpoint. ## Breaking and non-breaking changes Additive fields and enum values can appear in API responses. Clients should ignore unknown object fields and handle unexpected enum values defensively where the language permits it. Removing operations, changing required fields, or changing field types requires explicit migration guidance. ## Other interfaces Active product-specific protocols and retired HTTP APIs are not part of the V2 REST contract. See [Other Telnyx interfaces](/docs/development/api-fundamentals/legacy-apis) to distinguish them, and contact Support before modifying an existing integration whose lifecycle is unclear. --- ### Other interfaces > Source: https://developers.telnyx.com/docs/development/api-fundamentals/legacy-apis.md The `https://api.telnyx.com/v2` conventions apply to the current Telnyx REST API. Telnyx also provides active product-specific interfaces with different protocols, authentication, media types, and response contracts. These interfaces are not deprecated merely because they do not use the V2 REST conventions. ## Active product-specific interfaces - **Cloud Storage S3 operations** use S3-compatible credentials and AWS Signature Version 4. Follow [Cloud Storage API endpoints](/docs/cloud-storage/api-endpoints). - **WebRTC clients** use short-lived client tokens and WebRTC signaling rather than a server-side Telnyx API key. - **WebSocket APIs** define connection-specific authentication messages, event schemas, and lifecycle behavior. Follow the selected product's WebSocket guide. - **Webhook deliveries** are inbound callbacks with product-specific validation and acknowledgment contracts. Follow [Webhook fundamentals](/docs/development/api-fundamentals/webhooks/receiving-webhooks) and the selected product's webhook reference. Do not apply V2 REST authentication, JSON envelopes, methods, pagination, or retry behavior to these interfaces unless their own documentation declares the same contract. ## Retired HTTP API inventory **Do not use these HTTP endpoints for new integrations** The endpoints below predate the current V2 REST API. Use the current [API reference](/api-reference) for new integrations. Contact [Telnyx Support](https://support.telnyx.com) before changing an existing integration that still depends on one of them. - `https://api.telnyx.com/origination` - `https://api.telnyx.com/termination` - `https://api.telnyx.com/messaging` - `https://api.telnyx.com/reporting` - `https://api.telnyx.com/security` - `https://api.telnyx.com/account` - `https://api.telnyx.com/caller-information` - `https://api.telnyx.com/LRN` - `https://api.telnyx.com/LRNLookup` - `https://sms.telnyx.com/messages` ## Existing DNS ENUM and XML UDP integrations DNS ENUM and XML UDP behavior is outside the V2 REST contract. Do not infer its lifecycle or migration path from the REST API version. Contact [Telnyx Support](https://support.telnyx.com) before creating or modifying an integration that depends on `api.telnyx.com` or `lrnlookup.telnyx.com` through those protocols. ## Migration No universal one-to-one migration applies to retired or protocol-specific interfaces. Locate the corresponding current product in the [API reference](/api-reference), compare schemas and operational behavior, and validate the replacement in a non-production environment. Use [API versions and deprecations](/docs/development/api-fundamentals/api-versions) for the migration checklist. --- ### Troubleshooting > Source: https://developers.telnyx.com/docs/development/api-fundamentals/troubleshooting.md Start with a minimal read-only request so product provisioning and side effects do not obscure transport or authentication failures: ```bash curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: Bearer $TELNYX_API_KEY" \ --header "Accept: application/json" \ --verbose ``` Redact the `Authorization` header before sharing command output. ## Diagnostic sequence 1. Confirm the request uses `https://api.telnyx.com/v2` and the method/path from the API reference. 2. Confirm the header is exactly `Authorization: Bearer `. 3. Confirm that the environment variable exists in the current process, then confirm the key has not expired or been revoked and belongs to the expected account. 4. Record the HTTP status, Telnyx error `code`, `title`, `detail`, and `source` fields. 5. Compare the request with the endpoint schema, including media type, required fields, formats, and query parameters. 6. Check account level, balance, resource ownership, and product provisioning when authorization fails. 7. Apply rate-limit or retry handling only after classifying the failure. ## Common failures ### 401 Unauthorized Check for a missing Bearer header, truncated or invalid key, revoked key, or an environment variable that was not loaded by the current shell or process. Inspect only whether the variable is present—do not print its secret value. Create or rotate the key only after separating a local environment-loading failure from an API credential failure, then repeat the read-only balance request. ### 403 Forbidden Authentication succeeded, but the operation is not permitted. Check resource ownership, account verification, product capability requirements, provisioning, and restrictions shown in Mission Control Portal. Do not repeatedly retry a `403` without changing the access condition. ### 404 Not Found Confirm the API version, path, and resource identifier. A resource belonging to another account can also be unavailable to the current credential. ### 400 or 422 validation failure Read every member of the `errors` array. Use `source.pointer` for a request-body field and `source.parameter` for a query parameter. Correct the request before retrying. ### 429 Too Many Requests Stop requests in the affected scope and follow [API rate limiting](/docs/development/api-fundamentals/reliability/rate-limiting). Honor `Retry-After` when present. ### 5xx or network failure Check [Telnyx Status](https://status.telnyx.com) and preserve request context. Retry only when the operation is safe according to [API retries and reliability](/docs/development/api-fundamentals/reliability/command-retries). A timed-out mutating request can still have completed. ## Correct common curl mistakes ### Missing `Bearer` scheme Incorrect: ```bash curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: $TELNYX_API_KEY" ``` Correct: ```bash curl --request GET \ --url "https://api.telnyx.com/v2/balance" \ --header "Authorization: Bearer $TELNYX_API_KEY" ``` ### Query strings with square-bracket parameters Quote URLs containing `&` so the shell does not split the command. Also disable curl URL globbing when parameter names contain square brackets. Incorrect: ```bash curl --request GET \ --url https://api.telnyx.com/v2/available_phone_numbers?filter[country_code]=US&filter[locality]=Chicago \ --header "Authorization: Bearer $TELNYX_API_KEY" ``` Correct: ```bash curl --globoff --request GET \ --url "https://api.telnyx.com/v2/available_phone_numbers?filter[country_code]=US&filter[locality]=Chicago" \ --header "Authorization: Bearer $TELNYX_API_KEY" ``` Percent-encoding the brackets as `%5B` and `%5D` is equivalent to using `--globoff`. ## Collect support evidence Provide the UTC timestamp, method and path, HTTP status and Telnyx error code, a returned request or correlation identifier when the response supplies one, redacted request and response bodies, product resource identifiers, and reproduction frequency. Never provide API keys, Bearer headers, webhook signing keys, or unredacted personal data. ## References - [API error codes](/docs/development/api-fundamentals/api-errors) - [Requests and responses](/docs/development/api-fundamentals/request-response) - [Telnyx Support](https://support.telnyx.com) --- ## Server-side SDKs ### Overview > Source: https://developers.telnyx.com/docs/development/sdk.md ## Install an SDK - [TypeScript / Node.js](/docs/development/sdk/node): `npm install telnyx` - [Python](/docs/development/sdk/python): `pip install telnyx` - [Go](/docs/development/sdk/golang): `go get github.com/team-telnyx/telnyx-go/v4` - [Java](/docs/development/sdk/java): add `com.telnyx.sdk:telnyx` from [Maven Central](https://central.sonatype.com/artifact/com.telnyx.sdk/telnyx) - [Ruby](/docs/development/sdk/ruby): `bundle add telnyx` - [PHP](/docs/development/sdk/php): `composer require telnyx/telnyx-php` Create an [API key](/docs/development/api-fundamentals/authentication-and-security), export it as `TELNYX_API_KEY`, and run the language's read-only `GET /balance` method to verify authentication. Each [resource map](/docs/development/sdk/node/resource-map) maps SDK methods to REST operations. ## Coverage and release cadence Telnyx generates the server-side SDKs from the public REST API definition. Resource and method names follow the API model, while each library retains language-specific types and conventions. SDK releases can follow REST API changes at different times. Before adopting a newly released endpoint or field: 1. Update to the current package release. 2. Confirm the generated method and model in the language resource map. 3. Use direct HTTP when an API capability is available before the matching SDK release. ## SDK, CLI, or direct HTTP | Interface | Use for | | --- | --- | | SDK | Application integrations that require typed models, pagination, retries, and structured errors | | [Telnyx CLI](/docs/development/cli) | Shell workflows and automation | | Direct HTTP | Endpoint tests, unsupported runtimes, or API capabilities not yet available in an SDK release | The [API reference](/api-reference) provides endpoint schemas and runnable HTTP and SDK examples. ## Get help Report SDK defects in the corresponding GitHub repository. For account or API behavior issues, contact [Telnyx Support](https://support.telnyx.com). Include the SDK language, package version, affected resource or method, and a minimal reproduction with credentials removed. --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/node.md The official [telnyx](https://www.npmjs.com/package/telnyx) package provides a typed TypeScript and Node.js client generated from the same OpenAPI definition as the [API reference](/api-reference). Request and response types, file uploads, and automatic pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install ```bash npm install telnyx ``` ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://www.npmjs.com/package/telnyx) - [Release history](https://github.com/team-telnyx/telnyx-node/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-node) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/node/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/node/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/node/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/node/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/node/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook helper verifies the signature against your account's public key and parses the payload into a typed event. Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` — the client reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers to `client.webhooks.unwrap()`. Verification needs the exact bytes Telnyx sent, so read the body as text rather than letting the framework parse it first: ```typescript import express from "express"; import Telnyx from "telnyx"; const client = new Telnyx(); // reads TELNYX_API_KEY and TELNYX_PUBLIC_KEY const app = express(); app.post( "/webhooks/telnyx", express.text({ type: "application/json" }), (req, res) => { try { const event = client.webhooks.unwrap(req.body, { headers: req.headers as Record, }); console.log(event.data?.event_type); res.sendStatus(200); } catch { res.sendStatus(400); // signature invalid or payload malformed } }, ); app.listen(3000); ``` `unwrap()` throws when the signature does not match, and returns the parsed event as a typed union of every webhook event the API sends — narrow on `event.data?.event_type` to handle specific events. ## Skipping verification `client.webhooks.unsafeUnwrap(body)` parses a payload without checking the signature. Only use it for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors, retries, and timeouts](/docs/development/sdk/node/errors-and-retries) covers the SDK's error classes. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/node/advanced.md --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/python.md The official [telnyx](https://pypi.org/project/telnyx/) package provides synchronous and asynchronous Python clients generated from the same OpenAPI definition as the [API reference](/api-reference). Typed models, nested parameters, file uploads, and pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install ```bash pip install telnyx ``` ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://pypi.org/project/telnyx/) - [Release history](https://github.com/team-telnyx/telnyx-python/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-python) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/python/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/python/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/python/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/python/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/python/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook helper verifies the signature against your account's public key and parses the payload into a typed event. Webhook verification needs the optional `webhooks` extra: ```bash pip install "telnyx[webhooks]" ``` Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` — the client reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers to `client.webhooks.unwrap()`. Verification needs the exact bytes Telnyx sent, so read the body directly rather than re-serializing parsed JSON: ```python from fastapi import FastAPI, Request, Response from telnyx import Telnyx client = Telnyx() # reads TELNYX_API_KEY and TELNYX_PUBLIC_KEY app = FastAPI() @app.post("/webhooks/telnyx") async def telnyx_webhook(request: Request) -> Response: payload = (await request.body()).decode("utf-8") try: event = client.webhooks.unwrap(payload, headers=request.headers) except Exception: return Response(status_code=400) # signature invalid or payload malformed print(event.data.event_type) return Response(status_code=200) ``` `unwrap()` raises when the signature does not match, and returns the parsed event as a typed union of every webhook event the API sends — check `event.data.event_type` to handle specific events. ## Skipping verification `client.webhooks.unsafe_unwrap(payload)` parses a payload without checking the signature. Only use it for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors, retries, and timeouts](/docs/development/sdk/python/errors-and-retries) covers the SDK's exception hierarchy. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/python/advanced.md --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/golang.md The official [telnyx-go](https://pkg.go.dev/github.com/team-telnyx/telnyx-go/v4) module provides a Go client generated from the same OpenAPI definition as the [API reference](/api-reference). Request fields and unions, response models, options, uploads, and pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install ```bash go get github.com/team-telnyx/telnyx-go/v4 ``` ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://pkg.go.dev/github.com/team-telnyx/telnyx-go/v4) - [Release history](https://github.com/team-telnyx/telnyx-go/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-go) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/golang/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/golang/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/golang/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/golang/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/golang/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook service verifies the signature against your account's public key and parses the payload into a typed event union. Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` — `telnyx.NewClient()` reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers to `client.Webhooks.Unwrap()`: ```go package main import ( "io" "log" "net/http" "github.com/team-telnyx/telnyx-go/v4" ) func main() { client := telnyx.NewClient() // reads TELNYX_API_KEY and TELNYX_PUBLIC_KEY http.HandleFunc("/webhooks/telnyx", func(w http.ResponseWriter, r *http.Request) { payload, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) return } event, err := client.Webhooks.Unwrap(payload, r.Header) if err != nil { // signature invalid or payload malformed w.WriteHeader(http.StatusBadRequest) return } log.Println(event.Data.EventType) w.WriteHeader(http.StatusOK) }) log.Fatal(http.ListenAndServe(":3000", nil)) } ``` `Unwrap()` returns an error when the signature does not match, and returns the parsed event as a union of every webhook event the API sends — switch on `event.Data.EventType` or use the union's `As...()` accessors to handle specific events. `client.Webhooks.Verify(payload, headers)` checks the signature without parsing. ## Skipping verification `client.Webhooks.UnsafeUnwrap(payload)` parses a payload without checking the signature. Only use it for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors, retries, and timeouts](/docs/development/sdk/golang/errors-and-retries) covers the SDK's error types. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/golang/advanced.md --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/java.md The official [telnyx](https://central.sonatype.com/artifact/com.telnyx.sdk/telnyx) package provides Java and Kotlin-compatible clients generated from the same OpenAPI definition as the [API reference](/api-reference). Immutable request and response models, uploads, raw responses, and pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install Add `com.telnyx.sdk:telnyx` to the Gradle or Maven build using the current version published on [Maven Central](https://central.sonatype.com/artifact/com.telnyx.sdk/telnyx). ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://central.sonatype.com/artifact/com.telnyx.sdk/telnyx) - [Release history](https://github.com/team-telnyx/telnyx-java/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-java) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/java/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/java/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/java/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/java/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/java/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook service verifies the signature against your account's public key and parses the payload into a typed event. Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` (or the `telnyx.publicKey` system property) — `TelnyxOkHttpClient.fromEnv()` reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers from your HTTP framework to `client.webhooks().unwrap()`: ```java import java.util.List; import java.util.Map; import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; import com.telnyx.sdk.core.UnwrapWebhookParams; import com.telnyx.sdk.core.http.Headers; import com.telnyx.sdk.errors.TelnyxWebhookException; import com.telnyx.sdk.models.webhooks.UnwrapWebhookEvent; public class TelnyxWebhookHandler { private final TelnyxClient client = TelnyxOkHttpClient.fromEnv(); // Call with the raw request body and headers from your HTTP framework. public void handle(String body, Map> requestHeaders) { Headers headers = Headers.builder().putAll(requestHeaders).build(); try { UnwrapWebhookEvent event = client.webhooks().unwrap( UnwrapWebhookParams.builder() .body(body) .headers(headers) .build()); // Handle the typed event. } catch (TelnyxWebhookException e) { // Signature invalid — respond with HTTP 400. } } } ``` `unwrap(UnwrapWebhookParams)` throws `TelnyxWebhookException` when the signature does not match and `TelnyxInvalidDataException` when the payload cannot be parsed. ## Skipping verification `client.webhooks().unsafeUnwrap(body)` — and the single-argument `unwrap(String body)` overload — parse a payload without checking the signature. Only use them for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors, retries, and timeouts](/docs/development/sdk/java/errors-and-retries) covers the SDK's exception hierarchy. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/java/advanced.md --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/ruby.md The official [telnyx](https://rubygems.org/gems/telnyx) gem provides a Ruby client generated from the same OpenAPI definition as the [API reference](/api-reference). Models, Sorbet types, file uploads, and pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install ```bash bundle add telnyx ``` ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://rubygems.org/gems/telnyx) - [Release history](https://github.com/team-telnyx/telnyx-ruby/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-ruby) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/ruby/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/ruby/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/ruby/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/ruby/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/ruby/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook helper verifies the signature against your account's public key and parses the payload into a typed event. Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` — the client reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers to `client.webhooks.unwrap`. Rack prefixes and upcases incoming header names, so convert them back before passing them in: ```ruby require "sinatra" require "telnyx" client = Telnyx::Client.new # reads TELNYX_API_KEY and TELNYX_PUBLIC_KEY post "/webhooks/telnyx" do payload = request.body.read headers = request.env .select { |name, _| name.start_with?("HTTP_") } .transform_keys { |name| name.delete_prefix("HTTP_").downcase.tr("_", "-") } begin event = client.webhooks.unwrap(payload, headers: headers) rescue StandardError halt 400 # signature invalid or payload malformed end puts event.data.event_type 200 end ``` `unwrap` raises when the signature does not match, and returns the parsed event as a typed union of every webhook event the API sends — check `event.data.event_type` to handle specific events. ## Skipping verification `client.webhooks.unsafe_unwrap(payload)` parses a payload without checking the signature. Only use it for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors, retries, and timeouts](/docs/development/sdk/ruby/errors-and-retries) covers the SDK's error classes. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/ruby/advanced.md --- ### Overview and quickstart > Source: https://developers.telnyx.com/docs/development/sdk/php.md The official [telnyx/telnyx-php](https://packagist.org/packages/telnyx/telnyx-php) package provides a PHP client generated from the same OpenAPI definition as the [API reference](/api-reference). Value objects, file uploads, and pagination. Search every SDK resource and method and open the matching REST endpoint. Handle structured errors and configure retry and timeout behavior. Verify ED25519 signatures and process webhook events. Configure language-specific logging, transport, raw responses, and custom requests. ## Install ```bash composer require telnyx/telnyx-php ``` ## Initialize the client and make a request Quickstart from the current SDK source, using `TELNYX_API_KEY` for authentication: ## Source and releases - [Package and current version](https://packagist.org/packages/telnyx/telnyx-php) - [Release history](https://github.com/team-telnyx/telnyx-php/releases) - [Source and issue tracker](https://github.com/team-telnyx/telnyx-php) SDK releases can follow REST API changes at different times. Check the package registry for the current version and use the [resource map](/docs/development/sdk/php/resource-map) to confirm method availability. --- ### Requests, types, and pagination > Source: https://developers.telnyx.com/docs/development/sdk/php/requests-and-types.md --- ### Resource map > Source: https://developers.telnyx.com/docs/development/sdk/php/resource-map.md --- ### Errors and retries > Source: https://developers.telnyx.com/docs/development/sdk/php/errors-and-retries.md --- ### Webhooks > Source: https://developers.telnyx.com/docs/development/sdk/php/webhooks.md Telnyx signs every webhook delivery with an ED25519 signature carried in the `telnyx-signature-ed25519` and `telnyx-timestamp` request headers. The SDK's webhook service verifies the signature against your account's public key and parses the payload into a typed event. Copy your public key from the Mission Control Portal and expose it as `TELNYX_PUBLIC_KEY` — the client reads it automatically, the same way it reads `TELNYX_API_KEY`: ```bash export TELNYX_PUBLIC_KEY="..." ``` ## Verify and parse an event Pass the raw request body and the request headers to `$client->webhooks->unwrap()`: ```php webhooks->unwrap($body, getallheaders()); } catch (WebhookException $e) { http_response_code(400); // signature invalid or payload malformed exit; } http_response_code(200); ``` `unwrap()` throws `WebhookException` when the signature does not match or the payload cannot be parsed, and returns the event as a typed union of every webhook event the API sends. ## Skipping verification `$client->webhooks->unsafeUnwrap($body)` parses a payload without checking the signature. Only use it for payloads you have already verified by other means, or in tests. ## Related - [Receiving webhooks](/docs/development/api-fundamentals/webhooks/receiving-webhooks) covers delivery, retries, and failover URLs. - [Errors and retries](/docs/development/sdk/php/errors-and-retries) covers the SDK's exception classes. --- ### Advanced > Source: https://developers.telnyx.com/docs/development/sdk/php/advanced.md --- ## Telnyx CLI ### Overview > Source: https://developers.telnyx.com/docs/development/cli.md The Telnyx CLI is the official command-line interface for managing Telnyx resources directly from your terminal. Send messages, manage phone numbers, control calls, and more — all without leaving the command line. ## When to Use the CLI vs the API | Use Case | CLI | API | |----------|-----|-----| | Quick manual tasks | ✅ Best choice | Overkill | | Scripting & automation | ✅ Great for bash/shell | ✅ Better for complex logic | | CI/CD pipelines | ✅ Simple integrations | ✅ Full control | | Production applications | ❌ Not recommended | ✅ Use SDKs or direct API | | Exploring the API | ✅ Fast iteration | Slower feedback loop | The CLI is ideal for operators, developers exploring the API, and simple automation. For production applications, use the [Telnyx SDKs](/docs/development/sdk) or call the [REST API](/internal/pages/api-reference-overview) directly. Building an AI agent, or want zero-to-working-capability in one command? The [Telnyx Agent CLI](/docs/development/cli/agent-cli) (`@telnyx/agent-cli`) provides composite setup commands — `setup-sms`, `setup-voice`, `setup-ai` — that collapse multi-step workflows into a single call. The two CLIs install side by side. ## Features Access all Telnyx APIs — messaging, voice, numbers, 10DLC, AI, verification, storage, and more JSON, YAML, pretty-print, and raw output for scripting and human readability Always in sync with the latest Telnyx API endpoints Inspect HTTP requests and responses for troubleshooting ## Quick Example ```bash # Set your API key export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx # List your phone numbers telnyx phone-numbers list # Search for available phone numbers telnyx available-phone-numbers list --filter.country-code US # Send an SMS telnyx messages send --from +15551234567 --to +15559876543 --text "Hello from CLI!" # Check your balance telnyx balance retrieve ``` ## Installation Install via Go: ```bash go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` Requires [Go 1.22+](https://go.dev/doc/install). After installation, ensure `$GOPATH/bin` is in your PATH. Detailed installation instructions and troubleshooting ## Documentation Get up and running in 5 minutes Configure your API key Output formats, filtering, and scripting Full list of all CLI commands ## Resources View source, report issues, and contribute Release notes and version history Full API documentation (CLI wraps these endpoints) --- ### Install > Source: https://developers.telnyx.com/docs/development/cli/getting-started/install.md The Telnyx CLI is supported on macOS, Windows, and Linux. The Telnyx CLI requires **Go 1.22 or later**. If you don't have Go installed, follow the [official installation guide](https://go.dev/doc/install). ## Installation Install the CLI using Go: ```bash go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` This downloads, compiles, and installs the `telnyx` binary to your Go bin directory. ## Add to PATH After installation, ensure the Go bin directory is in your PATH: ```bash # Check your Go bin path go env GOPATH # Add to your shell profile (~/.bashrc, ~/.zshrc, etc.) export PATH="$PATH:$(go env GOPATH)/bin" ``` Reload your shell or restart your terminal for changes to take effect. ## Verify Installation ```bash telnyx --version ``` You should see output similar to: ``` telnyx version 0.1.0 ``` ## Update To update to the latest version, run the install command again: ```bash go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` ## Alternative: Run Without Installing You can run the CLI directly without installing: ```bash go run github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest --help ``` ## Troubleshooting ### "command not found: telnyx" If the command isn't found after installation: 1. Verify Go's bin directory: ```bash ls $(go env GOPATH)/bin/telnyx ``` 2. Add Go bin to your PATH: ```bash export PATH="$PATH:$(go env GOPATH)/bin" ``` 3. Reload your shell config: ```bash source ~/.bashrc # or ~/.zshrc ``` ### "command not found: go" Install Go first: - **macOS**: `brew install go` - **Linux**: Use your package manager or download from [go.dev](https://go.dev/dl/) - **Windows**: Download the installer from [go.dev](https://go.dev/dl/) ### Build errors If you encounter build errors: 1. Ensure you have Go 1.22+: ```bash go version ``` 2. Clear Go's module cache and retry: ```bash go clean -modcache go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` ## Next Steps Configure authentication and run your first commands Full list of all CLI commands --- --- ### Quickstart > Source: https://developers.telnyx.com/docs/development/cli/getting-started/quickstart.md This quickstart guide will help you install the Telnyx CLI, configure authentication, and run your first commands. ## Prerequisites - [Go 1.22+](https://go.dev/doc/install) installed - A [Telnyx account](https://portal.telnyx.com/) - A [Telnyx API key](https://portal.telnyx.com/#/app/api-keys) ## Step 1: Install the CLI ```bash go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` Ensure Go's bin directory is in your PATH: ```bash export PATH="$PATH:$(go env GOPATH)/bin" ``` Verify the installation: ```bash telnyx --version ``` ## Step 2: Configure Authentication Set your API key as an environment variable. You can get your API key from the [Telnyx Portal](https://portal.telnyx.com/#/app/api-keys). ```bash export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` Add this line to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.) to persist it across sessions. ### Verify Authentication Test that your credentials are working: ```bash telnyx balance retrieve ``` You should see your account balance information. ## Step 3: Run Your First Commands ### Check Your Balance ```bash telnyx balance retrieve ``` ### List Your Phone Numbers ```bash telnyx phone-numbers list ``` ### Search for Available Numbers ```bash telnyx available-phone-numbers list --filter.country-code US --filter.limit 5 ``` ### Send a Test Message You'll need a [messaging-enabled phone number](https://portal.telnyx.com/#/app/numbers/my-numbers) and a configured [messaging profile](https://portal.telnyx.com/#/app/messaging). ```bash telnyx messages send \ --from +15551234567 \ --to +15559876543 \ --text "Hello from the Telnyx CLI!" ``` ## Step 4: Explore Commands ### Get Help ```bash # List all commands telnyx --help # Get help for a specific resource telnyx phone-numbers --help telnyx messages --help # Get help for a specific action telnyx messages send --help ``` ## Common Commands | Command | Description | |---------|-------------| | `telnyx phone-numbers list` | List your phone numbers | | `telnyx available-phone-numbers list` | Search available numbers | | `telnyx number-orders create` | Purchase phone numbers | | `telnyx messages send` | Send an SMS/MMS message | | `telnyx calls dial` | Initiate an outbound call | | `telnyx balance retrieve` | Check account balance | | `telnyx messaging-10dlc:brand list` | List 10DLC brands | | `telnyx messaging-10dlc:campaign list` | List 10DLC campaigns | | `telnyx ai:chat create-completion` | Chat with AI models | | `telnyx ai:assistants list` | List AI assistants | ## Output Formats The CLI supports multiple output formats: ```bash # Auto format (default, interactive exploration) telnyx phone-numbers list # JSON format (for scripting) telnyx phone-numbers list --format json # YAML format telnyx phone-numbers list --format yaml # Pretty-print JSON telnyx phone-numbers list --format pretty # Filter output with GJSON telnyx phone-numbers list --format json --transform "0.phone_number" ``` ## Debug Mode To see full HTTP request/response details: ```bash telnyx phone-numbers list --debug ``` ## Next Steps Learn about authentication options Output formats, scripting, and CI/CD integration --- --- ### Authentication > Source: https://developers.telnyx.com/docs/development/cli/getting-started/authentication.md The Telnyx CLI authenticates using an API key set via environment variable. ## Setting Your API Key Set the `TELNYX_API_KEY` environment variable: ```bash export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` Add this line to your shell profile (`~/.bashrc`, `~/.zshrc`, etc.) to persist it across terminal sessions. ## Verify Authentication Test that your credentials are working by running any command: ```bash telnyx balance retrieve ``` If authenticated successfully, you'll see your account balance. If not, you'll receive an authentication error. ## Getting Your API Key 1. Log in to the [Telnyx Portal](https://portal.telnyx.com/) 2. Navigate to [API Keys](https://portal.telnyx.com/#/app/api-keys) 3. Click **Create API Key** 4. Copy the key (it won't be shown again) API keys start with `KEY_`. If you're using a v1 API key (starting with a different prefix), you'll need to create a new v2 key. ## Multiple Accounts If you work with multiple Telnyx accounts (e.g., production and staging), you have several options: ### Option 1: Shell Aliases Create aliases for different accounts: ```bash # Add to ~/.bashrc or ~/.zshrc alias telnyx-prod='TELNYX_API_KEY=KEY_production_xxx telnyx' alias telnyx-staging='TELNYX_API_KEY=KEY_staging_xxx telnyx' ``` Usage: ```bash telnyx-prod phone-numbers list telnyx-staging phone-numbers list ``` ### Option 2: Separate Terminal Sessions Set different API keys in different terminal windows: ```bash # Terminal 1 (Production) export TELNYX_API_KEY=KEY_production_xxx # Terminal 2 (Staging) export TELNYX_API_KEY=KEY_staging_xxx ``` ### Option 3: Inline Override Override the API key for a single command: ```bash TELNYX_API_KEY=KEY_other_xxx telnyx balance retrieve ``` ## CI/CD Integration ### GitHub Actions ```yaml name: Deploy Notification on: deployment: types: [completed] jobs: notify: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Install Telnyx CLI run: go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest - name: Send SMS notification env: TELNYX_API_KEY: ${{ secrets.TELNYX_API_KEY }} run: | telnyx messages send \ --from "${{ vars.TELNYX_NUMBER }}" \ --to "${{ vars.ONCALL_NUMBER }}" \ --text "✅ Deployment complete: ${{ github.repository }}" ``` ### GitLab CI ```yaml notify: image: golang:1.22 script: - go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest - export PATH="$PATH:$(go env GOPATH)/bin" - telnyx messages send --from $FROM_NUMBER --to $TO_NUMBER --text "Build complete" variables: TELNYX_API_KEY: $TELNYX_API_KEY ``` ### Shell Scripts ```bash #!/bin/bash # deploy-notify.sh # Load from environment or secrets manager export TELNYX_API_KEY="${TELNYX_API_KEY:-$(vault read -field=api_key secret/telnyx)}" telnyx messages send \ --from "+15551234567" \ --to "+15559876543" \ --text "Deployment complete at $(date)" ``` ## Security Best Practices Use environment variables or secrets management. Add `.env` files to `.gitignore`. Create different API keys for production, staging, and development. This limits blast radius if a key is compromised. Regenerate API keys periodically and update your configurations. Store API keys in GitHub Secrets, GitLab CI Variables, AWS Secrets Manager, HashiCorp Vault, etc. ## Troubleshooting ### "Unauthorized" Error ``` Error: Request failed with status 401: Unauthorized ``` **Solutions:** - Verify your API key is set: `echo $TELNYX_API_KEY` - Check if the key starts with `KEY_` - Verify the key hasn't been revoked in the [Portal](https://portal.telnyx.com/#/app/api-keys) - Ensure there are no extra spaces or characters in the key ### "No API key" Error **Solutions:** - Set the environment variable: `export TELNYX_API_KEY=KEY_xxx` - Check for typos in the variable name - Ensure the variable is exported (not just set) ## Next Steps Run your first CLI commands Output formats, scripting, and CI/CD --- --- ### Scripting & Automation > Source: https://developers.telnyx.com/docs/development/cli/general-usage.md This guide covers common patterns for automating workflows with the Telnyx CLI — output formats, filtering, and integration with scripts and CI/CD pipelines. ## Output Formats The CLI supports multiple output formats via the `--format` flag. ### Auto Format (Default) Interactive exploration mode, best for browsing data: ```bash telnyx phone-numbers list ``` ### JSON Format Machine-readable output for scripting and automation: ```bash telnyx phone-numbers list --format json ``` ### YAML Format Human-readable structured output: ```bash telnyx phone-numbers list --format yaml ``` ### Pretty Format Indented, colorized JSON: ```bash telnyx phone-numbers list --format pretty ``` ### Raw Format Unformatted API response: ```bash telnyx phone-numbers list --format raw ``` ### All Format Options | Format | Description | Best For | |--------|-------------|----------| | `auto` | Interactive exploration (default) | Browsing data | | `json` | Compact JSON | Scripting, piping to jq | | `jsonl` | JSON Lines (one object per line) | Streaming, large datasets | | `pretty` | Indented, colorized JSON | Debugging | | `yaml` | YAML format | Human-readable configs | | `raw` | Unformatted API response | Debugging | ## Transforming Output with GJSON Use `--transform` to extract specific fields using [GJSON syntax](https://github.com/tidwall/gjson/blob/master/SYNTAX.md): ```bash # Get first phone number telnyx phone-numbers list --format json --transform "data.0.phone_number" # Get all phone numbers as array telnyx phone-numbers list --format json --transform "data.#.phone_number" # Filter by status telnyx phone-numbers list --format json --transform 'data.#(status=="active")#' ``` ### Filtering JSON with jq Combine with [jq](https://jqlang.github.io/jq/) for powerful filtering: ```bash # Get just phone numbers telnyx phone-numbers list --format json | jq -r '.data[].phone_number' # Count active numbers telnyx phone-numbers list --format json | jq '[.data[] | select(.status == "active")] | length' ``` ## Pagination List commands support pagination via filter parameters: ```bash # Limit results telnyx phone-numbers list --page-size 10 # Paginate through results telnyx phone-numbers list --page-size 50 --page-number 2 ``` ## Filtering Most list commands support filtering via individual `--filter.*` flags: ```bash # Filter numbers by status telnyx phone-numbers list --filter.status active # Filter by country (note: kebab-case, not snake_case) telnyx available-phone-numbers list --filter.country-code US # Multiple filters telnyx phone-numbers list --filter.status active --filter.country-iso-alpha2 US # Filter with features telnyx available-phone-numbers list --filter.country-code US --filter.features '[sms]' ``` Filter flag names use **kebab-case** (e.g., `--filter.country-code`, not `--filter.country_code`). ## Global Flags These flags work with all commands: | Flag | Description | |------|-------------| | `--format ` | Output format (auto, json, jsonl, pretty, yaml, raw) | | `--format-error ` | Error output format | | `--transform ` | Transform output with GJSON | | `--debug` | Show HTTP request/response details | | `--base-url ` | Override API base URL | | `--help` | Show help for the command | | `--version` | Show CLI version | ## Environment Variables | Variable | Description | |----------|-------------| | `TELNYX_API_KEY` | API key (required) | ## Scripting Examples ### Bash: Bulk SMS Send ```bash #!/bin/bash # send-bulk-sms.sh FROM="+15551234567" NUMBERS=("15559876543" "15551112222" "15553334444") MESSAGE="Your appointment is confirmed for tomorrow." for number in "${NUMBERS[@]}"; do telnyx messages send --from "$FROM" --to "+$number" --text "$MESSAGE" echo "Sent to +$number" sleep 0.5 # Rate limiting done ``` ### Bash: Export Numbers to CSV ```bash #!/bin/bash # export-numbers.sh echo "phone_number,status,connection_id" > numbers.csv telnyx phone-numbers list --format json | \ jq -r '.data[] | [.phone_number, .status, .connection_id] | @csv' >> numbers.csv echo "Exported to numbers.csv" ``` ### Bash: Monitor Account Balance ```bash #!/bin/bash # check-balance.sh THRESHOLD=100 balance=$(telnyx balance retrieve --format json | jq -r '.data.balance') balance_int=${balance%.*} if [ "$balance_int" -lt "$THRESHOLD" ]; then echo "⚠️ Low balance warning: \$$balance" # Send alert, etc. else echo "✓ Balance OK: \$$balance" fi ``` ### GitHub Actions: Deploy Notification ```yaml name: Deploy Notification on: deployment: types: [completed] jobs: notify: runs-on: ubuntu-latest steps: - name: Install Go uses: actions/setup-go@v5 with: go-version: '1.22' - name: Install Telnyx CLI run: | go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest echo "$(go env GOPATH)/bin" >> $GITHUB_PATH - name: Send SMS notification env: TELNYX_API_KEY: ${{ secrets.TELNYX_API_KEY }} run: | telnyx messages send \ --from "${{ vars.TELNYX_NUMBER }}" \ --to "${{ vars.ONCALL_NUMBER }}" \ --text "✅ Deployment complete: ${{ github.repository }}@${{ github.sha }}" ``` ## Debug Mode To inspect the full HTTP request and response: ```bash telnyx phone-numbers list --debug ``` This is useful for: - Troubleshooting authentication issues - Understanding the exact API calls being made - Debugging unexpected responses ## Next Steps Full list of all commands Common issues and solutions --- --- ### Command Reference > Source: https://developers.telnyx.com/docs/development/cli/reference.md This page provides a comprehensive reference for all available CLI commands. Use `telnyx --help` for detailed options. This reference documents the current Go-based [Telnyx CLI](https://github.com/team-telnyx/telnyx-cli), which uses plural resource names such as `telnyx messages`. The deprecated Node.js `@telnyx/api-cli` uses singular resource names such as `telnyx message` and supports short flags such as `-f` and `-t`. See the [legacy command reference](/docs/development/cli/legacy/reference) for that syntax. The CLI is auto-generated from the [Telnyx REST API](/internal/pages/api-reference-overview). For full request/response schemas, see the corresponding API reference for each resource. ## Global Options These flags work with all commands: ```bash --debug # Enable debug logging (shows HTTP requests/responses) --base-url # Override the API base URL --format # Output format: auto, json, jsonl, pretty, yaml, raw --format-error # Error output format --transform # Transform output using GJSON syntax --help, -h # Show help --version, -v # Show version ``` ## Phone Numbers See [Phone Numbers API](/api-reference/phone-number-configurations/list-phone-numbers) for full response schemas. ### List & Manage Numbers ```bash # List your phone numbers telnyx phone-numbers list telnyx phone-numbers list --filter.status active telnyx phone-numbers list --page-size 50 # Get number details telnyx phone-numbers retrieve --id # Update number settings telnyx phone-numbers update --phone-number-id --connection-id # Delete a number telnyx phone-numbers delete --id ``` ### Search Available Numbers ```bash # Search available numbers telnyx available-phone-numbers list --filter.country-code US telnyx available-phone-numbers list --filter.country-code US --filter.limit 10 telnyx available-phone-numbers list --filter.country-code US --filter.locality "San Francisco" # Search number blocks telnyx available-phone-number-blocks list --filter.country-code US ``` ### Purchase Numbers ```bash # Create a number order telnyx number-orders create --phone-number '{phone_number: +15551234567}' telnyx number-orders create --phone-number '{phone_number: +15551234567}' --messaging-profile-id # List/retrieve orders telnyx number-orders list telnyx number-orders retrieve --number-order-id ``` ### Number Reservations ```bash telnyx number-reservations create --phone-number '{phone_number: +15551234567}' telnyx number-reservations list telnyx number-reservations retrieve --number-reservation-id ``` ## Messaging See [Messaging API](/api-reference/messages/send-a-message) for full payload options. ### Send Messages ```bash # Send SMS telnyx messages send --from +15551234567 --to +15559876543 --text "Hello!" # Send MMS telnyx messages send --from +15551234567 --to +15559876543 \ --text "Check this out" \ --media-url https://example.com/image.jpg # Send WhatsApp message telnyx messages whatsapp --from +15551234567 --to +15559876543 \ --type WHATSAPP --whatsapp-message '{text: {body: "Hello!"}}' # Schedule a message # Set SEND_AT to an ISO 8601 timestamp at least one minute in the future telnyx messages schedule --from +15551234567 --to +15559876543 \ --text "Reminder!" --send-at "$SEND_AT" # Cancel scheduled message telnyx messages cancel-scheduled --id ``` ### Retrieve Messages ```bash telnyx messages retrieve --id ``` ### Messaging Profiles ```bash telnyx messaging-profiles list telnyx messaging-profiles retrieve --messaging-profile-id telnyx messaging-profiles create --name "Production" --whitelisted-destination '["*"]' telnyx messaging-profiles update --messaging-profile-id --name "Updated Name" telnyx messaging-profiles delete --messaging-profile-id # List associated phone numbers telnyx messaging-profiles list-phone-numbers --messaging-profile-id ``` ### Optouts ```bash telnyx messaging-optouts list ``` ## 10DLC (US A2P Messaging) See [10DLC documentation](/docs/messaging/10dlc/quickstart) for registration requirements. ### Brands ```bash # List brands telnyx messaging-10dlc:brand list # Create brand telnyx messaging-10dlc:brand create \ --entity-type PRIVATE_PROFIT \ --display-name "My Company" \ --company-name "My Company Inc" \ --email "support@example.com" \ --ein 12-3456789 \ --phone +15551234567 \ --street "123 Main St" \ --city "San Francisco" \ --state CA \ --postal-code 94102 \ --country US \ --vertical TECHNOLOGY \ --website https://example.com # Retrieve/update brand (update requires the full set of required brand fields) telnyx messaging-10dlc:brand retrieve --brand-id telnyx messaging-10dlc:brand update --brand-id \ --display-name "New Name" \ --email "support@example.com" \ --entity-type PRIVATE_PROFIT \ --country US \ --vertical TECHNOLOGY # Revet brand (resubmit for verification) telnyx messaging-10dlc:brand revet --brand-id # SMS OTP verification for sole proprietor telnyx messaging-10dlc:brand trigger-sms-otp --brand-id \ --pin-sms "Your verification PIN is @OTP_PIN@" \ --success-sms "Your brand has been verified" telnyx messaging-10dlc:brand verify-sms-otp --brand-id --otp-pin 123456 # Get brand feedback telnyx messaging-10dlc:brand get-feedback --brand-id # Delete brand telnyx messaging-10dlc:brand delete --brand-id ``` ### Campaigns ```bash # List campaigns telnyx messaging-10dlc:campaign list --brand-id # Retrieve campaign telnyx messaging-10dlc:campaign retrieve --campaign-id # Update campaign (only sample messages editable) telnyx messaging-10dlc:campaign update --campaign-id --sample1 "New sample" # Get campaign operation status telnyx messaging-10dlc:campaign get-operation-status --campaign-id # Deactivate campaign telnyx messaging-10dlc:campaign deactivate --campaign-id # Submit appeal for rejected campaign telnyx messaging-10dlc:campaign submit-appeal --campaign-id \ --appeal-reason "Detailed explanation of the changes made to address the rejection" ``` ### Use Cases ```bash # Get the upfront and monthly cost for a use case telnyx messaging-10dlc:campaign:usecase get-cost --usecase MARKETING ``` ### Phone Number Campaigns ```bash telnyx messaging-10dlc:phone-number-campaigns list telnyx messaging-10dlc:phone-number-campaigns retrieve --phone-number +15551234567 ``` ## Voice / Call Control See [Call Control API](/docs/voice/programmable-voice/voice-api-fundamentals) for advanced call flow options. ### Make Calls ```bash # Dial outbound call telnyx calls dial \ --connection-id \ --from +15551234567 \ --to +15559876543 # With answering machine detection telnyx calls dial \ --connection-id \ --from +15551234567 \ --to +15559876543 \ --answering-machine-detection detect ``` ### Call Status ```bash telnyx calls retrieve-status --call-control-id ``` ### Call Actions ```bash # Answer incoming call telnyx calls:actions answer --call-control-id # Hang up telnyx calls:actions hangup --call-control-id # Transfer call telnyx calls:actions transfer --call-control-id --to +15559876543 # Bridge two calls telnyx calls:actions bridge --call-control-id-to-bridge --call-control-id-to-bridge-with # Play audio telnyx calls:actions start-playback --call-control-id --audio-url https://... # Stop audio telnyx calls:actions stop-playback --call-control-id # Text-to-speech telnyx calls:actions speak --call-control-id \ --payload "Hello, how can I help?" --voice AWS.Polly.Joanna # Gather DTMF input telnyx calls:actions gather --call-control-id --minimum-digits 1 --maximum-digits 4 # Send DTMF telnyx calls:actions send-dtmf --call-control-id --digits "1234" # Start recording telnyx calls:actions start-recording --call-control-id --channels single --format mp3 # Stop recording telnyx calls:actions stop-recording --call-control-id # Start transcription telnyx calls:actions start-transcription --call-control-id # Stop transcription telnyx calls:actions stop-transcription --call-control-id # Start AI assistant telnyx calls:actions start-ai-assistant --call-control-id --assistant '{id: }' # Stop AI assistant telnyx calls:actions stop-ai-assistant --call-control-id ``` ### Call Control Applications ```bash telnyx call-control-applications list telnyx call-control-applications retrieve --id telnyx call-control-applications create --application-name "My App" --webhook-event-url https://... telnyx call-control-applications update --id --application-name "Updated" --webhook-event-url https://... telnyx call-control-applications delete --id ``` ### Conferences ```bash telnyx conferences list telnyx conferences retrieve --id telnyx conferences create --call-control-id --name "Team Call" # Conference actions telnyx conferences:actions join --id --call-control-id telnyx conferences:actions mute --id --call-control-id --call-control-id telnyx conferences:actions unmute --id --call-control-id --call-control-id ``` ### Recordings ```bash telnyx recordings list telnyx recordings retrieve --recording-id telnyx recordings delete --recording-id # Transcriptions telnyx recording-transcriptions list telnyx recording-transcriptions retrieve --recording-transcription-id ``` ## AI ### Chat Completions ```bash telnyx ai:openai:chat create-completion --model meta-llama/Meta-Llama-3.1-8B-Instruct \ --message '{role: user, content: "Hello!"}' ``` ### AI Assistants ```bash # List/create assistants telnyx ai:assistants list telnyx ai:assistants create --name "My Assistant" \ --model meta-llama/Meta-Llama-3.1-8B-Instruct \ --instructions "You are a helpful assistant" telnyx ai:assistants retrieve --assistant-id telnyx ai:assistants update --assistant-id --name "Updated" telnyx ai:assistants delete --assistant-id # Chat with assistant telnyx ai:assistants chat --assistant-id --conversation-id --content "Hello!" # Clone assistant telnyx ai:assistants clone --assistant-id ``` ### Audio (Speech-to-Text / Text-to-Speech) ```bash # Transcribe audio telnyx ai:audio transcribe --file-url https://example.com/audio.mp3 \ --model openai/whisper-large-v3-turbo # Text-to-speech telnyx text-to-speech generate-speech --text "Hello world" --voice Telnyx.Ultra.Clara ``` ### Embeddings ```bash # Embed raw text (OpenAI-compatible endpoint) telnyx ai:openai:embeddings create-embeddings --input "Your text here" --model # Embed the contents of a storage bucket telnyx ai:embeddings create --bucket-name my-bucket ``` ### Conversations ```bash telnyx ai:conversations list telnyx ai:conversations create --name "Support chat" telnyx ai:conversations retrieve --conversation-id telnyx ai:conversations:messages list --conversation-id ``` ## Verify (2FA) ### Profiles ```bash telnyx verify-profiles list telnyx verify-profiles retrieve --verify-profile-id telnyx verify-profiles create --name "my-app" --sms '{default_verification_timeout_secs: 300}' telnyx verify-profiles update --verify-profile-id --name "updated" telnyx verify-profiles delete --verify-profile-id # Message templates (account-wide) telnyx verify-profiles create-template --text "Your code is {{code}}" telnyx verify-profiles retrieve-templates ``` ### Send Verification ```bash # Trigger SMS verification telnyx verifications trigger-sms --phone-number +15551234567 --verify-profile-id # Trigger voice call verification telnyx verifications trigger-call --phone-number +15551234567 --verify-profile-id # Trigger flash call verification telnyx verifications trigger-flashcall --phone-number +15551234567 --verify-profile-id # Retrieve verification status telnyx verifications retrieve --verification-id ``` ### Verify Code ```bash telnyx verifications:actions verify --verification-id --code 123456 ``` ## Fax ```bash # Send fax telnyx faxes create \ --connection-id \ --from +15551234567 \ --to +15559876543 \ --media-url https://example.com/document.pdf # List/retrieve faxes telnyx faxes list telnyx faxes retrieve --id telnyx faxes delete --id ``` ## Number Lookup ```bash telnyx number-lookup retrieve --phone-number +15551234567 ``` ## Billing ```bash # Check balance telnyx balance retrieve # Billing groups telnyx billing-groups list telnyx billing-groups retrieve --id telnyx billing-groups create --name "Production" telnyx billing-groups update --id --name "Updated" telnyx billing-groups delete --id ``` ## SIM Cards (IoT) ```bash # List SIM cards telnyx sim-cards list telnyx sim-cards retrieve --id telnyx sim-cards update --sim-card-id --tag production telnyx sim-cards delete --id # SIM card groups telnyx sim-card-groups list telnyx sim-card-groups create --name "Fleet 1" telnyx sim-card-groups retrieve --id telnyx sim-card-groups delete --id # SIM card orders telnyx sim-card-orders list telnyx sim-card-orders create --quantity 10 --address-id ``` ## Porting ```bash # Porting orders telnyx porting-orders list telnyx porting-orders retrieve --id telnyx porting-orders create --phone-number +15551234567 # Portability check telnyx portability-checks run --phone-number +15551234567 # Port-outs telnyx portouts list telnyx portouts retrieve --id ``` ## Storage ```bash # Presigned URLs for upload/download telnyx storage:buckets create-presigned-url --bucket-name my-bucket --object-name my-file.txt ``` ## Video Rooms ```bash # Rooms telnyx rooms list telnyx rooms create --unique-name "Team Meeting" --max-participants 10 telnyx rooms retrieve --room-id telnyx rooms update --room-id --max-participants 20 telnyx rooms delete --room-id # Sessions for a specific room telnyx rooms:sessions list-1 --room-id # Sessions across the whole account telnyx rooms:sessions list-0 # Recordings telnyx room-recordings list telnyx room-recordings retrieve --room-recording-id telnyx room-recordings delete --room-recording-id # Compositions telnyx room-compositions list telnyx room-compositions create --session-id ``` ## Networking ### WireGuard ```bash telnyx wireguard-interfaces list telnyx wireguard-interfaces create --body '{network_id: , region_code: ashburn-va}' telnyx wireguard-interfaces retrieve --id telnyx wireguard-interfaces delete --id telnyx wireguard-peers list --filter.wireguard-interface-id telnyx wireguard-peers create --body '{wireguard_interface_id: }' ``` ### Global IPs ```bash telnyx global-ips list telnyx global-ips create telnyx global-ips retrieve --id telnyx global-ips delete --id ``` ## Getting Help ```bash telnyx --help # General help telnyx --help # Resource help telnyx --help # Command help # Examples telnyx phone-numbers --help telnyx messages send --help telnyx calls:actions --help ``` --- --- ### 10DLC Registration > Source: https://developers.telnyx.com/docs/development/cli/workflows/10dlc.md This guide shows you how to complete 10DLC (10-Digit Long Code) registration using the Telnyx CLI, from brand creation through campaign approval. ## Why 10DLC? US carriers require 10DLC registration for Application-to-Person (A2P) messaging from local phone numbers. Without it, your messages may be blocked or throttled. Registration establishes your business identity with carriers and unlocks higher throughput based on your trust score. For a deeper explanation of 10DLC, trust scores, and carrier requirements, see [Understanding 10DLC](/docs/messaging/10dlc/quickstart). ## Prerequisites - Telnyx account with [verified status](https://portal.telnyx.com/#/account/verification) - [Telnyx CLI installed](/docs/development/cli/getting-started/install) - `TELNYX_API_KEY` environment variable set - Business information ready (EIN, address, website) - At least one US phone number ## Registration Steps ### Step 1: Create a Brand A brand represents your business identity for 10DLC registration. #### Standard Business ```bash telnyx messaging-10dlc:brand create \ --entity-type PRIVATE_PROFIT \ --display-name "Acme Corp" \ --company-name "Acme Corporation Inc" \ --email "support@acme.com" \ --ein 12-3456789 \ --phone +15551234567 \ --street "123 Main Street" \ --city "San Francisco" \ --state CA \ --postal-code 94102 \ --country US \ --vertical TECHNOLOGY \ --website https://acme.com ``` #### Sole Proprietor For sole proprietors, additional SMS OTP verification is required: ```bash # Create sole proprietor brand telnyx messaging-10dlc:brand create \ --entity-type SOLE_PROPRIETOR \ --display-name "John's Plumbing" \ --phone +15551234567 \ --email john@example.com \ --country US \ --vertical TECHNOLOGY # Trigger SMS OTP telnyx messaging-10dlc:brand trigger-sms-otp --brand-id \ --pin-sms "Your verification PIN is @OTP_PIN@" \ --success-sms "Your brand has been verified" # Verify with OTP code received via SMS telnyx messaging-10dlc:brand verify-sms-otp --brand-id --otp-pin 123456 ``` **Entity Types:** - `PRIVATE_PROFIT` - Private company - `PUBLIC_PROFIT` - Publicly traded company - `NON_PROFIT` - Non-profit organization - `GOVERNMENT` - Government entity - `SOLE_PROPRIETOR` - Individual / sole proprietor ### Step 2: Check Brand Status ```bash # List all brands telnyx messaging-10dlc:brand list # Get specific brand details telnyx messaging-10dlc:brand retrieve --brand-id # Get feedback if brand was rejected telnyx messaging-10dlc:brand get-feedback --brand-id ``` ### Step 3: Create a Campaign Once your brand is approved, create a campaign to define your messaging use case: ```bash # First, check the cost of your intended use case telnyx messaging-10dlc:campaign:usecase get-cost --usecase MARKETING # Create the campaign (via Portal or API - see note below) ``` Campaign creation is done via the [Telnyx Portal](https://portal.telnyx.com/#/app/messaging/campaign-registry) or the [API](/api-reference/campaign/submit-campaign). The CLI supports retrieving and managing existing campaigns. ### Step 4: Manage Campaigns ```bash # List campaigns for a brand telnyx messaging-10dlc:campaign list --brand-id # Get campaign details telnyx messaging-10dlc:campaign retrieve --campaign-id # Check MNO (Mobile Network Operator) status telnyx messaging-10dlc:campaign get-mno-metadata --campaign-id # Check operation status at carrier level telnyx messaging-10dlc:campaign get-operation-status --campaign-id ``` ### Step 5: Phone Number Assignment Check phone number campaign assignments: ```bash # List phone number campaign assignments telnyx messaging-10dlc:phone-number-campaigns list # Get assignment for specific number telnyx messaging-10dlc:phone-number-campaigns retrieve --phone-number +15551234567 ``` ### Step 6: Verify Setup ```bash # Check brand status telnyx messaging-10dlc:brand list --format json | jq '.data[] | {id, display_name, status}' # Check campaign status telnyx messaging-10dlc:campaign list --brand-id --format json | jq '.data[] | {id, usecase, status}' # Verify number is assigned telnyx messaging-10dlc:phone-number-campaigns retrieve --phone-number +15551234567 ``` ## Campaign Approval After submission, campaigns go through carrier approval: | Status | Meaning | |--------|---------| | `PENDING` | Awaiting review | | `APPROVED` | Ready to send messages | | `REJECTED` | Review feedback and resubmit | Campaign approval can take 1-7 business days. Do not send A2P messages until approved. ### Appeal Rejected Campaigns If your campaign was rejected, you can submit an appeal: ```bash telnyx messaging-10dlc:campaign submit-appeal --campaign-id \ --appeal-reason "Detailed explanation of the changes made to address the rejection" ``` ### Deactivate a Campaign ```bash telnyx messaging-10dlc:campaign deactivate --campaign-id ``` Once deactivated, a campaign cannot be restored. ## Best Practices ### Sample Messages Your sample messages should: - Represent actual messages you'll send - Include opt-out language ("Reply STOP to unsubscribe") - Match your stated use case - Not contain placeholder text ### Throughput 10DLC throughput depends on your trust score: | Trust Score | Messages/Second | |-------------|-----------------| | Low | 0.2 | | Medium | 1 | | High | 10+ | Higher trust scores come from: - Verified business information - Good messaging practices - Low spam/complaint rates ## Troubleshooting ### "Brand verification failed" - Double-check EIN matches IRS records exactly - Verify business address is current - Ensure phone number is associated with business Check feedback: ```bash telnyx messaging-10dlc:brand get-feedback --brand-id ``` ### "Campaign rejected" Common reasons: - Sample messages don't match use case - Missing opt-out language - Vague or generic description **Solution:** Review feedback, update campaign via Portal, and resubmit. ### Revet a Brand If your brand information has changed or was rejected, you can revet (resubmit): ```bash telnyx messaging-10dlc:brand revet --brand-id ``` Revetting is allowed once after successful registration, then limited to once every 3 months. ## Complete Script Example ```bash #!/bin/bash # 10dlc-check.sh - Check 10DLC registration status set -e echo "=== Brands ===" telnyx messaging-10dlc:brand list --format json | \ jq -r '.data[] | "\(.display_name): \(.status)"' echo "" echo "=== Campaigns ===" # Get first brand ID BRAND_ID=$(telnyx messaging-10dlc:brand list --format json | jq -r '.data[0].id') if [ "$BRAND_ID" != "null" ]; then telnyx messaging-10dlc:campaign list --brand-id "$BRAND_ID" --format json | \ jq -r '.data[] | "\(.usecase): \(.status)"' else echo "No brands found" fi echo "" echo "=== Phone Number Assignments ===" telnyx messaging-10dlc:phone-number-campaigns list --format json | \ jq -r '.data[] | "\(.phone_number): \(.campaign_id)"' | head -10 ``` ## Next Steps Start sending SMS after approval Deep dive on trust scores and carrier requirements Throughput tiers and trust scores Common errors and solutions --- --- ### Troubleshooting > Source: https://developers.telnyx.com/docs/development/cli/troubleshooting.md This reference covers common issues you may encounter when using the Telnyx CLI and how to resolve them. Most CLI errors map directly to API error codes. For a complete list, see [API Error Codes](/docs/development/api-fundamentals/api-errors). ## Authentication Errors ### "Unauthorized" (401) ``` Error: Request failed with status 401: Unauthorized ``` **Causes:** - Invalid or expired API key - API key not set - API key has extra whitespace or characters **Solutions:** 1. Verify your API key is set: ```bash echo $TELNYX_API_KEY ``` 2. Check the key format (should start with `KEY_`): ```bash # Correct format export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` 3. Verify the key in the [Telnyx Portal](https://portal.telnyx.com/#/app/api-keys) 4. Test with a simple command: ```bash telnyx balance retrieve ``` ### "No API key" Error **Causes:** - Environment variable not set - Environment variable not exported **Solutions:** 1. Set the environment variable: ```bash export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` 2. Verify it's exported (not just set): ```bash # Wrong (not exported) TELNYX_API_KEY=KEY_xxx # Correct (exported) export TELNYX_API_KEY=KEY_xxx ``` 3. Add to your shell profile for persistence: ```bash echo 'export TELNYX_API_KEY=KEY_xxx' >> ~/.bashrc source ~/.bashrc ``` ## Permission Errors ### "Forbidden" (403) ``` Error: Request failed with status 403: Forbidden ``` **Causes:** - API key doesn't have permission for this action - Resource belongs to a different account - Account verification required **Solutions:** 1. Check API key permissions in the Portal 2. Verify you're using the correct API key for the account 3. Some features require account verification ([verify here](https://portal.telnyx.com/#/account/verification)) ## Resource Errors ### "Not Found" (404) ``` Error: Request failed with status 404: Not Found ``` **Causes:** - Resource ID is incorrect - Resource was deleted - Resource belongs to a different account **Solutions:** 1. Verify the resource exists: ```bash telnyx phone-numbers list telnyx messaging-profiles list ``` 2. Check for typos in the resource ID 3. Ensure you're using the correct API key if you have multiple accounts ### "Phone number not found" **Solution:** List your numbers to see what's available: ```bash telnyx phone-numbers list ``` ## Rate Limiting ### "Too Many Requests" (429) ``` Error: Request failed with status 429: Too Many Requests ``` **Causes:** - Exceeded API rate limits - Too many requests in short period **Solutions:** 1. Add delays between requests in scripts: ```bash for number in "${NUMBERS[@]}"; do telnyx messages send --from "$FROM" --to "$number" --text "$MSG" sleep 0.5 # Add delay done ``` 2. Use bulk endpoints when available 3. Check [rate limits documentation](/docs/development/api-fundamentals/reliability/rate-limiting) ## Messaging Errors ### "Number not enabled for messaging" ``` Error: The phone number +15551234567 is not enabled for messaging ``` **Solutions:** 1. Enable messaging on the number via the Portal or API 2. Or purchase a messaging-enabled number: ```bash telnyx available-phone-numbers list --filter.country-code US --filter.features '[sms]' ``` ### "10DLC campaign required" ``` Error: US A2P messaging requires 10DLC registration ``` **Solution:** Register for 10DLC via the Portal or API. See the [10DLC documentation](/docs/messaging/10dlc/quickstart). ### "Invalid 'to' number" ``` Error: The 'to' phone number is invalid ``` **Solutions:** 1. Use E.164 format (include country code): ```bash # Wrong telnyx messages send --to 5551234567 ... # Correct telnyx messages send --to +15551234567 ... ``` 2. Verify the number is valid: ```bash telnyx number-lookup retrieve --phone-number +15551234567 ``` ## Installation Issues ### "command not found: telnyx" **Causes:** - CLI not installed - Go bin directory not in PATH - Shell not reloaded after install **Solutions:** 1. Verify Go's bin directory contains telnyx: ```bash ls $(go env GOPATH)/bin/telnyx ``` 2. Add Go bin to PATH: ```bash export PATH="$PATH:$(go env GOPATH)/bin" ``` 3. Reinstall if needed: ```bash go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` 4. Reload your shell config: ```bash source ~/.bashrc # or ~/.zshrc ``` ### "command not found: go" **Causes:** - Go not installed **Solutions:** Install Go: ```bash # macOS brew install go # Linux (Debian/Ubuntu) sudo apt install golang-go # Or download from go.dev # https://go.dev/dl/ ``` ### Go version error ``` Error: requires go >= 1.22 ``` **Solution:** Upgrade Go: ```bash # macOS brew upgrade go # Or download latest from go.dev ``` ### Build/compile errors **Solutions:** 1. Ensure you have Go 1.22+: ```bash go version ``` 2. Clear module cache and retry: ```bash go clean -modcache go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` ## Connection Issues ### Network error / Connection refused **Causes:** - No internet connection - Firewall blocking requests - Proxy misconfiguration **Solutions:** 1. Check internet connectivity 2. Verify you can reach the API: ```bash curl -I https://api.telnyx.com/v2 ``` 3. Check proxy settings if applicable ### Timeout errors **Solutions:** 1. Check your internet connection 2. Try again (may be temporary) 3. For large operations, the API may need more time ## Getting More Help ### Enable Debug Mode For detailed HTTP request/response logging: ```bash telnyx phone-numbers list --debug ``` ### Check CLI Version Ensure you're on the latest version: ```bash telnyx --version # Update to latest go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` ### Get Support - **GitHub Issues**: [Report bugs](https://github.com/team-telnyx/telnyx-cli/issues) - **Telnyx Support**: [Contact support](https://telnyx.com/contact-us) - **Community**: [Slack](https://joinslack.telnyx.com/) - **API Status**: [status.telnyx.com](https://status.telnyx.com) --- --- ### Agent CLI > Source: https://developers.telnyx.com/docs/development/cli/agent-cli.md The Telnyx Agent CLI (`@telnyx/agent-cli`, bin `telnyx-agent`) is a command-line tool built for AI agents and for developers who want the shortest path from API key to working capability. Where the [Telnyx CLI](/docs/development/cli) exposes each API resource individually, the Agent CLI ships **composite commands**: one call creates the messaging profile, finds and buys a number, and wires everything together. ## Install ```bash npm install -g @telnyx/agent-cli export TELNYX_API_KEY="KEY_xxx" ``` Requires Node.js 20+. No separate login step — the CLI reads `TELNYX_API_KEY` from the environment. ## Quick start ```bash # Account health at a glance — balance, numbers, profiles, connections telnyx-agent status # Machine-readable list of everything the CLI can do telnyx-agent capabilities --json # Zero to sending SMS: creates a profile, buys an SMS-capable number, # and assigns it — in one command telnyx-agent setup-sms --json ``` Every command supports `--json` for machine-readable output. `setup-sms`, `setup-voice`, and `setup-verify` are **idempotent**: re-running them reuses the resources they already provisioned instead of buying more (`--force` provisions fresh resources). Other setup commands — `setup-ai`, `setup-10dlc`, `setup-porting` — create new resources on each run, so check for existing resources before repeating them. ## When to use the Agent CLI vs the Telnyx CLI | Use case | Agent CLI (`telnyx-agent`) | Telnyx CLI (`telnyx`) | |----------|---------------------------|----------------------| | Zero-to-working-capability setup | ✅ One composite command | Multiple commands | | AI agents provisioning autonomously | ✅ Idempotent, `--json`, self-describing | Works, but more steps | | Fine-grained control over one resource | Limited | ✅ Per-resource CRUD | | Exploring the full API surface | Limited | ✅ Full coverage | The two install side by side and share the `TELNYX_API_KEY` environment variable. ## Composite setup commands | Command | What it does | |---------|--------------| | `setup-sms` | Messaging profile + SMS-capable number, purchased and assigned | | `setup-voice` | Voice connection + voice-capable number | | `setup-ai` | AI assistant on a voice-capable phone number | | `setup-verify` | Verify profile ready to send verification codes | | `setup-10dlc` | 10DLC brand and campaign registration flow | | `setup-whatsapp` | WhatsApp Business Account wiring and number verification | | `setup-iot` | IoT SIM setup | | `setup-porting` | Portability check + port-in order creation and submission | | `setup-wireguard` | WireGuard network and interface | Beyond setup, the CLI covers day-to-day operations — `send-sms`, `call-dial`, `fax-send`, `tts`/`stt`, `rcs-send`, `verify-send`, `fund-account`, and more. `telnyx-agent capabilities --json` returns a machine-readable catalog of API capabilities and selected composite commands — a curated catalog rather than the complete command inventory, so pair it with `telnyx-agent --help` for the full command list. ## For AI agents If you are an agent (or building one), the fast path is: 1. Get an API key — programmatic signup runbook at [telnyx.com/agent-signup.md](https://telnyx.com/agent-signup.md). 2. `npm install -g @telnyx/agent-cli` 3. `telnyx-agent capabilities --json` to discover what you can do, then run the `setup-*` command for the capability you need. The machine-readable agent entry point at [telnyx.com/agents/start](https://telnyx.com/agents/start) and the [team-telnyx/ai](https://github.com/team-telnyx/ai) repo's `agent.json` manifest both describe the CLI in structured form. ## Source and issues The Agent CLI lives in the open-source [team-telnyx/ai](https://github.com/team-telnyx/ai/tree/main/cli) repository — file issues and PRs there. --- ### Overview > Source: https://developers.telnyx.com/docs/development/cli/legacy.md **This CLI is deprecated.** The `@telnyx/api-cli` package is no longer actively maintained. For new projects, use the [Telnyx CLI (Go)](/docs/development/cli) which offers better performance, simpler authentication, and full API coverage. ## About the Legacy CLI The `@telnyx/api-cli` is a Node.js-based command-line interface for interacting with the Telnyx API. It provides commands for managing phone numbers, sending messages, making calls, and more. ### Features - **Interactive Setup** — Guided authentication with `telnyx auth setup` - **Profile Management** — Multiple API key profiles for different environments - **10DLC Wizard** — Step-by-step 10DLC brand and campaign registration - **Shell Autocomplete** — Tab completion for commands and options - **Dry Run Mode** — Preview destructive operations before executing ## Legacy Documentation npm installation instructions API keys, profiles, and config files Full command reference ## Migrating to the current CLI The current [Telnyx CLI (Go)](/docs/development/cli) uses plural resource names and long-form flags. Common command equivalents: | Legacy CLI (`@telnyx/api-cli`) | Current CLI (Go) | |---|---| | `telnyx auth setup` | `export TELNYX_API_KEY=KEY...` (no interactive setup) | | `telnyx number search --country US` | `telnyx available-phone-numbers list --filter.country-code US` | | `telnyx number order +15551234567` | `telnyx number-orders create --phone-number '{phone_number: +15551234567}'` | | `telnyx number list` | `telnyx phone-numbers list` | | `telnyx number get ` | `telnyx phone-numbers retrieve --id ` | | `telnyx number update ...` | `telnyx phone-numbers update --phone-number-id ...` | | `telnyx number delete ` | `telnyx phone-numbers delete --id ` | | `telnyx message send -f -t --text "Hi"` | `telnyx messages send --from --to --text "Hi"` | | `telnyx message get ` | `telnyx messages retrieve --id ` | | `telnyx messaging-profile list` | `telnyx messaging-profiles list` | | `telnyx call dial -f -t --connection-id ` | `telnyx calls dial --from --to --connection-id ` | | `telnyx call hangup ` | `telnyx calls:actions hangup --call-control-id ` | | `telnyx call speak "Hi"` | `telnyx calls:actions speak --call-control-id --payload "Hi" --voice AWS.Polly.Joanna` | | `telnyx call transfer ` | `telnyx calls:actions transfer --call-control-id --to ` | | `telnyx 10dlc brand list` | `telnyx messaging-10dlc:brand list` | | `telnyx 10dlc campaign list ` | `telnyx messaging-10dlc:campaign list --brand-id ` | | `telnyx billing balance` | `telnyx balance retrieve` | | `telnyx verify send -n --profile-id ` | `telnyx verifications trigger-sms --phone-number --verify-profile-id ` | | `telnyx verify check -n -c --profile-id ` | `telnyx verifications:actions verify --verification-id --code ` | Listing sent messages (`telnyx message list`) has no direct equivalent in the current CLI — use [MDR reports](/api-reference/mdr-usage-reports/create-mdr-usage-report) instead. ## Resources - [npm Package](https://www.npmjs.com/package/@telnyx/api-cli) — Version history - [GitHub Repository](https://github.com/team-telnyx/telnyx-api-cli) — Source code --- ### Installation > Source: https://developers.telnyx.com/docs/development/cli/legacy/install.md **This CLI is deprecated.** For new projects, use the [current Telnyx CLI](/docs/development/cli/getting-started/install) instead. ## Requirements The legacy CLI requires **Node.js 20 or later**. ## Installation Install globally via npm: ```bash npm install -g @telnyx/api-cli ``` This makes the `telnyx` command available from any directory. ## Verify Installation ```bash telnyx --version ``` Expected output: ``` @telnyx/api-cli/1.1.0 darwin-arm64 node-v20.10.0 ``` ## Update To update to the latest version: ```bash npm update -g @telnyx/api-cli ``` ## Troubleshooting ### "command not found: telnyx" If the command isn't found after installation: 1. Verify it installed: ```bash npm list -g @telnyx/api-cli ``` 2. Check npm's global bin is in your PATH: ```bash npm config get prefix # Add /bin to your PATH if needed ``` 3. Restart your terminal or reload your shell config: ```bash source ~/.bashrc # or ~/.zshrc ``` ### Permission errors If you get `EACCES` permission errors: 1. Follow [npm's guide to fix permissions](https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally) 2. Or use a Node version manager (nvm, fnm) which doesn't require sudo ## Next Steps Configure API keys and profiles --- ### Authentication > Source: https://developers.telnyx.com/docs/development/cli/legacy/authentication.md **This CLI is deprecated.** The new [Telnyx CLI](/docs/development/cli) uses environment variables only (`TELNYX_API_KEY`). Profile management is not available in the new CLI. ## Authentication Methods The legacy CLI supports three authentication methods, checked in order: flag → environment variable → config file. ### 1. Interactive Setup (Recommended) ```bash telnyx auth setup ``` You'll be prompted to enter your API key. Configuration is stored in `~/.config/telnyx/config.json`. ### 2. Environment Variable ```bash export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` ### 3. Per-Command Environment Override ```bash TELNYX_API_KEY=KEY_xxxxxxxxxxxxx telnyx number list ``` ## Verify Authentication ```bash telnyx auth status ``` Example output: ``` ✓ Authenticated Account: My Company Email: developer@example.com Balance: $125.50 Profile: default ``` ## Multiple Profiles Use named profiles to manage multiple Telnyx accounts or environments. ### Create a Profile ```bash telnyx auth setup --profile production telnyx auth setup --profile staging ``` ### List Profiles ```bash telnyx profile list ``` ### Use a Profile ```bash telnyx number list --profile production telnyx billing balance --profile staging ``` ### Set Default Profile ```bash telnyx profile use production ``` ### Delete a Profile ```bash telnyx profile delete staging ``` ## Configuration File The CLI stores configuration in `~/.config/telnyx/config.json`: ```json { "defaultProfile": "production", "profiles": { "default": { "apiKey": "KEY_xxxxxxxxxxxxx" }, "production": { "apiKey": "KEY_yyyyyyyyyyyyy" }, "staging": { "apiKey": "KEY_zzzzzzzzzzzzz" } } } ``` Keep your config file secure. It contains sensitive API keys. The file is created with restricted permissions (600) by default. ## Environment Variables | Variable | Description | |----------|-------------| | `TELNYX_API_KEY` | API key (overrides config file) | | `TELNYX_PROFILE` | Default profile name | | `TELNYX_CONFIG_DIR` | Custom config directory | ## Getting Your API Key 1. Log in to the [Telnyx Portal](https://portal.telnyx.com/) 2. Navigate to [API Keys](https://portal.telnyx.com/#/app/api-keys) 3. Click **Create API Key** 4. Copy the key (it won't be shown again) API keys start with `KEY_`. If you're using a v1 API key, you'll need to create a new v2 key. ## Next Steps Full command reference for the legacy CLI --- ### Command Reference > Source: https://developers.telnyx.com/docs/development/cli/legacy/reference.md **This CLI is deprecated.** For the current CLI commands, see [Command Reference](/docs/development/cli/reference). ## Authentication & Profiles ```bash telnyx auth setup # Interactive API key setup telnyx auth setup --profile prod # Setup named profile telnyx auth status # Check current auth status telnyx profile list # List all profiles telnyx profile use # Set the default profile telnyx profile delete # Delete a profile ``` ## Phone Numbers ### Search & Purchase ```bash # Search available numbers telnyx number search --country US telnyx number search --country US --contains 555 telnyx number search --country US --type toll_free telnyx number search --country CA --locality Toronto --limit 20 # Purchase numbers telnyx number order +15551234567 telnyx number order +15551234567 +15559876543 --messaging-profile-id ``` ### Manage Numbers ```bash telnyx number list telnyx number list --status active telnyx number list --tag production telnyx number get +15551234567 telnyx number update +15551234567 --connection-id telnyx number update +15551234567 --tags production,us-west telnyx number delete +15551234567 --force telnyx number delete +15551234567 --dry-run ``` ## Messaging ### Send Messages These examples use the deprecated `@telnyx/api-cli` syntax with the singular resource name `telnyx message`. Both the long-form flags (`--from`, `--to`) and their short aliases (`-f`, `-t`) are valid. On the current Go-based CLI the equivalent is `telnyx messages send --from --to --text "Hello!"` — see [Send Messages in the current reference](/docs/development/cli/reference#send-messages). ```bash # Send SMS with long-form flags telnyx message send --from +15551234567 --to +15559876543 --text "Hello!" # Equivalent short-form aliases telnyx message send -f +15551234567 -t +15559876543 --text "Hello!" # Send MMS telnyx message send --from +15551234567 --to +15559876543 \ --text "Check this out" \ --media https://example.com/image.jpg ``` ### List & Retrieve ```bash telnyx message list telnyx message list --direction outbound --limit 50 telnyx message list --from +15551234567 telnyx message get ``` ### Messaging Profiles ```bash telnyx messaging-profile list telnyx messaging-profile get telnyx messaging-profile create --name "Production" --webhook-url https://... telnyx messaging-profile delete --force ``` ## Voice ### Make Calls ```bash telnyx call dial --from +15551234567 --to +15559876543 --connection-id telnyx call dial -f +15551234567 -t +15559876543 --connection-id # With answering machine detection telnyx call dial --from +15551234567 --to +15559876543 \ --connection-id \ --answering-machine-detection detect ``` ### Call Control ```bash telnyx call list telnyx call list --direction outgoing --status active telnyx call hangup telnyx call speak "Hello, how can I help you?" telnyx call transfer +15559876543 ``` ### Voice Profiles & Connections ```bash telnyx voice-profile list telnyx voice-profile get telnyx voice-profile create --name "Production" --concurrent-call-limit 100 telnyx connection list telnyx connection list --type credential telnyx connection create --name "My Voice App" --type credential --webhook-url https://... ``` ## 10DLC ### Interactive Setup ```bash telnyx 10dlc wizard # Guided setup wizard ``` ### Brand Management ```bash telnyx 10dlc brand list telnyx 10dlc brand get telnyx 10dlc brand create --display-name "My Company" \ --email "support@example.com" --vertical TECHNOLOGY # Sole proprietor brand telnyx 10dlc brand create --display-name "John's Plumbing" \ --email john@example.com --vertical TECHNOLOGY --sole-prop \ --first-name John --last-name Doe --phone +15551234567 ``` ### Campaign Management ```bash telnyx 10dlc campaign list telnyx 10dlc campaign create --brand-id --usecase MARKETING \ --description "Marketing messages for opted-in customers" \ --sample1 "Hi! Your order has shipped." \ --message-flow "Customers opt in via web form and can reply STOP to opt out" ``` ## Billing ```bash telnyx billing balance # Check account balance ``` ## Verification ```bash telnyx verify send -n +15551234567 --profile-id -t sms telnyx verify check -n +15551234567 -c 123456 --profile-id ``` ## Shell Autocomplete ```bash telnyx autocomplete # Setup instructions telnyx autocomplete bash # Bash completion script telnyx autocomplete zsh # Zsh completion script ``` ## Global Options | Flag | Description | |------|-------------| | `--profile ` (`-p`) | Use specific profile | | `--output ` (`-o`) | Output format: table, json, csv, tsv, ids | | `--json` | Output raw JSON | | `--verbose` (`-v`) | Show detailed output including API requests | | `--help` | Show command help | | `--version` | Show CLI version | | `--dry-run` | Preview without executing (some commands) | To override the API key for a single command, set the `TELNYX_API_KEY` environment variable instead of a flag. ## Migration to New CLI See the [Legacy CLI Overview](/docs/development/cli/legacy) for a command mapping to the new Go-based CLI. --- ## Migration Guides ### Call Control Migration > Source: https://developers.telnyx.com/docs/development/migration/call-control-migration-guide.md Call Control in v1 is now known as Voice API in v2 and has been designed to make migration smooth. This guide highlights the main changes to be aware of when migrating your Call Control application from API v1 to Voice API v2. Voice API v2 offers the same great call experience but with some changes aimed at making it even easier to have granular-level control over your calls. For new Telnyx users, SDKs available in multiple languages and the introduction of TeXML enable you to get started in minutes. For users with an existing API v1 application, we’ll cover the main changes you should make to migrate to our latest API version. There are three main areas that require minor changes: 1. API v2 Authentication 2. Webhook Structure and Signature Validation 3. Endpoints for Commands ## 1. API v2 authentication for voice API Voice API v2 utilizes a different authentication strategy that will require you to generate a new API key for your Voice application. You can do that easily via the [Telnyx Mission Control Portal](https://portal.telnyx.com/#/app/auth/v2). Once you have logged into your Mission Control Portal account, in the left navigation click “Auth”. Then, ensure that Auth v2 is selected in the horizontal navigation. ![API Key View](/assets/images/voice_programmable-voice_voice-api-v2-migration-guide_portal-authentication-v2.png) Click “Create Key”. You will be presented with a pop-up reminding you to store your new API key securely. Click “Create” to confirm. You will then be presented with your new v2 key. You will not be able to see the full key again after this point. Once a key has been successfully created, you can disable or delete it easily from the main Auth v2 page. Information on creation and recent usage of each key is also available. ## 2. Webhook structure and signature validation for voice API Next, let’s compare the webhook response for when a call is answered in both API v1 and v2 so that we can see the differences: **API v1:** ```json { "record_type": "event", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "event_type": "call_answered", "created_at": "2018-02-02T22:25:27.521992Z", "payload": { "call_control_id": "AgDIxmoRX6QMuaIj_uXRXnPAXP0QlNfXczRrZvZakpWxBlpw48KyZQ==", "to": "+18005550199", "from": "+35319605860", "connection_id": "7267xxxxxxxxxxxxxx", "call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1", "call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1", "client_state": "aGF2ZSBhIG5pY2UgZGF5ID1d", "state": "answered", "occurred_at": "2018-02-02T22:25:27.521992Z" } } ``` **API v2:** ```json { "data": { "record_type": "event", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "event_type": "call.answered", "occurred_at": "2018-02-02T22:25:27.521992Z", "payload": { "call_control_id": "AgDIxmoRX6QMuaIj_uXRXnPAXP0QlNfX", "to": "+18005550199", "from": "+18005550100", "connection_id": "7267xxxxxxxxxxxxxx", "call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1", "call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1", "client_state": "aGF2ZSBhIG5pY2UgZGF5ID1d", "state": "answered" } } } ``` #### Data object Firstly, you will notice that the structure of the payload has changed. There is a top-level `data` object that contains all subsequent information about the webhook. You will also notice that the top level `created_at` field in API v1 has been renamed `occurred_at` - this is the time that the event occurred. #### Event type naming convention The naming convention of the `event_type` field has also changed for API v2. While the field names remain in `snake_case`, for `event_type` the call event being described will be in `dot.case` for all call events. Events can contain multiple dots to indicate a relationship. For example, in API v1 when initiating text-to-speech, if the command is successful, your application will receive a webhook containing `"event_type":"speak_started"`. In API v2, your application would receive `"event_type": "call.speak.started"` for this call event. #### Enabling API v2 Webhooks API v2 webhook structures are not enabled by default. To begin receiving webhooks in the new format, you will need to update your [Call Control Application](https://portal.telnyx.com/#/app/call-control/applications) settings for any application you wish to migrate to API v2. ![API V2 Webhook](/assets/images/voice_programmable-voice_voice-api-v2-migration-guide_portal-voice-application-settings-api-v2.png) #### Webhook signatures Each messaging webhook event that we send you will include a Telnyx signature. The signature allows you to validate that webhooks were not sent by a third-party. While API v1 uses an HMAC with the SHA256 hash function to sign webhooks, API v2 uses the [EdDSA](https://en.wikipedia.org/wiki/EdDSA) digital signature scheme with a public key. In API v1, webhooks can be validated using information in the `X-Telnyx-Signature` header and the raw request payload of the webhook in bytes. Webhook signing in API V2 uses public key encryption. Telnyx stores a public-private key pair and uses the private key to sign the payload. The public key is available to you so that you can verify the request. Your public key can be viewed in the [Mission Control Portal](https://portal.telnyx.com/#/app/account/public-key). The signature for the payload is calculated by building a string that is the combination of the timestamp of when the request was initiated, the pipe `|` character and the JSON payload. The signature is then `Base64` encoded. ``` Base64.encode64("#{timestamp}|#{payload}") ``` The signature (`Base64` encoded) and the timestamp (in Unix format) are assigned to the request headers `telnyx-signature-ed25519` and `telnyx-timestamp` respectively. You can then use cryptographic libraries in your language of choice to verify the signature using the public key. Refer to the [Telnyx SDKs](/docs/development/sdk) for implementation examples in your preferred language. ## 3. Endpoints for commands (call control) API v2 commands have different endpoints to API v1 commands. The base URL for API v2 is `https://api.telnyx.com/v2/` The commands carry out the same functions, just at a different URL. To answer a call in API v1: `https://api.telnyx.com/calls/{call_control_id}/actions/answer` To answer a call in API v2: `https://api.telnyx.com/v2/calls/{call_control_id}/actions/answer` For further reading, view the [Call Control API Reference](https://developers.telnyx.com/docs/voice/programmable-voice/voice-api-commands-and-resources) and the [quickstart guide](https://developers.telnyx.com/docs/voice/programmable-voice/sending-commands). --- ### Messaging Migration > Source: https://developers.telnyx.com/docs/development/migration/messaging-migration-guide.md The SMS/MMS API v2 has been designed to make migration from Messaging v1 smooth. This guide highlights the main changes to be aware of when migrating your Messaging application from API v1 to API v2. SMS/MMS in API v2 offers the same great messaging functionality but with some changes aimed at making it even easier to have granular-level control over your messaging metrics and deliverability. For new Telnyx users, [server SDKs](/docs/development/sdk) are available in multiple languages to help you get started quickly. For users with an existing API v1 application, we'll cover the main changes you should make to migrate to our latest API version. There are three main areas that require minor changes: 1. API v2 Authentication 2. Webhook Structure and Signature Validation 3. Endpoints for Sending Messages ## 1. API v2 Authentication SMS/MMS API v2 utilizes a different authentication strategy that will require you to generate a new API key for your messaging application. You can do that easily via the [Telnyx Mission Control Portal](https://portal.telnyx.com/#/app/auth/v2). Once you have logged into your Mission Control Portal account, in the left navigation click “Auth”. Then, ensure that Auth v2 is selected in the horizontal navigation. ![API Key View](/assets/images/mms-api-v2-migration-guide_authentication-settings-v2.png) Click “Create Key”. You will be presented with a pop-up reminding you to store your new API key securely. Click “Create” to confirm. You will then be presented with your new v2 key. You will not be able to see the full key again after this point. Once a key has been successfully created, you can disable or delete it easily from the main Auth v2 page. Information on creation and recent usage of each key is also available. ## 2. Webhook Structure and Signature Validation Next, let’s compare the webhook response for when a message is sent in both API v1 and v2 so that we can see the differences: **API v1:** ```json { "type": "SMS", "sms_id": "403171cc-e934-4978-bada-2701bbdb69e7", "sms_gw_id": "403171cc-e934-4978-bada-2701bbdb69e7", "user_id": "d63fjl62-0003-4dab-7832-29b7b22628d8", "profile_id": "3dgnn65-7f81-4b71-b4g6-64a65ac29e8d", "created": 1588280767640, "updated": 1588280767727, "date_created": "2020-04-30T21:06:07.640000", "date_updated": "2020-04-30T21:06:07.727000", "to": "+18005550199", "from": "+18005550100", "cost": null, "currency": null, "direction": "outbound", "status": "sent", "delivery_status": "", "on_net": false, "carrier": "OMNIPOINT COMMUNICATIONS MIDWEST OPERATIONS LLC", "line_type": "Wireless", "errors": [], "body": { "text": "Hello, World!", "text_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "coding": 0, "num_chars": 4, "num_bytes": 4, "bytes_hash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", "parts": 1 } } ``` **API v2:** ```json { "data": { "record_type": "event", "event_type": "message.sent", "id": "1f1243a9-93a5-48d1-bf4b-d680b03565a0", "occurred_at": "2020-04-30T20:58:39.421+00:00", "payload": { "id": "403171cc-e25d-45cc-96b2-f3c54cfc3747", "record_type": "message", "type": "SMS", "to": [ { "carrier": "OMNIPOINT COMMUNICATIONS MIDWEST OPERATIONS LLC", "line_type": "Wireless", "phone_number": "+18005550199", "status": "sent" } ], "from": "+18005550100", "text": "Hello, World!", "completed_at": null, "cost": null, "direction": "outbound", "encoding": "GSM-7", "media": [], "parts": 1, "tags": [], "webhook_url": "https://hookb.in/G9J9pghfoeZJcpadWdQoxm", "webhook_failover_url": "", "valid_until": "2020-04-30T21:58:39.342+00:00", "sent_at": "2020-04-30T20:58:39.421+00:00", "received_at": "2020-04-30T20:58:39.342+00:00", "messaging_profile_id": "3edefe37-7f02-4b71-b2a6-64a65ac29e8d", "organization_id": "d63fjl62-0003-4dab-7832-29b7b22628d8", "errors": [], } }, "meta": { "attempt": 1, "delivered_to": "https://hookb.in/G9J9pghfoeZJcpadWdQoxm" } } ``` #### Data Object Firstly, you will notice that the structure of the payload has changed. There is a top-level `data` object that contains all subsequent information about the webhook. You will also notice that the top level `created` field in API v1 has been renamed `occurred_at` - this is the time that the event occurred. #### Event Type Naming Convention The naming convention of the `event_type` field has also changed for SMS/MMS API v2. While the field names remain in `snake_case`, for `event_type` the call event being described will be in `dot.case` for all call events. Events can contain multiple dots to indicate a relationship. For example, in API v1 when sending an SMS, if the send is successful, your application will receive a webhook containing `"event_type":"delivered"`. In SMS/MMS API v2, your application would receive `"event_type": "message.finalized"` for this webhook event. #### Enabling SMS/MMS API v2 Webhooks API v2 webhook structures are not enabled by default. To begin receiving webhooks in the new format, you will need to update your [Messaging Profile](https://portal.telnyx.com/#/app/messaging) settings for any application you wish to migrate to SMS/MMS API v2. ![Messaging Webhook Version](/assets/images/mms-api-v2-migration-guide_messaging-profile-settings-api-v2.png) #### Webhook Signatures Each messaging webhook event that we send you will include a Telnyx signature. The signature allows you to validate that webhooks were not sent by a third-party. While API v1 uses an HMAC with the SHA256 hash function to sign webhooks, SMS/MMS API v2 uses the [EdDSA](https://en.wikipedia.org/wiki/EdDSA) digital signature scheme with a public key. In API v1, webhooks can be validated using information in the `X-Telnyx-Signature` header and the raw request payload of the webhook in bytes. Webhook signing in SMS/MMS API V2 uses public key encryption. Telnyx stores a public-private key pair and uses the private key to sign the payload. The public key is available to you so that you can verify the request. Your public key can be viewed in the [Mission Control Portal](https://portal.telnyx.com/#/app/account/public-key). The signature for the payload is calculated by building a string that is the combination of the timestamp of when the request was initiated, the pipe `|` character and the JSON payload. The signature is then `Base64` encoded. ``` Base64.encode64("#{timestamp}|#{payload}") ``` The signature (`Base64` encoded) and the timestamp (in Unix format) are assigned to the request headers `telnyx-signature-ed25519` and `telnyx-timestamp` respectively. You can then use cryptographic libraries in your language of choice to verify the signature using the public key. Refer to the [Telnyx SDKs](/docs/development/sdk) for implementation examples in your preferred language. ## 3. Endpoints for Messages SMS/MMS API v2 requests have different endpoints to API v1 commands. The base URL for SMS/MMS API v2 is `https://api.telnyx.com/v2/` The endpoints carry out the same functions, just at a different URL. To send a message in API v1: `https://sms.telnyx.com/messages` To send a message in API v2: `https://api.telnyx.com/v2/messages` For further reading, view the [Messaging API Reference](https://developers.telnyx.com/api-reference/profiles/create-a-messaging-profile#create-a-messaging-profile) and the [quickstart guide](https://developers.telnyx.com/docs/messaging/messages/send-message). --- ### Twilio Migration > Source: https://developers.telnyx.com/docs/development/migration/twilio-migration-guide.md | [cURL](#curl) | [Python](#python) | [PHP](#php) | [Node](#node) | [Java](#java) | [.NET](#net) | [Ruby](#ruby) | ----- As of December 17th, Twilio will go forward with sunsetting support for their Programmable Fax offering. As such, we have outlined a step-by-step guide to make the transition to Telnyx's Programmable Fax system as painless as possible. This guide will inform and detail the process from start to finish to get you started using Fax with Telnyx! Transitioning is quite simple, as the general configuration of the app mirrors Twilio's implementation. In most cases, the only change you will have to make in the code itself is the authentication parameters and the send function. ## cURL ### Part 1: Account configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) Do note, to receive updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and recieving faxes with Telnyx! ### Part 2: Sending faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: Don't forget to update `YOUR_API_KEY` in the examples. ``` curl -X POST https://api.telnyx.com/v2/faxes \ --data-urlencode "media_url=https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" \ --data-urlencode "connection_id=YOUR_FAX_APP_ID" \ --data-urlencode "to=YOUR_DESTINATION_NUMBER" \ --data-urlencode "from=YOUR_FROM_NUMBER" \ --header "Authorization: Bearer YOUR_API_KEY" ``` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```xml ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## Python ### Part 1: Account configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to receive updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and receiving faxes with Telnyx! ### Part 2: Sending Faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: ```python import telnyx telnyx.api_key = "YOUR_API_KEY" fax_app_id = "YOUR_FAX_APP_ID" your_telnyx_number = "YOUR_TELNYX_NUMBER" desitnation_number = "YOUR_DESIRED_DESTINATION_NUMBER" fax_send = telnyx.Fax.create( connection_id=TELNYX_FAX_CONNECTION_ID, to=to_phone_number, from_=from_phone_number, media_url=file_url ) ``` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```bash ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## PHP ### Part 1: Account configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to receive updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and receiving faxes with Telnyx! ### Part 2: Sending Faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: ```php $your_telnyx_number, 'to' => $destination_number, 'connection_id' => $connection_id, 'media_url' => $media_url]); ``` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```bash ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## Node ### Part 1: Account Configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to receive updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and receiving faxes with Telnyx! ### Part 2: Sending Faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: ```javascript import Telnyx from 'telnyx'; const telnyx = new Telnyx("YOUR_API_KEY"); telnyx.faxes.create( { 'from': 'YOUR_FROM_NUMBER', 'to': 'YOUR_DESTINATION_NUMBER', 'connection_id': 'YOUR_FAX_APP_ID' 'media_url': 'YOUR_MEDIA_URL' }, function(err, response) { // asynchronously called console.log(response); } ); ``` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving Faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```xml ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## Java ### Part 1: Account Configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to receive updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Receiving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and receiving faxes with Telnyx! ### Part 2: Sending faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: ``` curl -X POST https://api.telnyx.com/v2/faxes \ --data-urlencode "media_url=https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" \ --data-urlencode "connection_id=YOUR_FAX_APP_ID" \ --data-urlencode "to=YOUR_DESTINATION_NUMBER" \ --data-urlencode "from=YOUR_FROM_NUMBER" \ --header "Authorization: Bearer YOUR_API_KEY" ``` A successful example JSON response to the request will look like: ``` { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```bash ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## .NET ### Part 1: Account configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to recieve updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and recieving faxes with Telnyx! ### Part 2: Sending faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. Follow the steps below to send Fax messages with dotnet core v3.1+ 1. Using the dotnet CLI create a new console application and change directories to the newly created folder. Then add the Telnyx.net package. ```bash $ dotnet new console --output send-fax $ cd send-fax $ dotnet add package Telnyx.net ``` 2. Open the 'Program.cs' file created for you in the directory. It should look something like the code below: ```csharp using System; namespace send_sms { class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); } } } ``` 3. Tell the application to use Telnyx.net by adding: `using Telnyx;` before the `namespace` 4. In order to use the Asynchronous methods, we need to modify our Main method to return a Task and make it async. 4.1 `static void Main(string[] args)` should be `static async Task Main(string[] args) 4.2 Add `using System.Threading.Tasks;` before the `namespace` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Recieving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```bash ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` ## Ruby ### Part 1: Account configuration To get started using Programmable Fax with Telnyx, you will be required to make an account and attain the following items. A guide on how to set this up can be found at our [Quickstart](/docs/programmable-fax/quickstart) You will ultimately need the following configured: - A valid [Telnyx Portal Account](https://telnyx.com/sign-up) - A [Telnyx Outbound Voice Profile](https://portal.telnyx.com/#/app/outbound-profiles?utm_source=referral&utm_medium=github_referral&utm_campaign=cross-site-link) (If you are intending to send Faxes Outbound) - A [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - A [Telnyx Phone Number](https://portal.telnyx.com/#/app/numbers/search-numbers) that's enabled with a [Telnyx Fax Appliction](https://portal.telnyx.com/#/app/fax/applications) Do note, to recieve updates and status of your faxes (both inbound and outbound), you will need to setup a Webhook in the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications). This is where we will be sending you all information regarding the fax. For more information on this, you can scroll down to "Part 3: Recieving Faxes" section. After your account is configured, take note of the following items that you will need to send your specified faxes programmatically. - Your [API V2 Key](https://portal.telnyx.com/#/app/api-keys) - Your App ID of the [Telnyx Fax Application](https://portal.telnyx.com/#/app/fax/applications) - Your [Phone Number](https://portal.telnyx.com/#/app/numbers/my-numbers) that you procured from the previous step. That's it from the portal perspective! With the 3 pieces of information from above we are ready to start sending and recieving faxes with Telnyx! ### Part 2: Sending faxes Sending outbound faxes requires: - A *To* number (Destination) - A *From* number (Generally the number you have procured from above) - A public facing URL which points to the document you are intending to send, in PDF format. The code to initiate a fax sendoff would be as follows: ``` curl -X POST https://api.telnyx.com/v2/faxes \ --data-urlencode "media_url=https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf" \ --data-urlencode "connection_id=YOUR_FAX_APP_ID" \ --data-urlencode "to=YOUR_DESTINATION_NUMBER" \ --data-urlencode "from=YOUR_FROM_NUMBER" \ --header "Authorization: Bearer YOUR_API_KEY" ``` A successful example JSON response to the request will look like: ```bash { "data": { "connection_id": "c-1", "created_at": "2020-05-05T09:59:12", "direction": "outbound", "from": "+123", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "media_url": "http://www.example.com/fax.pdf", "quality": "high", "record_type": "fax", "status": "queued", "store_media": true, "stored_media_url": "https://s3.amazonaws.com/faxes-dev/user-1/cf4a6b52-bf8e-4945-9f49-611d0d2b083b.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=xxxxxxxxxx%2F20200505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200505T095917Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=fac2af40464fcc77673ad762db86e34f9c1b91a82699b5578c5327f53874df51", "to": "+456", "updated_at": "2020-05-05T09:59:12", "webhook_failover_url": "", "webhook_url": "http://www.example.com/webhooks" } } ``` ### Part 3: Receiving faxes In order to receive faxes, you will need to setup a webhook mentioned earlier. In order for the webhooks in this tutorial to work, Telnyx must be able to send your web application an HTTP request over the Internet. That means your application needs to have a URL or IP address that Telnyx can reach. Telnyx sends webhooks to the URL or IP address to notify your application of incoming faxes. For the purpose of this tutorial, we're using [ngrok](https://ngrok.com/), a popular tunneling tool used to expose a locally running application to the internet. ngrok gives you a public URL for a local port on your development machine, which you can use to configure your Telnyx webhooks as described above. Download and install ngrok, then use it at the command line to create a tunnel to whatever port your web application is running on. For example, this command will create a public URL for a web application listening on port 3000. ```bash ngrok http 3000 ``` After executing that command, you will see that ngrok has given your application a public URL that you can use in your webhook connection configuration in the [Telnyx Mission Control Portal](https://portal.telnyx.com/). ![TwiML Twilio Telnyx Conference Flow](/assets/images/twiml-conferencing-3.png) Grab your ngrok public URL and head back to the Programmable Fax Application you configured earlier. Now in the field under "Send a webhook to the URL" enter your new ngrok URL from either of the "Forwarding" URLs ngrok provided us with depending on if you want to use HTTP or HTTPS. You're now all set up to receive webhooks for events related to inbound faxes. If you use the same Programmable Fax Application for sending faxes, you will receive events to the same ngrok URL you just created. #### Example Webhooks If you have set everything up correctly, any time an inbound fax is received you can expect to receive the following webhooks: | Webhook Name | Description | |-------------|-------------| | `fax.receiving.started` | The fax has begun transmitting to Telnyx successfully. | | `fax.media.processing.started` | Telnyx has received the fax and is generating the digital PDF file. | | `fax.received` | The PDF has been generated and the file is ready to be downloaded. | | `fax.failed` | Transmission of the fax failed. Check the `failure_reason` for more details. | #### Fax has begun transmitting to Telnyx ```json { "data": { "event_type": "fax.receiving.started", "id": "bc004786-f166-4dd3-8c5d-737990b501bc", "occurred_at": "2020-08-27T16:33:29.684247Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "9fbc3f0d-5495-42af-9a4e-c57a235d9182", "from": "+16132484872", "status": "receiving", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Fax transmission is complete and Telnyx is converting to PDF ```json { "data": { "event_type": "fax.media.processing.started", "id": "35e33b02-6365-47d0-93b7-3bfec97c467e", "occurred_at": "2020-08-27T16:33:33.175396Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "status": "media.processing", "page_count": 2, "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### PDF has been generated and is ready for download The `media_url` field contains a signed AWS link to a PDF of the received fax. This URL is valid for 10 minutes before the file is no longer accessible so be sure to download the file if you wish to keep it! ```json { "data": { "event_type": "fax.received", "id": "4844b70c-3c6c-4c3a-ba2e-e4c785f02d24", "occurred_at": "2020-08-27T16:33:36.843054Z", "payload": { "call_duration_secs": 50, "connection_id": "1447842681660114324", "direction": "inbound", "fax_id": "f72eebbe-f9b6-4f0f-b652-03e742e110d5", "from": "+16132484850", "media_url": "https://s3.amazonaws.com/faxes-prod/19a75cea-02c6-4b9a-84fa-c9bc8341feb8/f72eebbe-f9b6-4f0f-b652-03e742e110d5.pdf?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=...%2F20200827%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20200827T163336Z&X-Amz-Expires=7200&X-Amz-SignedHeaders=host&X-Amz-Signature=...", "page_count": 2, "partial_content": false, "status": "received", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` #### Uh oh, something has gone wrong and the fax failed Inbound faxes can fail for a variety of reasons. Some of the most common reasons are that the sending party hung up before the fax was finished transmitting or didn't send anything at all. ```json { "data": { "event_type": "fax.failed", "id": "1a7405a6-696c-4369-a0b1-168e4bb7e22c", "occurred_at": "2020-08-27T16:17:51.844250Z", "payload": { "connection_id": "1447842681660114324", "direction": "inbound", "failure_reason": "sender_call_dropped", "fax_id": "181533f3-b0b8-4bcd-ab01-b33cd8698508", "from": "+16617480240", "status": "failed", "to": "+17733372863", "user_id": "19a75cea-02c6-4b9a-84fa-c9bc8341feb8" }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://1a3097.ngrok.io/" } } ``` --- ## For AI Agents ### Agent-readable docs > Source: https://developers.telnyx.com/docs/development/agent-readable-documentation.md Telnyx documentation is published for browser-based development and direct machine consumption. Use the smallest authoritative source that contains the required context. ## Documentation formats - [Documentation index](/llms.txt): product and subsection indexes designed for selective retrieval by an AI agent. - [Complete documentation](/llms-full.txt): consolidated guide content for tools that require a complete documentation corpus. - [API error catalog](/data/api-errors.json): normalized API and product errors with scope, source provenance, and remediation metadata. - [Webhook event catalog](/data/webhook-events.json): concrete callback payloads, media types, source specifications, and publication selectors. ### Page-level Markdown Append `.md` to a documentation page URL to retrieve clean Markdown for that page. For example: ```text https://developers.telnyx.com/docs/development/api-fundamentals/api-errors.md ``` Interactive browser controls are excluded from agent-facing Markdown. When an interactive component carries documentation value, its Markdown export contains a concise text fallback or an authoritative machine-readable source instead of the component implementation. ### OpenAPI and API reference Use the [consolidated OpenAPI specification](https://raw.githubusercontent.com/team-telnyx/openapi/master/openapi/spec3.json) for REST paths, request and response schemas, and webhook definitions. Published endpoint pages provide the corresponding API reference and ordered samples for: - JavaScript - Python - Go - Java - Ruby - PHP - Telnyx CLI Use the OpenAPI operation as the contract. Use authored guides for product setup, lifecycle constraints, and operational behavior that cannot be represented completely in a schema. ## Production integration path Apply this sequence when implementing a Telnyx API integration: 1. Select the relevant product quickstart or guide from the [documentation index](/llms.txt). 2. Inspect the endpoint request, response, and language sample in the API reference. 3. Implement authentication according to [API authentication](/docs/development/api-fundamentals/authentication). 4. Handle retryable and terminal failures using [API error codes](/docs/development/api-fundamentals/api-errors) and the [machine-readable error catalog](/data/api-errors.json). 5. If the product emits callbacks, implement signature verification, asynchronous processing, deduplication, and product-specific retry handling from [Webhook fundamentals](/docs/development/api-fundamentals/webhooks/receiving-webhooks). 6. Retrieve exact callback payloads from the [webhook event catalog](/data/webhook-events.json). 7. Apply [rate-limit handling](/docs/development/api-fundamentals/reliability/rate-limiting) and [command retry guidance](/docs/development/api-fundamentals/reliability/command-retries). ## Source selection - **Product setup or workflow:** authored guide Markdown. - **Endpoint contract:** API reference or OpenAPI. - **Language-specific request:** endpoint code sample. - **API failure:** error guide and error catalog. - **Callback payload:** webhook reference and webhook catalog. - **Broad retrieval:** subsection `llms.txt` index before a full-content export. Do not infer a universal webhook retry schedule or payload envelope. Delivery behavior, event fields, and correlation identifiers can differ by product. Follow the product-specific source linked by the corresponding catalog entry. --- ### Telnyx Local MCP Server > Source: https://developers.telnyx.com/docs/development/mcp/local-mcp.md # Telnyx Local Model Context Protocol (MCP) Server Official Telnyx Local Model Context Protocol (MCP) Server that enables interaction with powerful telephony, messaging, and AI assistant APIs. This server allows MCP clients like Claude Desktop, Cursor, Windsurf, OpenAI Agents and others to manage phone numbers, send messages, make calls, and create AI assistants. ## Quickstart with Claude Desktop Generate or copy an API key in the [Telnyx Mission Control Portal](https://portal.telnyx.com/#/app/apikeys). Install the Python package manager with `curl -LsSf https://astral.sh/uv/install.sh | sh`, `brew install uv`, or any other method documented in the [`uv` repository](https://github.com/astral-sh/uv). Go to **Claude > Settings > Developer > Edit Config > claude_desktop_config.json**, then add the Telnyx server configuration: ```json { "mcpServers": { "Telnyx": { "command": "uvx", "args": ["--from", "git+https://github.com/team-telnyx/telnyx-mcp-server.git", "telnyx-mcp-server"], "env": { "TELNYX_API_KEY": "" } } } } ``` If you're using Windows, you will have to enable "Developer Mode" in Claude Desktop to use the MCP server. Click "Help" in the hamburger menu at the top left and select "Enable Developer Mode". ## Running After Download Copy an API key from the [Mission Control Portal](https://portal.telnyx.com/#/app/apikeys) so the MCP server can authenticate. Install the Python package manager via `curl -LsSf https://astral.sh/uv/install.sh | sh`, `brew install uv`, or another method listed in the [`uv` documentation](https://github.com/astral-sh/uv). ```bash git clone https://github.com/team-telnyx/telnyx-mcp-server.git cd telnyx-mcp-server ``` Update your Claude config to reference the local folder by using the `--from` argument: ```json { "mcpServers": { "Telnyx": { "command": "uvx", "args": ["--from", "/path/to/telnyx-mcp-server", "telnyx-mcp-server"], "env": { "TELNYX_API_KEY": "" } } } } ``` Claude now invokes the server from the cloned directory. Replace `/path/to/telnyx-mcp-server` with the actual local path. ## Available Tools ### Assistant Tools * Create AI assistants with custom instructions and configurations * List existing assistants * Get assistant details * Update assistant properties * Delete assistants * Get assistant TEXML configurations ### Call Control Tools * Make outbound phone calls * Hang up active calls * Transfer calls to new destinations * Play audio files during calls * Stop audio playback * Send DTMF tones * Speak text using text-to-speech ### Messaging Tools * Send SMS and MMS messages * Get message details ### WhatsApp Tools * Send WhatsApp messages (template or free-form text) * List WhatsApp Business Accounts (WABAs) * List and create message templates * Get template details and approval status * List WhatsApp-enabled phone numbers * Get and update business profiles ### Phone Number Tools * List your phone numbers * Buy new phone numbers * Update phone number configurations * List available phone numbers ### Connection Tools * List voice connections * Get connection details * Update connection configurations ### Cloud Storage Tools * Create buckets compatible with Telnyx Cloud Storage * List buckets across all regions * Upload files * Download files * List objects in a bucket * Delete objects * Get bucket location information ### Embeddings Tools * List existing embedded buckets * Scrape and embed a website URL * Create embeddings for your own files ### Secrets Manager Tools * List integration secrets * Create new bearer or basic secrets * Delete integration secrets ## Example Usage Try asking Claude: * "Create an AI agent that can handle customer service for an e-commerce business" * "Send a text message to +5555551234 saying 'Your appointment is confirmed for tomorrow at 3pm'" * "Make a call to my customer at +5555551234 and transfer them to my support team" * "Find me a phone number in Chicago with area code 312" * "Create an auto-attendant system using Telnyx AI assistants and voice features" * "Upload /Volumes/Drive/contract.pdf to the 'legal-docs' bucket in Telnyx Cloud Storage" * "Embed the knowledge base at https://example.com/docs so the assistant can answer user questions" * "Create a integration secret named openai-token with my openai key XYZ" ## Contributing See https://github.com/team-telnyx/telnyx-mcp-server for more information. --- ### Telnyx Remote MCP > Source: https://developers.telnyx.com/docs/development/mcp/remote-mcp.md # Telnyx Remote Model Context Protocol (MCP) ## Remote endpoint The canonical Telnyx API MCP endpoint is `https://api.telnyx.com/v2/mcp`. Use this endpoint for MCP clients or scanners that need Telnyx API actions. It uses streamable HTTP and Bearer authentication with `Authorization: Bearer `. The canonical MCP server card is published at `https://telnyx.com/.well-known/mcp/server-card.json`. The `developers.telnyx.com` server card is a secondary discovery mirror for the documentation site and points back to that canonical card. `https://developers.telnyx.com/mcp` and other `developers.telnyx.com` MCP discovery paths may expose documentation/search MCP capabilities. Do not treat those docs endpoints as the API action MCP; API actions should connect to `https://api.telnyx.com/v2/mcp`. ## Quickstart with Claude Desktop ### Connect via Portal *Requires a Claude / Claude Desktop plan with access to Custom Connectors Go to Claude > Settings > Connectors ![Claude Desktop Step 1](/assets/images/claude-desktop-custom-connector.png) ![Claude Desktop Step 2](/assets/images/new-claude-desktop-connector-config.png) ![Claude Desktop Step 3](/assets/images/claude-desktop-connector-connect.png) Grant access in the Telnyx Portal (must be logged in) ![Claude Desktop Step 4](/assets/images/claude-desktop-portal-grant.png) ![Claude Desktop Step 5](/assets/images/new-claude-desktop-list-tools.png) For information previously shared on this page regarding connecting to our "legacy" MCP Server, [see here](/docs/development/mcp/remote-mcp/legacy). ---