# 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.md · Root index: https://developers.telnyx.com/llms.txt ## ### Development > 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 → Level up your workflow with Postman collections, ngrok tunneling, and Node-RED recipes for rapid testing. Get the toolkit → 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. --- ## APIs fundamentals ### Create API Keys > Source: https://developers.telnyx.com/docs/development/api-fundamentals/create-api-keys.md API keys are essential for authenticating your requests to any Telnyx API. This guide shows you how to create and manage your API keys through the Mission Control Portal. ## Creating Your API Key 1. In the Mission Control Portal, click on your name in the upper right corner, and click **API Keys**. 2. Click the **Create API Key** button. ![API Keys Page](/assets/images/voice-programmable-voice-voice-api-fundamentals-portal-api-keys.png) 3. In the Create API Key dialog, add a descriptive tag (e.g., "Voice API Development", "SMS Production", etc.) and choose your expiration settings. ![Create API Key Dialog](/assets/images/voice-programmable-voice-voice-api-fundamentals-create-api-key-dialog.png) 4. Click **Create**. ## Important: Save Your API Key Securely We'll show the full API key value only once at creation. If you lose the key, you'll need to generate a new one. We recommend using a secure password manager or secrets vault once you've created it. We're doing this to reduce the risk of accidental key leaks and help keep your account secure. This approach aligns with our best-in-class security standards and helps prevent accidental key exposures. ## Storing Your API Key **Best Practices:** - Never commit API keys to version control (Git, SVN, etc.). - Use environment variables in your applications. - Rotate keys regularly for production applications. - Use separate keys for development and production. Example of setting an environment variable: ```bash export TELNYX_API_KEY="YOUR_API_KEY" ``` ## Using Your API Key Once created, you can use your API key with any Telnyx service: ### REST API ```bash curl -X GET \ --header "Authorization: Bearer YOUR_API_KEY" \ "https://api.telnyx.com/v2/endpoint" ``` ### SDKs ```javascript // Node.js const telnyx = require('telnyx')('YOUR_API_KEY'); // Python import telnyx telnyx.api_key = "YOUR_API_KEY" // Ruby Telnyx.api_key = "YOUR_API_KEY" ``` --- ### API Authentication > Source: https://developers.telnyx.com/docs/development/api-fundamentals/authentication.md All Telnyx APIs use consistent authentication mechanisms to ensure secure access to your resources. This guide covers the universal authentication patterns used across Voice, Messaging, Cloud Storage, IoT, and all other Telnyx services. ## API Keys ### Overview Telnyx uses API Keys as the primary authentication method across all services. Your API Keys carry significant privileges and provide access to all Telnyx resources associated with your account. ### Security Best Practices - **Keep API Keys secure**: Never share API Keys in publicly accessible areas such as GitHub, client-side code, or logs - **Use environment variables**: Store API Keys in environment variables or secure configuration files - **Rotate keys regularly**: Periodically generate new API Keys and deactivate old ones - **Use least privilege**: If available, use API Keys with minimal required permissions ### Managing API Keys You can view and manage your API Keys in the Auth section of your [Mission Control portal](https://portal.telnyx.com). ## Authentication Methods ### Bearer Token Authentication Most Telnyx APIs use Bearer token authentication in the Authorization header: ```bash curl -X GET \ --header "Authorization: Bearer YOUR_API_KEY" \ "https://api.telnyx.com/v2/endpoint" ``` ### SDK Authentication When using Telnyx SDKs, authentication is typically configured once during initialization: ```javascript // Node.js SDK const telnyx = require('telnyx')('YOUR_API_KEY'); // Python SDK import telnyx telnyx.api_key = "YOUR_API_KEY" // Ruby SDK Telnyx.api_key = "YOUR_API_KEY" ``` ## Common Authentication Patterns ### RESTful APIs - **Voice API**: Bearer token in Authorization header - **Messaging API**: Bearer token in Authorization header - **Cloud Storage**: AWS Signature Version 4 or Bearer token - **IoT APIs**: Bearer token in Authorization header ### Real-time Connections - **WebRTC**: JWT tokens for client authentication - **WebSocket connections**: Bearer token during connection establishment ## Error Handling ### Authentication Errors Common authentication-related HTTP status codes: - **401 Unauthorized**: Invalid or missing API Key - **403 Forbidden**: Valid API Key but insufficient permissions - **429 Too Many Requests**: Rate limit exceeded ### Debugging Authentication Issues 1. **Verify API Key format**: Ensure the key is correctly formatted and complete 2. **Check headers**: Confirm the Authorization header is properly set 3. **Validate permissions**: Ensure your API Key has the required permissions for the resource 4. **Test with curl**: Use curl to isolate authentication issues from SDK problems ## Environment-Specific Considerations ### Development vs Production - Use separate API Keys for development and production environments - Never use production API Keys in development or testing - Consider using restricted API Keys for development ### Regional Considerations Some Telnyx services may have regional API endpoints. Always check the specific service documentation for the correct base URL. ## Account Management ### Account Levels and Access Account levels determine which APIs and features are available to you. For detailed information about account types, capabilities, and verification requirements, see [Account Levels and Capabilities](https://developers.telnyx.com/docs/account-setup/levels-and-capabilities). ## Next Steps - **API Reliability & Retries** - Handle authentication failures gracefully - **Webhook Security** - Secure your webhook endpoints - **SDKs & Tools** - Language-specific authentication setup --- ### HTTP Patterns > Source: https://developers.telnyx.com/docs/development/api-fundamentals/request-response.md Understanding common request and response patterns will help you build robust integrations across all Telnyx services. This guide covers the universal HTTP concepts that apply to Voice, Messaging, Cloud Storage, IoT, and all other Telnyx APIs. ## HTTP Methods Telnyx APIs follow RESTful conventions using standard HTTP methods: ### **GET** - Retrieve Resources Used to fetch information without making changes: ```bash GET /v2/messaging_profiles GET /v2/calls/{call_id} GET /v2/storage/buckets ``` ### **POST** - Create Resources Used to create new resources or trigger actions: ```bash POST /v2/calls # Make a phone call POST /v2/messages # Send a message POST /v2/storage/objects # Upload a file ``` ### **PATCH** - Update Resources Used to modify existing resources: ```bash PATCH /v2/messaging_profiles/{id} # Update profile PATCH /v2/phone_numbers/{id} # Update phone number settings ``` ### **DELETE** - Remove Resources Used to delete resources: ```bash DELETE /v2/messaging_profiles/{id} # Delete messaging profile DELETE /v2/telephony_credentials/{id} # Delete telephony credential ``` ## Request Format ### Content-Type Headers Most Telnyx APIs expect JSON payloads: ```bash Content-Type: application/json ``` For file uploads or form data: ```bash Content-Type: multipart/form-data Content-Type: application/x-www-form-urlencoded ``` ### Request Structure ```bash curl -X POST \ --header "Authorization: Bearer YOUR_API_KEY" \ --header "Content-Type: application/json" \ --data '{ "to": "+1234567890", "from": "+0987654321", "text": "Hello World" }' \ "https://api.telnyx.com/v2/messages" ``` ## Response Format ### Standard Response Structure Most Telnyx APIs return JSON responses with consistent structure: ```json { "data": { "id": "resource_id", "record_type": "resource_type", // ... resource properties }, "meta": { "page_number": 1, "page_size": 20, "total_pages": 5, "total_results": 100 } } ``` ### Success Responses - **200 OK**: Request successful, data returned - **201 Created**: Resource successfully created - **202 Accepted**: Request accepted, processing asynchronously - **204 No Content**: Request successful, no data to return ### Error Responses Error responses include details to help troubleshoot issues: ```json { "errors": [ { "code": "10001", "title": "Invalid parameter", "detail": "The 'to' field is required", "source": { "pointer": "/data/attributes/to" } } ] } ``` ### Telnyx API Error Codes For a comprehensive list of all Telnyx-specific error codes and their meanings, see the [API Error Codes reference](/docs/development/api-fundamentals/api-errors). This resource provides detailed explanations for each error code to help you troubleshoot and handle API errors effectively. Common error patterns include: - **10xxx codes**: Parameter validation errors - **20xxx codes**: Authentication and authorization errors - **30xxx codes**: Resource not found or unavailable errors - **40xxx codes**: Rate limiting and quota errors - **50xxx codes**: Server-side errors ## HTTP Status Codes ### Client Errors (4xx) - **400 Bad Request**: Invalid request format or parameters - **401 Unauthorized**: Authentication failed - **403 Forbidden**: Authentication succeeded but access denied - **404 Not Found**: Resource doesn't exist - **422 Unprocessable Entity**: Valid request format but logical errors - **429 Too Many Requests**: Rate limit exceeded ### Server Errors (5xx) - **500 Internal Server Error**: Unexpected server error - **502 Bad Gateway**: Upstream service error - **503 Service Unavailable**: Service temporarily unavailable - **504 Gateway Timeout**: Request timeout ## Common Headers ### Request Headers ```bash Authorization: Bearer YOUR_API_KEY # Authentication Content-Type: application/json # Request format Accept: application/json # Expected response format User-Agent: YourApp/1.0 # Client identification ``` ### Response Headers ```bash Content-Type: application/json # Response format X-RateLimit-Limit: 100 # Rate limit maximum X-RateLimit-Remaining: 75 # Remaining requests X-RateLimit-Reset: 1640995200 # Rate limit reset time ``` ## Pagination For endpoints that return lists, Telnyx uses consistent pagination: ### Request Parameters ```bash GET /v2/messages?page[number]=2&page[size]=50 ``` ### Response Metadata ```json { "data": [...], "meta": { "page_number": 2, "page_size": 50, "total_pages": 10, "total_results": 500 } } ``` ## Filtering and Sorting ### Common Filter Patterns ```bash # Filter by date range GET /v2/messages?filter[created_at][gte]=2023-01-01 # Filter by status GET /v2/calls?filter[status]=completed # Sort results GET /v2/messages?sort=created_at GET /v2/calls?sort=-created_at # Descending order ``` ## Best Practices ### Request Optimization - **Use appropriate HTTP methods**: Don't use POST for retrieving data - **Include relevant headers**: Specify Content-Type and Accept headers - **Validate input**: Check parameters before sending requests - **Handle timeouts**: Set appropriate timeout values ### Response Handling - **Check status codes**: Don't assume all responses are successful - **Parse error messages**: Use error details for troubleshooting - **Handle edge cases**: Account for empty results and partial failures - **Log appropriately**: Log errors but avoid logging sensitive data ## Next Steps - **API Reliability & Retries** - Handle failed requests - **Webhook Fundamentals** - Receive asynchronous notifications - **API Glossary** - Reference for API terminology --- ### API error codes > Source: https://developers.telnyx.com/docs/development/api-fundamentals/api-errors.md This page lists the general Telnyx API error codes. 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](https://developers.telnyx.com/data/api-errors.json): normalized entries with product scope, source provenance, and authored remediation metadata. - [Catalog source registry](https://developers.telnyx.com/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 error codes | 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 occured. | | 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 #. | | 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 In order to protect our services, we employ the use of [rate limits](https://en.wikipedia.org/wiki/Rate_limiting) on the majority of `api.telnyx.com` endpoints. These limits are typically static, but are subject to change based on usage and may be adjusted to align with changes in capacity. For this reason, we include headers in our API responses that should be parsed and respected by your application. These headers aim to help you understand your current consumption rate and self-diagnose or prevent potential throttling issues. ## Rate Limit Headers | Term | Description | | --------------------- | -------------------------------------------------------------------------------- | | x-ratelimit-limit | Displays the applicable rate limits for the current request | | x-ratelimit-remaining | Indicates how many requests a user can still make within the current time window | | x-ratelimit-reset | Shows the time in seconds until the rate limit resets | When the rate limit is exceeded, responses with status code 429 will be returned, indicating that you have exhausted the number of requests allowed in the current window. ## Rate Limit Response ### HTTP Status Code The status code of rate limit responses is [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429). ### Response Body ```json { "errors": [ { "code": "10011", "title": "Too many requests", "detail": "You have exceeded the maximum number of allowed requests." } ] } ``` ## Handling Rate Limits ### Best Practices 1. **Monitor Headers**: Always check the rate limit headers in API responses 2. **Implement Backoff**: Use exponential backoff when receiving 429 responses 3. **Cache Results**: Cache API responses when possible to reduce request frequency 4. **Distribute Load**: Spread requests across multiple time windows ### Over Your Rate Limit? Contact support@telnyx.com if you find you are exceeding the rate limit. ## Product-Specific Rate Limits Different Telnyx services may have different rate limiting strategies: - **Messaging**: See [Rate Limiting](/docs/messaging/messages/rate-limiting) and [Message Encoding](/docs/messaging/messages/message-encoding) for messaging-specific limits - **10DLC**: See [10DLC rate limits](/docs/messaging/10dlc/10dlc-rate-limits) for campaign-specific limits - **Voice API**: Standard API rate limits apply to call control endpoints - **Cloud Storage**: Rate limits apply to S3-compatible operations --- ### API Reliability & Retries > Source: https://developers.telnyx.com/docs/development/api-fundamentals/reliability/command-retries.md When building applications with Telnyx APIs, you may encounter various reliability challenges that require robust error handling and retry strategies. These patterns apply across all Telnyx services including Voice, Messaging, Cloud Storage, and more. ## Common Reliability Challenges Applications may encounter the following situations across any Telnyx API: - **5XX Errors**: Server errors (500, 501, 503, 504) that indicate temporary service issues - **Network Timeouts**: Requests that don't complete within expected timeframes - **Duplicate Responses**: Identical responses that may occasionally be delivered ## Best Practices for API Reliability Telnyx carefully monitors all API platforms for 5XX errors, latency, and duplicate responses, and actively works to keep all of these to a minimum across all services. For added reliability, there are several steps developers can take to handle errors, latency, and duplicate responses across any Telnyx API: ### **Retry Strategies** - **Retry on 5XX Errors**: If your application receives a 500-level error, implement exponential backoff and retry - **Timeout Handling**: If your application fails to receive an HTTP response within a reasonable timeframe (typically 500ms-5s depending on the operation), retry the request - **Maximum Retry Attempts**: Implement a maximum retry limit (typically 3-5 attempts) to avoid infinite loops ### **Error Handling Patterns** - **Exponential Backoff**: Increase wait time between retries (e.g., 1s, 2s, 4s, 8s) - **Circuit Breaker**: Temporarily stop making requests if error rates exceed thresholds - **Graceful Degradation**: Design your application to continue functioning even when some API calls fail --- ### Webhook Fundamentals > Source: https://developers.telnyx.com/docs/development/api-fundamentals/webhooks/receiving-webhooks.md One application can provide another application with real-time updates via a webhook (also referred to as a web callback or HTTP push API). A webhook delivers data to other applications as it happens, meaning you get data immediately. In the past, APIs would typically need to poll for data very frequently to get it promptly. This makes webhooks much more efficient for both providers and consumers. The only drawback to webhooks is the difficulty of initially setting them up - [this](/docs/messaging/messages/send-receive-mms) tutorial walks through how to consume webhooks. Webhooks are sometimes referred to as "Reverse APIs," as they give you what amounts to an API spec, and you must design an API for the webhook to use. The webhook will make an HTTP request to your app (typically a POST), and you will then be charged with interpreting it. Telnyx can send webhook events that notify your application any time an event happens on your account. This is especially useful for events like receiving an SMS or MMS message and getting feedback on Voice API events. The [messaging webhooks](/docs/messaging/messages/receiving-webhooks) section goes into a bit more detail on how SMS and MMS webhooks work. The [machine-readable webhook event catalog](https://developers.telnyx.com/data/webhook-events.json) contains the concrete request payload, media type, source specification, and publication selector for every canonical Telnyx webhook. Use the catalog when callback-page Markdown exports do not include the OpenAPI request example. ## Delivery contract Apply the following handling sequence: 1. Preserve the raw request body and the `telnyx-timestamp` and `telnyx-signature-ed25519` headers. 2. Verify the signature before trusting or queuing the event. 3. Record the event identifier and the product-specific correlation identifiers. 4. Return a `2xx` response promptly. Perform network calls and other long-running work asynchronously. 5. Process the queued event idempotently. Treat the event identifier as the deduplication key where the product envelope supplies one. Do not depend on delivery order or single delivery. Events can be concurrent, duplicated, delayed, or delivered out of order. Reconcile state using `occurred_at` and product resource identifiers where those fields exist; do not use arrival time as authoritative event order. Primary URL, failover URL, timeout, and retry behavior are configured and documented by product. A failed primary delivery can be retried or sent to a configured failover URL. Do not assume one retry schedule applies to every Telnyx product. ## Webhook Setup Options Choose one of the following options based on your development stage: ### Option A: Local Development with ngrok (Recommended for Testing) 1. Install ngrok following our [ngrok setup guide](/docs/development/development-tools/ngrok-setup). 2. Start your local webhook server (see example below). 3. Create a tunnel: `ngrok http 3000`. 4. Use the provided HTTPS URL (e.g., `https://abc123.ngrok.io/webhooks`). ### Option B: Quick Testing with webhook.site 1. Visit [webhook.site](https://webhook.site). 2. Copy your unique URL. 3. Use this for initial testing (note: this won't allow you to respond to webhooks). ### Option C: Production Deployment Deploy your webhook handler to a cloud service like: - AWS Lambda with API Gateway. - Google Cloud Functions. - Heroku. - DigitalOcean App Platform. ## Webhook delivery characteristics Webhook consumers must support these delivery characteristics: - **Does not guarantee delivery order**: Webhooks may arrive out of sequence - **Retries failed delivery**: Retry timing and failover behavior depend on the product configuration - **Delivers concurrently**: Multiple webhooks may arrive simultaneously As a result, your application should be prepared to handle: - **Out-of-order webhooks**: Events may not arrive in chronological order - **Simultaneous webhooks**: Multiple events may be delivered at the same time - **Duplicate webhooks**: The same event may be delivered more than once ## Handling Duplicate Events Duplicate webhooks can cause your application to process the same event multiple times. To prevent this: - **Use idempotency keys**: Include unique identifiers in your API requests (such as `command_id`, `idempotency_key`, etc.) - **Implement deduplication**: Track processed webhook IDs to avoid duplicate processing - **Design idempotent operations**: Ensure that processing the same event multiple times has no adverse effects ## Webhook payload structure JSON event envelopes commonly contain these identification fields. TeXML callbacks use `application/x-www-form-urlencoded` fields instead. Consult the [webhook event catalog](https://developers.telnyx.com/data/webhook-events.json) for the exact media type and payload for each callback. - **Event ID**: Unique identifier for the webhook event - **Timestamp**: When the event occurred - **Resource IDs**: Identifiers that correlate the webhook with your resources (calls, messages, etc.) - **Event Type**: Describes what action triggered the webhook ## Security & Protocols ### HTTP and HTTPS - Unsecure (HTTP) URLs are allowed for webhooks. - If HTTPS (TLS) is used, the certificate will be validated. ### Event type naming Where possible, events map to the C(R)UD operations, but this is certainly not always be applicable. - resource.created - resource.updated - resource.deleted When the CRUD operations are not applicable, events will be named with past tense verbs. - message.created - message.deleted - message.delivered - message.received - porting_sub_request.ported - porting_sub_request.closed ## Webhook structure The top-level structure varies by product and protocol. Voice API and Messaging use different JSON envelopes; TeXML uses form-encoded callbacks. Within a product family, `event_type` or an equivalent field determines the event-specific payload. Parse according to the documented media type and event schema rather than assuming a universal envelope. ### Voice API top-level structure ```json { "call_leg_id": "e97d8d4c-1a25-11cd-bc67-02620a0f6d42", "call_session_id": "e97da4f0-1a25-11bd-909f-02620a0f6d642", "event_timestamp": "2019-11-10T22:25:27.521992Z", "metadata": { "attempt": 1, "delivered_to": "https://www.example.com/callback", "event": { "event_type": "call.initiated", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "occurred_at": "2019-11-10T22:25:27.521992Z", "payload": { ... }, "record_type": "event" }, "status": "delivered" }, "name": "call.initiated", "organization_id": null, "type": "webhook", "user_id": "901dbc74-1597-4d15-aad2-xxxxxxxxxxxx" } ``` | FIELD NAME | DESCRIPTION | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `call_leg_id` | ID that is unique to the call and can be used to correlate webhook events. | | `call_session_id` | ID that is unique to the call session and can be used to correlate webhook events. | | `event_timestamp` | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) datetime of when the event occurred. | | `attempt` | The number of attempts made to deliver the webhook. Multiple attempts will occur if your application does not send Telnyx `HTTP 200 OK` on receipt of the webhook. | | `delivered_to` | URL that the webhook was sent to. | | `event_type` | The type of event being delivered which also determines the structure of the `payload`. | | `id` | Unique ID of the event. | | `occurred_at` | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) datetime of when the event occurred. | | `record_type` | Will always be `event`. | | `status` | Status of the webhook for debugging purposes. | | `name` | Event name. | | `organization_id` | ID of the organization. | ### Messaging top-level structure ```json { "data": { "event_type": "message.finalized", "id": "4ef8c3a6-4195-4389-b3a6-38e3cb9eb4ae", "occurred_at": "2019-11-10T22:30:14.148+00:00", "payload": { ... }, "record_type": "event" }, "meta": { "attempt": 1, "delivered_to": "https://www.example.com/messaging" } } ``` | FIELD NAME | DESCRIPTION | | -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `event_type` | The type of event being delivered which also determines the structure of the `payload`. | | `id` | Unique ID of the event. | | `occurred_at` | [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) datetime of when the event occurred. | | `payload` | The main data for the event. The structure is denoted by the `event_type`. | | `record_type` | Will always be `event`. | | `attempt` | The number of attempts made to deliver the webhook. Multiple attempts will occur if your application does not send Telnyx a `2xx` HTTP status code within 2s of receipt of the webhook. | | `delivered_to` | URL that the webhook was sent to. | ## Example: Receiving a Webhook When you place an incoming call to a number associated with your Voice API Application, you will receive a callback for the incoming call. It should look something like the JSON below: ```json { "data": { "record_type": "event", "event_type": "call.initiated", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "occurred_at": "2018-02-02T22:25:27.521992Z", "payload": { "call_control_id": "d14dbcee-880b-11eb-8204-02420a0f7568", "connection_id": "7267xxxxxxxxxxxxxx", "call_leg_id": "d14dbcee-880b-11eb-8204-02420a0f7568", "call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1", "client_state": "aGF2ZSBhIG5pY2UgZGF5ID1d", "from": "+1-202-555-0133", "to": "+12025550131", "direction": "incoming", "state": "parked" } }, "meta": { "attempt": 1, "delivered_to": "http://example.com/webhooks" } } ``` > **Note:** After pasting the above content, Kindly check and remove any new line added Field Value record_type Description of the record. event_type The type of event detected by the Telnyx system id unique id for the webhook occurred_at ISO-8601 datetime of when event occured call_control_id call id used to issue commands via Voice API connection_id Voice API App ID (formerly Telnyx connection ID) used in the call. call_leg_id ID that is unique to the call and can be used to correlate webhook events call_session_id ID that is unique to the call session and can be used to correlate webhook events. Call session is a group of related call legs that logically belong to the same phone call, e.g. an inbound and outbound leg of a transferred call. client_state State received from a command from Number or SIP URI placing the call to Destination number or SIP URI of the call direction Whether the call is 'incoming' or 'outgoing' state Whether the call is in 'bridging' or 'parked' state ### Full Voice API example ```json { "call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1", "call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1", "event_timestamp": "2019-11-10T22:26:27.521992Z", "metadata": { "attempt": 1, "delivered_to": "https://www.example.com/callback", "event": { "event_type": "call.answered", "id": "0ccc7b54-4df3-4bca-a65a-3da1ecc777f0", "occurred_at": "2019-11-10T22:26:27.521992Z", "payload": { "call_control_id": "v2:F5_vIJVqrosogeY_2L_JhCEHd2Dh-x4xz7tROTbh34tg6Zsk4JJc-w", "call_leg_id": "428c31b6-7af4-4bcb-b7f5-5013ef9657c1", "call_session_id": "428c31b6-abf3-3bc1-b7f4-5013ef9657c1", "client_state": null, "connection_id": "7267xxxxxxxxxxxxxx", "from": "+8005550199", "start_time": "2019-11-10T22:26:26.521992Z", "to": "+8005550100" }, "record_type": "event" }, "status": "delivered" }, "name": "call.answered", "organization_id": null, "type": "webhook", "user_id": "901dbc74-1597-4d15-aad2-xxxxxxxxxxxx" } ``` ## Responding to a webhook To acknowledge receipt of a webhook, return a `2xx` HTTP status code. Response headers and bodies are not used to process the event. Responses outside the `2xx` range, including redirects, indicate failed delivery. ## Retries Treat timeout, network, and non-`2xx` responses as possible retry conditions. Product-specific retry and failover policies determine the attempts and destinations. The endpoint must tolerate repeated delivery even after an earlier attempt completed processing but its acknowledgment was not observed. ## Best practices Return the acknowledgment before performing complex logic or network calls. Queue the verified event, return `2xx`, and process it asynchronously. Make event processing idempotent. Store processed event identifiers with a retention period appropriate to the product, and make resource updates conditional so replaying an event has no additional effect. Verify webhook signatures before recording an event as accepted. Log the event identifier, event type, delivery attempt when present, and product resource identifiers for correlation and failure analysis. ## Webhook signing Telnyx signs the webhook events it sends to clients so that the authenticity of the request can be verified. 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. The public key can be viewed in the [Mission Control Portal](https://portal.telnyx.com/#/api-keys/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. ```ruby 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. --- ### Parameters & Field Names > Source: https://developers.telnyx.com/docs/development/api-fundamentals/data-standards/parameters-fields.md The Parameter & Field names section provides an overview of patterns for API request and response parameters and field names. ## Data Types ### Booleans Boolean values are presented as `true` and `false` values. They will not be `1` or `0` nor will they be strings such as "true" and "false". ### Date-times All date-times are represented in UTC with precisely the following format: `YYYY-MM-DDThh:mm:ss.fffZ` where `fff` is the first three decimals of the fractional seconds (i.e., millisecond precision). API V2 accepts date-times in _at least_ the following 12 formats: - `YYYY-MM-DDThh:mm:ss.fffZ` - `YYYY-MM-DDThh:mm:ssZ` - `YYYY-MM-DDThh:mmZ` - The above with `-00`, `-0000`, or `-00:00` instead of the `Z` timezone identifier. ### Times (no date portion) All times are represented in UTC with precisely the following format: `hh:mm:ss.fffZ` where `fff` is the first three decimals of the fractional seconds (i.e., millisecond precision). ### Durations If a parameter represents a unit of time, then the unit name should be part of the field name so that the consumer knows what the value represents. For example, a retry timeout value would be named `retry_timeout_secs` or `retry_timeout_millis`. Valid field suffixes are: - millis - secs - hours - days - weeks - months - years API V2 does not use ISO8601 time durations (e.g. `P4Y`, `PT0,42M` or `P3Y6M4DT12H30M5.423S`). ### Time zones Time zone field names are always spelled as `timezone` and the value is always the Time Zone Database area name spelled out as `Europe/Berlin`, `America/Chicago` for example. ## Date Literals User-friendly date ranges use this naming convention. | Date Literal | Range | | ------------ | -------------------------------------------------------------------------------------------------------------------------------------- | | yesterday | Starts 00:00:00 the day before and continues for 24 hours. | | today | Starts 00:00:00 of the current day and continues for 24 hours. | | tomorrow | Starts 00:00:00 after the current day and continues for 24 hours. | | last_week | Starts 00:00:00 on the first day of the week before the most recent first day of the week and continues for seven full days. | | this_week | Starts 00:00:00 on the most recent first day of the week before the current day and continues for seven full days. | | next_week | Starts 00:00:00 on the most recent first day of the week after the current day and continues for seven full days. | | last_month | Starts 00:00:00 on the first day of the month before the current day and continues for all the days of that month. | | this_month | Starts 00:00:00 on the first day of the month that the current day is in and continues for all the days of that month. | | next_month | Starts 00:00:00 on the first day of the month after the month that the current day is in and continues for all the days of that month. | | last_N_hours | For the number n provided, starts at 00 of the last hour and continues for the past n hours. | | next_N_hours | For the number n provided, starts at 00 of the next hour and continues for the next n hours. | | last_N_days | For the number n provided, starts 00:00:00 of the current day and continues for the past n days. | | next_N_days | For the number n provided, starts 00:00:00 of the current day and continues for the next n days. | | last_N_weeks | For the number n provided, starts 00:00:00 of the last day of the previous week and continues for the past n weeks. | | next_N_weeks | For the number n provided, starts 00:00:00 of the first day of the next week and continues for the next n weeks. | ## HTTP Headers Date-times in HTTP headers follow [RFC-7231 §7.1.1.1](https://www.rfc-editor.org/rfc/rfc7231)'s recommended "IMF-fixdate" format. An example of the preferred format is Sun, 06 Nov 1994 08:49:37 GMT ; IMF-fixdate ## Naming Conventions ### Enums and string literals Enum and string literal parameters use snake case. If there is an acronym involved, there will not be an underscore between every letter. For example, `by_ani` instead of`ByANI`, `byAni`, or `by_a_n_i`. ### Country codes The field name `country_code` is always used to represent a country. It will be in [ISO 3166-1 alpha-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) format in capital letters to represent the country. For example `DE` for Germany. ### Phone numbers Phone numbers are always specified in [e164](https://en.wikipedia.org/wiki/E.164) format. For example, `+18005550199`. If the country calling code needs to be represented in the API, the field name will always be `country_calling_code`. If representing the actual country via its alpha 2 representation, `country_code` will be used. Ex: `{"country_calling_code": "1", "country_code": "US"}` ### City names City names are always called `locality` and represented in title case. For example, `New York City` instead of `NEW YORK CITY`. ## Address Format Addresses are represented like this: ```json { "street_address": "311 W Superior St", "extended_address": "Suite 504", "locality": "Chicago", "administrative_area": "IL" "country_code": "US", "postal_code": "60654" } ``` ### U.S. addresses US states are always represented in their two-digit form in capital letters. For example, `NY` for New York. ## Pagination The parameter which contains pagination is `page`. This parameter is a map of pagination attributes. ### Example `GET /phone_numbers?page[number]=3&page[size]=1 HTTP/1.1` The default number of items per page is 20; however, sometimes, this may not be appropriate. Page numbering is 1-based and omitting the `page`, or the `page[number]` parameter will return the first page. Generally speaking, the maximum allowable results will not be more than 250, although there may be some exceptions to this rule. The total number of results is provided in the `total_pages` field so that clients will know how many page options to display. ### Example Response ```bash HEADERS Total-Pages:13 ``` Response: ```json { "meta": { "total_pages": 13, "total_results": 26, "page_number": 3, "page_size": 2 }, "data": [ { "record_type": "phone_number", "id": "4567890987", "phone_number": "+18005550100", "purchased_at": "2015-05-22T14:56:29.000Z", ... }, { "record_type": "phone_number", "id": "44568890987", "phone_number": "+18005550199", "purchased_at": "2015-05-22T14:56:29.000Z", ... } ] } ``` ## Sorting An endpoint may support requests to sort the primary data with a `sort` query parameter. ### Example ```bash GET /connections?sort=name HTTP/1.1 ``` Unless not appropriate, the default sort will be `created_at DESC` An endpoint may also support multiple sort fields using the array syntax. Sort fields will be applied in the order specified. ### Multiple Sort Fields ```bash GET /connections?sort[]=name&sort[]=created_at HTTP/1.1 ``` The sort order for each sort field will be ascending unless it is prefixed with a minus (U+002D HYPHEN-MINUS, "-"), in which case it will be descending. ```bash GET /connections?sort[]=-created_at&sort[]=name HTTP/1.1 ``` The above example should return the newest connections first. Any connections created on the same date will then be sorted by their name in ascending alphabetical order. ## Filtering Filtering of a resource collection based upon associations do so by allowing query parameters that combine the filter with the association name. For example, the following is a request for all phone_numbers associated with a particular tag: ```bash GET /phone_numbers?filter[tag]=tag_one HTTP/1.1 ``` Filtering to values within an array can be achieved using query parameter array syntax: ```bash GET /phone_numbers?filter[tag][]=tag_one&filter[tag][]=tag_two HTTP/1.1 ``` Or an example using comments: ```bash GET /comments?filter[tag]=tag_one,tag_two HTTP/1.1 ``` Use the string `null` to filter on resources that don't have a particular value set: ```bash GET /comments?filter[author]=null HTTP/1.1 ``` ### Filtering on values of nested or related objects To denote that a filter applies to an attribute of a nested object, use the dot notation. For example, the phone numbers endpoint returns data in this format: ```json { "id": "d460a653-8ee6-4061-ae9a-5b8a52539fb4", "phone_number": "18005550199", "record_type": "phone_number", ... "voice": { "e911_address_id" : "", "connection_name" : false, "inbound_call_recording_channels" : "single", ... } } ``` To filter by the connection name the path and request would look like: ```bash GET /phone_numbers?filter[voice.connection_name]=conn_one HTTP/1.1 ``` Similarly by connection ID: ```bash GET /regions?filter[voice.connection_id]=d460a653-8pp6-4061-ae9a-5b8a57339fb4 HTTP/1.1 ``` However, if `name` was a top-level key as in the below example: ```json { "id": "d460a653-8pp6-4061-ae9a-5b8a57339fb4", "name": "conn_one", "record_type": "connection", ... } ``` then the query would be: ```bash GET /connections?filter[name]=conn_one HTTP/1.1 ``` ### Complex filters When filtering, you may need to specify more complex filters than `equal to`. Options are: - `eq` - `ne` - `gt` - `gte` - `lt` - `lte` - `starts_with` - `ends_with` - `contains` Return phone numbers purchased before 2018-02-21: ```bash GET /phone_numbers?filter[purchased_at][lt]=2018-02-21 HTTP/1.1 ``` If using `eq` then: ```bash GET /phone_numbers?filter[purchased_at][eq]=2018-02-21 HTTP/1.1 ``` and: ```bash GET /phone_numbers?filter[purchased_at]=2018-02-21 HTTP/1.1 ``` are equivalent. To filter using string data use `starts_with`, `ends_with` or `contains`: ```bash GET /phone_numbers?filter[voice.connection_name][contains]=conn HTTP/1.1 ``` --- ## Server-side SDKs ### Node.js > Source: https://developers.telnyx.com/docs/development/sdk/node.md --- ### Python > Source: https://developers.telnyx.com/docs/development/sdk/python.md --- ### PHP > Source: https://developers.telnyx.com/docs/development/sdk/php.md ```php $region, 'version' => 'latest', 'endpoint' => $endpoint, 'credentials' => [ 'key' => $telnyxAPIKey, 'secret' => $telnyxAPIKey, ], 'use_path_style_endpoint' => true ]); $bucketName = "test-bucket-" . $region . '-' . date('H-i') . '-' . rand(0, 1000000); echo "Generated bucket name: " . $bucketName . PHP_EOL; // 2. Create a bucket try { $s3Client->createBucket([ 'Bucket' => $bucketName ]); echo "Created bucket: {$bucketName}" . PHP_EOL; } catch (AwsException $e) { die("Unable to create bucket: " . $e->getMessage()); } // 3. Upload two objects with random data for ($i = 0; $i < 2; $i++) { $content = random_bytes(1024 * 32); // 32KB of random data $objName = "{$i}.txt"; try { $s3Client->putObject([ 'Bucket' => $bucketName, 'Key' => $objName, 'Body' => $content ]); echo "Uploaded file ({$objName}) to bucket: {$bucketName}" . PHP_EOL; } catch (AwsException $e) { die("Unable to upload file ({$objName}): " . $e->getMessage()); } } // 4. List objects in the bucket try { $result = $s3Client->listObjects([ 'Bucket' => $bucketName ]); foreach ($result['Contents'] as $item) { echo "Listed object: " . $item['Key'] . PHP_EOL; } } catch (AwsException $e) { die("Unable to list objects: " . $e->getMessage()); } // 5. Download the first object try { $result = $s3Client->getObject([ 'Bucket' => $bucketName, 'Key' => '1.txt' ]); $data = $result['Body']->getContents(); echo "Downloaded file size: " . strlen($data) . PHP_EOL; } catch (AwsException $e) { die("Unable to download object: " . $e->getMessage()); } // 6. Create a presigned URL for the first file $url = "https://api.telnyx.com/v2/storage/buckets/{$bucketName}/1.txt/presigned_url"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['TTL' => 30])); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $telnyxAPIKey, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpcode != 200) { die("Unexpected status code: {$httpcode} | response: {$response}"); } $presignedData = json_decode($response, true); $presignedURL = $presignedData['data']['presigned_url']; echo "Generated presigned URL: {$presignedURL}" . PHP_EOL; // 7. Download the file using the presigned URL $ch = curl_init($presignedURL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); curl_close($ch); echo "Downloaded presigned URL data size: " . strlen($result) . PHP_EOL; ?> ``` --- ### Java > Source: https://developers.telnyx.com/docs/development/sdk/java.md ## Add Dependency ``` software.amazon.awssdk s3 2.20.0 ``` ## Create S3 Bucket ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; public class CreateBucket { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "-- api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) // Only perform CRC checks `when_required` .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED) .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // create bucket CreateBucketRequest createBucketRequest = CreateBucketRequest.builder() .bucket(bucketName) .build(); s3.createBucket(createBucketRequest); System.out.println("Bucket created successfully: " + bucketName); // Close the S3 client s3.close(); } } ``` ## Upload an Object ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import java.net.URI; import java.nio.file.Paths; public class UploadObjectToS3 { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; String keyName = "your-object-key"; String filePath = "--path to file for upload--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // upload object PutObjectRequest putObjectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); // Upload the file to S3 s3.putObject(putObjectRequest, RequestBody.fromFile(Paths.get(filePath))); // Close the S3 client s3.close(); } } ``` ## List Objects ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; import software.amazon.awssdk.services.s3.model.S3Object; import java.net.URI; public class ListObjects { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // Create a ListObjectsV2Request ListObjectsV2Request listObjectsRequest = ListObjectsV2Request.builder() .bucket(bucketName) .build(); // Get the list of objects in the bucket ListObjectsV2Response listObjectsResponse = s3.listObjectsV2(listObjectsRequest); for (S3Object s3Object : listObjectsResponse.contents()) { System.out.println( s3Object.key()); } // Close the S3 client s3.close(); } } ``` ## Download Object ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; public class DownloadObject { public static void main(String[] args) throws IOException { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; String keyName = "your-object-key"; S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // Create a GetObjectRequest GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); // Download the object and transform the response to a byte array ResponseBytes objectBytes = s3.getObject(getObjectRequest, ResponseTransformer.toBytes()); // Write the file to the specified path File downloadedFile = new File("-- path to where to save the file --"); try (FileOutputStream fos = new FileOutputStream(downloadedFile)) { fos.write(objectBytes.asByteArray()); System.out.println("File downloaded successfully to -- path to where to save the file --"); } // Close the S3 client s3.close(); } } ``` ## Generate Presigned URLs for Upload and Download In order for this part to work, we will need to add json decoding library and http client. Any libraries will do, but for this example we picked: gson and okhttp3. ``` com.squareup.okhttp3 okhttp 4.9.2 com.google.code.gson gson 2.8.7 ``` ``` import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import okhttp3.*; import java.io.IOException; import java.util.Map; public class GeneratePresignedURLAndDownloadObject { public static void main(String[] args) throws IOException { OkHttpClient httpClient = new OkHttpClient(); Gson gson = new Gson(); String presignedUrlRequestJson = gson.toJson(Map.of("TTL", 30)); RequestBody presignedUrlRequestBody = RequestBody.create(MediaType.parse("application/json"), presignedUrlRequestJson); Request presignedUrlRequest = new Request.Builder() .url("https://api.telnyx.com/v2/storage/buckets/-- name of the bucket --/--name of the object--/presigned_url") .header("Authorization", "Bearer --your api key---") .post(presignedUrlRequestBody) .build(); try (Response response = httpClient.newCall(presignedUrlRequest).execute()) { if (!response.isSuccessful()) { throw new IOException("Failed to create presigned URL: " + response); } String responseBody = response.body().string(); Map responseBodyMap = gson.fromJson(responseBody, new TypeToken>() {}.getType()); String presignedUrl = ((Map) responseBodyMap.get("data")).get("presigned_url"); System.out.println("Presigned URL: " + presignedUrl); // 6. Download the file using the presigned URL Request downloadRequest = new Request.Builder() .url(presignedUrl) .build(); try (Response downloadResponse = httpClient.newCall(downloadRequest).execute()) { if (!downloadResponse.isSuccessful()) { throw new IOException("Failed to download file using presigned URL: " + downloadResponse); } System.out.println("Downloaded via presigned URL: " + downloadResponse.body().string()); } } } } ``` --- ### Ruby > Source: https://developers.telnyx.com/docs/development/sdk/ruby.md --- ### Go > Source: https://developers.telnyx.com/docs/development/sdk/golang.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](/api-reference/overview) directly. ## 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. The CLI is auto-generated from the [Telnyx REST API](/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/numbers/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 --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 +15551234567 telnyx number-orders create --phone-number +15551234567 --messaging-profile-id # List/retrieve orders telnyx number-orders list telnyx number-orders retrieve --id ``` ### Number Reservations ```bash telnyx number-reservations create --phone-numbers +15551234567 telnyx number-reservations list telnyx number-reservations retrieve --id telnyx number-reservations delete --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 send-whatsapp --from +15551234567 --to +15559876543 --text "Hello!" # Schedule a message telnyx messages schedule --from +15551234567 --to +15559876543 \ --text "Reminder!" --send-at "2024-12-01T10:00:00Z" # 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 --id telnyx messaging-profiles create --name "Production" telnyx messaging-profiles update --id --name "Updated Name" telnyx messaging-profiles delete --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" \ --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 telnyx messaging-10dlc:brand retrieve --brand-id telnyx messaging-10dlc:brand update --brand-id --display-name "New Name" # 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 telnyx messaging-10dlc:brand verify-sms-otp --brand-id --otp 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 --sample-messages "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 ``` ### Use Cases ```bash telnyx messaging-10dlc:campaign:usecase list ``` ### 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 --call-control-id-b # 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?" # 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 # 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" 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-ids , telnyx conferences:actions unmute --id --call-control-ids , ``` ### Recordings ```bash telnyx recordings list telnyx recordings retrieve --id telnyx recordings delete --id # Transcriptions telnyx recording-transcriptions list telnyx recording-transcriptions retrieve --id ``` ## AI ### Chat Completions ```bash telnyx ai:chat create-completion --model meta-llama/Meta-Llama-3.1-8B-Instruct \ --messages '[{"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 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 --input "Hello!" # Clone assistant telnyx ai:assistants clone --assistant-id ``` ### Audio (Speech-to-Text / Text-to-Speech) ```bash # Transcribe audio telnyx ai:audio create-transcription --file @audio.mp3 --model openai/whisper-large-v3 # Text-to-speech telnyx ai:audio create-speech --input "Hello world" --voice alloy ``` ### Embeddings ```bash telnyx ai:embeddings create --input "Your text here" --model text-embedding-ada-002 ``` ### Conversations ```bash telnyx ai:conversations list telnyx ai:conversations create --assistant-id 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" --default-verification-timeout-secs 300 telnyx verify-profiles update --verify-profile-id --name "updated" telnyx verify-profiles delete --verify-profile-id # Message templates telnyx verify-profiles create-template --verify-profile-id --text "Your code is {{code}}" telnyx verify-profiles retrieve-templates --verify-profile-id ``` ### 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 --id --tags 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-numbers +15551234567 # Portability check telnyx portability-checks create --phone-numbers +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 --key 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 telnyx rooms:sessions list --room-id # 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 --room-session-id ``` ## Networking ### WireGuard ```bash telnyx wireguard-interfaces list telnyx wireguard-interfaces create --network-id telnyx wireguard-interfaces retrieve --id telnyx wireguard-interfaces delete --id telnyx wireguard-peers list --wireguard-interface-id telnyx wireguard-peers create --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" \ --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 # Trigger SMS OTP telnyx messaging-10dlc:brand trigger-sms-otp --brand-id # Verify with OTP code received via SMS telnyx messaging-10dlc:brand verify-sms-otp --brand-id --otp 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, list available use cases telnyx messaging-10dlc:campaign:usecase list # 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 ``` ### 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) --- --- ### 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 ## 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. Command-Line Flag ```bash telnyx number list --api-key KEY_xxxxxxxxxxxxx ``` ## 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 set-default 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 set-default # Set 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 ```bash # Send SMS telnyx message send --from +15551234567 --to +15559876543 --text "Hello!" 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 update --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 telnyx call playback --audio-url https://... ``` ### 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" --entity-type PRIVATE_PROFIT ``` ### Campaign Management ```bash telnyx 10dlc campaign list telnyx 10dlc campaign get telnyx 10dlc campaign create --brand-id --use-case MARKETING ``` ## Billing ```bash telnyx billing balance # Check account balance ``` ## Verification ```bash telnyx verify start +15551234567 --channel sms telnyx verify check --code 123456 ``` ## Shell Autocomplete ```bash telnyx autocomplete # Setup instructions telnyx autocomplete bash # Bash completion script telnyx autocomplete zsh # Zsh completion script ``` ## Global Options | Flag | Description | |------|-------------| | `--api-key ` | Override API key | | `--profile ` | Use specific profile | | `--json` | Output as JSON | | `--help` | Show command help | | `--version` | Show CLI version | | `--dry-run` | Preview without executing (some commands) | ## Migration to New CLI See the [Legacy CLI Overview](/docs/development/cli/legacy) for a command mapping to the new Go-based CLI. --- ## Development Tools ### Postman Setup > Source: https://developers.telnyx.com/docs/development/development-tools/postman-setup.md Postman is an API platform available as a web or desktop application. A great way to understand an API is to make requests and review the responses. Postman exactly does that by providing a UI for testing and experimenting with API calls without the need to write code. Hence, we recommend using Postman to get started quickly and get the taste of Telnyx APIs. You can easily accomplish this by utilizing [our Postman collections](https://www.postman.com/telnyx-api?tab=collections). Steps to use these collections: * Configure your local environment * Import a collection. * Send a test request and inspect the responses. ## Configure environment An environment is a set of [variables](https://learning.postman.com/docs/sending-requests/variables/) you can use in your Postman requests. You can use environments to group related sets of values together. By the end of this tutorial, you would have imported and configured environment to use with Telnyx collections. 1. Create an API Key following the below steps. - [Sign up](https://telnyx.com/sign-up) for a free Telnyx account - Navigate to the [API Keys](https://portal.telnyx.com/#/app/api-keys) section and create an API Key by clicking **Create API Key**. You need to obtain your API key so Telnyx can authenticate your [API requests](https://api.telnyx.com/v2/rooms). Copy and save this key in a safe place and don't share it with anyone as it is a sensitive value. 2. Sign up at [Postman](https://identity.getpostman.com/signup) or [download](https://www.postman.com/downloads/) and install the Postman application. 3. Once signed in to Postman, select an existing workspace or create a new workspace for your Telnyx collections. If you are new to Postman, learn more about creating a workspace [here](https://learning.postman.com/docs/collaborating-in-postman/using-workspaces/creating-workspaces/). 4. Once you are in your desired workspace, click Import in the top left corner, select Link from the options and paste this link in the **Enter a URL** text box: `https://tlyx.co/telnyx-postman-environment` ![Import Telnyx Postman Environment](/assets/images/importpostmanenvironment-1.png) Then click continue and it should show basic details of the environment you are about to import. Click Import and you should see a success confirmation at the bottom right ![Import Postman Confirmation](/assets/images/importpostmanconfirmation-1.png) 5. Go to Environments tab on the left and select `Telnyx Environment` ![Postman Environment](/assets/images/postmanenvironment-2.png) You should see list of variables with the ability to edit existing variables and add new variables. Please do the following steps here: - For the `customerApiKey` variable, in the **Initial Value** and **Current Value** columns, enter your API key that you created earlier in Step 1. - Click Save at the top right to save the value to the environment. 6. Click the box in the top right corner that has list of environments and select `Telnyx Environment` from the list. Initially it shows up as `No Environment`. Doing this will set the workspace to use `Telnyx Environment` moving forward. ![Postman Environment](/assets/images/postmanenvironmentselection-1.png) **You are all set with the Telnyx environment for Postman.** ## Import collections Postman Collections are a group of saved requests. We made it easy to import postman collections by adding a `Run in Postman` button in all the API reference pages that allows you to fork the collections, test API requests, and see the results immediately without writing any code. For example, Use the **Run in Postman** button below to import the Phone Numbers API collection: [![Run in Postman](https://run.pstmn.io/button.svg)](https://god.gw.postman.com/run-collection/19300194-3ed78399-2d3d-4a67-a4db-1d6bc07689a8?action=collection%2Ffork&collection-url=entityId%3D19300194-3ed78399-2d3d-4a67-a4db-1d6bc07689a8%26entityType%3Dcollection%26workspaceId%3Dba40e23b-d67e-47e1-9174-d8c640348288) Then, it should show a dialog box with some information on benefits of forking and links to view/import the collection instead of forking. Click `Fork Collection` ![Fork Collection](/assets/images/forkcollection.png) After clicking Fork Collection, you will see a small form with some details to fill before you fork: - Fork label: Make sure you provide a relevant label for you to easily identify it. Eg: `telnyx's fork` - Workspace: Choose which workspace you would like this collection to be part of. - Watch original collection: Checking this box will notify you when updates are made to the collection so you can pull the latest changes made to the collection. ![Fork Details](/assets/images/forkcollectiondetails.png) Congratulations on forking the collection. You should now be able to see the collection under your selected workspace. ## Send request As you've added your `API KEY` to the environment and imported a collection from the previous steps, you're now ready to send a request. >`Note:` Make sure you have selected Telnyx Environment at the top right from the list of environments As we have imported Phone Numbers API collection from previous steps, let us send a request to list the phone numbers in your account: 1. Once you are in your desired workspace where you imported this collection, Select the **Collections** tab in Postman on the left and expand the **Phone Numbers** collection. 2. Expand the **Number Configurations** folder and select **List phone numbers**. This loads the List phone numbers request into Postman, ready to send. 3. Click **Send**. The result pane automatically displays the results of your request. 4. In case you would like to use any filters, just select the checkbox for any filter you would like from the Params tab, set the value and click **Send**. ![Send Request Sample](/assets/images/sendrequestpostman.png) If you receive an error, it's likely that one of the values in the environment isn't set correctly. Check the values and try again. 5. You can play with the API and if you want to save the request with the modified parameters or any other data, just click save and it should save your changes in the collection. This change would be local to you and would not effect the original collection you forked from. > If you would like to get the latest changes made to the original collection into your local collection, click on the Phone Numbers collection folder and then click on the three dots beside Save button which gives you a list of options. Select `Pull Changes` and it will fetch you the latest updates in that collection. > ![Pull Changes](/assets/images/pullchanges.png) Wohoo!! You have completed your first request with Telnyx API and now you're ready to explore what all the Telnyx API has to offer. If you would like to see list of all collections, check [here](/docs/development/development-tools/postman-setup/collections-list) --- ### ngrok Setup > Source: https://developers.telnyx.com/docs/development/development-tools/ngrok-setup.md This guide walks through how to get ngrok up and running on your machine. To test it out with Telnyx webhooks, you'll need to [sign up](https://telnyx.com/sign-up). If you'd like to test out your ngrok instance by receiving a webhook associated with an API-enabled phone call, jump to our [Receiving Webhooks in Voice API](https://developers.telnyx.com/docs/voice/programmable-voice/receiving-webhooks) after you complete these steps! [ngrok](https://ngrok.com) is a popular tunneling tool used to expose a locally running application to the internet. You can download it for free with all of the functionality you need [here](https://ngrok.com/download). This is useful for receiving webhooks to your local applications for testing. For the sake of this tutorial, we'll assume that your local application is running locally on port `5000`. Now you’ll need the ability to send a request to that port from Telnyx. You can easily do this using ngrok when developing your application. Sign up for ngrok and follow the setup and installation steps to get up and running. The final step in the process is to start an HTTP tunnel to your application. The instructions specify `$ ./ngrok http 80`, which will tunnel traffic to port `80` on your machine. As our application is running on port `5000`, you should use that instead: `$ ./ngrok http 5000`. When you run this command, you should see output similar to the following: ```bash ngrok by @inconshreveable Session Status online Account Little Bobby Tables (Plan: Free) Version 2.3.28 Region United States (us) Web Interface http://127.0.0.1:4040 Forwarding http://ead8b6b4.ngrok.io -> localhost:5000 Forwarding https://ead8b6b4.ngrok.io -> localhost:5000 Connections ttl opn rt1. rt5 p50 p90 0 0 0.00 0.00 0.00 0.00 ``` ## ngrok forwarding address The forwarding addresses will be different for you, but they should still point to `localhost:5000`. Copy the https forwarding address, as you'll need it to configure your Mission Control Portal. ## Messaging With ngrok For messaging, webhooks set the webhook URL on your messaging profile from the Telnyx Portal Messaging dashboard. Edit your Messaging Profile by clicking the “Basic Options” button [✎]. Select the “Inbound” section and paste the forwarding address from ngrok into the Webhook URL field. Append `/webhooks` to the end of the URL to direct the request to the webhook endpoint in your local application. ## Resending webhooks For now, you'll leave “Failover URL” blank, but if you wanted to have Telnyx resend the webhook — if sending to the Webhook URL fails — you can specify an alternate address in this field. ## Next steps We hope this guide helped you understand how to use ngrok. Next, why not dive into our API and start sending text messages and making API-enabled phone calls? [Create an account](https://telnyx.com/sign-up) and enjoy Telnyx APIs! --- ### Node-RED > Source: https://developers.telnyx.com/docs/development/development-tools/node-red.md **(aka `@telnyx/node-red-telnyx`)** | Field | Value | |--------|-------| | **Name** | `Node-RED` | | **Author** | `OpenJS Foundation & Contributors` | | **URL** | `https://nodered.org` | ![node-red-telnyx](/assets/images/node-red-2.png) ## Overview Node-RED is an open-source flow-based programming tool that provides a visual development environment for building applications by wiring together nodes. It was originally developed by IBM Emerging Technology Services and is now part of the JS Foundation. Node-RED allows users to create applications and services by connecting pre-built nodes together in a flowchart-like manner. Each node represents a specific task or function, such as reading data from a sensor, processing data, making decisions, or interacting with external systems. Users can drag and drop nodes onto a canvas, connect them together, and configure their properties. The flows created in Node-RED are executed by a runtime engine, which runs on a server or device where Node-RED is installed. The runtime executes the flow in a sequential manner, passing data between nodes as it progresses through the flow. The flows can be easily modified and deployed, making it a flexible tool for building and prototyping Internet of Things (IoT) applications, automation workflows, and data integration processes. ## Start the journey **node-red-telnyx** is the Telnyx powerful integration that allows you to combine the capabilities of Node-RED, a flow-based programming tool, with Telnyx, a cloud-based communications platform. With **node-red-telnyx**, you can create complex workflows and automate various telecommunications tasks. **node-red-telnyx** can be integrated with other services and platforms through Node-RED's extensive library of nodes. You can connect Telnyx's communications capabilities with databases, APIs, messaging platforms, and IoT devices to build end-to-end automation solutions. e.g., you can use **node-red-telnyx** to send SMS messages programmatically. This can be useful for notifications, alerts, or two-factor authentication (2FA) purposes. You can configure the flow to trigger SMS messages based on specific events or conditions. To get started, [sign up](https://telnyx.com/sign-up) for a Portal account, then follow the steps in our quickstart guide to buy an SMS-enabled number. ## Usage The package needs to be configured with your MCP account's API key and some other details you can find in the Telnyx [Mission Control Portal](https://portal.telnyx.com). ![node-red-usage](/assets/images/node-red-1.png) Both ways of sending SMS are supported. - **Alphanumeric**: Alphanumeric Sender ID allows you to set your company name or brand as the Sender ID when sending one-way SMS messages to international destinations. Find more information [here](https://support.telnyx.com/en/articles/4371498-sending-alphanumeric-sms-sender-id). - **Two-way**: You'll need an SMS-capable phone number purchased from, or ported into, the Telnyx platform. If purchasing a new number, select the SMS number feature when searching. In general, numbers that are ported in will be messaging-capable. [Learn more](https://developers.telnyx.com/docs/messaging/messages/send-message). ## Resources - [Node-RED pages](https://flows.nodered.org/node/@telnyx/node-red-telnyx) - [Example flows using node-red-telnyx](https://flows.nodered.org/flow/5aa1fec6ccb1ef9a719c6a78b838eb31) - Getting Started Video (Coming Soon) ## Support Our team provides open source support in a best effort fashion, ensuring that we offer assistance and guidance to the community based on our expertise and resources. For support, install the [`@telnyx/node-red-telnyx`](https://www.npmjs.com/package/@telnyx/node-red-telnyx) package from npm and reach out via the [Telnyx support center](https://support.telnyx.com) with questions or issues. --- ## 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/" } } ``` --- ## Glossary ### AI glossary > Source: https://developers.telnyx.com/docs/glossary/ai-glossary.md | Term | Definition | |:-------------------------------------|:----------------------------------------------------------------------------------------| | AI Alignment | Ensuring AI behavior aligns with human goals and values. | | API Latency | Time delay between request and response in a deployed AI service. | | AUC (Area Under Curve) | Measure of model’s ability to distinguish between classes. | | Accuracy | Proportion of correct predictions made by a model. | | Activation Function | Function that introduces non-linearity into a neural network (e.g., ReLU, Sigmoid). | | Artificial Intelligence (AI) | Simulation of human intelligence in machines programmed to think and learn. | | Attention Mechanism | Mechanism that enables models to focus on relevant parts of the input. | | Backpropagation | Algorithm for updating neural network weights. | | Batch Normalization | Normalizes activations to improve training speed and stability. | | Bias | Systematic error introduced by assumptions in data or model. | | Chain-of-Thought (CoT) | Technique where models generate intermediate reasoning steps. | | Computer Vision | AI field that enables machines to interpret and make decisions based on visual data. | | Confusion Matrix | Table showing true vs predicted classifications. | | Data Privacy | Protection of sensitive user data during model training and usage. | | Deep Learning | Subset of ML using neural networks with many layers to model complex patterns. | | Dropout | Regularization technique that randomly drops units in a neural network during training. | | Embedding | Numerical representation of data, often used for similarity or search. | | Epoch | One complete pass through the training dataset. | | Explainable AI (XAI) | Techniques to interpret and understand model predictions. | | F1 Score | Harmonic mean of precision and recall. | | Few-shot Learning | Model learns from a few labeled examples. | | Fine-Tuning | Training a pre-trained model on a specific task or dataset. | | Generative AI | AI models that can generate new content like text, images, audio, or code. | | Gradient Descent | Optimization algorithm for minimizing loss function. | | Hallucination | Generated output that is fluent but factually incorrect. | | HuggingFace | Ecosystem for pretrained NLP models and transformers. | | Inference | Running a trained model to make predictions. | | LangChain | Framework for building LLM-powered applications using composable chains. | | Large Language Model (LLM) | A transformer-based model trained on large corpora of text data. | | LlamaIndex | Tool for indexing and querying external data with LLMs. | | LoRA (Low-Rank Adaptation) | Efficient method for fine-tuning large models with fewer parameters. | | Loss Function | Function that measures error between predicted and actual values. | | Machine Learning (ML) | Subset of AI that allows systems to learn from data without explicit programming. | | Mixture of Experts | Model architecture that routes input through subsets of expert networks. | | Model Checkpointing | Saving model states during training to resume or analyze progress. | | Model Fairness | Ensuring model performance does not discriminate against subgroups. | | Model Serving | Hosting and providing access to ML models for inference. | | Multimodal AI | Models that process and generate across multiple data types (e.g., text, image, audio). | | Natural Language Processing (NLP) | AI branch that deals with understanding and generation of human language. | | Neural Network | Computational model inspired by the human brain, used in deep learning. | | ONNX | Open Neural Network Exchange; format for model interoperability. | | Open Weight Model | AI model with publicly available weights for reuse and fine-tuning. | | Overfitting | Model learns training data too well and fails to generalize. | | Positional Encoding | Adds information about the position of tokens in sequences to transformer models. | | Pre-training | Initial training of a model on a large generic dataset. | | Precision | Proportion of true positive predictions among all positive predictions. | | Prompt Engineering | Crafting effective prompts to guide LLM responses. | | Proprietary Model | Model with restricted access, typically hosted and maintained by a company. | | PyTorch | Popular deep learning library developed by Facebook. | | ROC Curve | Graphical plot showing performance of classification model. | | Recall | Proportion of true positives among all actual positives. | | Reinforcement Learning | Learning method where agents learn by taking actions and receiving rewards. | | Residual Connection | Skip connections in neural networks that help prevent vanishing gradients. | | Responsible AI | Ethical and accountable development and deployment of AI. | | Retrieval-Augmented Generation (RAG) | LLM approach that augments prompts with relevant context from a document store. | | Scikit-learn | Python library for traditional machine learning. | | Self-Attention | Mechanism allowing models to weigh importance of different parts of input. | | Semi-Supervised Learning | Uses a small amount of labeled data with a large amount of unlabeled data. | | Supervised Learning | Training a model on labeled data. | | TensorFlow | Google’s open-source deep learning framework. | | TensorRT | NVIDIA platform for optimizing and deploying deep learning models. | | Tokenization | Breaking text into smaller units (tokens) for processing. | | Transformer | Deep learning model architecture that uses self-attention for sequence tasks. | | Underfitting | Model is too simple to capture underlying patterns in data. | | Unsupervised Learning | Training a model on data without labels to find patterns. | | Variance | Model's sensitivity to small fluctuations in training data. | | Vector Database | Database optimized for storing and querying high-dimensional embeddings. | | Zero-shot Learning | Model predicts on tasks without having seen labeled examples. | --- ### APIs glossary > Source: https://developers.telnyx.com/docs/glossary/api-glossary.md | Term | Definition | |:----------------------------------------|:---------------------------------------------------------------------------------------------| | API (Application Programming Interface) | A set of rules that allows software applications to communicate with each other. | | API Documentation | Instructions and details on how to use an API. | | API Key | A token passed in an API call to authenticate the client. | | Basic Auth | Authentication method using a username and password encoded in base64. | | Bearer Token | An access token used in the Authorization header. | | DELETE | HTTP method to delete a resource. | | Endpoint | A specific URL where an API can access the resources it needs. | | Form Data | A way to send key-value pairs, often used with file uploads. | | GET | HTTP method to retrieve data from a server. | | GraphQL | A query language for APIs that enables clients to request specific data. | | gRPC | A high-performance, open-source RPC framework by Google. | | HTTP | Hypertext Transfer Protocol; the foundation of API communication. | | HTTPS | Secure version of HTTP using encryption. | | Header | Key-value pairs in HTTP requests and responses that provide metadata. | | Idempotency | The property of an operation to have the same result no matter how many times it is applied. | | JSON | JavaScript Object Notation; a lightweight data format used in API communication. | | JWT (JSON Web Token) | A compact and self-contained method for securely transmitting information. | | Multipart | A type of form data that allows multiple files or fields to be sent in a single request. | | OAuth | An open-standard protocol for authorization. | | OpenAPI | A specification for describing RESTful APIs. | | PATCH | HTTP method to make partial updates to a resource. | | POST | HTTP method to send data to a server. | | PUT | HTTP method to update an existing resource. | | Pagination | Splitting API responses into smaller parts or pages. | | Payload | The actual data sent in a request or returned in a response. | | REST | Representational State Transfer; an architecture for stateless communication. | | RESTful API | An API that adheres to the REST architecture. | | Rate Limiting | Restricting the number of API calls a client can make. | | Request | An action initiated by a client to an API server. | | Resource | An object or representation of something accessible via an API. | | Response | The data sent back by the server after processing a request. | | Route | The path portion of a URL used to access an API resource, excluding the domain and protocol. | | SDK (Software Development Kit) | A collection of tools for building applications with an API. | | Status Code | A number indicating the result of an HTTP request (e.g., 200, 404, 500). | | Swagger | A set of tools for developing and documenting OpenAPI specifications. | | Throttling | Intentionally slowing down the response rate from the API. | | Versioning | Maintaining multiple iterations of an API (e.g., v1, v2). | | Webhooks | Callbacks sent from the server to the client when an event occurs. | | XML | Extensible Markup Language; another data format used in some APIs. | --- ### Telecom glossary > Source: https://developers.telnyx.com/docs/glossary/telecom-glossary.md | Term | Definition | |---------------|-------------------------------------------------------------------------------------------------------------------------| | ACD | Average Call Duration — Mean time a call lasts. | | ANI | Automatic Number Identification — Identifies the caller’s number. | | ASR | Answer-Seizure Ratio — Ratio of answered to attempted calls. | | B2BUA | Back-to-Back User Agent — VoIP architecture for media and signaling control. | | CDR | Call Detail Record — Metadata generated for a telecom transaction. | | CLD | Calling Line Destination — Identifies the called party’s number in a VoIP call setup. | | CLI | Calling Line Identification — Displays the caller’s phone number. | | CNAM | Caller Name — Displays the name associated with the caller’s number. | | CPE | Customer Premises Equipment — Devices installed at a customer’s location. | | CPaaS | Communications Platform as a Service — Telecom services offered via cloud. | | Codec | Audio compression methods (G.711, G.729, Opus) used in VoIP. | | DID | Direct Inward Dialing — Allows external callers to reach an internal extension. | | DNIS | Dialed Number Identification Service — Identifies the number dialed by the caller, used for routing inbound VoIP calls. | | DS0/DS1/DS3 | Digital Signal Levels — T-carrier transmission system levels (e.g., DS1 = T1 line). | | DTLS | Datagram TLS — Used in WebRTC encryption. | | DTMF | Dual Tone Multi-Frequency — Signals used for dialing and input (touch-tone). | | E.164 | Numbering Format — International telephone numbering standard. | | E911 | Enhanced 911 — Provides caller location info to emergency services. | | ENUM | Telephone Number Mapping — Converts phone numbers to Internet addresses. | | FAS | False Answer Supervision — Fraudulent call charge without real connection. | | ICE | Interactive Connectivity Establishment — Helps with NAT traversal in VoIP. | | IVR | Interactive Voice Response — Automated telephony system for user interaction. | | Jitter | Variation in packet arrival time that can affect voice quality. | | Jitter Buffer | Helps to smooth audio variations in VoIP packets. | | LATA | Local Access and Transport Area — Geographic area for call routing. | | LEC | Local Exchange Carrier — Provides local phone service. | | LNP | Local Number Portability — Keep phone numbers when changing providers. | | Latency | Delay between sending and receiving data. | | MOS | Mean Opinion Score — Subjective quality rating of voice (1–5). | | NPA-NXX | Numbering format: NPA = area code; NXX = central office code. | | PBX | Private Branch Exchange — Internal phone switching system in organizations. | | PDD | Post Dial Delay — Time from call initiation to ringing. | | POTS | Plain Old Telephone Service — Basic analog phone service. | | PRI | Primary Rate Interface — ISDN line with multiple voice/data channels. | | PSTN | Public Switched Telephone Network — Traditional circuit-switched network. | | QoS | Quality of Service — Measures reliability and performance of telecom service. | | RTP | Real-Time Transport Protocol — Used for transmitting audio/video streams. | | Rate Center | A geographic area used to determine local vs. long-distance calls. | | SBC | Session Border Controller — Secures and manages VoIP traffic. | | SDC | Short Duration Calling — Often used in VoIP fraud detection and SIP trunk analysis. | | SHAKEN/STIR | Caller ID verification to prevent spoofing. | | SIP | Session Initiation Protocol — Initiates and manages VoIP calls. | | SIP Proxy | A SIP server that routes and forwards SIP requests, enforcing policy and facilitating call setup. | | SIP Trunk | Virtual VoIP trunk line — Replaces traditional PRI. | | SIPS | SIP over TLS — Secure VoIP signaling. | | SRTP | Secure RTP — Encrypts RTP media streams. | | STUN/TURN | Servers to support NAT traversal in real-time communications. | | T.38 | Protocol for Fax over IP (FoIP). | | TLS | Transport Layer Security — Encrypts communications over IP. | | UCaaS | Unified Communications as a Service — Integrated voice, video, messaging. | | VoIP | Voice over Internet Protocol — Sends voice over IP networks. | | WebRTC | Web Real-Time Communication — Browser-based real-time media exchange. | --- ## 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](/development/mcp/remote-mcp/legacy). --- ### Agent Skills > Source: https://developers.telnyx.com/docs/development/agent-skills.md ## Installation Quickstart Choose your setup method: The Skills CLI works with Codex, Cursor, OpenClaw, Gemini CLI, GitHub Copilot, and more. ```bash npx skills add team-telnyx/skills --skill --agent ``` **Example:** ```bash npx skills add team-telnyx/skills --skill telnyx-voice-python --agent codex ``` ### Agent-specific commands ```bash npx skills add team-telnyx/skills --skill --agent codex ``` ```bash npx skills add team-telnyx/skills --skill --agent claude-code ``` ```bash npx skills add team-telnyx/skills --skill --agent cursor ``` ```bash npx skills add team-telnyx/skills --skill --agent openclaw ``` ```bash npx skills add team-telnyx/skills --skill --agent gemini-cli ``` ```bash npx skills add team-telnyx/skills --skill --agent github-copilot ``` See the [full list of supported agents](https://github.com/vercel-labs/skills#supported-agents). Use only the skills your project actually needs. Loading too many skills wastes tokens and dilutes context. Plugins are curated bundles of related Telnyx Agent skills. **Step 1.** Add the Telnyx skills marketplace (one-time): ```bash /plugin marketplace add team-telnyx/skills ``` **Step 2.** Install a plugin: ```bash /plugin install @skills ``` | Plugin | Language | |--------|----------| | `telnyx-python` | Python | | `telnyx-javascript` | JavaScript / Node.js | | `telnyx-go` | Go | | `telnyx-java` | Java | | `telnyx-ruby` | Ruby | | `telnyx-curl` | curl (REST API) | | `telnyx-webrtc-client` | WebRTC client SDKs (JS, iOS, Android, Flutter, React Native) | | `telnyx-twilio-migration` | Migrate from Twilio to Telnyx | | `telnyx-cli` | Telnyx CLI | **Examples:** ```bash /plugin install telnyx-python@skills /plugin install telnyx-twilio-migration@skills ``` Each language plugin includes all 36 Telnyx products. For Cursor, Windsurf, or agents without native skill support. **Cursor:** 1. Open **Settings > Rules > Project Rules**. 2. Create a rule file (e.g., `.cursor/rules/telnyx.mdc`). 3. Paste the contents of the relevant `SKILL.md` from the [skills repository](https://github.com/team-telnyx/skills). **Windsurf:** 1. Create a `.windsurfrules` file in your project root. 2. Paste the contents of the relevant `SKILL.md`. **Direct URL:** ``` https://raw.githubusercontent.com/team-telnyx/skills/main/telnyx-python/skills/telnyx-messaging-python/SKILL.md ``` Replace `telnyx-python` and `telnyx-messaging-python` with your desired language and product. You'll need a [Telnyx API key](https://portal.telnyx.com/#/api-keys) when you're ready to make API calls. ## Available Skills Skills are organized by product and language. Each product skill is available in **curl**, **JavaScript**, **Python**, **Go**, **Java**, and **Ruby**. Replace `*` with your language suffix (e.g., `telnyx-voice-python`, `telnyx-messaging-go`). ### Messaging | Skill | Description | |-------|-------------| | `telnyx-messaging-*` | Send/receive SMS/MMS, manage messaging numbers, handle opt-outs | | `telnyx-messaging-profiles-*` | Messaging profiles, number pools, short codes | | `telnyx-messaging-hosted-*` | Hosted SMS numbers, toll-free verification, RCS | | `telnyx-10dlc-*` | 10DLC brand/campaign registration for A2P compliance | ### Voice & Communications | Skill | Description | |-------|-------------| | `telnyx-voice-*` | Call control: dial, answer, hangup, transfer, bridge | | `telnyx-voice-media-*` | Audio playback, text-to-speech, call recording | | `telnyx-voice-gather-*` | DTMF/speech input collection, AI-powered gather | | `telnyx-voice-streaming-*` | Real-time audio streaming, forking, transcription | | `telnyx-voice-conferencing-*` | Conference calls, queues, multi-party sessions | | `telnyx-voice-advanced-*` | DTMF sending, SIPREC, noise suppression, supervisor | | `telnyx-texml-*` | TeXML (TwiML-compatible) voice applications | | `telnyx-sip-*` | SIP trunking connections, outbound voice profiles | | `telnyx-sip-integrations-*` | Call recordings, media storage, Dialogflow integration | | `telnyx-webrtc-*` | WebRTC credentials and push notification setup (server-side) | ### Numbers | Skill | Description | |-------|-------------| | `telnyx-numbers-*` | Search, order, and manage phone numbers | | `telnyx-numbers-config-*` | Phone number configuration and settings | | `telnyx-numbers-compliance-*` | Regulatory requirements, bundles, documents | | `telnyx-numbers-services-*` | Voicemail, voice channels, E911 | | `telnyx-porting-in-*` | Port numbers into Telnyx | | `telnyx-porting-out-*` | Manage port-out requests | | `telnyx-verify-*` | Phone verification, number lookup, 2FA | ### AI | Skill | Description | |-------|-------------| | `telnyx-ai-assistants-*` | AI voice assistants with knowledge bases | | `telnyx-ai-inference-*` | LLM inference, embeddings, AI analytics | | `telnyx-missions-*` | Automated AI-driven workflows and tasks | ### IoT & Networking | Skill | Description | |-------|-------------| | `telnyx-iot-*` | IoT SIM cards, eSIMs, data plans | | `telnyx-networking-*` | Private networks, VPN gateways | ### Other Products | Skill | Description | |-------|-------------| | `telnyx-storage-*` | S3-compatible cloud storage | | `telnyx-video-*` | Video rooms and conferencing | | `telnyx-fax-*` | Programmable fax | | `telnyx-oauth-*` | OAuth 2.0 authentication flows | ### Account Management | Skill | Description | |-------|-------------| | `telnyx-account-*` | Balance, payments, invoices, webhooks, audit logs | | `telnyx-account-access-*` | Addresses, auth providers, IP access, billing groups | | `telnyx-account-management-*` | Sub-account management (resellers) | | `telnyx-account-notifications-*` | Notification channels and settings | | `telnyx-account-reports-*` | Usage reports for billing and analytics | ## WebRTC Client SDKs The skills above cover **server-side** Telnyx APIs. For building **calling apps** where users make/receive VoIP calls, you need client-side WebRTC SDKs: | Skill | Platform | Language | |-------|----------|----------| | `telnyx-webrtc-client-js` | Browser | JavaScript | | `telnyx-webrtc-client-ios` | iOS | Swift | | `telnyx-webrtc-client-android` | Android | Kotlin | | `telnyx-webrtc-client-flutter` | Flutter | Dart | | `telnyx-webrtc-client-react-native` | React Native | TypeScript | Each covers authentication, making/receiving calls, call controls, push notifications, and AI Agent integration. Building a calling app typically requires **two skills**: a server-side plugin (e.g. `telnyx-voice-python`) for credentials/tokens, and a client-side WebRTC skill for the UI. ## Twilio Migration A comprehensive 6-phase orchestrated workflow for migrating from Twilio to Telnyx. ```bash npx skills add team-telnyx/skills --skill telnyx-twilio-migration --agent ``` **What's covered:** | Area | Description | |------|-------------| | Voice | TwiML → TeXML compatibility (15 verbs, 8 nouns) + Call Control API | | Messaging | Parameter mapping, messaging profiles, 10DLC registration | | WebRTC | Architecture differences, endpoint migration, mobile SDK guides | | Number Porting | FastPort API for same-day US/Canada activation | | Verify (2FA) | SMS, voice, flash calling, PSD2 verification | | SIP Trunking | Connection setup, credential auth, FQDN migration | | Auth Changes | Basic → Bearer, webhook signatures (HMAC-SHA1 → Ed25519) | Includes automated scripts for pre-flight checks, usage scanning, linting, validation, and smoke tests. ## Example Prompts Once installed, try asking your agent: | Prompt | What it builds | |--------|----------------| | "Send an SMS to +15551234567 saying 'Your order shipped'." | Messaging integration with error handling | | "Create a webhook server to receive inbound calls." | Express/Flask server with Call Control | | "Search for toll-free numbers in the US." | Number search and provisioning code | | "Build an IVR that routes calls based on keypad input." | TeXML application with DTMF handling | | "Create a Voice AI agent for appointment scheduling." | AI Assistant with custom tools | | "Port my number from Twilio to Telnyx." | Porting request with required fields | ## How It Works 1. Describe what you want to build in natural language. 2. The agent reads Telnyx SDK documentation through the installed skill. 3. The agent writes production-ready code with proper auth, error handling, and best practices. 4. Review and iterate until complete. Skills provide: - Complete SDK reference documentation - Code examples and patterns - Error handling best practices - Authentication setup guides - Webhook configuration examples ## Resources - [Agent Skills Repository](https://github.com/team-telnyx/skills) - [Agent Skills Specification](https://agentskills.io/specification) - [GitHub: Telnyx SDKs](https://github.com/team-telnyx) - [API Reference](/api-reference) - [Get API Keys](https://portal.telnyx.com/#/api-keys) ## Contributing See the [Agent Skills Repository](https://github.com/team-telnyx/skills) for contribution guidelines and to report issues. ---