# Create an Access Token. Source: https://developers.telnyx.com/api-reference/access-tokens/create-an-access-token https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml post /telephony_credentials/{id}/token Create an Access Token (JWT) for the credential. # Accepts this address suggestion as a new emergency address for Operator Connect and finishes the uploads of the numbers associated with it to Microsoft. Source: https://developers.telnyx.com/api-reference/addresses/accepts-this-address-suggestion-as-a-new-emergency-address-for-operator-connect-and-finishes-the-uploads-of-the-numbers-associated-with-it-to-microsoft https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml post /addresses/{id}/actions/accept_suggestions # Creates an address Source: https://developers.telnyx.com/api-reference/addresses/creates-an-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml post /addresses Creates an address. # Deletes an address Source: https://developers.telnyx.com/api-reference/addresses/deletes-an-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml delete /addresses/{id} Deletes an existing address. # List all addresses Source: https://developers.telnyx.com/api-reference/addresses/list-all-addresses https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml get /addresses Returns a list of your addresses. # Retrieve an address Source: https://developers.telnyx.com/api-reference/addresses/retrieve-an-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml get /addresses/{id} Retrieves the details of an existing address. # Validate an address Source: https://developers.telnyx.com/api-reference/addresses/validate-an-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/addresses.yml post /addresses/actions/validate Validates an address for emergency services. # Create Advanced Order Source: https://developers.telnyx.com/api-reference/advanced-number-orders/create-advanced-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /advanced_orders # Get Advanced Order Source: https://developers.telnyx.com/api-reference/advanced-number-orders/get-advanced-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /advanced_orders/{order_id} # List Advanced Orders Source: https://developers.telnyx.com/api-reference/advanced-number-orders/list-advanced-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /advanced_orders # Update Advanced Order Source: https://developers.telnyx.com/api-reference/advanced-number-orders/update-advanced-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /advanced_orders/{advanced-order-id}/requirement_group # Add Assistant Tag Source: https://developers.telnyx.com/api-reference/assistants/add-assistant-tag https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/tags # Add Assistant Tool Source: https://developers.telnyx.com/api-reference/assistants/add-assistant-tool https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml put /ai/assistants/{assistant_id}/tools/{tool_id} # Assistant Chat (BETA) Source: https://developers.telnyx.com/api-reference/assistants/assistant-chat-beta https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/chat This endpoint allows a client to send a chat message to a specific AI Assistant. The assistant processes the message and returns a relevant reply based on the current conversation context. Refer to the Conversation API to [create a conversation](https://developers.telnyx.com/api-reference/conversations/create-a-conversation), [filter existing conversations](https://developers.telnyx.com/api-reference/conversations/list-conversations), [fetch messages for a conversation](https://developers.telnyx.com/api-reference/conversations/get-conversation-messages), and [manually add messages to a conversation](https://developers.telnyx.com/api-reference/conversations/create-message). # Assistant Sms Chat Source: https://developers.telnyx.com/api-reference/assistants/assistant-sms-chat https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/chat/sms Send an SMS message for an assistant. This endpoint: 1. Validates the assistant exists and has messaging profile configured 2. If should_create_conversation is true, creates a new conversation with metadata 3. Sends the SMS message (If `text` is set, this will be sent. Otherwise, if this is the first message in the conversation and the assistant has a `greeting` configured, this will be sent. Otherwise the assistant will generate the text to send.) 4. Updates conversation metadata if provided 5. Returns the conversation ID # Clone Assistant Source: https://developers.telnyx.com/api-reference/assistants/clone-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/clone Clone an existing assistant, excluding telephony and messaging settings. # Create a new assistant test Source: https://developers.telnyx.com/api-reference/assistants/create-a-new-assistant-test https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/tests Creates a comprehensive test configuration for evaluating AI assistant performance # Create a scheduled event Source: https://developers.telnyx.com/api-reference/assistants/create-a-scheduled-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/scheduled_events Create a scheduled event for an assistant # Create an assistant Source: https://developers.telnyx.com/api-reference/assistants/create-an-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants Create a new AI Assistant. # Create Canary Deploy Source: https://developers.telnyx.com/api-reference/assistants/create-canary-deploy https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/canary-deploys Endpoint to create a canary deploy configuration for an assistant. Creates a new canary deploy configuration with multiple version IDs and their traffic percentages for A/B testing or gradual rollouts of assistant versions. # Delete a scheduled event Source: https://developers.telnyx.com/api-reference/assistants/delete-a-scheduled-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id}/scheduled_events/{event_id} If the event is pending, this will cancel the event. Otherwise, this will simply remove the record of the event. # Delete a specific assistant version Source: https://developers.telnyx.com/api-reference/assistants/delete-a-specific-assistant-version https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id}/versions/{version_id} Permanently removes a specific version of an assistant. Can not delete main version # Delete an assistant Source: https://developers.telnyx.com/api-reference/assistants/delete-an-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id} Delete an AI Assistant by `assistant_id`. # Delete an assistant test Source: https://developers.telnyx.com/api-reference/assistants/delete-an-assistant-test https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/tests/{test_id} Permanently removes an assistant test and all associated data # Delete Canary Deploy Source: https://developers.telnyx.com/api-reference/assistants/delete-canary-deploy https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id}/canary-deploys Endpoint to delete a canary deploy configuration for an assistant. Removes all canary deploy configurations for the specified assistant. # Get a scheduled event Source: https://developers.telnyx.com/api-reference/assistants/get-a-scheduled-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/scheduled_events/{event_id} Retrieve a scheduled event by event ID # Get a specific assistant version Source: https://developers.telnyx.com/api-reference/assistants/get-a-specific-assistant-version https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/versions/{version_id} Retrieves a specific version of an assistant by assistant_id and version_id # Get All Tags Source: https://developers.telnyx.com/api-reference/assistants/get-all-tags https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tags # Get all test suite names Source: https://developers.telnyx.com/api-reference/assistants/get-all-test-suite-names https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests/test-suites Retrieves a list of all distinct test suite names available to the current user # Get all versions of an assistant Source: https://developers.telnyx.com/api-reference/assistants/get-all-versions-of-an-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/versions Retrieves all versions of a specific assistant with complete configuration and metadata # Get an assistant Source: https://developers.telnyx.com/api-reference/assistants/get-an-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id} Retrieve an AI Assistant configuration by `assistant_id`. # Get assistant test by ID Source: https://developers.telnyx.com/api-reference/assistants/get-assistant-test-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests/{test_id} Retrieves detailed information about a specific assistant test # Get assistant texml Source: https://developers.telnyx.com/api-reference/assistants/get-assistant-texml https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/texml Get an assistant texml by `assistant_id`. # Get Canary Deploy Source: https://developers.telnyx.com/api-reference/assistants/get-canary-deploy https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/canary-deploys Endpoint to get a canary deploy configuration for an assistant. Retrieves the current canary deploy configuration with all version IDs and their traffic percentages for the specified assistant. # Get specific test run details Source: https://developers.telnyx.com/api-reference/assistants/get-specific-test-run-details https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests/{test_id}/runs/{run_id} Retrieves detailed information about a specific test run execution # Get test run history for a specific test Source: https://developers.telnyx.com/api-reference/assistants/get-test-run-history-for-a-specific-test https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests/{test_id}/runs Retrieves paginated execution history for a specific assistant test with filtering options # Get test suite run history Source: https://developers.telnyx.com/api-reference/assistants/get-test-suite-run-history https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests/test-suites/{suite_name}/runs Retrieves paginated history of test runs for a specific test suite with filtering options # Import assistants from external provider Source: https://developers.telnyx.com/api-reference/assistants/import-assistants-from-external-provider https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/import Import assistants from external providers. Any assistant that has already been imported will be overwritten with its latest version from the importing provider. # List assistant tests with pagination Source: https://developers.telnyx.com/api-reference/assistants/list-assistant-tests-with-pagination https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/tests Retrieves a paginated list of assistant tests with optional filtering capabilities # List assistants Source: https://developers.telnyx.com/api-reference/assistants/list-assistants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants Retrieve a list of all AI Assistants configured by the user. # List scheduled events Source: https://developers.telnyx.com/api-reference/assistants/list-scheduled-events https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/assistants/{assistant_id}/scheduled_events Get scheduled events for an assistant with pagination and filtering # Promote an assistant version to main Source: https://developers.telnyx.com/api-reference/assistants/promote-an-assistant-version-to-main https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/versions/{version_id}/promote Promotes a specific version to be the main/current version of the assistant. This will delete any existing canary deploy configuration and send all live production traffic to this version. # Remove Assistant Tag Source: https://developers.telnyx.com/api-reference/assistants/remove-assistant-tag https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id}/tags/{tag} # Remove Assistant Tool Source: https://developers.telnyx.com/api-reference/assistants/remove-assistant-tool https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/assistants/{assistant_id}/tools/{tool_id} # Test Assistant Tool Source: https://developers.telnyx.com/api-reference/assistants/test-assistant-tool https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/tools/{tool_id}/test Test a webhook tool for an assistant # Trigger a manual test run Source: https://developers.telnyx.com/api-reference/assistants/trigger-a-manual-test-run https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/tests/{test_id}/runs Initiates immediate execution of a specific assistant test # Trigger test suite execution Source: https://developers.telnyx.com/api-reference/assistants/trigger-test-suite-execution https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/tests/test-suites/{suite_name}/runs Executes all tests within a specific test suite as a batch operation # Update a specific assistant version Source: https://developers.telnyx.com/api-reference/assistants/update-a-specific-assistant-version https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id}/versions/{version_id} Updates the configuration of a specific assistant version. Can not update main version # Update an assistant Source: https://developers.telnyx.com/api-reference/assistants/update-an-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/assistants/{assistant_id} Update an AI Assistant's attributes. # Update an assistant test Source: https://developers.telnyx.com/api-reference/assistants/update-an-assistant-test https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml put /ai/assistants/tests/{test_id} Updates an existing assistant test configuration with new settings # Update Canary Deploy Source: https://developers.telnyx.com/api-reference/assistants/update-canary-deploy https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml put /ai/assistants/{assistant_id}/canary-deploys Endpoint to update a canary deploy configuration for an assistant. Updates the existing canary deploy configuration with new version IDs and percentages. All old versions and percentages are replaces by new ones from this request. # Transcribe speech to text Source: https://developers.telnyx.com/api-reference/audio/transcribe-speech-to-text https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/speech-to-text-filebased/speech-to-text-filebased.yml post /ai/audio/transcriptions Transcribe speech to text. This endpoint is consistent with the [OpenAI Transcription API](https://platform.openai.com/docs/api-reference/audio/createTranscription) and may be used with the OpenAI JS or Python SDK. # List Audit Logs Source: https://developers.telnyx.com/api-reference/audit-logs/list-audit-logs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/audit.yml get /audit_events Retrieve a list of audit log entries. Audit logs are a best-effort, eventually consistent record of significant account-related changes. # Creates an authentication provider Source: https://developers.telnyx.com/api-reference/authentication-providers/creates-an-authentication-provider https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/authentication-providers.yml post /authentication_providers Creates an authentication provider. # Deletes an authentication provider Source: https://developers.telnyx.com/api-reference/authentication-providers/deletes-an-authentication-provider https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/authentication-providers.yml delete /authentication_providers/{id} Deletes an existing authentication provider. # List all SSO authentication providers Source: https://developers.telnyx.com/api-reference/authentication-providers/list-all-sso-authentication-providers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/authentication-providers.yml get /authentication_providers Returns a list of your SSO authentication providers. # Retrieve an authentication provider Source: https://developers.telnyx.com/api-reference/authentication-providers/retrieve-an-authentication-provider https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/authentication-providers.yml get /authentication_providers/{id} Retrieves the details of an existing authentication provider. # Update an authentication provider Source: https://developers.telnyx.com/api-reference/authentication-providers/update-an-authentication-provider https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/authentication-providers.yml patch /authentication_providers/{id} Updates settings of an existing authentication provider. # List auto recharge preferences Source: https://developers.telnyx.com/api-reference/autorechargepreferences/list-auto-recharge-preferences https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/payment.yml get /payments/auto_recharge_prefs Returns the payment auto recharge preferences. # Update auto recharge preferences Source: https://developers.telnyx.com/api-reference/autorechargepreferences/update-auto-recharge-preferences https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/payment.yml patch /payments/auto_recharge_prefs Update payment auto recharge preferences. # Create a billing group Source: https://developers.telnyx.com/api-reference/billing-groups/create-a-billing-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/billing-groups.yml post /billing_groups # Delete a billing group Source: https://developers.telnyx.com/api-reference/billing-groups/delete-a-billing-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/billing-groups.yml delete /billing_groups/{id} # Get a billing group Source: https://developers.telnyx.com/api-reference/billing-groups/get-a-billing-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/billing-groups.yml get /billing_groups/{id} # List all billing groups Source: https://developers.telnyx.com/api-reference/billing-groups/list-all-billing-groups https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/billing-groups.yml get /billing_groups # Update a billing group Source: https://developers.telnyx.com/api-reference/billing-groups/update-a-billing-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/billing-groups.yml patch /billing_groups/{id} # Get user balance details Source: https://developers.telnyx.com/api-reference/billing/get-user-balance-details https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/balance.yml get /balance # Create Brand Source: https://developers.telnyx.com/api-reference/brands/create-brand https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml post /10dlc/brand This endpoint is used to create a new brand. A brand is an entity created by The Campaign Registry (TCR) that represents an organization or a company. It is this entity that TCR created campaigns will be associated with. Each brand creation will entail an upfront, non-refundable $4 expense. # Delete Brand Source: https://developers.telnyx.com/api-reference/brands/delete-brand https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml delete /10dlc/brand/{brandId} Delete Brand. This endpoint is used to delete a brand. Note the brand cannot be deleted if it contains one or more active campaigns, the campaigns need to be inactive and at least 3 months old due to billing purposes. # Get Brand Source: https://developers.telnyx.com/api-reference/brands/get-brand https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand/{brandId} Retrieve a brand by `brandId`. # Get Brand Feedback By Id Source: https://developers.telnyx.com/api-reference/brands/get-brand-feedback-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand_feedback/{brandId} Get feedback about a brand by ID. This endpoint can be used after creating or revetting a brand. Possible values for `.category[].id`: * `TAX_ID` - Data mismatch related to tax id and its associated properties. * `STOCK_SYMBOL` - Non public entity registered as a public for profit entity or the stock information mismatch. * `GOVERNMENT_ENTITY` - Non government entity registered as a government entity. Must be a U.S. government entity. * `NONPROFIT` - Not a recognized non-profit entity. No IRS tax-exempt status found. * `OTHERS` - Details of the data misrepresentation if any. # Get Brand SMS OTP Status Source: https://developers.telnyx.com/api-reference/brands/get-brand-sms-otp-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand/smsOtp/{referenceId} Query the status of an SMS OTP (One-Time Password) for Sole Proprietor brand verification. This endpoint allows you to check the delivery and verification status of an OTP sent during the Sole Proprietor brand verification process. You can query by either: * `referenceId` - The reference ID returned when the OTP was initially triggered * `brandId` - Query parameter for portal users to look up OTP status by Brand ID The response includes delivery status, verification dates, and detailed delivery information. # Get Brand SMS OTP Status by Brand ID Source: https://developers.telnyx.com/api-reference/brands/get-brand-sms-otp-status-by-brand-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand/{brandId}/smsOtp Query the status of an SMS OTP (One-Time Password) for Sole Proprietor brand verification using the Brand ID. This endpoint allows you to check the delivery and verification status of an OTP sent during the Sole Proprietor brand verification process by looking it up with the brand ID. The response includes delivery status, verification dates, and detailed delivery information. **Note:** This is an alternative to the `/10dlc/brand/smsOtp/{referenceId}` endpoint when you have the Brand ID but not the reference ID. # Import External Vetting Record Source: https://developers.telnyx.com/api-reference/brands/import-external-vetting-record https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml put /10dlc/brand/{brandId}/externalVetting This operation can be used to import an external vetting record from a TCR-approved vetting provider. If the vetting provider confirms validity of the record, it will be saved with the brand and will be considered for future campaign qualification. # List Brands Source: https://developers.telnyx.com/api-reference/brands/list-brands https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand This endpoint is used to list all brands associated with your organization. # List External Vettings Source: https://developers.telnyx.com/api-reference/brands/list-external-vettings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/brand/{brandId}/externalVetting Get list of valid external vetting record for a given brand # Order Brand External Vetting Source: https://developers.telnyx.com/api-reference/brands/order-brand-external-vetting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml post /10dlc/brand/{brandId}/externalVetting Order new external vetting for a brand. Duplicate orders for the same `evpId` and `vettingClass` return `400` with code `10012` if a successful vetting exists within the last 180 days, or one is currently being processed. Failed vettings can be retried immediately. # Resend brand 2FA email Source: https://developers.telnyx.com/api-reference/brands/resend-brand-2fa-email https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml post /10dlc/brand/{brandId}/2faEmail # Revet Brand Source: https://developers.telnyx.com/api-reference/brands/revet-brand https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml put /10dlc/brand/{brandId}/revet This operation allows you to revet the brand. However, revetting is allowed once after the successful brand registration and thereafter limited to once every 3 months. # Trigger Brand SMS OTP Source: https://developers.telnyx.com/api-reference/brands/trigger-brand-sms-otp https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml post /10dlc/brand/{brandId}/smsOtp Trigger or re-trigger an SMS OTP (One-Time Password) for Sole Proprietor brand verification. **Important Notes:** * Only allowed for Sole Proprietor (`SOLE_PROPRIETOR`) brands * Triggers generation of a one-time password sent to the `mobilePhone` number in the brand's profile * Campaigns cannot be created until OTP verification is complete * US/CA numbers only for real OTPs; mock brands can use non-US/CA numbers for testing * Returns a `referenceId` that can be used to check OTP status via the GET `/10dlc/brand/smsOtp/{referenceId}` endpoint **Use Cases:** * Initial OTP trigger after Sole Proprietor brand creation * Re-triggering OTP if the user didn't receive or needs a new code # Update Brand Source: https://developers.telnyx.com/api-reference/brands/update-brand https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml put /10dlc/brand/{brandId} Update a brand's attributes by `brandId`. # Verify Brand SMS OTP Source: https://developers.telnyx.com/api-reference/brands/verify-brand-sms-otp https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml put /10dlc/brand/{brandId}/smsOtp Verify the SMS OTP (One-Time Password) for Sole Proprietor brand verification. **Verification Flow:** 1. User receives OTP via SMS after triggering 2. User submits the OTP pin through this endpoint 3. Upon successful verification: - A `BRAND_OTP_VERIFIED` webhook event is sent to the CSP - The brand's `identityStatus` changes to `VERIFIED` - Campaigns can now be created for this brand **Error Handling:** Provides proper error responses for: * Invalid OTP pins * Expired OTPs * OTP verification failures # Add SSL Certificate Source: https://developers.telnyx.com/api-reference/bucket-ssl-certificate/add-ssl-certificate https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml put /storage/buckets/{bucketName}/ssl_certificate Uploads an SSL certificate and its matching secret so that you can use Telnyx's storage as your CDN. # Get Bucket SSL Certificate Source: https://developers.telnyx.com/api-reference/bucket-ssl-certificate/get-bucket-ssl-certificate https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/buckets/{bucketName}/ssl_certificate Returns the stored certificate detail of a bucket, if applicable. # Remove SSL Certificate Source: https://developers.telnyx.com/api-reference/bucket-ssl-certificate/remove-ssl-certificate https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml delete /storage/buckets/{bucketName}/ssl_certificate Deletes an SSL certificate and its matching secret. # Get API Usage Source: https://developers.telnyx.com/api-reference/bucket-usage/get-api-usage https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/buckets/{bucketName}/usage/api Returns the detail on API usage on a bucket of a particular time period, group by method category. # Get Bucket Usage Source: https://developers.telnyx.com/api-reference/bucket-usage/get-bucket-usage https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/buckets/{bucketName}/usage/storage Returns the amount of storage space and number of files a bucket takes up. # Assign Messaging Profile To Campaign Source: https://developers.telnyx.com/api-reference/bulk-phone-number-campaigns/assign-messaging-profile-to-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml post /10dlc/phoneNumberAssignmentByProfile This endpoint allows you to link all phone numbers associated with a Messaging Profile to a campaign. **Please note:** if you want to assign phone numbers to a campaign that you did not create with Telnyx 10DLC services, this endpoint allows that provided that you've shared the campaign with Telnyx. In this case, only provide the parameter, `tcrCampaignId`, and not `campaignId`. In all other cases (where the campaign you're assigning was created with Telnyx 10DLC services), only provide `campaignId`, not `tcrCampaignId`. # Get Assignment Task Status Source: https://developers.telnyx.com/api-reference/bulk-phone-number-campaigns/get-assignment-task-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml get /10dlc/phoneNumberAssignmentByProfile/{taskId} Check the status of the task associated with assigning all phone numbers on a messaging profile to a campaign by `taskId`. # Get Phone Number Status Source: https://developers.telnyx.com/api-reference/bulk-phone-number-campaigns/get-phone-number-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml get /10dlc/phoneNumberAssignmentByProfile/{taskId}/phoneNumbers Check the status of the individual phone number/campaign assignments associated with the supplied `taskId`. # Delete a batch of numbers Source: https://developers.telnyx.com/api-reference/bulk-phone-number-operations/delete-a-batch-of-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/jobs/delete_phone_numbers Creates a new background job to delete a batch of numbers. At most one thousand numbers can be updated per API call. # Lists the phone numbers jobs Source: https://developers.telnyx.com/api-reference/bulk-phone-number-operations/lists-the-phone-numbers-jobs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/jobs # Retrieve a phone numbers job Source: https://developers.telnyx.com/api-reference/bulk-phone-number-operations/retrieve-a-phone-numbers-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/jobs/{id} # Update a batch of numbers Source: https://developers.telnyx.com/api-reference/bulk-phone-number-operations/update-a-batch-of-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/jobs/update_phone_numbers Creates a new background job to update a batch of numbers. At most one thousand numbers can be updated per API call. At least one of the updateable fields must be submitted. IMPORTANT: You must either specify filters (using the filter parameters) or specific phone numbers (using the phone_numbers parameter in the request body). If you specify filters, ALL phone numbers that match the given filters (up to 1000 at a time) will be updated. If you want to update only specific numbers, you must use the phone_numbers parameter in the request body. When using the phone_numbers parameter, ensure you follow the correct format as shown in the example (either phone number IDs or phone numbers in E164 format). # Update the emergency settings from a batch of numbers Source: https://developers.telnyx.com/api-reference/bulk-phone-number-operations/update-the-emergency-settings-from-a-batch-of-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/jobs/update_emergency_settings Creates a background job to update the emergency settings of a collection of phone numbers. At most one thousand numbers can be updated per API call. # Get Bundle By Id Source: https://developers.telnyx.com/api-reference/bundles/get-bundle-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/billing_bundles/{bundle_id} Get a single bundle by ID. # Retrieve Bundles Source: https://developers.telnyx.com/api-reference/bundles/retrieve-bundles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/billing_bundles Get all allowed bundles. # Add messages to AI Assistant Source: https://developers.telnyx.com/api-reference/call-commands/add-messages-to-ai-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/ai-assistant-add-messages.yml post /calls/{call_control_id}/actions/ai_assistant_add_messages Add messages to the conversation started by an AI assistant on the call. # Answer call Source: https://developers.telnyx.com/api-reference/call-commands/answer-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/answer.yml post /calls/{call_control_id}/actions/answer Answer an incoming call. You must issue this command before executing subsequent commands on an incoming call. **Expected Webhooks:** - `call.answered` - `call.hold` and `call.unhold` if the call is held/unheld - `call.deepfake_detection.result` if `deepfake_detection` was enabled - `call.deepfake_detection.error` if `deepfake_detection` was enabled and an error occurred - `streaming.started`, `streaming.stopped` or `streaming.failed` if `stream_url` was set When the `record` parameter is set to `record-from-answer`, the response will include a `recording_id` field. # Bridge calls Source: https://developers.telnyx.com/api-reference/call-commands/bridge-calls https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/bridge.yml post /calls/{call_control_id}/actions/bridge Bridge two call control calls. **Expected Webhooks:** - `call.bridged` for Leg A - `call.bridged` for Leg B # Dial Source: https://developers.telnyx.com/api-reference/call-commands/dial https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml post /calls Dial a number or SIP URI from a given connection. A successful response will include a `call_leg_id` which can be used to correlate the command with subsequent webhooks. **Expected Webhooks:** - `call.initiated` - `call.answered` or `call.hangup` - `call.hold` and `call.unhold` if the call is held/unheld - `call.machine.detection.ended` if `answering_machine_detection` was requested - `call.machine.greeting.ended` if `answering_machine_detection` was requested to detect the end of machine greeting - `call.machine.premium.detection.ended` if `answering_machine_detection=premium` was requested - `call.machine.premium.greeting.ended` if `answering_machine_detection=premium` was requested and a beep was detected - `call.deepfake_detection.result` if `deepfake_detection` was enabled - `call.deepfake_detection.error` if `deepfake_detection` was enabled and an error occurred - `streaming.started`, `streaming.stopped` or `streaming.failed` if `stream_url` was set When the `record` parameter is set to `record-from-answer`, the response will include a `recording_id` field. # Enqueue call Source: https://developers.telnyx.com/api-reference/call-commands/enqueue-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/enqueue.yml post /calls/{call_control_id}/actions/enqueue Put the call in a queue. # Forking start Source: https://developers.telnyx.com/api-reference/call-commands/forking-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/fork-start.yml post /calls/{call_control_id}/actions/fork_start Call forking allows you to stream the media from a call to a specific target in realtime. This stream can be used to enable realtime audio analysis to support a variety of use cases, including fraud detection, or the creation of AI-generated audio responses. Requests must specify either the `target` attribute or the `rx` and `tx` attributes. **Expected Webhooks:** - `call.fork.started` - `call.fork.stopped` # Forking stop Source: https://developers.telnyx.com/api-reference/call-commands/forking-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/fork-stop.yml post /calls/{call_control_id}/actions/fork_stop Stop forking a call. **Expected Webhooks:** - `call.fork.stopped` # Gather Source: https://developers.telnyx.com/api-reference/call-commands/gather https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather.yml post /calls/{call_control_id}/actions/gather Gather DTMF signals to build interactive menus. You can pass a list of valid digits. The `Answer` command must be issued before the `gather` command. **Expected Webhooks:** - `call.dtmf.received` (you may receive many of these webhooks) - `call.gather.ended` # Gather stop Source: https://developers.telnyx.com/api-reference/call-commands/gather-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-stop.yml post /calls/{call_control_id}/actions/gather_stop Stop current gather. **Expected Webhooks:** - `call.gather.ended` # Gather using AI Source: https://developers.telnyx.com/api-reference/call-commands/gather-using-ai https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-ai.yml post /calls/{call_control_id}/actions/gather_using_ai Gather parameters defined in the request payload using a voice assistant. You can pass parameters described as a JSON Schema object and the voice assistant will attempt to gather these informations. **Expected Webhooks:** - `call.ai_gather.ended` - `call.conversation.ended` - `call.ai_gather.partial_results` (if `send_partial_results` is set to `true`) - `call.ai_gather.message_history_updated` (if `send_message_history_updates` is set to `true`) # Gather using audio Source: https://developers.telnyx.com/api-reference/call-commands/gather-using-audio https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-audio.yml post /calls/{call_control_id}/actions/gather_using_audio Play an audio file on the call until the required DTMF signals are gathered to build interactive menus. You can pass a list of valid digits along with an 'invalid_audio_url', which will be played back at the beginning of each prompt. Playback will be interrupted when a DTMF signal is received. The `Answer command must be issued before the `gather_using_audio` command. **Expected Webhooks:** - `call.playback.started` - `call.playback.ended` - `call.dtmf.received` (you may receive many of these webhooks) - `call.gather.ended` # Gather using speak Source: https://developers.telnyx.com/api-reference/call-commands/gather-using-speak https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-speak.yml post /calls/{call_control_id}/actions/gather_using_speak Convert text to speech and play it on the call until the required DTMF signals are gathered to build interactive menus. You can pass a list of valid digits along with an 'invalid_payload', which will be played back at the beginning of each prompt. Speech will be interrupted when a DTMF signal is received. The `Answer` command must be issued before the `gather_using_speak` command. **Expected Webhooks:** - `call.dtmf.received` (you may receive many of these webhooks) - `call.gather.ended` # Hangup call Source: https://developers.telnyx.com/api-reference/call-commands/hangup-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/hangup.yml post /calls/{call_control_id}/actions/hangup Hang up the call. **Expected Webhooks:** - `call.hangup` - `call.recording.saved` # Join AI Assistant Conversation Source: https://developers.telnyx.com/api-reference/call-commands/join-ai-assistant-conversation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/ai-assistant-join.yml post /calls/{call_control_id}/actions/ai_assistant_join Add a participant to an existing AI assistant conversation. Use this command to bring an additional call leg into a running AI conversation. # Noise Suppression Start (BETA) Source: https://developers.telnyx.com/api-reference/call-commands/noise-suppression-start-beta https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/suppression-start.yml post /calls/{call_control_id}/actions/suppression_start # Noise Suppression Stop (BETA) Source: https://developers.telnyx.com/api-reference/call-commands/noise-suppression-stop-beta https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/suppression-stop.yml post /calls/{call_control_id}/actions/suppression_stop # Play audio URL Source: https://developers.telnyx.com/api-reference/call-commands/play-audio-url https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/playback-start.yml post /calls/{call_control_id}/actions/playback_start Play an audio file on the call. If multiple play audio commands are issued consecutively, the audio files will be placed in a queue awaiting playback. *Notes:* - When `overlay` is enabled, `target_legs` is limited to `self`. - A customer cannot Play Audio with `overlay=true` unless there is a Play Audio with `overlay=false` actively playing. **Expected Webhooks:** - `call.playback.started` - `call.playback.ended` # Record pause Source: https://developers.telnyx.com/api-reference/call-commands/record-pause https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-pause.yml post /calls/{call_control_id}/actions/record_pause Pause recording the call. Recording can be resumed via Resume recording command. **Expected Webhooks:** There are no webhooks associated with this command. # Record resume Source: https://developers.telnyx.com/api-reference/call-commands/record-resume https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-resume.yml post /calls/{call_control_id}/actions/record_resume Resume recording the call. **Expected Webhooks:** There are no webhooks associated with this command. # Recording start Source: https://developers.telnyx.com/api-reference/call-commands/recording-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-start.yml post /calls/{call_control_id}/actions/record_start Start recording the call. Recording will stop on call hang-up, or can be initiated via the Stop Recording command. **Expected Webhooks:** - `call.recording.saved` - `call.recording.transcription.saved` - `call.recording.error` # Recording stop Source: https://developers.telnyx.com/api-reference/call-commands/recording-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-stop.yml post /calls/{call_control_id}/actions/record_stop Stop recording the call. **Expected Webhooks:** - `call.recording.saved` # Reject a call Source: https://developers.telnyx.com/api-reference/call-commands/reject-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/reject.yml post /calls/{call_control_id}/actions/reject Reject an incoming call. **Expected Webhooks:** - `call.hangup` # Remove call from a queue Source: https://developers.telnyx.com/api-reference/call-commands/remove-call-from-a-queue https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/leave-queue.yml post /calls/{call_control_id}/actions/leave_queue Removes the call from a queue. # Send DTMF Source: https://developers.telnyx.com/api-reference/call-commands/send-dtmf https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/send-dtmf.yml post /calls/{call_control_id}/actions/send_dtmf Sends DTMF tones from this leg. DTMF tones will be heard by the other end of the call. **Expected Webhooks:** There are no webhooks associated with this command. # SIP Refer a call Source: https://developers.telnyx.com/api-reference/call-commands/sip-refer-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/refer.yml post /calls/{call_control_id}/actions/refer Initiate a SIP Refer on a Call Control call. You can initiate a SIP Refer at any point in the duration of a call. **Expected Webhooks:** - `call.refer.started` - `call.refer.completed` - `call.refer.failed` # SIPREC start Source: https://developers.telnyx.com/api-reference/call-commands/siprec-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/siprec-start.yml post /calls/{call_control_id}/actions/siprec_start Start siprec session to configured in SIPREC connector SRS. **Expected Webhooks:** - `siprec.started` - `siprec.stopped` - `siprec.failed` # SIPREC stop Source: https://developers.telnyx.com/api-reference/call-commands/siprec-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/siprec-stop.yml post /calls/{call_control_id}/actions/siprec_stop Stop SIPREC session. **Expected Webhooks:** - `siprec.stopped` # Speak text Source: https://developers.telnyx.com/api-reference/call-commands/speak-text https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/speak.yml post /calls/{call_control_id}/actions/speak Convert text to speech and play it back on the call. If multiple speak text commands are issued consecutively, the audio files will be placed in a queue awaiting playback. **Expected Webhooks:** - `call.speak.started` - `call.speak.ended` # Start AI Assistant Source: https://developers.telnyx.com/api-reference/call-commands/start-ai-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/ai-assistant-start.yml post /calls/{call_control_id}/actions/ai_assistant_start Start an AI assistant on the call. **Expected Webhooks:** - `call.conversation.ended` - `call.conversation_insights.generated` # Stop AI Assistant Source: https://developers.telnyx.com/api-reference/call-commands/stop-ai-assistant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/ai-assistant-stop.yml post /calls/{call_control_id}/actions/ai_assistant_stop Stop an AI assistant on the call. # Stop audio playback Source: https://developers.telnyx.com/api-reference/call-commands/stop-audio-playback https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/playback-stop.yml post /calls/{call_control_id}/actions/playback_stop Stop audio being played on the call. **Expected Webhooks:** - `call.playback.ended` or `call.speak.ended` # Streaming start Source: https://developers.telnyx.com/api-reference/call-commands/streaming-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/streaming-start.yml post /calls/{call_control_id}/actions/streaming_start Start streaming the media from a call to a specific WebSocket address or Dialogflow connection in near-realtime. Audio will be delivered as base64-encoded RTP payload (raw audio), wrapped in JSON payloads. Please find more details about media streaming messages specification under the [link](https://developers.telnyx.com/docs/voice/programmable-voice/media-streaming). # Streaming stop Source: https://developers.telnyx.com/api-reference/call-commands/streaming-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/streaming-stop.yml post /calls/{call_control_id}/actions/streaming_stop Stop streaming a call to a WebSocket. **Expected Webhooks:** - `streaming.stopped` # Switch supervisor role Source: https://developers.telnyx.com/api-reference/call-commands/switch-supervisor-role https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/switch-supervisor-role.yml post /calls/{call_control_id}/actions/switch_supervisor_role Switch the supervisor role for a bridged call. This allows switching between different supervisor modes during an active call # Transcription start Source: https://developers.telnyx.com/api-reference/call-commands/transcription-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transcription-start.yml post /calls/{call_control_id}/actions/transcription_start Start real-time transcription. Transcription will stop on call hang-up, or can be initiated via the Transcription stop command. **Expected Webhooks:** - `call.transcription` # Transcription stop Source: https://developers.telnyx.com/api-reference/call-commands/transcription-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transcription-stop.yml post /calls/{call_control_id}/actions/transcription_stop Stop real-time transcription. # Transfer call Source: https://developers.telnyx.com/api-reference/call-commands/transfer-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml post /calls/{call_control_id}/actions/transfer Transfer a call to a new destination. If the transfer is unsuccessful, a `call.hangup` webhook for the other call (Leg B) will be sent indicating that the transfer could not be completed. The original call will remain active and may be issued additional commands, potentially transfering the call to an alternate destination. **Expected Webhooks:** - `call.initiated` - `call.bridged` to Leg B - `call.answered` or `call.hangup` - `call.machine.detection.ended` if `answering_machine_detection` was requested - `call.machine.greeting.ended` if `answering_machine_detection` was requested to detect the end of machine greeting - `call.machine.premium.detection.ended` if `answering_machine_detection=premium` was requested - `call.machine.premium.greeting.ended` if `answering_machine_detection=premium` was requested and a beep was detected # Update client state Source: https://developers.telnyx.com/api-reference/call-commands/update-client-state https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/client-state-update.yml put /calls/{call_control_id}/actions/client_state_update Updates client state # Create a call control application Source: https://developers.telnyx.com/api-reference/call-control-applications/create-a-call-control-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/applications.yml post /call_control_applications Create a call control application. # Delete a call control application Source: https://developers.telnyx.com/api-reference/call-control-applications/delete-a-call-control-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/applications.yml delete /call_control_applications/{id} Deletes a call control application. # List call control applications Source: https://developers.telnyx.com/api-reference/call-control-applications/list-call-control-applications https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/applications.yml get /call_control_applications Return a list of call control applications. # Retrieve a call control application Source: https://developers.telnyx.com/api-reference/call-control-applications/retrieve-a-call-control-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/applications.yml get /call_control_applications/{id} Retrieves the details of an existing call control application. # Update a call control application Source: https://developers.telnyx.com/api-reference/call-control-applications/update-a-call-control-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/applications.yml patch /call_control_applications/{id} Updates settings of an existing call control application. # List all active calls for given connection Source: https://developers.telnyx.com/api-reference/call-information/list-all-active-calls-for-given-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/active-calls.yml get /connections/{connection_id}/active_calls Lists all active calls for given connection. Acceptable connections are either SIP connections with webhook_url or xml_request_url, call control or texml. Returned results are cursor paginated. # Create a custom storage credential Source: https://developers.telnyx.com/api-reference/call-recordings/create-a-custom-storage-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml post /custom_storage_credentials/{connection_id} Creates a custom storage credentials configuration. # Delete a call recording Source: https://developers.telnyx.com/api-reference/call-recordings/delete-a-call-recording https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml delete /recordings/{recording_id} Permanently deletes a call recording. # Delete a list of call recordings Source: https://developers.telnyx.com/api-reference/call-recordings/delete-a-list-of-call-recordings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml post /recordings/actions/delete Permanently deletes a list of call recordings. # Delete a recording transcription Source: https://developers.telnyx.com/api-reference/call-recordings/delete-a-recording-transcription https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml delete /recording_transcriptions/{recording_transcription_id} Permanently deletes a recording transcription. # Delete a stored credential Source: https://developers.telnyx.com/api-reference/call-recordings/delete-a-stored-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml delete /custom_storage_credentials/{connection_id} Deletes a stored custom credentials configuration. # List all call recordings Source: https://developers.telnyx.com/api-reference/call-recordings/list-all-call-recordings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml get /recordings Returns a list of your call recordings. # List all recording transcriptions Source: https://developers.telnyx.com/api-reference/call-recordings/list-all-recording-transcriptions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml get /recording_transcriptions Returns a list of your recording transcriptions. # Retrieve a call recording Source: https://developers.telnyx.com/api-reference/call-recordings/retrieve-a-call-recording https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml get /recordings/{recording_id} Retrieves the details of an existing call recording. # Retrieve a recording transcription Source: https://developers.telnyx.com/api-reference/call-recordings/retrieve-a-recording-transcription https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml get /recording_transcriptions/{recording_transcription_id} Retrieves the details of an existing recording transcription. # Retrieve a stored credential Source: https://developers.telnyx.com/api-reference/call-recordings/retrieve-a-stored-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml get /custom_storage_credentials/{connection_id} Returns the information about custom storage credentials. # Update a stored credential Source: https://developers.telnyx.com/api-reference/call-recordings/update-a-stored-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/call-recordings.yml put /custom_storage_credentials/{connection_id} Updates a stored custom credentials configuration. # Call ai gather ended Source: https://developers.telnyx.com/api-reference/callbacks/call-ai-gather-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-ai.yml webhook CallAIGatherEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call ai gather message history updated Source: https://developers.telnyx.com/api-reference/callbacks/call-ai-gather-message-history-updated https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-ai.yml webhook CallAIGatherMessageHistoryUpdated This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call ai gather partial results Source: https://developers.telnyx.com/api-reference/callbacks/call-ai-gather-partial-results https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-ai.yml webhook CallAIGatherPartialResults This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call answered Source: https://developers.telnyx.com/api-reference/callbacks/call-answered https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callAnswered This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call bridged Source: https://developers.telnyx.com/api-reference/callbacks/call-bridged https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml webhook callBridged This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call conversation ended Source: https://developers.telnyx.com/api-reference/callbacks/call-conversation-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-ai.yml webhook CallConversationEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call conversation insights generated Source: https://developers.telnyx.com/api-reference/callbacks/call-conversation-insights-generated https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/ai-assistant-join.yml webhook callConversationInsightsGenerated This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call deepfake detection error Source: https://developers.telnyx.com/api-reference/callbacks/call-deepfake-detection-error https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callDeepfakeDetectionError This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call deepfake detection result Source: https://developers.telnyx.com/api-reference/callbacks/call-deepfake-detection-result https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callDeepfakeDetectionResult This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call dtmf received Source: https://developers.telnyx.com/api-reference/callbacks/call-dtmf-received https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-speak.yml webhook callDtmfReceived This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call enqueued Source: https://developers.telnyx.com/api-reference/callbacks/call-enqueued https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/enqueue.yml webhook callEnqueued This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call fork started Source: https://developers.telnyx.com/api-reference/callbacks/call-fork-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/fork-start.yml webhook callForkStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call fork stopped Source: https://developers.telnyx.com/api-reference/callbacks/call-fork-stopped https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/fork-stop.yml webhook callForkStopped This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call gather ended Source: https://developers.telnyx.com/api-reference/callbacks/call-gather-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/gather-using-speak.yml webhook callGatherEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call hangup Source: https://developers.telnyx.com/api-reference/callbacks/call-hangup https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/reject.yml webhook callHangup This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call initiated Source: https://developers.telnyx.com/api-reference/callbacks/call-initiated https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callInitiated This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call left queue Source: https://developers.telnyx.com/api-reference/callbacks/call-left-queue https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/enqueue.yml webhook callLeftQueue This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call machine detection ended Source: https://developers.telnyx.com/api-reference/callbacks/call-machine-detection-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml webhook callMachineDetectionEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call machine greeting ended Source: https://developers.telnyx.com/api-reference/callbacks/call-machine-greeting-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml webhook callMachineGreetingEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call machine premium detection ended Source: https://developers.telnyx.com/api-reference/callbacks/call-machine-premium-detection-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml webhook callMachinePremiumDetectionEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call machine premium greeting ended Source: https://developers.telnyx.com/api-reference/callbacks/call-machine-premium-greeting-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transfer.yml webhook callMachinePremiumGreetingEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call playback ended Source: https://developers.telnyx.com/api-reference/callbacks/call-playback-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/playback-stop.yml webhook callPlaybackEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call playback started Source: https://developers.telnyx.com/api-reference/callbacks/call-playback-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/playback-start.yml webhook callPlaybackStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call recording error Source: https://developers.telnyx.com/api-reference/callbacks/call-recording-error https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-start.yml webhook callRecordingError This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call recording saved Source: https://developers.telnyx.com/api-reference/callbacks/call-recording-saved https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-stop.yml webhook callRecordingSaved This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call recording transcription saved Source: https://developers.telnyx.com/api-reference/callbacks/call-recording-transcription-saved https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/record-start.yml webhook callRecordingTranscriptionSaved This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call refer completed Source: https://developers.telnyx.com/api-reference/callbacks/call-refer-completed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/refer.yml webhook callReferCompleted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call refer failed Source: https://developers.telnyx.com/api-reference/callbacks/call-refer-failed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/refer.yml webhook callReferFailed This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call refer started Source: https://developers.telnyx.com/api-reference/callbacks/call-refer-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/refer.yml webhook callReferStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call siprec failed Source: https://developers.telnyx.com/api-reference/callbacks/call-siprec-failed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/siprec-start.yml webhook callSiprecFailed This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call siprec started Source: https://developers.telnyx.com/api-reference/callbacks/call-siprec-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/siprec-start.yml webhook callSiprecStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call siprec stopped Source: https://developers.telnyx.com/api-reference/callbacks/call-siprec-stopped https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/siprec-stop.yml webhook callSiprecStopped This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call speak ended Source: https://developers.telnyx.com/api-reference/callbacks/call-speak-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/speak.yml webhook callSpeakEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call speak started Source: https://developers.telnyx.com/api-reference/callbacks/call-speak-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/speak.yml webhook callSpeakStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call streaming failed Source: https://developers.telnyx.com/api-reference/callbacks/call-streaming-failed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callStreamingFailed This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call streaming started Source: https://developers.telnyx.com/api-reference/callbacks/call-streaming-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callStreamingStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Call streaming stopped Source: https://developers.telnyx.com/api-reference/callbacks/call-streaming-stopped https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/dial.yml webhook callStreamingStopped This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Campaign status update Source: https://developers.telnyx.com/api-reference/callbacks/campaign-status-update https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml webhook campaignStatusUpdate This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference created Source: https://developers.telnyx.com/api-reference/callbacks/conference-created https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceCreated This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference ended Source: https://developers.telnyx.com/api-reference/callbacks/conference-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference floor changed Source: https://developers.telnyx.com/api-reference/callbacks/conference-floor-changed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceFloorChanged This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant joined Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-joined https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantJoined This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant left Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-left https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantLeft This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant playback ended Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-playback-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantPlaybackEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant playback started Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-playback-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantPlaybackStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant speak ended Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-speak-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantSpeakEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference participant speak started Source: https://developers.telnyx.com/api-reference/callbacks/conference-participant-speak-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceParticipantSpeakStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference playback ended Source: https://developers.telnyx.com/api-reference/callbacks/conference-playback-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferencePlaybackEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference playback started Source: https://developers.telnyx.com/api-reference/callbacks/conference-playback-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferencePlaybackStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference recording saved Source: https://developers.telnyx.com/api-reference/callbacks/conference-recording-saved https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceRecordingSaved This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference speak ended Source: https://developers.telnyx.com/api-reference/callbacks/conference-speak-ended https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceSpeakEnded This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Conference speak started Source: https://developers.telnyx.com/api-reference/callbacks/conference-speak-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml webhook conferenceSpeakStarted This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Delivery update Source: https://developers.telnyx.com/api-reference/callbacks/delivery-update https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml webhook deliveryUpdate This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Fax delivered Source: https://developers.telnyx.com/api-reference/callbacks/fax-delivered https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml webhook fax.delivered This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Fax failed Source: https://developers.telnyx.com/api-reference/callbacks/fax-failed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml webhook fax.failed This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Fax media processed Source: https://developers.telnyx.com/api-reference/callbacks/fax-media-processed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml webhook fax.media.processed This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Fax queued Source: https://developers.telnyx.com/api-reference/callbacks/fax-queued https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml webhook fax.queued This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Fax sending started Source: https://developers.telnyx.com/api-reference/callbacks/fax-sending-started https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml webhook fax.sending.started This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Inbound message Source: https://developers.telnyx.com/api-reference/callbacks/inbound-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml webhook inboundMessage This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Number order status update Source: https://developers.telnyx.com/api-reference/callbacks/number-order-status-update https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml webhook numberOrderStatusUpdate This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Replaced link click Source: https://developers.telnyx.com/api-reference/callbacks/replaced-link-click https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml webhook replacedLinkClick This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml ai gather Source: https://developers.telnyx.com/api-reference/callbacks/texml-ai-gather https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlAiGatherWebhook Webhook sent when AI Gather completes with transcription results. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call amd Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-amd https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallAmdWebhook Webhook sent when Answering Machine Detection (AMD) completes during a TeXML call. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call answered Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-answered https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallAnsweredWebhook Webhook sent when a TeXML call is answered. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call completed Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-completed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallCompletedWebhook Webhook sent when a TeXML call is completed. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call dtmf Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-dtmf https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallDtmfWebhook Webhook sent when a DTMF digit is received during a TeXML call. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call initiated Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-initiated https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallInitiatedWebhook Webhook sent when a TeXML call is initiated. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml call ringing Source: https://developers.telnyx.com/api-reference/callbacks/texml-call-ringing https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlCallRingingWebhook Webhook sent when a TeXML call is ringing. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml conference end Source: https://developers.telnyx.com/api-reference/callbacks/texml-conference-end https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conferences.yml webhook TexmlConferenceEndWebhook Webhook sent when a TeXML conference ends. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml conference join Source: https://developers.telnyx.com/api-reference/callbacks/texml-conference-join https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml webhook TexmlConferenceJoinWebhook Webhook sent when a participant joins a TeXML conference. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml conference leave Source: https://developers.telnyx.com/api-reference/callbacks/texml-conference-leave https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml webhook TexmlConferenceLeaveWebhook Webhook sent when a participant leaves a TeXML conference. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml conference speaker Source: https://developers.telnyx.com/api-reference/callbacks/texml-conference-speaker https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml webhook TexmlConferenceSpeakerWebhook Webhook sent when a participant starts or stops speaking in a TeXML conference. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml conference start Source: https://developers.telnyx.com/api-reference/callbacks/texml-conference-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conferences.yml webhook TexmlConferenceStartWebhook Webhook sent when a TeXML conference starts. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml gather Source: https://developers.telnyx.com/api-reference/callbacks/texml-gather https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlGatherWebhook Webhook sent when a Gather command completes (sent to the action URL). This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml http request Source: https://developers.telnyx.com/api-reference/callbacks/texml-http-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlHttpRequestWebhook Webhook sent as response to an HTTP Request instruction. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml queue Source: https://developers.telnyx.com/api-reference/callbacks/texml-queue https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml webhook TexmlQueueWebhook Webhook sent for queue status events (triggered by Enqueue command waitUrl). This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml recording completed Source: https://developers.telnyx.com/api-reference/callbacks/texml-recording-completed https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml webhook TexmlRecordingCompletedWebhook Webhook sent when a recording is completed during a TeXML call (triggered by recordingStatusCallbackEvent). This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml recording in progress Source: https://developers.telnyx.com/api-reference/callbacks/texml-recording-in-progress https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml webhook TexmlRecordingInProgressWebhook Webhook sent when a recording starts during a TeXML call (triggered by recordingStatusCallbackEvent). This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml refer status Source: https://developers.telnyx.com/api-reference/callbacks/texml-refer-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml webhook TexmlReferStatusWebhook Webhook sent for SIP REFER status updates. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml siprec Source: https://developers.telnyx.com/api-reference/callbacks/texml-siprec https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/siprec.yml webhook TexmlSiprecWebhook Webhook sent for SIPREC session status updates. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml stream Source: https://developers.telnyx.com/api-reference/callbacks/texml-stream https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/streams.yml webhook TexmlStreamWebhook Webhook sent for media streaming status updates. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Texml transcription Source: https://developers.telnyx.com/api-reference/callbacks/texml-transcription https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/transcriptions.yml webhook TexmlTranscriptionWebhook Webhook sent when a recording transcription is completed. This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Transcription Source: https://developers.telnyx.com/api-reference/callbacks/transcription https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control-commands/transcription-start.yml webhook transcription This webhook uses Telnyx headers (telnyx-timestamp, telnyx-signature-ed25519) that are compatible with Standard Webhooks specification for SDK generation. Custom validation logic can map these to standard webhook-timestamp and webhook-signature equivalents. See https://github.com/standard-webhooks/standard-webhooks for details. # Accept Shared Campaign Source: https://developers.telnyx.com/api-reference/campaign/accept-shared-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml post /10dlc/campaign/acceptSharing/{campaignId} Manually accept a campaign shared with Telnyx # Deactivate campaign Source: https://developers.telnyx.com/api-reference/campaign/deactivate-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml delete /10dlc/campaign/{campaignId} Terminate a campaign. Note that once deactivated, a campaign cannot be restored. # Get campaign Source: https://developers.telnyx.com/api-reference/campaign/get-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/{campaignId} Retrieve campaign details by `campaignId`. # Get Campaign Cost Source: https://developers.telnyx.com/api-reference/campaign/get-campaign-cost https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/usecase_cost # Get Campaign Mno Metadata Source: https://developers.telnyx.com/api-reference/campaign/get-campaign-mno-metadata https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/{campaignId}/mnoMetadata Get the campaign metadata for each MNO it was submitted to. # Get campaign operation status Source: https://developers.telnyx.com/api-reference/campaign/get-campaign-operation-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/{campaignId}/operationStatus Retrieve campaign's operation status at MNO level. # Get OSR campaign attributes Source: https://developers.telnyx.com/api-reference/campaign/get-osr-campaign-attributes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/{campaignId}/osr_attributes # Get Sharing Status Source: https://developers.telnyx.com/api-reference/campaign/get-sharing-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign/{campaignId}/sharing # List Campaigns Source: https://developers.telnyx.com/api-reference/campaign/list-campaigns https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml get /10dlc/campaign Retrieve a list of campaigns associated with a supplied `brandId`. # Qualify By Usecase Source: https://developers.telnyx.com/api-reference/campaign/qualify-by-usecase https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaign-builder.yml get /10dlc/campaignBuilder/brand/{brandId}/usecase/{usecase} This endpoint allows you to see whether or not the supplied brand is suitable for your desired campaign use case. # Submit Campaign Source: https://developers.telnyx.com/api-reference/campaign/submit-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaign-builder.yml post /10dlc/campaignBuilder Before creating a campaign, use the [Qualify By Usecase endpoint](https://developers.telnyx.com/api-reference/campaign/qualify-by-usecase) to ensure that the brand you want to assign a new campaign to is qualified for the desired use case of that campaign. **Please note:** After campaign creation, you'll only be able to edit the campaign's sample messages. Creating a campaign will entail an upfront, non-refundable three month's cost that will depend on the campaign's use case ([see 10DLC Costs section for details](https://developers.telnyx.com/api-reference/campaign/get-campaign-cost)). # Submit campaign appeal for manual review Source: https://developers.telnyx.com/api-reference/campaign/submit-campaign-appeal-for-manual-review https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml post /10dlc/campaign/{campaignId}/appeal Submits an appeal for rejected native campaigns in TELNYX_FAILED or MNO_REJECTED status. The appeal is recorded for manual compliance team review and the campaign status is reset to TCR_ACCEPTED. Note: Appeal forwarding is handled manually to allow proper review before incurring upstream charges. # Update campaign Source: https://developers.telnyx.com/api-reference/campaign/update-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/campaigns.yml put /10dlc/campaign/{campaignId} Update a campaign's properties by `campaignId`. **Please note:** only sample messages are editable. # Create a new CDR report request Source: https://developers.telnyx.com/api-reference/cdr-reports/create-a-new-cdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy_reporting/batch_detail_records/voice Creates a new CDR report request with the specified filters # Delete a CDR report request Source: https://developers.telnyx.com/api-reference/cdr-reports/delete-a-cdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy_reporting/batch_detail_records/voice/{id} Deletes a specific CDR report request by ID # Get a specific CDR report request Source: https://developers.telnyx.com/api-reference/cdr-reports/get-a-specific-cdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/batch_detail_records/voice/{id} Retrieves a specific CDR report request by ID # Get all CDR report requests Source: https://developers.telnyx.com/api-reference/cdr-reports/get-all-cdr-report-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/batch_detail_records/voice Retrieves all CDR report requests for the authenticated user # Get available CDR report fields Source: https://developers.telnyx.com/api-reference/cdr-reports/get-available-cdr-report-fields https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/batch_detail_records/voice/fields Retrieves all available fields that can be used in CDR reports # Create a new legacy usage V2 CDR report request Source: https://developers.telnyx.com/api-reference/cdr-usage-reports/create-a-new-legacy-usage-v2-cdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy_reporting/usage_reports/voice Creates a new legacy usage V2 CDR report request with the specified filters # Delete a V2 legacy usage CDR report request Source: https://developers.telnyx.com/api-reference/cdr-usage-reports/delete-a-v2-legacy-usage-cdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy_reporting/usage_reports/voice/{id} Deletes a specific V2 legacy usage CDR report request by ID # Generates and fetches CDR Usage Reports Source: https://developers.telnyx.com/api-reference/cdr-usage-reports/generates-and-fetches-cdr-usage-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/cdr_usage_reports/sync Generate and fetch voice usage report synchronously. This endpoint will both generate and fetch the voice report over a specified time period. No polling is necessary but the response may take up to a couple of minutes. # Get a CDR usage report Source: https://developers.telnyx.com/api-reference/cdr-usage-reports/get-a-cdr-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/voice/{id} Fetch single cdr usage report by id. # List CDR usage reports Source: https://developers.telnyx.com/api-reference/cdr-usage-reports/list-cdr-usage-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/voice Fetch all previous requests for cdr usage reports. # Summarize file content Source: https://developers.telnyx.com/api-reference/chat/summarize-file-content https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/summarize Generate a summary of a file's contents. Supports the following text formats: - PDF, HTML, txt, json, csv Supports the following media formats (billed for both the transcription and summary): - flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm - Up to 100 MB # Compute new clusters Source: https://developers.telnyx.com/api-reference/clusters/compute-new-clusters https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/clusters Starts a background task to compute how the data in an [embedded storage bucket](https://developers.telnyx.com/api-reference/embeddings/embed-documents) is clustered. This helps identify common themes and patterns in the data. # Delete a cluster Source: https://developers.telnyx.com/api-reference/clusters/delete-a-cluster https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/clusters/{task_id} # Fetch a cluster Source: https://developers.telnyx.com/api-reference/clusters/fetch-a-cluster https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/clusters/{task_id} # Fetch a cluster visualization Source: https://developers.telnyx.com/api-reference/clusters/fetch-a-cluster-visualization https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/clusters/{task_id}/graph # List all clusters Source: https://developers.telnyx.com/api-reference/clusters/list-all-clusters https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/clusters # Conference recording pause Source: https://developers.telnyx.com/api-reference/conference-commands/conference-recording-pause https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/record_pause Pause conference recording. # Conference recording resume Source: https://developers.telnyx.com/api-reference/conference-commands/conference-recording-resume https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/record_resume Resume conference recording. # Conference recording start Source: https://developers.telnyx.com/api-reference/conference-commands/conference-recording-start https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/record_start Start recording the conference. Recording will stop on conference end, or via the Stop Recording command. **Expected Webhooks:** - `conference.recording.saved` # Conference recording stop Source: https://developers.telnyx.com/api-reference/conference-commands/conference-recording-stop https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/record_stop Stop recording the conference. **Expected Webhooks:** - `conference.recording.saved` # Create conference Source: https://developers.telnyx.com/api-reference/conference-commands/create-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences Create a conference from an existing call leg using a `call_control_id` and a conference name. Upon creating the conference, the call will be automatically bridged to the conference. Conferences will expire after all participants have left the conference or after 4 hours regardless of the number of active participants. **Expected Webhooks:** - `conference.created` - `conference.participant.joined` - `conference.participant.left` - `conference.ended` - `conference.recording.saved` - `conference.floor.changed` # End a conference Source: https://developers.telnyx.com/api-reference/conference-commands/end-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/end End a conference and terminate all active participants. # Gather DTMF using audio prompt in a conference Source: https://developers.telnyx.com/api-reference/conference-commands/gather-dtmf-using-audio-prompt-in-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/gather_using_audio Play an audio file to a specific conference participant and gather DTMF input. # Hold conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/hold-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/hold Hold a list of participants in a conference call # Join a conference Source: https://developers.telnyx.com/api-reference/conference-commands/join-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/join Join an existing call leg to a conference. Issue the Join Conference command with the conference ID in the path and the `call_control_id` of the leg you wish to join to the conference as an attribute. The conference can have up to a certain amount of active participants, as set by the `max_participants` parameter in conference creation request. **Expected Webhooks:** - `conference.participant.joined` - `conference.participant.left` # Leave a conference Source: https://developers.telnyx.com/api-reference/conference-commands/leave-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/leave Removes a call leg from a conference and moves it back to parked state. **Expected Webhooks:** - `conference.participant.left` # List conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/list-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml get /conferences/{conference_id}/participants Lists conference participants # List conferences Source: https://developers.telnyx.com/api-reference/conference-commands/list-conferences https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml get /conferences Lists conferences. Conferences are created on demand, and will expire after all participants have left the conference or after 4 hours regardless of the number of active participants. Conferences are listed in descending order by `expires_at`. # Mute conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/mute-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/mute Mute a list of participants in a conference call # Play audio to conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/play-audio-to-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/play Play audio to all or some participants on a conference call. # Retrieve a conference Source: https://developers.telnyx.com/api-reference/conference-commands/retrieve-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml get /conferences/{id} Retrieve an existing conference # Retrieve a conference participant Source: https://developers.telnyx.com/api-reference/conference-commands/retrieve-a-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml get /conferences/{id}/participants/{participant_id} Retrieve details of a specific conference participant by their ID or label. # Send DTMF to conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/send-dtmf-to-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/send_dtmf Send DTMF tones to one or more conference participants. # Speak text to conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/speak-text-to-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/speak Convert text to speech and play it to all or some participants. # Stop audio being played on the conference Source: https://developers.telnyx.com/api-reference/conference-commands/stop-audio-being-played-on-the-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/stop Stop audio being played to all or some participants on a conference call. # Unhold conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/unhold-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/unhold Unhold a list of participants in a conference call # Unmute conference participants Source: https://developers.telnyx.com/api-reference/conference-commands/unmute-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/unmute Unmute a list of participants in a conference call # Update a conference participant Source: https://developers.telnyx.com/api-reference/conference-commands/update-a-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml patch /conferences/{id}/participants/{participant_id} Update properties of a conference participant. # Update conference participant Source: https://developers.telnyx.com/api-reference/conference-commands/update-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/conferences.yml post /conferences/{id}/actions/update Update conference participant supervisor_role # List connections Source: https://developers.telnyx.com/api-reference/connections/list-connections https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /connections Returns a list of your connections irrespective of type. # Retrieve a connection Source: https://developers.telnyx.com/api-reference/connections/retrieve-a-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /connections/{id} Retrieves the high-level details of an existing connection. To retrieve specific authentication information, use the endpoint for the specific connection type. # Assign Insight Template To Group Source: https://developers.telnyx.com/api-reference/conversations/assign-insight-template-to-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/conversations/insight-groups/{group_id}/insights/{insight_id}/assign Assign an insight to a group # Create a conversation Source: https://developers.telnyx.com/api-reference/conversations/create-a-conversation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/conversations Create a new AI Conversation. # Create Insight Template Source: https://developers.telnyx.com/api-reference/conversations/create-insight-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/conversations/insights Create a new insight # Create Insight Template Group Source: https://developers.telnyx.com/api-reference/conversations/create-insight-template-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/conversations/insight-groups Create a new insight group # Create Message Source: https://developers.telnyx.com/api-reference/conversations/create-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/conversations/{conversation_id}/message Add a new message to the conversation. Used to insert a new messages to a conversation manually ( without using chat endpoint ) # Delete a conversation Source: https://developers.telnyx.com/api-reference/conversations/delete-a-conversation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/conversations/{conversation_id} Delete a specific conversation by its ID. # Delete Insight Template Source: https://developers.telnyx.com/api-reference/conversations/delete-insight-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/conversations/insights/{insight_id} Delete insight by ID # Delete Insight Template Group Source: https://developers.telnyx.com/api-reference/conversations/delete-insight-template-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/conversations/insight-groups/{group_id} Delete insight group by ID # Get a conversation Source: https://developers.telnyx.com/api-reference/conversations/get-a-conversation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/{conversation_id} Retrieve a specific AI conversation by its ID. # Get conversation messages Source: https://developers.telnyx.com/api-reference/conversations/get-conversation-messages https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/{conversation_id}/messages Retrieve messages for a specific conversation, including tool calls made by the assistant. # Get Insight Template Source: https://developers.telnyx.com/api-reference/conversations/get-insight-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/insights/{insight_id} Get insight by ID # Get Insight Template Group Source: https://developers.telnyx.com/api-reference/conversations/get-insight-template-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/insight-groups/{group_id} Get insight group by ID # Get Insight Template Groups Source: https://developers.telnyx.com/api-reference/conversations/get-insight-template-groups https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/insight-groups Get all insight groups # Get Insight Templates Source: https://developers.telnyx.com/api-reference/conversations/get-insight-templates https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/insights Get all insights # Get insights for a conversation Source: https://developers.telnyx.com/api-reference/conversations/get-insights-for-a-conversation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations/{conversation_id}/conversations-insights Retrieve insights for a specific conversation # List conversations Source: https://developers.telnyx.com/api-reference/conversations/list-conversations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/conversations Retrieve a list of all AI conversations configured by the user. Supports [PostgREST-style query parameters](https://postgrest.org/en/stable/api.html#horizontal-filtering-rows) for filtering. Examples are included for the standard metadata fields, but you can filter on any field in the metadata JSON object. For example, to filter by a custom field `metadata->custom_field`, use `metadata->custom_field=eq.value`. # Unassign Insight Template From Group Source: https://developers.telnyx.com/api-reference/conversations/unassign-insight-template-from-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/conversations/insight-groups/{group_id}/insights/{insight_id}/unassign Remove an insight from a group # Update conversation metadata Source: https://developers.telnyx.com/api-reference/conversations/update-conversation-metadata https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml put /ai/conversations/{conversation_id} Update metadata for a specific conversation. # Update Insight Template Source: https://developers.telnyx.com/api-reference/conversations/update-insight-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml put /ai/conversations/insights/{insight_id} Update an insight template # Update Insight Template Group Source: https://developers.telnyx.com/api-reference/conversations/update-insight-template-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml put /ai/conversations/insight-groups/{group_id} Update an insight template group # Get country coverage Source: https://developers.telnyx.com/api-reference/country-coverage/get-country-coverage https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/coverage.yml get /country_coverage Get country coverage # Get coverage for a specific country Source: https://developers.telnyx.com/api-reference/country-coverage/get-coverage-for-a-specific-country https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/coverage.yml get /country_coverage/countries/{country_code} Get coverage for a specific country # Check a Credential Connection Registration Status Source: https://developers.telnyx.com/api-reference/credential-connections/check-a-credential-connection-registration-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /credential_connections/{id}/actions/check_registration_status Checks the registration_status for a credential connection, (`registration_status`) as well as the timestamp for the last SIP registration event (`registration_status_updated_at`) # Create a credential connection Source: https://developers.telnyx.com/api-reference/credential-connections/create-a-credential-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /credential_connections Creates a credential connection. # Delete a credential connection Source: https://developers.telnyx.com/api-reference/credential-connections/delete-a-credential-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml delete /credential_connections/{id} Deletes an existing credential connection. # List credential connections Source: https://developers.telnyx.com/api-reference/credential-connections/list-credential-connections https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /credential_connections Returns a list of your credential connections. # Retrieve a credential connection Source: https://developers.telnyx.com/api-reference/credential-connections/retrieve-a-credential-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /credential_connections/{id} Retrieves the details of an existing credential connection. # Update a credential connection Source: https://developers.telnyx.com/api-reference/credential-connections/update-a-credential-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml patch /credential_connections/{id} Updates settings of an existing credential connection. # Create a credential Source: https://developers.telnyx.com/api-reference/credentials/create-a-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml post /telephony_credentials Create a credential. # Delete a credential Source: https://developers.telnyx.com/api-reference/credentials/delete-a-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml delete /telephony_credentials/{id} Delete an existing credential. # Get a credential Source: https://developers.telnyx.com/api-reference/credentials/get-a-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml get /telephony_credentials/{id} Get the details of an existing On-demand Credential. # List all credentials Source: https://developers.telnyx.com/api-reference/credentials/list-all-credentials https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml get /telephony_credentials List all On-demand Credentials. # Update a credential Source: https://developers.telnyx.com/api-reference/credentials/update-a-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/sdk-client-credentials.yml patch /telephony_credentials/{id} Update an existing credential. # Create a CSV download Source: https://developers.telnyx.com/api-reference/csv-downloads/create-a-csv-download https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/csv_downloads # List CSV downloads Source: https://developers.telnyx.com/api-reference/csv-downloads/list-csv-downloads https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/csv_downloads # Retrieve a CSV download Source: https://developers.telnyx.com/api-reference/csv-downloads/retrieve-a-csv-download https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/csv_downloads/{id} # Create a Migration Source: https://developers.telnyx.com/api-reference/data-migration/create-a-migration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml post /storage/migrations Initiate a migration of data from an external provider into Telnyx Cloud Storage. Currently, only S3 is supported. # Create a Migration Source Source: https://developers.telnyx.com/api-reference/data-migration/create-a-migration-source https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml post /storage/migration_sources Create a source from which data can be migrated from. # Delete a Migration Source Source: https://developers.telnyx.com/api-reference/data-migration/delete-a-migration-source https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml delete /storage/migration_sources/{id} # Get a Migration Source: https://developers.telnyx.com/api-reference/data-migration/get-a-migration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/migrations/{id} # Get a Migration Source Source: https://developers.telnyx.com/api-reference/data-migration/get-a-migration-source https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/migration_sources/{id} # List all Migration Sources Source: https://developers.telnyx.com/api-reference/data-migration/list-all-migration-sources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/migration_sources # List all Migrations Source: https://developers.telnyx.com/api-reference/data-migration/list-all-migrations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/migrations # List Migration Source coverage Source: https://developers.telnyx.com/api-reference/data-migration/list-migration-source-coverage https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml get /storage/migration_source_coverage # Stop a Migration Source: https://developers.telnyx.com/api-reference/data-migration/stop-a-migration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml post /storage/migrations/{id}/actions/stop # List call events Source: https://developers.telnyx.com/api-reference/debugging/list-call-events https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/call-control/call-events.yml get /call_events Filters call events by given filter parameters. Events are ordered by `occurred_at`. If filter for `leg_id` or `application_session_id` is not present, it only filters events from the last 24 hours. **Note**: Only one `filter[occurred_at]` can be passed. # Search detail records Source: https://developers.telnyx.com/api-reference/detail-records/search-detail-records https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/detail-records.yml get /detail_records Search for any detail record across the Telnyx Platform # Create a Dialogflow Connection Source: https://developers.telnyx.com/api-reference/dialogflow-integration/create-a-dialogflow-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/dialogflow-integration.yml post /dialogflow_connections/{connection_id} Save Dialogflow Credentiails to Telnyx, so it can be used with other Telnyx services. # Delete stored Dialogflow Connection Source: https://developers.telnyx.com/api-reference/dialogflow-integration/delete-stored-dialogflow-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/dialogflow-integration.yml delete /dialogflow_connections/{connection_id} Deletes a stored Dialogflow Connection. # Retrieve stored Dialogflow Connection Source: https://developers.telnyx.com/api-reference/dialogflow-integration/retrieve-stored-dialogflow-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/dialogflow-integration.yml get /dialogflow_connections/{connection_id} Return details of the Dialogflow connection associated with the given CallControl connection. # Update stored Dialogflow Connection Source: https://developers.telnyx.com/api-reference/dialogflow-integration/update-stored-dialogflow-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/dialogflow-integration.yml put /dialogflow_connections/{connection_id} Updates a stored Dialogflow Connection. # Delete a document Source: https://developers.telnyx.com/api-reference/documents/delete-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml delete /documents/{id} Delete a document.

A document can only be deleted if it's not linked to a service. If it is linked to a service, it must be unlinked prior to deleting. # Download a document Source: https://developers.telnyx.com/api-reference/documents/download-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml get /documents/{id}/download Download a document. # Generate a temporary download link for a document Source: https://developers.telnyx.com/api-reference/documents/generate-a-temporary-download-link-for-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml get /documents/{id}/download_link Generates a temporary pre-signed URL that can be used to download the document directly from the storage backend without authentication. # List all document links Source: https://developers.telnyx.com/api-reference/documents/list-all-document-links https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml get /document_links List all documents links ordered by created_at descending. # List all documents Source: https://developers.telnyx.com/api-reference/documents/list-all-documents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml get /documents List all documents ordered by created_at descending. # Retrieve a document Source: https://developers.telnyx.com/api-reference/documents/retrieve-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml get /documents/{id} Retrieve a document. # Update a document Source: https://developers.telnyx.com/api-reference/documents/update-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml patch /documents/{id} Update a document. # Upload a document Source: https://developers.telnyx.com/api-reference/documents/upload-a-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/documents.yml post /documents Upload a document.

Uploaded files must be linked to a service within 30 minutes or they will be automatically deleted. # Create a dynamic emergency address. Source: https://developers.telnyx.com/api-reference/dynamic-emergency-addresses/create-a-dynamic-emergency-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml post /dynamic_emergency_addresses Creates a dynamic emergency address. # Delete a dynamic emergency address Source: https://developers.telnyx.com/api-reference/dynamic-emergency-addresses/delete-a-dynamic-emergency-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml delete /dynamic_emergency_addresses/{id} Deletes the dynamic emergency address based on the ID provided # Get a dynamic emergency address Source: https://developers.telnyx.com/api-reference/dynamic-emergency-addresses/get-a-dynamic-emergency-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml get /dynamic_emergency_addresses/{id} Returns the dynamic emergency address based on the ID provided # List dynamic emergency addresses Source: https://developers.telnyx.com/api-reference/dynamic-emergency-addresses/list-dynamic-emergency-addresses https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml get /dynamic_emergency_addresses Returns the dynamic emergency addresses according to filters # Create a dynamic emergency endpoint. Source: https://developers.telnyx.com/api-reference/dynamic-emergency-endpoints/create-a-dynamic-emergency-endpoint https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml post /dynamic_emergency_endpoints Creates a dynamic emergency endpoints. # Delete a dynamic emergency endpoint Source: https://developers.telnyx.com/api-reference/dynamic-emergency-endpoints/delete-a-dynamic-emergency-endpoint https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml delete /dynamic_emergency_endpoints/{id} Deletes the dynamic emergency endpoint based on the ID provided # Get a dynamic emergency endpoint Source: https://developers.telnyx.com/api-reference/dynamic-emergency-endpoints/get-a-dynamic-emergency-endpoint https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml get /dynamic_emergency_endpoints/{id} Returns the dynamic emergency endpoint based on the ID provided # List dynamic emergency endpoints Source: https://developers.telnyx.com/api-reference/dynamic-emergency-endpoints/list-dynamic-emergency-endpoints https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/emergency.yml get /dynamic_emergency_endpoints Returns the dynamic emergency endpoints according to filters # Disable AI for an Embedded Bucket Source: https://developers.telnyx.com/api-reference/embeddings/disable-ai-for-an-embedded-bucket https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml delete /ai/embeddings/buckets/{bucket_name} Deletes an entire bucket's embeddings and disables the bucket for AI-use, returning it to normal storage pricing. # Embed documents Source: https://developers.telnyx.com/api-reference/embeddings/embed-documents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/embeddings Perform embedding on a Telnyx Storage Bucket using the a embedding model. The current supported file types are: - PDF - HTML - txt/unstructured text files - json - csv - audio / video (mp3, mp4, mpeg, mpga, m4a, wav, or webm ) - Max of 100mb file size. Any files not matching the above types will be attempted to be embedded as unstructured text. This process can be slow, so it runs in the background and the user can check the status of the task using the endpoint `/ai/embeddings/{task_id}`. **Important Note**: When you update documents in a Telnyx Storage bucket, their associated embeddings are automatically kept up to date. If you add or update a file, it is automatically embedded. If you delete a file, the embeddings are deleted for that particular file. You can also specify a custom `loader` param. Currently the only supported loader value is `intercom` which loads Intercom article jsons as specified by [the Intercom article API](https://developers.intercom.com/docs/references/rest-api/api.intercom.io/Articles/article/) This loader will split each article into paragraphs and save additional parameters relevant to Intercom docs, such as `article_url` and `heading`. These values will be returned by the `/v2/ai/embeddings/similarity-search` endpoint in the `loader_metadata` field. # Embed URL content Source: https://developers.telnyx.com/api-reference/embeddings/embed-url-content https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/embeddings/url Embed website content from a specified URL, including child pages up to 5 levels deep within the same domain. The process crawls and loads content from the main URL and its linked pages into a Telnyx Cloud Storage bucket. As soon as each webpage is added to the bucket, its content is immediately processed for embeddings, that can be used for [similarity search](https://developers.telnyx.com/api-reference/embeddings/search-for-documents) and [clustering](https://developers.telnyx.com/docs/inference/clusters). # Get an embedding task's status Source: https://developers.telnyx.com/api-reference/embeddings/get-an-embedding-tasks-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/embeddings/{task_id} Check the status of a current embedding task. Will be one of the following: - `queued` - Task is waiting to be picked up by a worker - `processing` - The embedding task is running - `success` - Task completed successfully and the bucket is embedded - `failure` - Task failed and no files were embedded successfully - `partial_success` - Some files were embedded successfully, but at least one failed # Get file-level embedding statuses for a bucket Source: https://developers.telnyx.com/api-reference/embeddings/get-file-level-embedding-statuses-for-a-bucket https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/embeddings/buckets/{bucket_name} Get all embedded files for a given user bucket, including their processing status. # Get Tasks by Status Source: https://developers.telnyx.com/api-reference/embeddings/get-tasks-by-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/embeddings Retrieve tasks for the user that are either `queued`, `processing`, `failed`, `success` or `partial_success` based on the query string. Defaults to `queued` and `processing`. # List embedded buckets Source: https://developers.telnyx.com/api-reference/embeddings/list-embedded-buckets https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml get /ai/embeddings/buckets Get all embedding buckets for a user. # Search for documents Source: https://developers.telnyx.com/api-reference/embeddings/search-for-documents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/analytics.yml post /ai/embeddings/similarity-search Perform a similarity search on a Telnyx Storage Bucket, returning the most similar `num_docs` document chunks to the query. Currently the only available distance metric is cosine similarity which will return a `distance` between 0 and 1. The lower the distance, the more similar the returned document chunks are to the query. A `certainty` will also be returned, which is a value between 0 and 1 where the higher the certainty, the more similar the document. You can read more about Weaviate distance metrics here: [Weaviate Docs](https://weaviate.io/developers/weaviate/config-refs/distances) If a bucket was embedded using a custom loader, such as `intercom`, the additional metadata will be returned in the `loader_metadata` field. # Create an enterprise Source: https://developers.telnyx.com/api-reference/enterprises/create-an-enterprise https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/enterprises.yml post /enterprises Create a new enterprise for Branded Calling / Number Reputation services. Registers the enterprise in the Branded Calling / Number Reputation services, enabling it to create Display Identity Records (DIRs) or enroll in Number Reputation monitoring. **Required Fields:** `legal_name`, `doing_business_as`, `organization_type`, `country_code`, `website`, `fein`, `industry`, `number_of_employees`, `organization_legal_type`, `organization_contact`, `billing_contact`, `organization_physical_address`, `billing_address` # Delete an enterprise Source: https://developers.telnyx.com/api-reference/enterprises/delete-an-enterprise https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/enterprises.yml delete /enterprises/{enterprise_id} Delete an enterprise and all associated resources. This action is irreversible. # Get an enterprise Source: https://developers.telnyx.com/api-reference/enterprises/get-an-enterprise https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/enterprises.yml get /enterprises/{enterprise_id} Retrieve details of a specific enterprise by ID. # List enterprises Source: https://developers.telnyx.com/api-reference/enterprises/list-enterprises https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/enterprises.yml get /enterprises Retrieve a paginated list of enterprises associated with your account. # Update an enterprise Source: https://developers.telnyx.com/api-reference/enterprises/update-an-enterprise https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/enterprises.yml put /enterprises/{enterprise_id} Update enterprise information. All fields are optional — only the provided fields will be updated. # Get Enum Source: https://developers.telnyx.com/api-reference/enum/get-enum https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/brands.yml get /10dlc/enum/{endpoint} # Creates an External Connection Source: https://developers.telnyx.com/api-reference/external-connections/creates-an-external-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml post /external_connections Creates a new External Connection based on the parameters sent in the request. The external_sip_connection and outbound voice profile id are required. Once created, you can assign phone numbers to your application using the `/phone_numbers` endpoint. # Creates an Upload request Source: https://developers.telnyx.com/api-reference/external-connections/creates-an-upload-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml post /external_connections/{id}/uploads Creates a new Upload request to Microsoft teams with the included phone numbers. Only one of civic_address_id or location_id must be provided, not both. The maximum allowed phone numbers for the numbers_ids array is 1000. # Deletes an External Connection Source: https://developers.telnyx.com/api-reference/external-connections/deletes-an-external-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml delete /external_connections/{id} Permanently deletes an External Connection. Deletion may be prevented if the application is in use by phone numbers, is active, or if it is an Operator Connect connection. To remove an Operator Connect integration please contact Telnyx support. # Dismiss a log message Source: https://developers.telnyx.com/api-reference/external-connections/dismiss-a-log-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml delete /external_connections/log_messages/{id} Dismiss a log message for an external connection associated with your account. # Get the count of pending upload requests Source: https://developers.telnyx.com/api-reference/external-connections/get-the-count-of-pending-upload-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/uploads/status Returns the count of all pending upload requests for the given external connection. # List all civic addresses and locations Source: https://developers.telnyx.com/api-reference/external-connections/list-all-civic-addresses-and-locations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/civic_addresses Returns the civic addresses and locations from Microsoft Teams. # List all External Connections Source: https://developers.telnyx.com/api-reference/external-connections/list-all-external-connections https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections This endpoint returns a list of your External Connections inside the 'data' attribute of the response. External Connections are used by Telnyx customers to seamless configure SIP trunking integrations with Telnyx Partners, through External Voice Integrations in Mission Control Portal. # List all log messages Source: https://developers.telnyx.com/api-reference/external-connections/list-all-log-messages https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/log_messages Retrieve a list of log messages for all external connections associated with your account. # List all phone numbers Source: https://developers.telnyx.com/api-reference/external-connections/list-all-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/phone_numbers Returns a list of all active phone numbers associated with the given external connection. # List all Releases Source: https://developers.telnyx.com/api-reference/external-connections/list-all-releases https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/releases Returns a list of your Releases for the given external connection. These are automatically created when you change the `connection_id` of a phone number that is currently on Microsoft Teams. # List all Upload requests Source: https://developers.telnyx.com/api-reference/external-connections/list-all-upload-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/uploads Returns a list of your Upload requests for the given external connection. # Refresh Operator Connect integration Source: https://developers.telnyx.com/api-reference/external-connections/refresh-operator-connect-integration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml post /operator_connect/actions/refresh This endpoint will make an asynchronous request to refresh the Operator Connect integration with Microsoft Teams for the current user. This will create new external connections on the user's account if needed, and/or report the integration results as [log messages](https://developers.telnyx.com/api-reference/external-connections/list-all-log-messages#list-all-log-messages). # Refresh the status of all Upload requests Source: https://developers.telnyx.com/api-reference/external-connections/refresh-the-status-of-all-upload-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml post /external_connections/{id}/uploads/refresh Forces a recheck of the status of all pending Upload requests for the given external connection in the background. # Retrieve a Civic Address Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-a-civic-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/civic_addresses/{address_id} Return the details of an existing Civic Address with its Locations inside the 'data' attribute of the response. # Retrieve a log message Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-a-log-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/log_messages/{id} Retrieve a log message for an external connection associated with your account. # Retrieve a phone number Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/phone_numbers/{phone_number_id} Return the details of a phone number associated with the given external connection. # Retrieve a Release request Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-a-release-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/releases/{release_id} Return the details of a Release request and its phone numbers. # Retrieve an External Connection Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-an-external-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id} Return the details of an existing External Connection inside the 'data' attribute of the response. # Retrieve an Upload request Source: https://developers.telnyx.com/api-reference/external-connections/retrieve-an-upload-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml get /external_connections/{id}/uploads/{ticket_id} Return the details of an Upload request and its phone numbers. # Retry an Upload request Source: https://developers.telnyx.com/api-reference/external-connections/retry-an-upload-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml post /external_connections/{id}/uploads/{ticket_id}/retry If there were any errors during the upload process, this endpoint will retry the upload request. In some cases this will reattempt the existing upload request, in other cases it may create a new upload request. Please check the ticket_id in the response to determine if a new upload request was created. # Update a location's static emergency address Source: https://developers.telnyx.com/api-reference/external-connections/update-a-locations-static-emergency-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml patch /external_connections/{id}/locations/{location_id} # Update a phone number Source: https://developers.telnyx.com/api-reference/external-connections/update-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml patch /external_connections/{id}/phone_numbers/{phone_number_id} Asynchronously update settings of the phone number associated with the given external connection. # Update an External Connection Source: https://developers.telnyx.com/api-reference/external-connections/update-an-external-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/external-connects.yml patch /external_connections/{id} Updates settings of an existing External Connection based on the parameters of the request. # Cancel a fine tuning job Source: https://developers.telnyx.com/api-reference/fine-tuning/cancel-a-fine-tuning-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/fine_tuning/jobs/{job_id}/cancel Cancel a fine tuning job. # Create a fine tuning job Source: https://developers.telnyx.com/api-reference/fine-tuning/create-a-fine-tuning-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/fine_tuning/jobs Create a new fine tuning job. # Get a fine tuning job Source: https://developers.telnyx.com/api-reference/fine-tuning/get-a-fine-tuning-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml get /ai/fine_tuning/jobs/{job_id} Retrieve a fine tuning job by `job_id`. # List fine tuning jobs Source: https://developers.telnyx.com/api-reference/fine-tuning/list-fine-tuning-jobs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml get /ai/fine_tuning/jobs Retrieve a list of all fine tuning jobs created by the user. # Create an FQDN connection Source: https://developers.telnyx.com/api-reference/fqdn-connections/create-an-fqdn-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /fqdn_connections Creates a FQDN connection. # Delete an FQDN connection Source: https://developers.telnyx.com/api-reference/fqdn-connections/delete-an-fqdn-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml delete /fqdn_connections/{id} Deletes an FQDN connection. # List FQDN connections Source: https://developers.telnyx.com/api-reference/fqdn-connections/list-fqdn-connections https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /fqdn_connections Returns a list of your FQDN connections. # Retrieve an FQDN connection Source: https://developers.telnyx.com/api-reference/fqdn-connections/retrieve-an-fqdn-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /fqdn_connections/{id} Retrieves the details of an existing FQDN connection. # Update an FQDN connection Source: https://developers.telnyx.com/api-reference/fqdn-connections/update-an-fqdn-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml patch /fqdn_connections/{id} Updates settings of an existing FQDN connection. # Create an FQDN Source: https://developers.telnyx.com/api-reference/fqdns/create-an-fqdn https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /fqdns Create a new FQDN object. # Delete an FQDN Source: https://developers.telnyx.com/api-reference/fqdns/delete-an-fqdn https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml delete /fqdns/{id} Delete an FQDN. # List FQDNs Source: https://developers.telnyx.com/api-reference/fqdns/list-fqdns https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /fqdns Get all FQDNs belonging to the user that match the given filters. # Retrieve an FQDN Source: https://developers.telnyx.com/api-reference/fqdns/retrieve-an-fqdn https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /fqdns/{id} Return the details regarding a specific FQDN. # Update an FQDN Source: https://developers.telnyx.com/api-reference/fqdns/update-an-fqdn https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml patch /fqdns/{id} Update the details of a specific FQDN. # Get invoice by ID Source: https://developers.telnyx.com/api-reference/get-invoice-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/invoices.yml get /invoices/{id} Retrieve a single invoice by its unique identifier. # Create a Global IP Source: https://developers.telnyx.com/api-reference/global-ips/create-a-global-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /global_ips Create a Global IP. # Create a Global IP assignment Source: https://developers.telnyx.com/api-reference/global-ips/create-a-global-ip-assignment https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /global_ip_assignments Create a Global IP assignment. # Create a Global IP health check Source: https://developers.telnyx.com/api-reference/global-ips/create-a-global-ip-health-check https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /global_ip_health_checks Create a Global IP health check. # Delete a Global IP Source: https://developers.telnyx.com/api-reference/global-ips/delete-a-global-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /global_ips/{id} Delete a Global IP. # Delete a Global IP assignment Source: https://developers.telnyx.com/api-reference/global-ips/delete-a-global-ip-assignment https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /global_ip_assignments/{id} Delete a Global IP assignment. # Delete a Global IP health check Source: https://developers.telnyx.com/api-reference/global-ips/delete-a-global-ip-health-check https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /global_ip_health_checks/{id} Delete a Global IP health check. # Global IP Assignment Health Check Metrics Source: https://developers.telnyx.com/api-reference/global-ips/global-ip-assignment-health-check-metrics https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_assignment_health # Global IP Assignment Usage Metrics Source: https://developers.telnyx.com/api-reference/global-ips/global-ip-assignment-usage-metrics https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_assignments/usage # Global IP Latency Metrics Source: https://developers.telnyx.com/api-reference/global-ips/global-ip-latency-metrics https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_latency # Global IP Usage Metrics Source: https://developers.telnyx.com/api-reference/global-ips/global-ip-usage-metrics https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_usage # List all Global IP Allowed Ports Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ip-allowed-ports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_allowed_ports List all Global IP Allowed Ports # List all Global IP assignments Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ip-assignments https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_assignments List all Global IP assignments. # List all Global IP Health check types Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ip-health-check-types https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_health_check_types List all Global IP Health check types. # List all Global IP health checks Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ip-health-checks https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_health_checks List all Global IP health checks. # List all Global IP Protocols Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ip-protocols https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_protocols List all Global IP Protocols # List all Global IPs Source: https://developers.telnyx.com/api-reference/global-ips/list-all-global-ips https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ips List all Global IPs. # Retrieve a Global IP Source: https://developers.telnyx.com/api-reference/global-ips/retrieve-a-global-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ips/{id} Retrieve a Global IP. # Retrieve a Global IP Source: https://developers.telnyx.com/api-reference/global-ips/retrieve-a-global-ip-1 https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_assignments/{id} Retrieve a Global IP assignment. # Retrieve a Global IP health check Source: https://developers.telnyx.com/api-reference/global-ips/retrieve-a-global-ip-health-check https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /global_ip_health_checks/{id} Retrieve a Global IP health check. # Update a Global IP assignment Source: https://developers.telnyx.com/api-reference/global-ips/update-a-global-ip-assignment https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml patch /global_ip_assignments/{id} Update a Global IP assignment. # Check hosted messaging eligibility Source: https://developers.telnyx.com/api-reference/hosted-numbers/check-hosted-messaging-eligibility https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml post /messaging_hosted_number_orders/eligibility_numbers_check # Create a messaging hosted number order Source: https://developers.telnyx.com/api-reference/hosted-numbers/create-a-messaging-hosted-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml post /messaging_hosted_number_orders # Create hosted number verification codes Source: https://developers.telnyx.com/api-reference/hosted-numbers/create-hosted-number-verification-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml post /messaging_hosted_number_orders/{id}/verification_codes Create verification codes to validate numbers of the hosted order. The verification codes will be sent to the numbers of the hosted order. # Delete a messaging hosted number Source: https://developers.telnyx.com/api-reference/hosted-numbers/delete-a-messaging-hosted-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml delete /messaging_hosted_numbers/{id} # Delete a messaging hosted number order Source: https://developers.telnyx.com/api-reference/hosted-numbers/delete-a-messaging-hosted-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml delete /messaging_hosted_number_orders/{id} Delete a messaging hosted number order and all associated phone numbers. # List messaging hosted number orders Source: https://developers.telnyx.com/api-reference/hosted-numbers/list-messaging-hosted-number-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml get /messaging_hosted_number_orders # Retrieve a messaging hosted number order Source: https://developers.telnyx.com/api-reference/hosted-numbers/retrieve-a-messaging-hosted-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml get /messaging_hosted_number_orders/{id} # Upload hosted number document Source: https://developers.telnyx.com/api-reference/hosted-numbers/upload-hosted-number-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml post /messaging_hosted_number_orders/{id}/actions/file_upload # Validate hosted number codes Source: https://developers.telnyx.com/api-reference/hosted-numbers/validate-hosted-number-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml post /messaging_hosted_number_orders/{id}/validation_codes Validate the verification codes sent to the numbers of the hosted order. The verification codes must be created in the verification codes endpoint. # Create an inexplicit number order Source: https://developers.telnyx.com/api-reference/inexplicit-number-orders/create-an-inexplicit-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /inexplicit_number_orders Create an inexplicit number order to programmatically purchase phone numbers without specifying exact numbers. # List inexplicit number orders Source: https://developers.telnyx.com/api-reference/inexplicit-number-orders/list-inexplicit-number-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /inexplicit_number_orders Get a paginated list of inexplicit number orders. # Retrieve an inexplicit number order Source: https://developers.telnyx.com/api-reference/inexplicit-number-orders/retrieve-an-inexplicit-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /inexplicit_number_orders/{id} Get an existing inexplicit number order by ID. # Create a secret Source: https://developers.telnyx.com/api-reference/integration-secrets/create-a-secret https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/integration-secrets.yml post /integration_secrets Create a new secret with an associated identifier that can be used to securely integrate with other services. # Delete an integration secret Source: https://developers.telnyx.com/api-reference/integration-secrets/delete-an-integration-secret https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/integration-secrets.yml delete /integration_secrets/{id} Delete an integration secret given its ID. # List integration secrets Source: https://developers.telnyx.com/api-reference/integration-secrets/list-integration-secrets https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/integration-secrets.yml get /integration_secrets Retrieve a list of all integration secrets configured by the user. # Delete Integration Connection Source: https://developers.telnyx.com/api-reference/integrations/delete-integration-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/integrations/connections/{user_connection_id} Delete a specific integration connection. # Get User Integration connection By Id Source: https://developers.telnyx.com/api-reference/integrations/get-user-integration-connection-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/integrations/connections/{user_connection_id} Get user setup integrations # List Integration By Id Source: https://developers.telnyx.com/api-reference/integrations/list-integration-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/integrations/{integration_id} Retrieve integration details # List Integrations Source: https://developers.telnyx.com/api-reference/integrations/list-integrations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/integrations List all available integrations. # List User Integrations Source: https://developers.telnyx.com/api-reference/integrations/list-user-integrations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/integrations/connections List user setup integrations # Create an inventory coverage request Source: https://developers.telnyx.com/api-reference/inventory-level/create-an-inventory-coverage-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/coverage.yml get /inventory_coverage Creates an inventory coverage request. If locality, npa or national_destination_code is used in groupBy, and no region or locality filters are used, the whole paginated set is returned. # Create new Access IP Address Source: https://developers.telnyx.com/api-reference/ip-addresses/create-new-access-ip-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml post /access_ip_address # Delete access IP address Source: https://developers.telnyx.com/api-reference/ip-addresses/delete-access-ip-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml delete /access_ip_address/{access_ip_address_id} # List all Access IP Addresses Source: https://developers.telnyx.com/api-reference/ip-addresses/list-all-access-ip-addresses https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml get /access_ip_address # Retrieve an access IP address Source: https://developers.telnyx.com/api-reference/ip-addresses/retrieve-an-access-ip-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml get /access_ip_address/{access_ip_address_id} # Create an Ip connection Source: https://developers.telnyx.com/api-reference/ip-connections/create-an-ip-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /ip_connections Creates an IP connection. # Delete an Ip connection Source: https://developers.telnyx.com/api-reference/ip-connections/delete-an-ip-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml delete /ip_connections/{id} Deletes an existing IP connection. # List Ip connections Source: https://developers.telnyx.com/api-reference/ip-connections/list-ip-connections https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /ip_connections Returns a list of your IP connections. # Retrieve an Ip connection Source: https://developers.telnyx.com/api-reference/ip-connections/retrieve-an-ip-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /ip_connections/{id} Retrieves the details of an existing ip connection. # Update an Ip connection Source: https://developers.telnyx.com/api-reference/ip-connections/update-an-ip-connection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml patch /ip_connections/{id} Updates settings of an existing IP connection. # Create new Access IP Range Source: https://developers.telnyx.com/api-reference/ip-ranges/create-new-access-ip-range https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml post /access_ip_ranges # Delete access IP ranges Source: https://developers.telnyx.com/api-reference/ip-ranges/delete-access-ip-ranges https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml delete /access_ip_ranges/{access_ip_range_id} # List all Access IP Ranges Source: https://developers.telnyx.com/api-reference/ip-ranges/list-all-access-ip-ranges https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/ip-addresses.yml get /access_ip_ranges # Create an Ip Source: https://developers.telnyx.com/api-reference/ips/create-an-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml post /ips Create a new IP object. # Delete an Ip Source: https://developers.telnyx.com/api-reference/ips/delete-an-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml delete /ips/{id} Delete an IP. # List Ips Source: https://developers.telnyx.com/api-reference/ips/list-ips https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /ips Get all IPs belonging to the user that match the given filters. # Retrieve an Ip Source: https://developers.telnyx.com/api-reference/ips/retrieve-an-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml get /ips/{id} Return the details regarding a specific IP. # Update an Ip Source: https://developers.telnyx.com/api-reference/ips/update-an-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/sip-connections.yml patch /ips/{id} Update the details of a specific IP. # List invoices Source: https://developers.telnyx.com/api-reference/list-invoices https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/invoices.yml get /invoices Retrieve a paginated list of invoices. # Create a new managed account. Source: https://developers.telnyx.com/api-reference/managed-accounts/create-a-new-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml post /managed_accounts Create a new managed account owned by the authenticated user. You need to be explictly approved by Telnyx in order to become a manager account. # Disables a managed account Source: https://developers.telnyx.com/api-reference/managed-accounts/disables-a-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml post /managed_accounts/{id}/actions/disable Disables a managed account, forbidding it to use Telnyx services, including sending or receiving phone calls and SMS messages. Ongoing phone calls will not be affected. The managed account and its sub-users will no longer be able to log in via the mission control portal. # Display information about allocatable global outbound channels for the current user. Source: https://developers.telnyx.com/api-reference/managed-accounts/display-information-about-allocatable-global-outbound-channels-for-the-current-user https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /managed_accounts/allocatable_global_outbound_channels Display information about allocatable global outbound channels for the current user. Only usable by account managers. # Enables a managed account Source: https://developers.telnyx.com/api-reference/managed-accounts/enables-a-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml post /managed_accounts/{id}/actions/enable Enables a managed account and its sub-users to use Telnyx services. # Lists accounts managed by the current user. Source: https://developers.telnyx.com/api-reference/managed-accounts/lists-accounts-managed-by-the-current-user https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /managed_accounts Lists the accounts managed by the current user. Users need to be explictly approved by Telnyx in order to become manager accounts. # Retrieve a managed account Source: https://developers.telnyx.com/api-reference/managed-accounts/retrieve-a-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /managed_accounts/{id} Retrieves the details of a single managed account. # Update a managed account Source: https://developers.telnyx.com/api-reference/managed-accounts/update-a-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml patch /managed_accounts/{id} Update a single managed account. # Update the amount of allocatable global outbound channels allocated to a specific managed account. Source: https://developers.telnyx.com/api-reference/managed-accounts/update-the-amount-of-allocatable-global-outbound-channels-allocated-to-a-specific-managed-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml patch /managed_accounts/{id}/update_global_channel_limit Update the amount of allocatable global outbound channels allocated to a specific managed account. # Create MCP Server Source: https://developers.telnyx.com/api-reference/mcp-servers/create-mcp-server https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml post /ai/mcp_servers Create a new MCP server. # Delete MCP Server Source: https://developers.telnyx.com/api-reference/mcp-servers/delete-mcp-server https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml delete /ai/mcp_servers/{mcp_server_id} Delete a specific MCP server. # Get MCP Server Source: https://developers.telnyx.com/api-reference/mcp-servers/get-mcp-server https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/mcp_servers/{mcp_server_id} Retrieve details for a specific MCP server. # List MCP Servers Source: https://developers.telnyx.com/api-reference/mcp-servers/list-mcp-servers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml get /ai/mcp_servers Retrieve a list of MCP servers. # Update MCP Server Source: https://developers.telnyx.com/api-reference/mcp-servers/update-mcp-server https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/assistants.yml put /ai/mcp_servers/{mcp_server_id} Update an existing MCP server. # Fetch all Mdr records Source: https://developers.telnyx.com/api-reference/mdr-detail-reports/fetch-all-mdr-records https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/mdrs Fetch all Mdr records # Create a new MDR detailed report request Source: https://developers.telnyx.com/api-reference/mdr-detailed-reports/create-a-new-mdr-detailed-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy_reporting/batch_detail_records/messaging Creates a new MDR detailed report request with the specified filters # Delete a MDR detailed report request Source: https://developers.telnyx.com/api-reference/mdr-detailed-reports/delete-a-mdr-detailed-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy_reporting/batch_detail_records/messaging/{id} Deletes a specific MDR detailed report request by ID # Get a specific MDR detailed report request Source: https://developers.telnyx.com/api-reference/mdr-detailed-reports/get-a-specific-mdr-detailed-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/batch_detail_records/messaging/{id} Retrieves a specific MDR detailed report request by ID # Get all MDR detailed report requests Source: https://developers.telnyx.com/api-reference/mdr-detailed-reports/get-all-mdr-detailed-report-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/batch_detail_records/messaging Retrieves all MDR detailed report requests for the authenticated user # Create a new legacy usage V2 MDR report request Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/create-a-new-legacy-usage-v2-mdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy_reporting/usage_reports/messaging Creates a new legacy usage V2 MDR report request with the specified filters # Create MDR Usage Report Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/create-mdr-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /reports/mdr_usage_reports Submit request for new new messaging usage report. This endpoint will pull and aggregate messaging data in specified time period. # Delete a V2 legacy usage MDR report request Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/delete-a-v2-legacy-usage-mdr-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy_reporting/usage_reports/messaging/{id} Deletes a specific V2 legacy usage MDR report request by ID # Delete MDR Usage Report Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/delete-mdr-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /reports/mdr_usage_reports/{id} Delete messaging usage report by id # Fetch all Messaging usage reports Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/fetch-all-messaging-usage-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/mdr_usage_reports Fetch all messaging usage reports. Usage reports are aggregated messaging data for specified time period and breakdown # Generate and fetch MDR Usage Report Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/generate-and-fetch-mdr-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/mdr_usage_reports/sync Generate and fetch messaging usage report synchronously. This endpoint will both generate and fetch the messaging report over a specified time period. No polling is necessary but the response may take up to a couple of minutes. # Get an MDR usage report Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/get-an-mdr-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/messaging/{id} Fetch single MDR usage report by id. # List MDR usage reports Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/list-mdr-usage-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/messaging Fetch all previous requests for MDR usage reports. # Retrieve messaging report Source: https://developers.telnyx.com/api-reference/mdr-usage-reports/retrieve-messaging-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/mdr_usage_reports/{id} Fetch a single messaging usage report by id # Deletes stored media Source: https://developers.telnyx.com/api-reference/media-storage-api/deletes-stored-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml delete /media/{media_name} Deletes a stored media file. # Download stored media Source: https://developers.telnyx.com/api-reference/media-storage-api/download-stored-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml get /media/{media_name}/download Downloads a stored media file. # List uploaded media Source: https://developers.telnyx.com/api-reference/media-storage-api/list-uploaded-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml get /media Returns a list of stored media files. # Retrieve stored media Source: https://developers.telnyx.com/api-reference/media-storage-api/retrieve-stored-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml get /media/{media_name} Returns the information about a stored media file. # Update stored media Source: https://developers.telnyx.com/api-reference/media-storage-api/update-stored-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml put /media/{media_name} Updates a stored media file. # Upload media Source: https://developers.telnyx.com/api-reference/media-storage-api/upload-media https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/media-storage.yml post /media Upload media file to Telnyx so it can be used with other Telnyx services # Cancel a scheduled message Source: https://developers.telnyx.com/api-reference/messages/cancel-a-scheduled-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml delete /messages/{id} Cancel a scheduled message that has not yet been sent. Only messages with `status=scheduled` and `send_at` more than a minute from now can be cancelled. # Retrieve a message Source: https://developers.telnyx.com/api-reference/messages/retrieve-a-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml get /messages/{id} Note: This API endpoint can only retrieve messages that are no older than 10 days since their creation. If you require messages older than this, please generate an [MDR report.](https://developers.telnyx.com/api-reference/mdr-usage-reports/create-mdr-usage-report) # Retrieve group MMS messages Source: https://developers.telnyx.com/api-reference/messages/retrieve-group-mms-messages https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml get /messages/group/{message_id} Retrieve all messages in a group MMS conversation by the group message ID. # Schedule a message Source: https://developers.telnyx.com/api-reference/messages/schedule-a-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/schedule Schedule a message with a Phone Number, Alphanumeric Sender ID, Short Code or Number Pool. This endpoint allows you to schedule a message with any messaging resource. Current messaging resources include: long-code, short-code, number-pool, and alphanumeric-sender-id. # Send a group MMS message Source: https://developers.telnyx.com/api-reference/messages/send-a-group-mms-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/group_mms # Send a long code message Source: https://developers.telnyx.com/api-reference/messages/send-a-long-code-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/long_code # Send a message Source: https://developers.telnyx.com/api-reference/messages/send-a-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages Send a message with a Phone Number, Alphanumeric Sender ID, Short Code or Number Pool. This endpoint allows you to send a message with any messaging resource. Current messaging resources include: long-code, short-code, number-pool, and alphanumeric-sender-id. # Send a message using an alphanumeric sender ID Source: https://developers.telnyx.com/api-reference/messages/send-a-message-using-an-alphanumeric-sender-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/alphanumeric/sender/id Send an SMS message using an alphanumeric sender ID. This is SMS only. # Send a message using number pool Source: https://developers.telnyx.com/api-reference/messages/send-a-message-using-number-pool https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/number_pool # Send a short code message Source: https://developers.telnyx.com/api-reference/messages/send-a-short-code-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/short_code # Get detailed messaging profile metrics Source: https://developers.telnyx.com/api-reference/messaging/get-detailed-messaging-profile-metrics https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging/profiles/{id}/metrics Get detailed metrics for a specific messaging profile, broken down by time interval. # List alphanumeric sender IDs for a messaging profile Source: https://developers.telnyx.com/api-reference/messaging/list-alphanumeric-sender-ids-for-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging/profiles/{id}/alphanumeric/sender/ids List all alphanumeric sender IDs associated with a specific messaging profile. # List messaging hosted numbers Source: https://developers.telnyx.com/api-reference/messaging/list-messaging-hosted-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml get /messaging/hosted/numbers List all hosted numbers associated with the authenticated user. # Regenerate messaging profile secret Source: https://developers.telnyx.com/api-reference/messaging/regenerate-messaging-profile-secret https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml post /messaging/profiles/{id}/actions/regenerate/secret Regenerate the v1 secret for a messaging profile. # Retrieve a messaging hosted number Source: https://developers.telnyx.com/api-reference/messaging/retrieve-a-messaging-hosted-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml get /messaging_hosted_numbers/{id} Retrieve a specific messaging hosted number by its ID or phone number. # Update a messaging hosted number Source: https://developers.telnyx.com/api-reference/messaging/update-a-messaging-hosted-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/hosted-numbers.yml patch /messaging_hosted_numbers/{id} Update the messaging settings for a hosted number. # Add step(s) to plan Source: https://developers.telnyx.com/api-reference/missions/add-steps-to-plan https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/plan/steps Add one or more steps to an existing plan # Cancel run Source: https://developers.telnyx.com/api-reference/missions/cancel-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/cancel Cancel a running or paused run # Clone mission Source: https://developers.telnyx.com/api-reference/missions/clone-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/clone Clone an existing mission # Create initial plan Source: https://developers.telnyx.com/api-reference/missions/create-initial-plan https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/plan Create the initial plan for a run # Create mission Source: https://developers.telnyx.com/api-reference/missions/create-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions Create a new mission definition # Delete mission Source: https://developers.telnyx.com/api-reference/missions/delete-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml delete /ai/missions/{mission_id} Delete a mission # Get event details Source: https://developers.telnyx.com/api-reference/missions/get-event-details https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id}/events/{event_id} Get details of a specific event # Get mission Source: https://developers.telnyx.com/api-reference/missions/get-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id} Get a mission by ID (includes tools, knowledge_bases, mcp_servers) # Get plan Source: https://developers.telnyx.com/api-reference/missions/get-plan https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id}/plan Get the plan (all steps) for a run # Get run details Source: https://developers.telnyx.com/api-reference/missions/get-run-details https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id} Get details of a specific run # Get step details Source: https://developers.telnyx.com/api-reference/missions/get-step-details https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id}/plan/steps/{step_id} Get details of a specific plan step # Link Telnyx agent to run Source: https://developers.telnyx.com/api-reference/missions/link-telnyx-agent-to-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/telnyx-agents Link a Telnyx AI agent (voice/messaging) to a run # List events Source: https://developers.telnyx.com/api-reference/missions/list-events https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id}/events List events for a run (paginated) # List linked Telnyx agents Source: https://developers.telnyx.com/api-reference/missions/list-linked-telnyx-agents https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs/{run_id}/telnyx-agents List all Telnyx agents linked to a run # List missions Source: https://developers.telnyx.com/api-reference/missions/list-missions https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions List all missions for the organization # List recent events Source: https://developers.telnyx.com/api-reference/missions/list-recent-events https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/events List recent events across all missions # List recent runs Source: https://developers.telnyx.com/api-reference/missions/list-recent-runs https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/runs List recent runs across all missions # List runs for mission Source: https://developers.telnyx.com/api-reference/missions/list-runs-for-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml get /ai/missions/{mission_id}/runs List all runs for a specific mission # Log event Source: https://developers.telnyx.com/api-reference/missions/log-event https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/events Log an event for a run # Pause run Source: https://developers.telnyx.com/api-reference/missions/pause-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/pause Pause a running run # Resume run Source: https://developers.telnyx.com/api-reference/missions/resume-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs/{run_id}/resume Resume a paused run # Start a run Source: https://developers.telnyx.com/api-reference/missions/start-a-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml post /ai/missions/{mission_id}/runs Start a new run for a mission # Unlink Telnyx agent Source: https://developers.telnyx.com/api-reference/missions/unlink-telnyx-agent https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml delete /ai/missions/{mission_id}/runs/{run_id}/telnyx-agents/{telnyx_agent_id} Unlink a Telnyx agent from a run # Update mission Source: https://developers.telnyx.com/api-reference/missions/update-mission https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml put /ai/missions/{mission_id} Update a mission definition # Update run Source: https://developers.telnyx.com/api-reference/missions/update-run https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml patch /ai/missions/{mission_id}/runs/{run_id} Update run status and/or result # Update step status Source: https://developers.telnyx.com/api-reference/missions/update-step-status https://us-central-1.telnyxcloudstorage.com/clawd-docs/openapi/ai/missions.yml patch /ai/missions/{mission_id}/runs/{run_id}/plan/steps/{step_id} Update the status of a plan step # Create a Network Source: https://developers.telnyx.com/api-reference/networks/create-a-network https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /networks Create a new Network. # Create Default Gateway. Source: https://developers.telnyx.com/api-reference/networks/create-default-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /networks/{id}/default_gateway Create Default Gateway. # Delete a Network Source: https://developers.telnyx.com/api-reference/networks/delete-a-network https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /networks/{id} Delete a Network. # Delete Default Gateway. Source: https://developers.telnyx.com/api-reference/networks/delete-default-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /networks/{id}/default_gateway Delete Default Gateway. # Get Default Gateway status. Source: https://developers.telnyx.com/api-reference/networks/get-default-gateway-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /networks/{id}/default_gateway Get Default Gateway status. # List all Interfaces for a Network. Source: https://developers.telnyx.com/api-reference/networks/list-all-interfaces-for-a-network https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /networks/{id}/network_interfaces List all Interfaces for a Network. # List all Networks Source: https://developers.telnyx.com/api-reference/networks/list-all-networks https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /networks List all Networks. # Retrieve a Network Source: https://developers.telnyx.com/api-reference/networks/retrieve-a-network https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /networks/{id} Retrieve a Network. # Update a Network Source: https://developers.telnyx.com/api-reference/networks/update-a-network https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml patch /networks/{id} Update a Network. # Add a Notification Setting Source: https://developers.telnyx.com/api-reference/notifications/add-a-notification-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml post /notification_settings Add a notification setting. # Create a notification channel Source: https://developers.telnyx.com/api-reference/notifications/create-a-notification-channel https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml post /notification_channels Create a notification channel. # Create a notification profile Source: https://developers.telnyx.com/api-reference/notifications/create-a-notification-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml post /notification_profiles Create a notification profile. # Delete a notification channel Source: https://developers.telnyx.com/api-reference/notifications/delete-a-notification-channel https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml delete /notification_channels/{id} Delete a notification channel. # Delete a notification profile Source: https://developers.telnyx.com/api-reference/notifications/delete-a-notification-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml delete /notification_profiles/{id} Delete a notification profile. # Delete a notification setting Source: https://developers.telnyx.com/api-reference/notifications/delete-a-notification-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml delete /notification_settings/{id} Delete a notification setting. # Get a notification channel Source: https://developers.telnyx.com/api-reference/notifications/get-a-notification-channel https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_channels/{id} Get a notification channel. # Get a notification profile Source: https://developers.telnyx.com/api-reference/notifications/get-a-notification-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_profiles/{id} Get a notification profile. # Get a notification setting Source: https://developers.telnyx.com/api-reference/notifications/get-a-notification-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_settings/{id} Get a notification setting. # List all Notifications Events Source: https://developers.telnyx.com/api-reference/notifications/list-all-notifications-events https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_events Returns a list of your notifications events. # List all Notifications Events Conditions Source: https://developers.telnyx.com/api-reference/notifications/list-all-notifications-events-conditions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_event_conditions Returns a list of your notifications events conditions. # List all Notifications Profiles Source: https://developers.telnyx.com/api-reference/notifications/list-all-notifications-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_profiles Returns a list of your notifications profiles. # List notification channels Source: https://developers.telnyx.com/api-reference/notifications/list-notification-channels https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_channels List notification channels. # List notification settings Source: https://developers.telnyx.com/api-reference/notifications/list-notification-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml get /notification_settings List notification settings. # Update a notification channel Source: https://developers.telnyx.com/api-reference/notifications/update-a-notification-channel https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml patch /notification_channels/{id} Update a notification channel. # Update a notification profile Source: https://developers.telnyx.com/api-reference/notifications/update-a-notification-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/notifications.yml patch /notification_profiles/{id} Update a notification profile. # Lookup phone number data Source: https://developers.telnyx.com/api-reference/number-lookup/lookup-phone-number-data https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/number-lookup.yml get /number_lookup/{phone_number} Returns information about the provided phone number. # Create a comment on a portout request Source: https://developers.telnyx.com/api-reference/number-portout/create-a-comment-on-a-portout-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml post /portouts/{id}/comments Creates a comment on a portout request. # Create a list of supporting documents on a portout request Source: https://developers.telnyx.com/api-reference/number-portout/create-a-list-of-supporting-documents-on-a-portout-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml post /portouts/{id}/supporting_documents Creates a list of supporting documents on a portout request. # Create a port-out related report Source: https://developers.telnyx.com/api-reference/number-portout/create-a-port-out-related-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml post /portouts/reports Generate reports about port-out operations. # Get a portout request Source: https://developers.telnyx.com/api-reference/number-portout/get-a-portout-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/{id} Returns the portout request based on the ID provided # List all comments for a portout request Source: https://developers.telnyx.com/api-reference/number-portout/list-all-comments-for-a-portout-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/{id}/comments Returns a list of comments for a portout request. # List all port-out events Source: https://developers.telnyx.com/api-reference/number-portout/list-all-port-out-events https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/events Returns a list of all port-out events. # List eligible port-out rejection codes for a specific order Source: https://developers.telnyx.com/api-reference/number-portout/list-eligible-port-out-rejection-codes-for-a-specific-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/rejections/{portout_id} Given a port-out ID, list rejection codes that are eligible for that port-out # List port-out related reports Source: https://developers.telnyx.com/api-reference/number-portout/list-port-out-related-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/reports List the reports generated about port-out operations. # List portout requests Source: https://developers.telnyx.com/api-reference/number-portout/list-portout-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts Returns the portout requests according to filters # List supporting documents on a portout request Source: https://developers.telnyx.com/api-reference/number-portout/list-supporting-documents-on-a-portout-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/{id}/supporting_documents List every supporting documents for a portout request. # Republish a port-out event Source: https://developers.telnyx.com/api-reference/number-portout/republish-a-port-out-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml post /portouts/events/{id}/republish Republish a specific port-out event. # Retrieve a report Source: https://developers.telnyx.com/api-reference/number-portout/retrieve-a-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/reports/{id} Retrieve a specific report generated. # Show a port-out event Source: https://developers.telnyx.com/api-reference/number-portout/show-a-port-out-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml get /portouts/events/{id} Show a specific port-out event. # Update Status Source: https://developers.telnyx.com/api-reference/number-portout/update-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/portout.yml patch /portouts/{id}/{status} Authorize or reject portout request # Disable Number Reputation Source: https://developers.telnyx.com/api-reference/number-reputation-settings/disable-number-reputation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/settings.yml delete /enterprises/{enterprise_id}/reputation Disable Number Reputation for an enterprise. This will: - Delete the reputation settings record - Log the deletion for audit purposes - Stop all future automated reputation checks **Note:** Can only be performed on `approved` reputation settings. # Enable Number Reputation Source: https://developers.telnyx.com/api-reference/number-reputation-settings/enable-number-reputation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/settings.yml post /enterprises/{enterprise_id}/reputation Enable Number Reputation service for an enterprise. **Requirements:** - Signed LOA (Letter of Authorization) document ID - Reputation check frequency (defaults to `business_daily`) - Number Reputation Terms of Service must be accepted **Flow:** 1. Registers the enterprise for reputation monitoring 2. Creates reputation settings with `pending` status 3. Awaits admin approval before monitoring begins **Resubmission After Rejection:** If a previously rejected record exists, this endpoint will delete it and create a new `pending` record. **Available Frequencies:** - `business_daily` — Monday–Friday - `daily` — Every day - `weekly` — Once per week - `biweekly` — Once every two weeks - `monthly` — Once per month - `never` — Manual refresh only # Get reputation settings Source: https://developers.telnyx.com/api-reference/number-reputation-settings/get-reputation-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/settings.yml get /enterprises/{enterprise_id}/reputation Retrieve the current Number Reputation settings for an enterprise. Returns the enrollment status (`pending`, `approved`, `rejected`, `deleted`), check frequency, and any rejection reasons. Returns `404` if reputation has not been enabled for this enterprise. # Update reputation check frequency Source: https://developers.telnyx.com/api-reference/number-reputation-settings/update-reputation-check-frequency https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/settings.yml patch /enterprises/{enterprise_id}/reputation/frequency Update how often reputation data is automatically refreshed. **Note:** The enterprise must have `approved` reputation settings. Updating frequency on `pending` or `rejected` settings will return an error. **Available Frequencies:** - `business_daily` — Monday–Friday - `daily` — Every day including weekends - `weekly` — Once per week - `biweekly` — Once every two weeks - `monthly` — Once per month - `never` — Manual refresh only (no automatic checks) # Bulk update phone number profiles Source: https://developers.telnyx.com/api-reference/number-settings/bulk-update-phone-number-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/phone-numbers.yml post /messaging_numbers/bulk_updates # List phone numbers with messaging settings Source: https://developers.telnyx.com/api-reference/number-settings/list-phone-numbers-with-messaging-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/phone-numbers.yml get /phone_numbers/messaging # Retrieve a phone number with messaging settings Source: https://developers.telnyx.com/api-reference/number-settings/retrieve-a-phone-number-with-messaging-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/phone-numbers.yml get /phone_numbers/{id}/messaging # Retrieve bulk update status Source: https://developers.telnyx.com/api-reference/number-settings/retrieve-bulk-update-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/phone-numbers.yml get /messaging_numbers/bulk_updates/{order_id} # Update the messaging profile and/or messaging product of a phone number Source: https://developers.telnyx.com/api-reference/number-settings/update-the-messaging-profile-andor-messaging-product-of-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/phone-numbers.yml patch /phone_numbers/{id}/messaging # Retrieve the features for a list of numbers Source: https://developers.telnyx.com/api-reference/numbers-features/retrieve-the-features-for-a-list-of-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/searching.yml post /numbers_features Retrieve the features for a list of numbers # Create OAuth client Source: https://developers.telnyx.com/api-reference/oauth-clients/create-oauth-client https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml post /oauth/clients Create a new OAuth client # Delete OAuth client Source: https://developers.telnyx.com/api-reference/oauth-clients/delete-oauth-client https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml delete /oauth/clients/{id} Delete an OAuth client # Get OAuth client Source: https://developers.telnyx.com/api-reference/oauth-clients/get-oauth-client https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/clients/{id} Retrieve a single OAuth client by ID # List OAuth clients Source: https://developers.telnyx.com/api-reference/oauth-clients/list-oauth-clients https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/clients Retrieve a paginated list of OAuth clients for the authenticated user # Update OAuth client Source: https://developers.telnyx.com/api-reference/oauth-clients/update-oauth-client https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml put /oauth/clients/{id} Update an existing OAuth client # Authorization server metadata Source: https://developers.telnyx.com/api-reference/oauth-discovery/authorization-server-metadata https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /.well-known/oauth-authorization-server OAuth 2.0 Authorization Server Metadata (RFC 8414) # Protected resource metadata Source: https://developers.telnyx.com/api-reference/oauth-discovery/protected-resource-metadata https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /.well-known/oauth-protected-resource OAuth 2.0 Protected Resource Metadata for resource discovery # Get OAuth grant Source: https://developers.telnyx.com/api-reference/oauth-grants/get-oauth-grant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/grants/{id} Retrieve a single OAuth grant by ID # List OAuth grants Source: https://developers.telnyx.com/api-reference/oauth-grants/list-oauth-grants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/grants Retrieve a paginated list of OAuth grants for the authenticated user # Revoke OAuth grant Source: https://developers.telnyx.com/api-reference/oauth-grants/revoke-oauth-grant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml delete /oauth/grants/{id} Revoke an OAuth grant # Dynamic client registration Source: https://developers.telnyx.com/api-reference/oauth-protocol/dynamic-client-registration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml post /oauth/register Register a new OAuth client dynamically (RFC 7591) # Get OAuth consent token Source: https://developers.telnyx.com/api-reference/oauth-protocol/get-oauth-consent-token https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/consent/{consent_token} Retrieve details about an OAuth consent token # JSON Web Key Set Source: https://developers.telnyx.com/api-reference/oauth-protocol/json-web-key-set https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/jwks Retrieve the JSON Web Key Set for token verification # OAuth authorization endpoint Source: https://developers.telnyx.com/api-reference/oauth-protocol/oauth-authorization-endpoint https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml get /oauth/authorize OAuth 2.0 authorization endpoint for the authorization code flow # OAuth token endpoint Source: https://developers.telnyx.com/api-reference/oauth-protocol/oauth-token-endpoint https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml post /oauth/token Exchange authorization code, client credentials, or refresh token for access token # Token introspection Source: https://developers.telnyx.com/api-reference/oauth-protocol/token-introspection https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/oauth.yml post /oauth/introspect Introspect an OAuth access token to check its validity and metadata # Create a chat completion (OpenAI-compatible) Source: https://developers.telnyx.com/api-reference/openai-chat/create-a-chat-completion-openai-compatible https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/openai/chat/completions Chat with a language model. This endpoint is consistent with the [OpenAI Chat Completions API](https://platform.openai.com/docs/api-reference/chat) and may be used with the OpenAI JS or Python SDK by setting the base URL to `https://api.telnyx.com/v2/ai/openai`. # Create an OpenAI-compatible response Source: https://developers.telnyx.com/api-reference/openai-chat/create-an-openai-compatible-response https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/openai/responses Create a response using Telnyx's OpenAI-compatible Responses API. This endpoint is compatible with the [OpenAI Responses API](https://developers.openai.com/api/reference/responses/overview) and may be used with the OpenAI JS or Python SDK by setting the base URL to `https://api.telnyx.com/v2/ai/openai`. The `conversation` parameter refers to a Telnyx Conversation rather than an OpenAI-hosted conversation object. To persist a thread across turns, first [create a conversation](https://developers.telnyx.com/api-reference/conversations/create-a-conversation) with `POST /ai/conversations`, then pass that conversation's `id` in the Responses request as `conversation`. The endpoint appends the new input, assistant output, reasoning, and tool-call messages to that conversation. Reuse the same `conversation` id on subsequent Responses requests, including tool-result followups, so the model receives the prior context. If `conversation` is omitted, the request is processed without persisting messages to a Telnyx conversation. Use the Conversations API to manage history: [list conversations](https://developers.telnyx.com/api-reference/conversations/list-conversations) (optionally filtered by metadata), [fetch messages](https://developers.telnyx.com/api-reference/conversations/get-conversation-messages) for a conversation, and optionally [add messages](https://developers.telnyx.com/api-reference/conversations/create-message) outside the Responses flow. You can attach arbitrary metadata when creating a conversation (for example to tag the conversation's source, channel, or user) and later filter by it when listing conversations. # Get available models (OpenAI-compatible) Source: https://developers.telnyx.com/api-reference/openai-chat/get-available-models-openai-compatible https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml get /ai/openai/models Lists every model currently available to your account on Telnyx Inference, including SOTA open-source LLMs hosted on Telnyx GPUs (for example `moonshotai/Kimi-K2.6`, `zai-org/GLM-5.1-FP8`, and `MiniMaxAI/MiniMax-M2.7`), embedding models, and any fine-tuned models you have created. Each entry is a `ModelMetadata` object describing the model id, owner, task, context length, supported languages, billing tier, pricing per 1M tokens, deployment regions, and whether the model supports vision or fine-tuning. Use this endpoint to discover model ids you can pass to `POST /v2/ai/openai/chat/completions`. Model ids follow the `{organization}/{model_name}` convention from Hugging Face (for example `moonshotai/Kimi-K2.6`). This endpoint is OpenAI-compatible: clients pointed at `https://api.telnyx.com/v2/ai/openai` can call `client.models.list()` to retrieve the same payload. # Create embeddings Source: https://developers.telnyx.com/api-reference/openai-embeddings/create-embeddings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml post /ai/openai/embeddings Creates an embedding vector representing the input text. This endpoint is compatible with the [OpenAI Embeddings API](https://platform.openai.com/docs/api-reference/embeddings) and may be used with the OpenAI JS or Python SDK by setting the base URL to `https://api.telnyx.com/v2/ai/openai`. # List embedding models Source: https://developers.telnyx.com/api-reference/openai-embeddings/list-embedding-models https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/ai/inference.yml get /ai/openai/embeddings/models Returns a list of available embedding models. This endpoint is compatible with the OpenAI Models API format. # Create auto-response setting Source: https://developers.telnyx.com/api-reference/opt-out-management/create-auto-response-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml post /messaging_profiles/{profile_id}/autoresp_configs # Delete Auto-Response Setting Source: https://developers.telnyx.com/api-reference/opt-out-management/delete-auto-response-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml delete /messaging_profiles/{profile_id}/autoresp_configs/{autoresp_cfg_id} # Get Auto-Response Setting Source: https://developers.telnyx.com/api-reference/opt-out-management/get-auto-response-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles/{profile_id}/autoresp_configs/{autoresp_cfg_id} # List Auto-Response Settings Source: https://developers.telnyx.com/api-reference/opt-out-management/list-auto-response-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles/{profile_id}/autoresp_configs # List opt-outs Source: https://developers.telnyx.com/api-reference/opt-out-management/list-opt-outs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/optouts.yml get /messaging_optouts Retrieve a list of opt-out blocks. # Update Auto-Response Setting Source: https://developers.telnyx.com/api-reference/opt-out-management/update-auto-response-setting https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml put /messaging_profiles/{profile_id}/autoresp_configs/{autoresp_cfg_id} # Delete organization user Source: https://developers.telnyx.com/api-reference/organization-users/delete-organization-user https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml post /organizations/users/{id}/actions/remove Deletes a user in your organization. # Get organization user Source: https://developers.telnyx.com/api-reference/organization-users/get-organization-user https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /organizations/users/{id} Returns a user in your organization. # Get organization users groups report Source: https://developers.telnyx.com/api-reference/organization-users/get-organization-users-groups-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /organizations/users/users_groups_report Returns a report of all users in your organization with their group memberships. This endpoint returns all users without pagination and always includes group information. The report can be retrieved in JSON or CSV format by sending specific content-type headers. # List organization users Source: https://developers.telnyx.com/api-reference/organization-users/list-organization-users https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/managed-accounts.yml get /organizations/users Returns a list of the users in your organization. # Get OTA update Source: https://developers.telnyx.com/api-reference/ota-updates/get-ota-update https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml get /ota_updates/{id} This API returns the details of an Over the Air (OTA) update. # List OTA updates Source: https://developers.telnyx.com/api-reference/ota-updates/list-ota-updates https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml get /ota_updates # Create an outbound voice profile Source: https://developers.telnyx.com/api-reference/outbound-voice-profiles/create-an-outbound-voice-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/outbound-voice-profiles.yml post /outbound_voice_profiles Create an outbound voice profile. # Delete an outbound voice profile Source: https://developers.telnyx.com/api-reference/outbound-voice-profiles/delete-an-outbound-voice-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/outbound-voice-profiles.yml delete /outbound_voice_profiles/{id} Deletes an existing outbound voice profile. # Get all outbound voice profiles Source: https://developers.telnyx.com/api-reference/outbound-voice-profiles/get-all-outbound-voice-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/outbound-voice-profiles.yml get /outbound_voice_profiles Get all outbound voice profiles belonging to the user that match the given filters. # Retrieve an outbound voice profile Source: https://developers.telnyx.com/api-reference/outbound-voice-profiles/retrieve-an-outbound-voice-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/outbound-voice-profiles.yml get /outbound_voice_profiles/{id} Retrieves the details of an existing outbound voice profile. # Updates an existing outbound voice profile. Source: https://developers.telnyx.com/api-reference/outbound-voice-profiles/updates-an-existing-outbound-voice-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/outbound-voice-profiles.yml patch /outbound_voice_profiles/{id} Updates an existing outbound voice profile. # Create a number block order Source: https://developers.telnyx.com/api-reference/phone-number-block-orders/create-a-number-block-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /number_block_orders Creates a phone number block order. # List number block orders Source: https://developers.telnyx.com/api-reference/phone-number-block-orders/list-number-block-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_block_orders Get a paginated list of number block orders. # Retrieve a number block order Source: https://developers.telnyx.com/api-reference/phone-number-block-orders/retrieve-a-number-block-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_block_orders/{number_block_order_id} Get an existing phone number block order. # Deletes all numbers associated with a phone number block Source: https://developers.telnyx.com/api-reference/phone-number-blocks-background-jobs/deletes-all-numbers-associated-with-a-phone-number-block https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_number_blocks/jobs/delete_phone_number_block Creates a new background job to delete all the phone numbers associated with the given block. We will only consider the phone number block as deleted after all phone numbers associated with it are removed, so multiple executions of this job may be necessary in case some of the phone numbers present errors during the deletion process. # Lists the phone number blocks jobs Source: https://developers.telnyx.com/api-reference/phone-number-blocks-background-jobs/lists-the-phone-number-blocks-jobs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_number_blocks/jobs # Retrieves a phone number blocks job Source: https://developers.telnyx.com/api-reference/phone-number-blocks-background-jobs/retrieves-a-phone-number-blocks-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_number_blocks/jobs/{id} # Create New Phone Number Campaign Source: https://developers.telnyx.com/api-reference/phone-number-campaigns/create-new-phone-number-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml post /10dlc/phone_number_campaigns # Create New Phone Number Campaign Source: https://developers.telnyx.com/api-reference/phone-number-campaigns/create-new-phone-number-campaign-1 https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml put /10dlc/phone_number_campaigns/{phoneNumber} # Delete Phone Number Campaign Source: https://developers.telnyx.com/api-reference/phone-number-campaigns/delete-phone-number-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml delete /10dlc/phone_number_campaigns/{phoneNumber} This endpoint allows you to remove a campaign assignment from the supplied `phoneNumber`. # Get Single Phone Number Campaign Source: https://developers.telnyx.com/api-reference/phone-number-campaigns/get-single-phone-number-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml get /10dlc/phone_number_campaigns/{phoneNumber} Retrieve an individual phone number/campaign assignment by `phoneNumber`. # List phone number campaigns Source: https://developers.telnyx.com/api-reference/phone-number-campaigns/list-phone-number-campaigns https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/phone-number-campaigns.yml get /10dlc/phone_number_campaigns # Change the bundle status for a phone number (set to being in a bundle or remove from a bundle) Source: https://developers.telnyx.com/api-reference/phone-number-configurations/change-the-bundle-status-for-a-phone-number-set-to-being-in-a-bundle-or-remove-from-a-bundle https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml patch /phone_numbers/{id}/actions/bundle_status_change # Delete a phone number Source: https://developers.telnyx.com/api-reference/phone-number-configurations/delete-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml delete /phone_numbers/{id} # Enable emergency for a phone number Source: https://developers.telnyx.com/api-reference/phone-number-configurations/enable-emergency-for-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/{id}/actions/enable_emergency # List phone numbers Source: https://developers.telnyx.com/api-reference/phone-number-configurations/list-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers # List phone numbers with voice settings Source: https://developers.telnyx.com/api-reference/phone-number-configurations/list-phone-numbers-with-voice-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/voice # Retrieve a phone number Source: https://developers.telnyx.com/api-reference/phone-number-configurations/retrieve-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/{id} # Retrieve a phone number with voice settings Source: https://developers.telnyx.com/api-reference/phone-number-configurations/retrieve-a-phone-number-with-voice-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/{id}/voice # Slim List phone numbers Source: https://developers.telnyx.com/api-reference/phone-number-configurations/slim-list-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/slim List phone numbers, This endpoint is a lighter version of the /phone_numbers endpoint having higher performance and rate limit. # Update a phone number Source: https://developers.telnyx.com/api-reference/phone-number-configurations/update-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml patch /phone_numbers/{id} # Update a phone number with voice settings Source: https://developers.telnyx.com/api-reference/phone-number-configurations/update-a-phone-number-with-voice-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml patch /phone_numbers/{id}/voice # Verify ownership of phone numbers Source: https://developers.telnyx.com/api-reference/phone-number-configurations/verify-ownership-of-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml post /phone_numbers/actions/verify_ownership Verifies ownership of the provided phone numbers and returns a mapping of numbers to their IDs, plus a list of numbers not found in the account. # Cancel a sub number order Source: https://developers.telnyx.com/api-reference/phone-number-orders/cancel-a-sub-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /sub_number_orders/{sub_number_order_id}/cancel Allows you to cancel a sub number order in 'pending' status. # Create a comment Source: https://developers.telnyx.com/api-reference/phone-number-orders/create-a-comment https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /comments # Create a number order Source: https://developers.telnyx.com/api-reference/phone-number-orders/create-a-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /number_orders Creates a phone number order. # Create a sub number orders report Source: https://developers.telnyx.com/api-reference/phone-number-orders/create-a-sub-number-orders-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /sub_number_orders/report Create a CSV report for sub number orders. The report will be generated asynchronously and can be downloaded once complete. # Download a sub number orders report Source: https://developers.telnyx.com/api-reference/phone-number-orders/download-a-sub-number-orders-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /sub_number_orders/report/{report_id}/download Download the CSV file for a completed sub number orders report. The report status must be 'success' before the file can be downloaded. # List number orders Source: https://developers.telnyx.com/api-reference/phone-number-orders/list-number-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_orders Get a paginated list of number orders. # List sub number orders Source: https://developers.telnyx.com/api-reference/phone-number-orders/list-sub-number-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /sub_number_orders Get a paginated list of sub number orders. # Mark a comment as read Source: https://developers.telnyx.com/api-reference/phone-number-orders/mark-a-comment-as-read https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /comments/{id}/read # Retrieve a comment Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-comment https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /comments/{id} # Retrieve a list of phone numbers associated to orders Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-list-of-phone-numbers-associated-to-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_order_phone_numbers Get a list of phone numbers associated to orders. # Retrieve a number order Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_orders/{number_order_id} Get an existing phone number order. # Retrieve a single phone number within a number order. Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-single-phone-number-within-a-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_order_phone_numbers/{number_order_phone_number_id} Get an existing phone number in number order. # Retrieve a sub number order Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-sub-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /sub_number_orders/{sub_number_order_id} Get an existing sub number order. # Retrieve a sub number orders report Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-a-sub-number-orders-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /sub_number_orders/report/{report_id} Get the status and details of a sub number orders report. # Retrieve all comments Source: https://developers.telnyx.com/api-reference/phone-number-orders/retrieve-all-comments https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /comments # Update a number order Source: https://developers.telnyx.com/api-reference/phone-number-orders/update-a-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /number_orders/{number_order_id} Updates a phone number order. # Update a sub number order's requirements Source: https://developers.telnyx.com/api-reference/phone-number-orders/update-a-sub-number-orders-requirements https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /sub_number_orders/{sub_number_order_id} Updates a sub number order. # Update requirements for a single phone number within a number order. Source: https://developers.telnyx.com/api-reference/phone-number-orders/update-requirements-for-a-single-phone-number-within-a-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml patch /number_order_phone_numbers/{number_order_phone_number_id} Updates requirements for a single phone number within a number order. # Run a portability check Source: https://developers.telnyx.com/api-reference/phone-number-porting/run-a-portability-check https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting.yml post /portability_checks Runs a portability check, returning the results immediately. # Create a number reservation Source: https://developers.telnyx.com/api-reference/phone-number-reservations/create-a-number-reservation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /number_reservations Creates a Phone Number Reservation for multiple numbers. # Extend a number reservation Source: https://developers.telnyx.com/api-reference/phone-number-reservations/extend-a-number-reservation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /number_reservations/{number_reservation_id}/actions/extend Extends reservation expiry time on all phone numbers. # List number reservations Source: https://developers.telnyx.com/api-reference/phone-number-reservations/list-number-reservations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_reservations Gets a paginated list of phone number reservations. # Retrieve a number reservation Source: https://developers.telnyx.com/api-reference/phone-number-reservations/retrieve-a-number-reservation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml get /number_reservations/{number_reservation_id} Gets a single phone number reservation. # List available phone number blocks Source: https://developers.telnyx.com/api-reference/phone-number-search/list-available-phone-number-blocks https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/searching.yml get /available_phone_number_blocks # List available phone numbers Source: https://developers.telnyx.com/api-reference/phone-number-search/list-available-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/searching.yml get /available_phone_numbers # Activate every number in a porting order asynchronously. Source: https://developers.telnyx.com/api-reference/porting-orders/activate-every-number-in-a-porting-order-asynchronously https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders/{id}/actions/activate Activate each number in a porting order asynchronously. This operation is limited to US FastPort orders only. # Cancel a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/cancel-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders/{id}/actions/cancel Cancel a porting order # Create a comment for a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-comment-for-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders/{id}/comments Creates a new comment for a porting order. # Create a list of additional documents Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-list-of-additional-documents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml post /porting_orders/{id}/additional_documents Creates a list of additional documents for a porting order. # Create a list of phone number configurations Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-list-of-phone-number-configurations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml post /porting_orders/phone_number_configurations Creates a list of phone number configurations. # Create a LOA configuration Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-loa-configuration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml post /porting/loa_configurations Create a LOA configuration. # Create a phone number block Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-phone-number-block https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml post /porting_orders/{porting_order_id}/phone_number_blocks Creates a new phone number block. # Create a phone number extension Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-phone-number-extension https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml post /porting_orders/{porting_order_id}/phone_number_extensions Creates a new phone number extension. # Create a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders Creates a new porting order object. # Create a porting related report Source: https://developers.telnyx.com/api-reference/porting-orders/create-a-porting-related-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml post /porting/reports Generate reports about porting operations. # Create an associated phone number Source: https://developers.telnyx.com/api-reference/porting-orders/create-an-associated-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml post /porting_orders/{porting_order_id}/associated_phone_numbers Creates a new associated phone number for a porting order. This is used for partial porting in GB to specify which phone numbers should be kept or disconnected. # Delete a LOA configuration Source: https://developers.telnyx.com/api-reference/porting-orders/delete-a-loa-configuration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml delete /porting/loa_configurations/{id} Delete a specific LOA configuration. # Delete a phone number block Source: https://developers.telnyx.com/api-reference/porting-orders/delete-a-phone-number-block https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml delete /porting_orders/{porting_order_id}/phone_number_blocks/{id} Deletes a phone number block. # Delete a phone number extension Source: https://developers.telnyx.com/api-reference/porting-orders/delete-a-phone-number-extension https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml delete /porting_orders/{porting_order_id}/phone_number_extensions/{id} Deletes a phone number extension. # Delete a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/delete-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml delete /porting_orders/{id} Deletes an existing porting order. This operation is restrict to porting orders in draft state. # Delete an additional document Source: https://developers.telnyx.com/api-reference/porting-orders/delete-an-additional-document https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml delete /porting_orders/{id}/additional_documents/{additional_document_id} Deletes an additional document for a porting order. # Delete an associated phone number Source: https://developers.telnyx.com/api-reference/porting-orders/delete-an-associated-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml delete /porting_orders/{porting_order_id}/associated_phone_numbers/{id} Deletes an associated phone number from a porting order. # Download a porting order loa template Source: https://developers.telnyx.com/api-reference/porting-orders/download-a-porting-order-loa-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml get /porting_orders/{id}/loa_template Download a porting order loa template # Edit a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/edit-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml patch /porting_orders/{id} Edits the details of an existing porting order. Any or all of a porting orders attributes may be included in the resource object included in a PATCH request. If a request does not include all of the attributes for a resource, the system will interpret the missing attributes as if they were included with their current values. To explicitly set something to null, it must be included in the request with a null value. # Initiate an action requirement Source: https://developers.telnyx.com/api-reference/porting-orders/initiate-an-action-requirement https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml post /porting_orders/{porting_order_id}/action_requirements/{id}/initiate Initiates a specific action requirement for a porting order. # List action requirements for a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/list-action-requirements-for-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml get /porting_orders/{porting_order_id}/action_requirements Returns a list of action requirements for a specific porting order. # List additional documents Source: https://developers.telnyx.com/api-reference/porting-orders/list-additional-documents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml get /porting_orders/{id}/additional_documents Returns a list of additional documents for a porting order. # List all associated phone numbers Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-associated-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml get /porting_orders/{porting_order_id}/associated_phone_numbers Returns a list of all associated phone numbers for a porting order. Associated phone numbers are used for partial porting in GB to specify which phone numbers should be kept or disconnected. # List all comments of a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-comments-of-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml get /porting_orders/{id}/comments Returns a list of all comments of a porting order. # List all exception types Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-exception-types https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-activation.yml get /porting_orders/exception_types Returns a list of all possible exception types for a porting order. # List all phone number blocks Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-phone-number-blocks https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml get /porting_orders/{porting_order_id}/phone_number_blocks Returns a list of all phone number blocks of a porting order. # List all phone number configurations Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-phone-number-configurations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml get /porting_orders/phone_number_configurations Returns a list of phone number configurations paginated. # List all phone number extensions Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-phone-number-extensions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml get /porting_orders/{porting_order_id}/phone_number_extensions Returns a list of all phone number extensions of a porting order. # List all porting activation jobs Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-porting-activation-jobs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-activation.yml get /porting_orders/{id}/activation_jobs Returns a list of your porting activation jobs. # List all porting events Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-porting-events https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml get /porting/events Returns a list of all porting events. # List all porting orders Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-porting-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml get /porting_orders Returns a list of your porting order. # List all porting phone numbers Source: https://developers.telnyx.com/api-reference/porting-orders/list-all-porting-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-phone-numbers.yml get /porting_phone_numbers Returns a list of your porting phone numbers. # List allowed FOC dates Source: https://developers.telnyx.com/api-reference/porting-orders/list-allowed-foc-dates https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml get /porting_orders/{id}/allowed_foc_windows Returns a list of allowed FOC dates for a porting order. # List available carriers in the UK Source: https://developers.telnyx.com/api-reference/porting-orders/list-available-carriers-in-the-uk https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml get /porting/uk_carriers List available carriers in the UK. # List LOA configurations Source: https://developers.telnyx.com/api-reference/porting-orders/list-loa-configurations https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml get /porting/loa_configurations List the LOA configurations. # List porting order requirements Source: https://developers.telnyx.com/api-reference/porting-orders/list-porting-order-requirements https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml get /porting_orders/{id}/requirements Returns a list of all requirements based on country/number type for this porting order. # List porting related reports Source: https://developers.telnyx.com/api-reference/porting-orders/list-porting-related-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml get /porting/reports List the reports generated about porting operations. # List verification codes Source: https://developers.telnyx.com/api-reference/porting-orders/list-verification-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml get /porting_orders/{id}/verification_codes Returns a list of verification codes for a porting order. # Preview a LOA configuration Source: https://developers.telnyx.com/api-reference/porting-orders/preview-a-loa-configuration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml get /porting/loa_configurations/{id}/preview Preview a specific LOA configuration. # Preview the LOA configuration parameters Source: https://developers.telnyx.com/api-reference/porting-orders/preview-the-loa-configuration-parameters https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml post /porting/loa_configurations/preview Preview the LOA template that would be generated without need to create LOA configuration. # Republish a porting event Source: https://developers.telnyx.com/api-reference/porting-orders/republish-a-porting-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml post /porting/events/{id}/republish Republish a specific porting event. # Retrieve a LOA configuration Source: https://developers.telnyx.com/api-reference/porting-orders/retrieve-a-loa-configuration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml get /porting/loa_configurations/{id} Retrieve a specific LOA configuration. # Retrieve a porting activation job Source: https://developers.telnyx.com/api-reference/porting-orders/retrieve-a-porting-activation-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-activation.yml get /porting_orders/{id}/activation_jobs/{activationJobId} Returns a porting activation job. # Retrieve a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/retrieve-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml get /porting_orders/{id} Retrieves the details of an existing porting order. # Retrieve a report Source: https://developers.telnyx.com/api-reference/porting-orders/retrieve-a-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml get /porting/reports/{id} Retrieve a specific report generated. # Retrieve the associated V1 sub_request_id and port_request_id Source: https://developers.telnyx.com/api-reference/porting-orders/retrieve-the-associated-v1-sub_request_id-and-port_request_id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-activation.yml get /porting_orders/{id}/sub_request Retrieve the associated V1 sub_request_id and port_request_id # Send the verification codes Source: https://developers.telnyx.com/api-reference/porting-orders/send-the-verification-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml post /porting_orders/{id}/verification_codes/send Send the verification code for all porting phone numbers. # Share a porting order Source: https://developers.telnyx.com/api-reference/porting-orders/share-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders/{id}/actions/share Creates a sharing token for a porting order. The token can be used to share the porting order with non-Telnyx users. # Show a porting event Source: https://developers.telnyx.com/api-reference/porting-orders/show-a-porting-event https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-events.yml get /porting/events/{id} Show a specific porting event. # Submit a porting order. Source: https://developers.telnyx.com/api-reference/porting-orders/submit-a-porting-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-orders.yml post /porting_orders/{id}/actions/confirm Confirm and submit your porting order. # Update a LOA configuration Source: https://developers.telnyx.com/api-reference/porting-orders/update-a-loa-configuration https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-documents.yml patch /porting/loa_configurations/{id} Update a specific LOA configuration. # Update a porting activation job Source: https://developers.telnyx.com/api-reference/porting-orders/update-a-porting-activation-job https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-activation.yml patch /porting_orders/{id}/activation_jobs/{activationJobId} Updates the activation time of a porting activation job. # Verify the verification code for a list of phone numbers Source: https://developers.telnyx.com/api-reference/porting-orders/verify-the-verification-code-for-a-list-of-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/porting-requirements.yml post /porting_orders/{id}/verification_codes/verify Verifies the verification code for a list of phone numbers. # Create Presigned Object URL Source: https://developers.telnyx.com/api-reference/presigned-object-urls/create-presigned-object-url https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/storage-data.yml post /storage/buckets/{bucketName}/{objectName}/presigned_url Returns a timed and authenticated URL to download (GET) or upload (PUT) an object. This is the equivalent to AWS S3’s “presigned” URL. Please note that Telnyx performs authentication differently from AWS S3 and you MUST NOT use the presign method of AWS s3api CLI or SDK to generate the presigned URL. Refer to: https://developers.telnyx.com/docs/cloud-storage/presigned-urls # Create a Private Wireless Gateway Source: https://developers.telnyx.com/api-reference/private-wireless-gateways/create-a-private-wireless-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /private_wireless_gateways Asynchronously create a Private Wireless Gateway for SIM cards for a previously created network. This operation may take several minutes so you can check the Private Wireless Gateway status at the section Get a Private Wireless Gateway. # Delete a Private Wireless Gateway Source: https://developers.telnyx.com/api-reference/private-wireless-gateways/delete-a-private-wireless-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /private_wireless_gateways/{id} Deletes the Private Wireless Gateway. # Get a Private Wireless Gateway Source: https://developers.telnyx.com/api-reference/private-wireless-gateways/get-a-private-wireless-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /private_wireless_gateways/{id} Retrieve information about a Private Wireless Gateway. # Get all Private Wireless Gateways Source: https://developers.telnyx.com/api-reference/private-wireless-gateways/get-all-private-wireless-gateways https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /private_wireless_gateways Get all Private Wireless Gateways belonging to the user. # Create a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/create-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml post /messaging_profiles # Delete a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/delete-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml delete /messaging_profiles/{id} # List messaging profiles Source: https://developers.telnyx.com/api-reference/profiles/list-messaging-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles # List phone numbers associated with a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/list-phone-numbers-associated-with-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles/{id}/phone_numbers # List short codes associated with a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/list-short-codes-associated-with-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles/{id}/short_codes # Retrieve a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/retrieve-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml get /messaging_profiles/{id} # Update a messaging profile Source: https://developers.telnyx.com/api-reference/profiles/update-a-messaging-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/profiles.yml patch /messaging_profiles/{id} # Creates a Fax Application Source: https://developers.telnyx.com/api-reference/programmable-fax-applications/creates-a-fax-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml post /fax_applications Creates a new Fax Application based on the parameters sent in the request. The application name and webhook URL are required. Once created, you can assign phone numbers to your application using the `/phone_numbers` endpoint. # Deletes a Fax Application Source: https://developers.telnyx.com/api-reference/programmable-fax-applications/deletes-a-fax-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml delete /fax_applications/{id} Permanently deletes a Fax Application. Deletion may be prevented if the application is in use by phone numbers. # List all Fax Applications Source: https://developers.telnyx.com/api-reference/programmable-fax-applications/list-all-fax-applications https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml get /fax_applications This endpoint returns a list of your Fax Applications inside the 'data' attribute of the response. You can adjust which applications are listed by using filters. Fax Applications are used to configure how you send and receive faxes using the Programmable Fax API with Telnyx. # Retrieve a Fax Application Source: https://developers.telnyx.com/api-reference/programmable-fax-applications/retrieve-a-fax-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml get /fax_applications/{id} Return the details of an existing Fax Application inside the 'data' attribute of the response. # Update a Fax Application Source: https://developers.telnyx.com/api-reference/programmable-fax-applications/update-a-fax-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml patch /fax_applications/{id} Updates settings of an existing Fax Application based on the parameters of the request. # Cancel a fax Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/cancel-a-fax https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml post /faxes/{id}/actions/cancel Cancel the outbound fax that is in one of the following states: `queued`, `media.processed`, `originated` or `sending` # Delete a fax Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/delete-a-fax https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml delete /faxes/{id} # Refresh a fax Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/refresh-a-fax https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml post /faxes/{id}/actions/refresh Refreshes the inbound fax's media_url when it has expired # Send a fax Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/send-a-fax https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml post /faxes Send a fax. Files have size limits and page count limit validations. If a file is bigger than 50MB or has more than 350 pages it will fail with `file_size_limit_exceeded` and `page_count_limit_exceeded` respectively. **Expected Webhooks:** - `fax.queued` - `fax.media.processed` - `fax.sending.started` - `fax.delivered` - `fax.failed` # View a fax Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/view-a-fax https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml get /faxes/{id} # View a list of faxes Source: https://developers.telnyx.com/api-reference/programmable-fax-commands/view-a-list-of-faxes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/fax.yml get /faxes # Create a Public Internet Gateway Source: https://developers.telnyx.com/api-reference/public-internet-gateways/create-a-public-internet-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /public_internet_gateways Create a new Public Internet Gateway. # Delete a Public Internet Gateway Source: https://developers.telnyx.com/api-reference/public-internet-gateways/delete-a-public-internet-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /public_internet_gateways/{id} Delete a Public Internet Gateway. # List all Public Internet Gateways Source: https://developers.telnyx.com/api-reference/public-internet-gateways/list-all-public-internet-gateways https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /public_internet_gateways List all Public Internet Gateways. # Retrieve a Public Internet Gateway Source: https://developers.telnyx.com/api-reference/public-internet-gateways/retrieve-a-public-internet-gateway https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /public_internet_gateways/{id} Retrieve a Public Internet Gateway. # Creates a new mobile push credential Source: https://developers.telnyx.com/api-reference/push-credentials/creates-a-new-mobile-push-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/mobile-push-credentials.yml post /mobile_push_credentials Creates a new mobile push credential # Deletes a mobile push credential Source: https://developers.telnyx.com/api-reference/push-credentials/deletes-a-mobile-push-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/mobile-push-credentials.yml delete /mobile_push_credentials/{push_credential_id} Deletes a mobile push credential based on the given `push_credential_id` # List mobile push credentials Source: https://developers.telnyx.com/api-reference/push-credentials/list-mobile-push-credentials https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/mobile-push-credentials.yml get /mobile_push_credentials List mobile push credentials # Retrieves a mobile push credential Source: https://developers.telnyx.com/api-reference/push-credentials/retrieves-a-mobile-push-credential https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/webrtc/mobile-push-credentials.yml get /mobile_push_credentials/{push_credential_id} Retrieves mobile push credential based on the given `push_credential_id` # Add RCS test number Source: https://developers.telnyx.com/api-reference/rcs/add-rcs-test-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml put /messaging/rcs/test_number_invite/{id}/{phone_number} Adds a test phone number to an RCS agent for testing purposes. # Check RCS capabilities Source: https://developers.telnyx.com/api-reference/rcs/check-rcs-capabilities https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml get /messaging/rcs/capabilities/{agent_id}/{phone_number} # Check RCS capabilities (batch) Source: https://developers.telnyx.com/api-reference/rcs/check-rcs-capabilities-batch https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml post /messaging/rcs/bulk_capabilities # Generate RCS deeplink Source: https://developers.telnyx.com/api-reference/rcs/generate-rcs-deeplink https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml get /messages/rcs_deeplinks/{agent_id} Generate a deeplink URL that can be used to start an RCS conversation with a specific agent. # List all RCS agents Source: https://developers.telnyx.com/api-reference/rcs/list-all-rcs-agents https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml get /messaging/rcs/agents # Modify an RCS agent Source: https://developers.telnyx.com/api-reference/rcs/modify-an-rcs-agent https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml patch /messaging/rcs/agents/{id} # Retrieve an RCS agent Source: https://developers.telnyx.com/api-reference/rcs/retrieve-an-rcs-agent https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml get /messaging/rcs/agents/{id} # Send an RCS message Source: https://developers.telnyx.com/api-reference/rcs/send-an-rcs-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/rcs.yml post /messages/rcs # List all Regions Source: https://developers.telnyx.com/api-reference/regions/list-all-regions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /regions List all regions and the interfaces that region supports # Retrieve regulatory requirements Source: https://developers.telnyx.com/api-reference/regulatory-requirements/retrieve-regulatory-requirements https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /regulatory_requirements # Retrieve regulatory requirements for a list of phone numbers Source: https://developers.telnyx.com/api-reference/regulatory-requirements/retrieve-regulatory-requirements-for-a-list-of-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/management-config.yml get /phone_numbers/regulatory_requirements # Create a Wireless Detail Records (WDRs) Report Source: https://developers.telnyx.com/api-reference/reporting/create-a-wireless-detail-records-wdrs-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml post /wireless/detail/records/reports Asynchronously create a report containing Wireless Detail Records (WDRs) for the SIM cards that consumed wireless data in the given time period. # Delete a Wireless Detail Record (WDR) Report Source: https://developers.telnyx.com/api-reference/reporting/delete-a-wireless-detail-record-wdr-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml delete /wireless/detail/records/reports/{id} Deletes one specific WDR report. # Get a Wireless Detail Record (WDR) Report Source: https://developers.telnyx.com/api-reference/reporting/get-a-wireless-detail-record-wdr-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml get /wireless/detail/records/reports/{id} Returns one specific WDR report # Get all Wireless Detail Records (WDRs) Reports Source: https://developers.telnyx.com/api-reference/reporting/get-all-wireless-detail-records-wdrs-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml get /wireless/detail/records/reports Returns the WDR Reports that match the given parameters. # Associate phone numbers for reputation Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/associate-phone-numbers-for-reputation https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml post /enterprises/{enterprise_id}/reputation/numbers Associate one or more phone numbers with an enterprise for Number Reputation monitoring. **Validations:** - Phone numbers must be in E.164 format (e.g., `+16035551234`) - Phone numbers must be in-service and belong to your account (verified via Warehouse) - Phone numbers must be US local numbers - Phone numbers cannot already be associated with any enterprise **Note:** This operation is atomic — if any number fails validation, the entire request fails. **Maximum:** 100 phone numbers per request. # Disassociate a phone number Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/disassociate-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml delete /enterprises/{enterprise_id}/reputation/numbers/{phone_number} Remove a phone number from Number Reputation monitoring for an enterprise. The number will no longer be tracked and reputation data will no longer be refreshed. # Disassociate a phone number (simplified) Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/disassociate-a-phone-number-simplified https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml delete /reputation/numbers/{phone_number} Remove a phone number from Number Reputation monitoring without requiring an `enterprise_id`. # Get reputation data for a phone number Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/get-reputation-data-for-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml get /enterprises/{enterprise_id}/reputation/numbers/{phone_number} Get detailed reputation data for a specific phone number associated with an enterprise. **Query Parameters:** - `fresh` (default: `false`): When `true`, fetches fresh reputation data (incurs API cost). When `false`, returns cached data. If no cached data exists, fresh data is automatically fetched. **Returns:** - `spam_risk`: Overall spam risk level (`low`, `medium`, `high`) - `spam_category`: Spam category classification - `maturity_score`: Maturity metric (0–100) - `connection_score`: Connection quality metric (0–100) - `engagement_score`: Engagement metric (0–100) - `sentiment_score`: Sentiment metric (0–100) - `last_refreshed_at`: Timestamp of last data refresh # Get reputation data for a phone number (simplified) Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/get-reputation-data-for-a-phone-number-simplified https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml get /reputation/numbers/{phone_number} Get reputation data for a specific phone number without requiring an `enterprise_id`. Same response as the enterprise-scoped endpoint. Uses cached data by default. # List reputation phone numbers Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/list-reputation-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml get /enterprises/{enterprise_id}/reputation/numbers List all phone numbers associated with an enterprise for Number Reputation monitoring. Returns phone numbers with their cached reputation data (if available). Supports pagination and filtering by phone number. # List reputation phone numbers (simplified) Source: https://developers.telnyx.com/api-reference/reputation-phone-numbers/list-reputation-phone-numbers-simplified https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/phone-numbers.yml get /reputation/numbers List all phone numbers enrolled in Number Reputation monitoring for your account. This is a simplified endpoint that does not require an `enterprise_id` — it returns numbers across all your enterprises. Supports pagination and filtering by phone number. # Create a new requirement group Source: https://developers.telnyx.com/api-reference/requirement-groups/create-a-new-requirement-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml post /requirement_groups # Delete a requirement group by ID Source: https://developers.telnyx.com/api-reference/requirement-groups/delete-a-requirement-group-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml delete /requirement_groups/{id} # Get a single requirement group by ID Source: https://developers.telnyx.com/api-reference/requirement-groups/get-a-single-requirement-group-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirement_groups/{id} # List requirement groups Source: https://developers.telnyx.com/api-reference/requirement-groups/list-requirement-groups https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirement_groups # Submit a Requirement Group for Approval Source: https://developers.telnyx.com/api-reference/requirement-groups/submit-a-requirement-group-for-approval https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml post /requirement_groups/{id}/submit_for_approval # Update requirement group for a phone number order Source: https://developers.telnyx.com/api-reference/requirement-groups/update-requirement-group-for-a-phone-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /number_order_phone_numbers/{id}/requirement_group # Update requirement group for a sub number order Source: https://developers.telnyx.com/api-reference/requirement-groups/update-requirement-group-for-a-sub-number-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/ordering.yml post /sub_number_orders/{id}/requirement_group # Update requirement values in requirement group Source: https://developers.telnyx.com/api-reference/requirement-groups/update-requirement-values-in-requirement-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml patch /requirement_groups/{id} # List all requirement types Source: https://developers.telnyx.com/api-reference/requirement-types/list-all-requirement-types https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirement_types List all requirement types ordered by created_at descending # Retrieve a requirement types Source: https://developers.telnyx.com/api-reference/requirement-types/retrieve-a-requirement-types https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirement_types/{id} Retrieve a requirement type by id # List all requirements Source: https://developers.telnyx.com/api-reference/requirements/list-all-requirements https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirements List all requirements with filtering, sorting, and pagination # Retrieve a document requirement Source: https://developers.telnyx.com/api-reference/requirements/retrieve-a-document-requirement https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/regulatory.yml get /requirements/{id} Retrieve a document requirement record # Create a room composition. Source: https://developers.telnyx.com/api-reference/room-compositions/create-a-room-composition https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /room_compositions Asynchronously create a room composition. # Delete a room composition. Source: https://developers.telnyx.com/api-reference/room-compositions/delete-a-room-composition https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml delete /room_compositions/{room_composition_id} Synchronously delete a room composition. # View a list of room compositions. Source: https://developers.telnyx.com/api-reference/room-compositions/view-a-list-of-room-compositions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_compositions # View a room composition. Source: https://developers.telnyx.com/api-reference/room-compositions/view-a-room-composition https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_compositions/{room_composition_id} # View a list of room participants. Source: https://developers.telnyx.com/api-reference/room-participants/view-a-list-of-room-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_participants # View a room participant. Source: https://developers.telnyx.com/api-reference/room-participants/view-a-room-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_participants/{room_participant_id} # Delete a room recording. Source: https://developers.telnyx.com/api-reference/room-recordings/delete-a-room-recording https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml delete /room_recordings/{room_recording_id} Synchronously delete a Room Recording. # Delete several room recordings in a bulk. Source: https://developers.telnyx.com/api-reference/room-recordings/delete-several-room-recordings-in-a-bulk https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml delete /room_recordings # View a list of room recordings. Source: https://developers.telnyx.com/api-reference/room-recordings/view-a-list-of-room-recordings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_recordings # View a room recording. Source: https://developers.telnyx.com/api-reference/room-recordings/view-a-room-recording https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_recordings/{room_recording_id} # End a room session. Source: https://developers.telnyx.com/api-reference/room-sessions/end-a-room-session https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /room_sessions/{room_session_id}/actions/end Note: this will also kick all participants currently present in the room # Kick participants from a room session. Source: https://developers.telnyx.com/api-reference/room-sessions/kick-participants-from-a-room-session https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /room_sessions/{room_session_id}/actions/kick # Mute participants in room session. Source: https://developers.telnyx.com/api-reference/room-sessions/mute-participants-in-room-session https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /room_sessions/{room_session_id}/actions/mute # Unmute participants in room session. Source: https://developers.telnyx.com/api-reference/room-sessions/unmute-participants-in-room-session https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /room_sessions/{room_session_id}/actions/unmute # View a list of room participants. Source: https://developers.telnyx.com/api-reference/room-sessions/view-a-list-of-room-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_sessions/{room_session_id}/participants # View a list of room sessions. Source: https://developers.telnyx.com/api-reference/room-sessions/view-a-list-of-room-sessions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_sessions # View a room session. Source: https://developers.telnyx.com/api-reference/room-sessions/view-a-room-session https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /room_sessions/{room_session_id} # Create Client Token to join a room. Source: https://developers.telnyx.com/api-reference/rooms-client-tokens/create-client-token-to-join-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /rooms/{room_id}/actions/generate_join_client_token Synchronously create an Client Token to join a Room. Client Token is necessary to join a Telnyx Room. Client Token will expire after `token_ttl_secs`, a Refresh Token is also provided to refresh a Client Token, the Refresh Token expires after `refresh_token_ttl_secs`. # Refresh Client Token to join a room. Source: https://developers.telnyx.com/api-reference/rooms-client-tokens/refresh-client-token-to-join-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /rooms/{room_id}/actions/refresh_client_token Synchronously refresh an Client Token to join a Room. Client Token is necessary to join a Telnyx Room. Client Token will expire after `token_ttl_secs`. # Create a room. Source: https://developers.telnyx.com/api-reference/rooms/create-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml post /rooms Synchronously create a Room. # Delete a room. Source: https://developers.telnyx.com/api-reference/rooms/delete-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml delete /rooms/{room_id} Synchronously delete a Room. Participants from that room will be kicked out, they won't be able to join that room anymore, and you won't be charged anymore for that room. # Update a room. Source: https://developers.telnyx.com/api-reference/rooms/update-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml patch /rooms/{room_id} Synchronously update a Room. # View a list of room sessions. Source: https://developers.telnyx.com/api-reference/rooms/view-a-list-of-room-sessions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /rooms/{room_id}/sessions # View a list of rooms. Source: https://developers.telnyx.com/api-reference/rooms/view-a-list-of-rooms https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /rooms # View a room. Source: https://developers.telnyx.com/api-reference/rooms/view-a-room https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/video.yml get /rooms/{room_id} # Get metadata overview Source: https://developers.telnyx.com/api-reference/session-analysis/get-metadata-overview https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/session-analysis.yml get /session_analysis/metadata Returns all available record types and supported query parameters for session analysis. # Get record type metadata Source: https://developers.telnyx.com/api-reference/session-analysis/get-record-type-metadata https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/session-analysis.yml get /session_analysis/metadata/{record_type} Returns detailed metadata for a specific record type, including relationships and examples. # Get session analysis Source: https://developers.telnyx.com/api-reference/session-analysis/get-session-analysis https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/session-analysis.yml get /session_analysis/{record_type}/{event_id} Retrieves a full session analysis tree for a given event, including costs, child events, and product linkages. # Retrieve Black Box Test Results Source: https://developers.telnyx.com/api-reference/seti-observability/retrieve-black-box-test-results https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/seti.yml get /seti/black_box_test_results Returns the results of the various black box tests # Get Sharing Status Source: https://developers.telnyx.com/api-reference/shared-campaigns/get-sharing-status https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/partner-campaigns.yml get /10dlc/partnerCampaign/{campaignId}/sharing # Get Single Shared Campaign Source: https://developers.telnyx.com/api-reference/shared-campaigns/get-single-shared-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/partner-campaigns.yml get /10dlc/partner_campaigns/{campaignId} Retrieve campaign details by `campaignId`. # List Shared Campaigns Source: https://developers.telnyx.com/api-reference/shared-campaigns/list-shared-campaigns https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/partner-campaigns.yml get /10dlc/partner_campaigns Retrieve all partner campaigns you have shared to Telnyx in a paginated fashion. This endpoint is currently limited to only returning shared campaigns that Telnyx has accepted. In other words, shared but pending campaigns are currently omitted from the response from this endpoint. # List shared partner campaigns Source: https://developers.telnyx.com/api-reference/shared-campaigns/list-shared-partner-campaigns https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/partner-campaigns.yml get /10dlc/partnerCampaign/sharedByMe Get all partner campaigns you have shared to Telnyx in a paginated fashion This endpoint is currently limited to only returning shared campaigns that Telnyx has accepted. In other words, shared but pending campaigns are currently omitted from the response from this endpoint. # Update Single Shared Campaign Source: https://developers.telnyx.com/api-reference/shared-campaigns/update-single-shared-campaign https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging-10dlc/partner-campaigns.yml patch /10dlc/partner_campaigns/{campaignId} Update campaign details by `campaignId`. **Please note:** Only webhook urls are editable. # List short codes Source: https://developers.telnyx.com/api-reference/short-codes/list-short-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/short-codes.yml get /short_codes # Retrieve a short code Source: https://developers.telnyx.com/api-reference/short-codes/retrieve-a-short-code https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/short-codes.yml get /short_codes/{id} # Update short code Source: https://developers.telnyx.com/api-reference/short-codes/update-short-code https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/short-codes.yml patch /short_codes/{id} Update the settings for a specific short code. To unbind a short code from a profile, set the `messaging_profile_id` to `null` or an empty string. To add or update tags, include the tags field as an array of strings. # Get bulk SIM card action details Source: https://developers.telnyx.com/api-reference/sim-card-actions/get-bulk-sim-card-action-details https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml get /bulk_sim_card_actions/{id} This API fetches information about a bulk SIM card action. A bulk SIM card action contains details about a collection of individual SIM card actions. # Get SIM card action details Source: https://developers.telnyx.com/api-reference/sim-card-actions/get-sim-card-action-details https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-card-actions.yml get /sim_card_actions/{id} This API fetches detailed information about a SIM card action to follow-up on an existing asynchronous operation. # List bulk SIM card actions Source: https://developers.telnyx.com/api-reference/sim-card-actions/list-bulk-sim-card-actions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml get /bulk_sim_card_actions This API lists a paginated collection of bulk SIM card actions. A bulk SIM card action contains details about a collection of individual SIM card actions. # List SIM card actions Source: https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-card-actions.yml get /sim_card_actions This API lists a paginated collection of SIM card actions. It enables exploring a collection of existing asynchronous operations using specific filters. # Get SIM card group action details Source: https://developers.telnyx.com/api-reference/sim-card-group-actions/get-sim-card-group-action-details https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml get /sim_card_group_actions/{id} This API allows fetching detailed information about a SIM card group action resource to make follow-ups in an existing asynchronous operation. # List SIM card group actions Source: https://developers.telnyx.com/api-reference/sim-card-group-actions/list-sim-card-group-actions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml get /sim_card_group_actions This API allows listing a paginated collection a SIM card group actions. It allows to explore a collection of existing asynchronous operation using specific filters. # Create a SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/create-a-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml post /sim_card_groups Creates a new SIM card group object # Delete a SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/delete-a-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml delete /sim_card_groups/{id} Permanently deletes a SIM card group # Get all SIM card groups Source: https://developers.telnyx.com/api-reference/sim-card-groups/get-all-sim-card-groups https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml get /sim_card_groups Get all SIM card groups belonging to the user that match the given filters. # Get SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/get-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml get /sim_card_groups/{id} Returns the details regarding a specific SIM card group # Request Private Wireless Gateway assignment for SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/request-private-wireless-gateway-assignment-for-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml post /sim_card_groups/{id}/actions/set_private_wireless_gateway This action will asynchronously assign a provisioned Private Wireless Gateway to the SIM card group. Completing this operation defines that all SIM cards in the SIM card group will get their traffic controlled by the associated Private Wireless Gateway. This operation will also imply that new SIM cards assigned to a group will inherit its network definitions. If it's moved to a different group that doesn't have a Private Wireless Gateway, it'll use Telnyx's default mobile network configuration. # Request Private Wireless Gateway removal from SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/request-private-wireless-gateway-removal-from-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml post /sim_card_groups/{id}/actions/remove_private_wireless_gateway This action will asynchronously remove an existing Private Wireless Gateway definition from a SIM card group. Completing this operation defines that all SIM cards in the SIM card group will get their traffic handled by Telnyx's default mobile network configuration. # Request Wireless Blocklist assignment for SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/request-wireless-blocklist-assignment-for-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml post /sim_card_groups/{id}/actions/set_wireless_blocklist This action will asynchronously assign a Wireless Blocklist to all the SIMs in the SIM card group. # Request Wireless Blocklist removal from SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/request-wireless-blocklist-removal-from-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml post /sim_card_groups/{id}/actions/remove_wireless_blocklist This action will asynchronously remove an existing Wireless Blocklist to all the SIMs in the SIM card group. # Update a SIM card group Source: https://developers.telnyx.com/api-reference/sim-card-groups/update-a-sim-card-group https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-groups.yml patch /sim_card_groups/{id} Updates a SIM card group # Create a SIM card order Source: https://developers.telnyx.com/api-reference/sim-card-orders/create-a-sim-card-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /sim_card_orders Creates a new order for SIM cards. # Get a single SIM card order Source: https://developers.telnyx.com/api-reference/sim-card-orders/get-a-single-sim-card-order https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml get /sim_card_orders/{id} Get a single SIM card order by its ID. # Get all SIM card orders Source: https://developers.telnyx.com/api-reference/sim-card-orders/get-all-sim-card-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml get /sim_card_orders Get all SIM card orders according to filters. # Preview SIM card orders Source: https://developers.telnyx.com/api-reference/sim-card-orders/preview-sim-card-orders https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /sim_card_order_preview Preview SIM card order purchases. # Create a new SIM card data usage notification Source: https://developers.telnyx.com/api-reference/sim-cards/create-a-new-sim-card-data-usage-notification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml post /sim_card_data_usage_notifications Creates a new SIM card data usage notification. # Delete SIM card data usage notifications Source: https://developers.telnyx.com/api-reference/sim-cards/delete-sim-card-data-usage-notifications https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml delete /sim_card_data_usage_notifications/{id} Delete the SIM Card Data Usage Notification. # Deletes a SIM card Source: https://developers.telnyx.com/api-reference/sim-cards/deletes-a-sim-card https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards.yml delete /sim_cards/{id} The SIM card will be decommissioned, removed from your account and you will stop being charged.
The SIM card won't be able to connect to the network after the deletion is completed, thus making it impossible to consume data.
Transitioning to the disabled state may take a period of time. Until the transition is completed, the SIM card status will be disabling disabling.
In order to re-enable the SIM card, you will need to re-register it. # Get a single SIM card data usage notification Source: https://developers.telnyx.com/api-reference/sim-cards/get-a-single-sim-card-data-usage-notification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /sim_card_data_usage_notifications/{id} Get a single SIM Card Data Usage Notification. # Get all SIM cards Source: https://developers.telnyx.com/api-reference/sim-cards/get-all-sim-cards https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards.yml get /sim_cards Get all SIM cards belonging to the user that match the given filters. # Get SIM card Source: https://developers.telnyx.com/api-reference/sim-cards/get-sim-card https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards.yml get /sim_cards/{id} Returns the details regarding a specific SIM card. # Get SIM card public IP definition Source: https://developers.telnyx.com/api-reference/sim-cards/get-sim-card-public-ip-definition https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /sim_cards/{id}/public_ip It returns the public IP requested for a SIM card. # List SIM card data usage notifications Source: https://developers.telnyx.com/api-reference/sim-cards/list-sim-card-data-usage-notifications https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /sim_card_data_usage_notifications Lists a paginated collection of SIM card data usage notifications. It enables exploring the collection using specific filters. # List wireless connectivity logs Source: https://developers.telnyx.com/api-reference/sim-cards/list-wireless-connectivity-logs https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-monitoring.yml get /sim_cards/{id}/wireless_connectivity_logs This API allows listing a paginated collection of Wireless Connectivity Logs associated with a SIM Card, for troubleshooting purposes. # Purchase eSIMs Source: https://developers.telnyx.com/api-reference/sim-cards/purchase-esims https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /actions/purchase/esims Purchases and registers the specified amount of eSIMs to the current user's account.

If sim_card_group_id is provided, the eSIMs will be associated with that group. Otherwise, the default group for the current user will be used.

# Register SIM cards Source: https://developers.telnyx.com/api-reference/sim-cards/register-sim-cards https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /actions/register/sim_cards Register the SIM cards associated with the provided registration codes to the current user's account.

If sim_card_group_id is provided, the SIM cards will be associated with that group. Otherwise, the default group for the current user will be used.

# Request a SIM card disable Source: https://developers.telnyx.com/api-reference/sim-cards/request-a-sim-card-disable https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /sim_cards/{id}/actions/disable This API disables a SIM card, disconnecting it from the network and making it impossible to consume data.
The API will trigger an asynchronous operation called a SIM Card Action. Transitioning to the disabled state may take a period of time. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. # Request a SIM card enable Source: https://developers.telnyx.com/api-reference/sim-cards/request-a-sim-card-enable https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /sim_cards/{id}/actions/enable This API enables a SIM card, connecting it to the network and making it possible to consume data.
To enable a SIM card, it must be associated with a SIM card group.
The API will trigger an asynchronous operation called a SIM Card Action. Transitioning to the enabled state may take a period of time. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. # Request bulk disabling voice on SIM cards. Source: https://developers.telnyx.com/api-reference/sim-cards/request-bulk-disabling-voice-on-sim-cards https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml post /sim_cards/actions/bulk_disable_voice This API triggers an asynchronous operation to disable voice on SIM cards belonging to a specified SIM Card Group.
For each SIM Card a SIM Card Action will be generated. The status of the SIM Card Actions can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. The overall status of the Bulk SIM Card Action can be followed through the [List Bulk SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-bulk-sim-card-actions) API. # Request bulk enabling voice on SIM cards. Source: https://developers.telnyx.com/api-reference/sim-cards/request-bulk-enabling-voice-on-sim-cards https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml post /sim_cards/actions/bulk_enable_voice This API triggers an asynchronous operation to enable voice on SIM cards belonging to a specified SIM Card Group.
For each SIM Card a SIM Card Action will be generated. The status of the SIM Card Actions can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. The overall status of the Bulk SIM Card Action can be followed through the [List Bulk SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-bulk-sim-card-actions) API. # Request bulk setting SIM card public IPs. Source: https://developers.telnyx.com/api-reference/sim-cards/request-bulk-setting-sim-card-public-ips https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml post /sim_cards/actions/bulk_set_public_ips This API triggers an asynchronous operation to set a public IP for each of the specified SIM cards.
For each SIM Card a SIM Card Action will be generated. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. # Request removing a SIM card public IP Source: https://developers.telnyx.com/api-reference/sim-cards/request-removing-a-sim-card-public-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml post /sim_cards/{id}/actions/remove_public_ip This API removes an existing public IP from a SIM card.

The API will trigger an asynchronous operation called a SIM Card Action. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. # Request setting a SIM card public IP Source: https://developers.telnyx.com/api-reference/sim-cards/request-setting-a-sim-card-public-ip https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml post /sim_cards/{id}/actions/set_public_ip This API makes a SIM card reachable on the public internet by mapping a random public IP to the SIM card.

The API will trigger an asynchronous operation called a SIM Card Action. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API.

Setting a Public IP to a SIM Card incurs a charge and will only succeed if the account has sufficient funds. # Request setting a SIM card to standby Source: https://developers.telnyx.com/api-reference/sim-cards/request-setting-a-sim-card-to-standby https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-provisioning.yml post /sim_cards/{id}/actions/set_standby The SIM card will be able to connect to the network once the process to set it to standby has been completed, thus making it possible to consume data.
To set a SIM card to standby, it must be associated with SIM card group.
The API will trigger an asynchronous operation called a SIM Card Action. Transitioning to the standby state may take a period of time. The status of the SIM Card Action can be followed through the [List SIM Card Action](https://developers.telnyx.com/api-reference/sim-card-actions/list-sim-card-actions) API. # Update a SIM card Source: https://developers.telnyx.com/api-reference/sim-cards/update-a-sim-card https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards.yml patch /sim_cards/{id} Updates SIM card data # Updates information for a SIM Card Data Usage Notification Source: https://developers.telnyx.com/api-reference/sim-cards/updates-information-for-a-sim-card-data-usage-notification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml patch /sim_card_data_usage_notifications/{id} Updates information for a SIM Card Data Usage Notification. # Validate SIM cards registration codes Source: https://developers.telnyx.com/api-reference/sim-cards/validate-sim-cards-registration-codes https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-bulk-actions.yml post /sim_cards/actions/validate_registration_codes It validates whether SIM card registration codes are valid or not. # Create a new Speech to Text batch report request Source: https://developers.telnyx.com/api-reference/speech-to-text-batch-reports/create-a-new-speech-to-text-batch-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy/reporting/batch/detail/records/speech/to/text Creates a new Speech to Text batch report request with the specified filters # Delete a Speech to Text batch report request Source: https://developers.telnyx.com/api-reference/speech-to-text-batch-reports/delete-a-speech-to-text-batch-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy/reporting/batch/detail/records/speech/to/text/{id} Deletes a specific Speech to Text batch report request by ID # Get a specific Speech to Text batch report request Source: https://developers.telnyx.com/api-reference/speech-to-text-batch-reports/get-a-specific-speech-to-text-batch-report-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy/reporting/batch/detail/records/speech/to/text/{id} Retrieves a specific Speech to Text batch report request by ID # Get all Speech to Text batch report requests Source: https://developers.telnyx.com/api-reference/speech-to-text-batch-reports/get-all-speech-to-text-batch-report-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy/reporting/batch/detail/records/speech/to/text Retrieves all Speech to Text batch report requests for the authenticated user # Get speech to text usage report Source: https://developers.telnyx.com/api-reference/speech-to-text-usage-reports/get-speech-to-text-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/speech_to_text Generate and fetch speech to text usage report synchronously. This endpoint will both generate and fetch the speech to text report over a specified time period. # Delete telco data usage report Source: https://developers.telnyx.com/api-reference/telco-data-usage-reports/delete-telco-data-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml delete /legacy_reporting/usage_reports/number_lookup/{id} Delete a specific telco data usage report by its ID # Get telco data usage report by ID Source: https://developers.telnyx.com/api-reference/telco-data-usage-reports/get-telco-data-usage-report-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/number_lookup/{id} Retrieve a specific telco data usage report by its ID # List telco data usage reports Source: https://developers.telnyx.com/api-reference/telco-data-usage-reports/list-telco-data-usage-reports https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /legacy_reporting/usage_reports/number_lookup Retrieve a paginated list of telco data usage reports # Submit telco data usage report Source: https://developers.telnyx.com/api-reference/telco-data-usage-reports/submit-telco-data-usage-report https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml post /legacy_reporting/usage_reports/number_lookup Submit a new telco data usage report # Agree to Number Reputation Terms of Service Source: https://developers.telnyx.com/api-reference/terms-of-service/agree-to-number-reputation-terms-of-service https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/number-reputation/settings.yml post /terms_of_service/number_reputation/agree Accept the Terms of Service for the Number Reputation product. Must be called before using Number Reputation endpoints. Returns `400` with error code `10015` if the user has already agreed to the current ToS version. # Creates a TeXML Application Source: https://developers.telnyx.com/api-reference/texml-applications/creates-a-texml-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/applications.yml post /texml_applications Creates a TeXML Application. # Deletes a TeXML Application Source: https://developers.telnyx.com/api-reference/texml-applications/deletes-a-texml-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/applications.yml delete /texml_applications/{id} Deletes a TeXML Application. # List all TeXML Applications Source: https://developers.telnyx.com/api-reference/texml-applications/list-all-texml-applications https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/applications.yml get /texml_applications Returns a list of your TeXML Applications. # Retrieve a TeXML Application Source: https://developers.telnyx.com/api-reference/texml-applications/retrieve-a-texml-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/applications.yml get /texml_applications/{id} Retrieves the details of an existing TeXML Application. # Update a TeXML Application Source: https://developers.telnyx.com/api-reference/texml-applications/update-a-texml-application https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/applications.yml patch /texml_applications/{id} Updates settings of an existing TeXML Application. # Create a new queue Source: https://developers.telnyx.com/api-reference/texml-rest-commands/create-a-new-queue https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml post /texml/Accounts/{account_sid}/Queues Creates a new queue resource. # Create a TeXML secret Source: https://developers.telnyx.com/api-reference/texml-rest-commands/create-a-texml-secret https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/secrets.yml post /texml/secrets Create a TeXML secret which can be later used as a Dynamic Parameter for TeXML when using Mustache Templates in your TeXML. In your TeXML you will be able to use your secret name, and this name will be replaced by the actual secret value when processing the TeXML on Telnyx side. The secrets are not visible in any logs. # Delete a conference participant Source: https://developers.telnyx.com/api-reference/texml-rest-commands/delete-a-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml delete /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Participants/{call_sid_or_participant_label} Deletes a conference participant # Delete a queue resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/delete-a-queue-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml delete /texml/Accounts/{account_sid}/Queues/{queue_sid} Delete a queue resource. # Delete a recording transcription Source: https://developers.telnyx.com/api-reference/texml-rest-commands/delete-a-recording-transcription https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/transcriptions.yml delete /texml/Accounts/{account_sid}/Transcriptions/{recording_transcription_sid}.json Permanently deletes a recording transcription. # Delete recording resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/delete-recording-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml delete /texml/Accounts/{account_sid}/Recordings/{recording_sid}.json Deletes recording resource identified by recording id. # Dial a new conference participant Source: https://developers.telnyx.com/api-reference/texml-rest-commands/dial-a-new-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml post /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Participants Dials a new conference participant # Fetch a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml get /texml/Accounts/{account_sid}/Calls/{call_sid} Returns an individual call identified by its CallSid. This endpoint is eventually consistent. # Fetch a conference resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-a-conference-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conferences.yml get /texml/Accounts/{account_sid}/Conferences/{conference_sid} Returns a conference resource. # Fetch a queue resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-a-queue-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml get /texml/Accounts/{account_sid}/Queues/{queue_sid} Returns a queue resource. # Fetch a recording transcription resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-a-recording-transcription-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/transcriptions.yml get /texml/Accounts/{account_sid}/Transcriptions/{recording_transcription_sid}.json Returns the recording transcription resource identified by its ID. # Fetch multiple call resources Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-multiple-call-resources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml get /texml/Accounts/{account_sid}/Calls Returns multiple call resouces for an account. This endpoint is eventually consistent. # Fetch multiple recording resources Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-multiple-recording-resources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml get /texml/Accounts/{account_sid}/Recordings.json Returns multiple recording resources for an account. # Fetch recording resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-recording-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml get /texml/Accounts/{account_sid}/Recordings/{recording_sid}.json Returns recording resource identified by recording id. # Fetch recordings for a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-recordings-for-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml get /texml/Accounts/{account_sid}/Calls/{call_sid}/Recordings.json Returns recordings for a call identified by call_sid. # Fetch recordings for a conference Source: https://developers.telnyx.com/api-reference/texml-rest-commands/fetch-recordings-for-a-conference https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml get /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Recordings.json Returns recordings for a conference identified by conference_sid. # Get conference participant resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/get-conference-participant-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml get /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Participants/{call_sid_or_participant_label} Gets conference participant resource # Initiate an outbound AI call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/initiate-an-outbound-ai-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml post /texml/ai_calls/{connection_id} Initiate an outbound AI call with warm-up support. Validates parameters, builds an internal TeXML with an AI Assistant configuration, encodes instructions into client state, and calls the dial API. The Twiml, Texml, and Url parameters are not allowed and will result in a 422 error. # Initiate an outbound call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/initiate-an-outbound-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml post /texml/Accounts/{account_sid}/Calls Initiate an outbound TeXML call. Telnyx will request TeXML from the XML Request URL configured for the connection in the Mission Control Portal. # List conference participants Source: https://developers.telnyx.com/api-reference/texml-rest-commands/list-conference-participants https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml get /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Participants Lists conference participants # List conference recordings Source: https://developers.telnyx.com/api-reference/texml-rest-commands/list-conference-recordings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml get /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Recordings Lists conference recordings # List conference resources Source: https://developers.telnyx.com/api-reference/texml-rest-commands/list-conference-resources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conferences.yml get /texml/Accounts/{account_sid}/Conferences Lists conference resources. # List queue resources Source: https://developers.telnyx.com/api-reference/texml-rest-commands/list-queue-resources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml get /texml/Accounts/{account_sid}/Queues Lists queue resources. # List recording transcriptions Source: https://developers.telnyx.com/api-reference/texml-rest-commands/list-recording-transcriptions https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/transcriptions.yml get /texml/Accounts/{account_sid}/Transcriptions.json Returns multiple recording transcription resources for an account. # Request recording for a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/request-recording-for-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Recordings.json Starts recording with specified parameters for call idientified by call_sid. # Request siprec session for a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/request-siprec-session-for-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/siprec.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Siprec.json Starts siprec session with specified parameters for call idientified by call_sid. # Start streaming media from a call. Source: https://developers.telnyx.com/api-reference/texml-rest-commands/start-streaming-media-from-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/streams.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Streams.json Starts streaming media from a call to a specific WebSocket address. # Update a conference participant Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-a-conference-participant https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conference-participants.yml post /texml/Accounts/{account_sid}/Conferences/{conference_sid}/Participants/{call_sid_or_participant_label} Updates a conference participant # Update a conference resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-a-conference-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/conferences.yml post /texml/Accounts/{account_sid}/Conferences/{conference_sid} Updates a conference resource. # Update a queue resource Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-a-queue-resource https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/queues.yml post /texml/Accounts/{account_sid}/Queues/{queue_sid} Updates a queue resource. # Update call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/calls.yml post /texml/Accounts/{account_sid}/Calls/{call_sid} Update TeXML call. Please note that the keys present in the payload MUST BE formatted in CamelCase as specified in the example. # Update recording on a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-recording-on-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/recordings.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Recordings/{recording_sid}.json Updates recording resource for particular call. # Update streaming on a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/update-streaming-on-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/streams.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Streams/{streaming_sid}.json Updates streaming resource for particular call. # Updates siprec session for a call Source: https://developers.telnyx.com/api-reference/texml-rest-commands/updates-siprec-session-for-a-call https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/texml/siprec.yml post /texml/Accounts/{account_sid}/Calls/{call_sid}/Siprec/{siprec_sid}.json Updates siprec session identified by siprec_sid. # Generate speech from text Source: https://developers.telnyx.com/api-reference/text-to-speech-commands/generate-speech-from-text https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/text-to-speech/text-to-speech.yml post /text-to-speech Generate synthesized speech audio from text input. Returns audio in the requested format (binary audio stream, base64-encoded JSON, or an audio URL for later retrieval). Authentication is provided via the standard `Authorization: Bearer ` header. The `voice` parameter provides a convenient shorthand to specify provider, model, and voice in a single string (e.g. `telnyx.NaturalHD.Alloy` or `Telnyx.Ultra.`). Alternatively, specify `provider` explicitly along with provider-specific parameters. Supported providers: `aws`, `telnyx`, `azure`, `elevenlabs`, `minimax`, `rime`, `resemble`, `xai`. The Telnyx `Ultra` model supports 44 languages with emotion control, speed adjustment, and volume control. Use the `telnyx` provider-specific parameters to configure these features. # List available voices Source: https://developers.telnyx.com/api-reference/text-to-speech-commands/list-available-voices https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/text-to-speech/text-to-speech.yml get /text-to-speech/voices Retrieve a list of available voices from one or all TTS providers. When `provider` is specified, returns voices for that provider only. Otherwise, returns voices from all providers. Some providers (ElevenLabs, Resemble) require an API key to list voices. # Stream text to speech over WebSocket Source: https://developers.telnyx.com/api-reference/text-to-speech-commands/stream-text-to-speech-over-websocket https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/text-to-speech/text-to-speech.yml get /text-to-speech Open a WebSocket connection to stream text and receive synthesized audio in real time. Authentication is provided via the standard `Authorization: Bearer ` header. Send JSON frames with text to synthesize; receive JSON frames containing base64-encoded audio chunks. Supported providers: `aws`, `telnyx`, `azure`, `murfai`, `minimax`, `rime`, `resemble`, `elevenlabs`, `xai`. **Connection flow:** 1. Open WebSocket with query parameters specifying provider, voice, and model. 2. Send an initial handshake message `{"text": " "}` (single space) with optional `voice_settings` to initialize the session. 3. Send text messages as `{"text": "Hello world"}`. 4. Receive audio chunks as JSON frames with base64-encoded audio. 5. A final frame with `isFinal: true` indicates the end of audio for the current text. To interrupt and restart synthesis mid-stream, send `{"force": true}` — the current worker is stopped and a new one is started. **Note:** The Telnyx `Ultra` model is not available over WebSocket. Use the HTTP POST `/text-to-speech/speech` endpoint instead. # Create a traffic policy profile Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/create-a-traffic-policy-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml post /traffic/policy/profiles Create a new traffic policy profile. At least one of `services`, `ip_ranges`, or `domains` must be provided. # Delete a traffic policy profile Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/delete-a-traffic-policy-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml delete /traffic/policy/profiles/{id} Deletes the traffic policy profile. # Get a traffic policy profile Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/get-a-traffic-policy-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /traffic/policy/profiles/{id} Returns the details regarding a specific traffic policy profile. # Get all available traffic policy profile services Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/get-all-available-traffic-policy-profile-services https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /traffic/policy/profiles/services Get all available PCEF services that can be used in traffic policy profiles. # Get all traffic policy profiles Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/get-all-traffic-policy-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /traffic/policy/profiles Get all traffic policy profiles belonging to the user that match the given filters. # Update a traffic policy profile Source: https://developers.telnyx.com/api-reference/traffic-policy-profiles/update-a-traffic-policy-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml patch /traffic/policy/profiles/{id} Updates a traffic policy profile. # Get Telnyx product usage data (BETA) Source: https://developers.telnyx.com/api-reference/usage-reports-beta/get-telnyx-product-usage-data-beta https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /usage_reports Get Telnyx usage data by product, broken out by the specified dimensions # Get Usage Reports query options (BETA) Source: https://developers.telnyx.com/api-reference/usage-reports-beta/get-usage-reports-query-options-beta https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /usage_reports/options Get the Usage Reports options for querying usage, including the products available and their respective metrics and dimensions # Create User Bundles Source: https://developers.telnyx.com/api-reference/user-bundles/create-user-bundles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml post /bundle_pricing/user_bundles/bulk Creates multiple user bundles for the user. # Deactivate User Bundle Source: https://developers.telnyx.com/api-reference/user-bundles/deactivate-user-bundle https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml delete /bundle_pricing/user_bundles/{user_bundle_id} Deactivates a user bundle by its ID. # Get Unused User Bundles Source: https://developers.telnyx.com/api-reference/user-bundles/get-unused-user-bundles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/user_bundles/unused Returns all user bundles that aren't in use. # Get User Bundle by Id Source: https://developers.telnyx.com/api-reference/user-bundles/get-user-bundle-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/user_bundles/{user_bundle_id} Retrieves a user bundle by its ID. # Get User Bundle Resources Source: https://developers.telnyx.com/api-reference/user-bundles/get-user-bundle-resources https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/user_bundles/{user_bundle_id}/resources Retrieves the resources of a user bundle by its ID. # Get User Bundles Source: https://developers.telnyx.com/api-reference/user-bundles/get-user-bundles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/bundles.yml get /bundle_pricing/user_bundles Get a paginated list of user bundles. # List User Tags Source: https://developers.telnyx.com/api-reference/user-tags/list-user-tags https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/taggings.yml get /user_tags List all user tags. # Creates a user address Source: https://developers.telnyx.com/api-reference/useraddresses/creates-a-user-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/taggings.yml post /user/addresses Creates a user address. # List all user addresses Source: https://developers.telnyx.com/api-reference/useraddresses/list-all-user-addresses https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/taggings.yml get /user/addresses Returns a list of your user addresses. # Retrieve a user address Source: https://developers.telnyx.com/api-reference/useraddresses/retrieve-a-user-address https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/taggings.yml get /user/addresses/{id} Retrieves the details of an existing user address. # Delete Verification Request Source: https://developers.telnyx.com/api-reference/verification-requests/delete-verification-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml delete /messaging_tollfree/verification/requests/{id} Delete a verification request A request may only be deleted when when the request is in the "rejected" state. * `HTTP 200`: request successfully deleted * `HTTP 400`: request exists but can't be deleted (i.e. not rejected) * `HTTP 404`: request unknown or already deleted # Get Verification Request Source: https://developers.telnyx.com/api-reference/verification-requests/get-verification-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml get /messaging_tollfree/verification/requests/{id} Get a single verification request by its ID. # Get Verification Request Status History Source: https://developers.telnyx.com/api-reference/verification-requests/get-verification-request-status-history https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml get /messaging/tollfree/verification/requests/{id}/status/history Get the history of status changes for a verification request. Returns a paginated list of historical status changes including the reason for each change and when it occurred. # List Verification Requests Source: https://developers.telnyx.com/api-reference/verification-requests/list-verification-requests https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml get /messaging_tollfree/verification/requests Get a list of previously-submitted tollfree verification requests # Submit Verification Request Source: https://developers.telnyx.com/api-reference/verification-requests/submit-verification-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml post /messaging_tollfree/verification/requests Submit a new tollfree verification request # Update Verification Request Source: https://developers.telnyx.com/api-reference/verification-requests/update-verification-request https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/toll-free-verification.yml patch /messaging_tollfree/verification/requests/{id} Update an existing tollfree verification request. This is particularly useful when there are pending customer actions to be taken. # Delete a verified number Source: https://developers.telnyx.com/api-reference/verified-numbers/delete-a-verified-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/verified-numbers.yml delete /verified_numbers/{phone_number} # List all Verified Numbers Source: https://developers.telnyx.com/api-reference/verified-numbers/list-all-verified-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/verified-numbers.yml get /verified_numbers Gets a paginated list of Verified Numbers. # Request phone number verification Source: https://developers.telnyx.com/api-reference/verified-numbers/request-phone-number-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/verified-numbers.yml post /verified_numbers Initiates phone number verification procedure. Supports DTMF extension dialing for voice calls to numbers behind IVR systems. # Retrieve a verified number Source: https://developers.telnyx.com/api-reference/verified-numbers/retrieve-a-verified-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/verified-numbers.yml get /verified_numbers/{phone_number} # Submit verification code Source: https://developers.telnyx.com/api-reference/verified-numbers/submit-verification-code https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/real-time-communications/verified-numbers.yml post /verified_numbers/{phone_number}/actions/verify # Create a Verify profile Source: https://developers.telnyx.com/api-reference/verify/create-a-verify-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verify_profiles Creates a new Verify profile to associate verifications with. # Create message template Source: https://developers.telnyx.com/api-reference/verify/create-message-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verify_profiles/templates Create a new Verify profile message template. # Delete Verify profile Source: https://developers.telnyx.com/api-reference/verify/delete-verify-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml delete /verify_profiles/{verify_profile_id} # List all Verify profiles Source: https://developers.telnyx.com/api-reference/verify/list-all-verify-profiles https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml get /verify_profiles Gets a paginated list of Verify profiles. # List verifications by phone number Source: https://developers.telnyx.com/api-reference/verify/list-verifications-by-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml get /verifications/by_phone_number/{phone_number} # Retrieve verification Source: https://developers.telnyx.com/api-reference/verify/retrieve-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml get /verifications/{verification_id} # Retrieve Verify profile Source: https://developers.telnyx.com/api-reference/verify/retrieve-verify-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml get /verify_profiles/{verify_profile_id} Gets a single Verify profile. # Retrieve Verify profile message templates Source: https://developers.telnyx.com/api-reference/verify/retrieve-verify-profile-message-templates https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml get /verify_profiles/templates List all Verify profile message templates. # Trigger Call verification Source: https://developers.telnyx.com/api-reference/verify/trigger-call-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verifications/call # Trigger Flash call verification Source: https://developers.telnyx.com/api-reference/verify/trigger-flash-call-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verifications/flashcall # Trigger SMS verification Source: https://developers.telnyx.com/api-reference/verify/trigger-sms-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verifications/sms # Update message template Source: https://developers.telnyx.com/api-reference/verify/update-message-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml patch /verify_profiles/templates/{template_id} Update an existing Verify profile message template. # Update Verify profile Source: https://developers.telnyx.com/api-reference/verify/update-verify-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml patch /verify_profiles/{verify_profile_id} # Verify verification code by ID Source: https://developers.telnyx.com/api-reference/verify/verify-verification-code-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verifications/{verification_id}/actions/verify # Verify verification code by phone number Source: https://developers.telnyx.com/api-reference/verify/verify-verification-code-by-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/verify.yml post /verifications/by_phone_number/{phone_number}/actions/verify # Create a Virtual Cross Connect Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/create-a-virtual-cross-connect https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /virtual_cross_connects Create a new Virtual Cross Connect.

For AWS and GCE, you have the option of creating the primary connection first and the secondary connection later. You also have the option of disabling the primary and/or secondary connections at any time and later re-enabling them. With Azure, you do not have this option. Azure requires both the primary and secondary connections to be created at the same time and they can not be independantly disabled. # Delete a Virtual Cross Connect Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/delete-a-virtual-cross-connect https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /virtual_cross_connects/{id} Delete a Virtual Cross Connect. # List all Virtual Cross Connects Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/list-all-virtual-cross-connects https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /virtual_cross_connects List all Virtual Cross Connects. # List Virtual Cross Connect Cloud Coverage Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/list-virtual-cross-connect-cloud-coverage https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /virtual_cross_connects/coverage List Virtual Cross Connects Cloud Coverage.

This endpoint shows which cloud regions are available for the `location_code` your Virtual Cross Connect will be provisioned in. # Retrieve a Virtual Cross Connect Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/retrieve-a-virtual-cross-connect https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /virtual_cross_connects/{id} Retrieve a Virtual Cross Connect. # Update the Virtual Cross Connect Source: https://developers.telnyx.com/api-reference/virtual-cross-connects/update-the-virtual-cross-connect https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml patch /virtual_cross_connects/{id} Update the Virtual Cross Connect.

Cloud IPs can only be patched during the `created` state, as GCE will only inform you of your generated IP once the pending connection requested has been accepted. Once the Virtual Cross Connect has moved to `provisioning`, the IPs can no longer be patched.

Once the Virtual Cross Connect has moved to `provisioned` and you are ready to enable routing, you can toggle the routing announcements to `true`. # List All Numbers using Channel Billing Source: https://developers.telnyx.com/api-reference/voice-channels/list-all-numbers-using-channel-billing https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml get /list Retrieve a list of all phone numbers using Channel Billing, grouped by Zone. # List Numbers using Channel Billing for a specific Zone Source: https://developers.telnyx.com/api-reference/voice-channels/list-numbers-using-channel-billing-for-a-specific-zone https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml get /list/{channel_zone_id} Retrieve a list of phone numbers using Channel Billing for a specific Zone. # List your voice channels for non-US zones Source: https://developers.telnyx.com/api-reference/voice-channels/list-your-voice-channels-for-non-us-zones https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml get /channel_zones Returns the non-US voice channels for your account. voice channels allow you to use Channel Billing for calls to your Telnyx phone numbers. Please check the Telnyx Support Articles section for full information and examples of how to utilize Channel Billing. # List your voice channels for US Zone Source: https://developers.telnyx.com/api-reference/voice-channels/list-your-voice-channels-for-us-zone https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml get /inbound_channels Returns the US Zone voice channels for your account. voice channels allows you to use Channel Billing for calls to your Telnyx phone numbers. Please check the Telnyx Support Articles section for full information and examples of how to utilize Channel Billing. # Update voice channels for non-US Zones Source: https://developers.telnyx.com/api-reference/voice-channels/update-voice-channels-for-non-us-zones https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml put /channel_zones/{channel_zone_id} Update the number of Voice Channels for the Non-US Zones. This allows your account to handle multiple simultaneous inbound calls to Non-US numbers. Use this endpoint to increase or decrease your capacity based on expected call volume. # Update voice channels for US Zone Source: https://developers.telnyx.com/api-reference/voice-channels/update-voice-channels-for-us-zone https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voice-channels.yml patch /inbound_channels Update the number of Voice Channels for the US Zone. This allows your account to handle multiple simultaneous inbound calls to US numbers. Use this endpoint to increase or decrease your capacity based on expected call volume. # Create a voice clone from a voice design Source: https://developers.telnyx.com/api-reference/voice-clones/create-a-voice-clone-from-a-voice-design /openapi/voice-clones.yml post /voice_clones Creates a new voice clone by capturing the voice identity of an existing voice design. The clone can then be used for text-to-speech synthesis. # Create a voice clone from an audio file upload Source: https://developers.telnyx.com/api-reference/voice-clones/create-a-voice-clone-from-an-audio-file-upload /openapi/voice-clones.yml post /voice_clones/from_upload Creates a new voice clone by uploading an audio file directly. Supported formats: WAV, MP3, FLAC, OGG, M4A. For best results, provide 5–10 seconds of clear speech. Maximum file size: 2MB. # Delete a voice clone Source: https://developers.telnyx.com/api-reference/voice-clones/delete-a-voice-clone /openapi/voice-clones.yml delete /voice_clones/{id} Permanently deletes a voice clone. This action cannot be undone. # Download voice clone audio sample Source: https://developers.telnyx.com/api-reference/voice-clones/download-voice-clone-audio-sample /openapi/voice-clones.yml get /voice_clones/{id}/sample Downloads the WAV audio sample that was used to create the voice clone. # List voice clones Source: https://developers.telnyx.com/api-reference/voice-clones/list-voice-clones /openapi/voice-clones.yml get /voice_clones Returns a paginated list of voice clones belonging to the authenticated account. # Update a voice clone Source: https://developers.telnyx.com/api-reference/voice-clones/update-a-voice-clone /openapi/voice-clones.yml patch /voice_clones/{id} Updates the name, language, or gender of a voice clone. # Create or add a version to a voice design Source: https://developers.telnyx.com/api-reference/voice-designs/create-or-add-a-version-to-a-voice-design /openapi/voice-designs.yml post /voice_designs Creates a new voice design (version 1) when `voice_design_id` is omitted. When `voice_design_id` is provided, adds a new version to the existing design instead. A design can have at most 50 versions. # Delete a specific version of a voice design Source: https://developers.telnyx.com/api-reference/voice-designs/delete-a-specific-version-of-a-voice-design /openapi/voice-designs.yml delete /voice_designs/{id}/versions/{version} Permanently deletes a specific version of a voice design. The version number must be a positive integer. # Delete a voice design Source: https://developers.telnyx.com/api-reference/voice-designs/delete-a-voice-design /openapi/voice-designs.yml delete /voice_designs/{id} Permanently deletes a voice design and all of its versions. This action cannot be undone. # Download voice design audio sample Source: https://developers.telnyx.com/api-reference/voice-designs/download-voice-design-audio-sample /openapi/voice-designs.yml get /voice_designs/{id}/sample Downloads the WAV audio sample for the voice design. Returns the latest version's sample by default, or a specific version when `?version=N` is provided. The `id` parameter accepts either a UUID or the design name. # Get a voice design Source: https://developers.telnyx.com/api-reference/voice-designs/get-a-voice-design /openapi/voice-designs.yml get /voice_designs/{id} Returns the latest version of a voice design, or a specific version when `?version=N` is provided. The `id` parameter accepts either a UUID or the design name. # List voice designs Source: https://developers.telnyx.com/api-reference/voice-designs/list-voice-designs /openapi/voice-designs.yml get /voice_designs Returns a paginated list of voice designs belonging to the authenticated account. # Rename a voice design Source: https://developers.telnyx.com/api-reference/voice-designs/rename-a-voice-design /openapi/voice-designs.yml patch /voice_designs/{id} Updates the name of a voice design. All versions retain their other properties. # Create voicemail Source: https://developers.telnyx.com/api-reference/voicemail/create-voicemail https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voicemail.yml post /phone_numbers/{phone_number_id}/voicemail Create voicemail settings for a phone number # Get voicemail Source: https://developers.telnyx.com/api-reference/voicemail/get-voicemail https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voicemail.yml get /phone_numbers/{phone_number_id}/voicemail Returns the voicemail settings for a phone number # Update voicemail Source: https://developers.telnyx.com/api-reference/voicemail/update-voicemail https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/numbers-identity/voicemail.yml patch /phone_numbers/{phone_number_id}/voicemail Update voicemail settings for a phone number # Fetches all Wdr records Source: https://developers.telnyx.com/api-reference/wdr-detail-reports/fetches-all-wdr-records https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/usage-reports.yml get /reports/wdrs Fetch all Wdr records # Find webhook_delivery details by ID Source: https://developers.telnyx.com/api-reference/webhooks/find-webhook_delivery-details-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/webhooks.yml get /webhook_deliveries/{id} Provides webhook_delivery debug data, such as timestamps, delivery status and attempts. # List webhook deliveries Source: https://developers.telnyx.com/api-reference/webhooks/list-webhook-deliveries https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/account-billing/webhooks.yml get /webhook_deliveries Lists webhook_deliveries for the authenticated user # Stream call media over WebSocket Source: https://developers.telnyx.com/api-reference/websockets/stream-call-media-over-websocket AsyncAPI specification for the Telnyx Media Streaming WebSocket connection. Media Streaming forks call media and delivers it to a customer-provided WebSocket URL configured through Call Control using `stream_url`. Telnyx opens the WebSocket connection, sends lifecycle and media frames, and can receive bidirectional media playback commands from the connected application. ## Connection Flow 1. Start media streaming with a Call Control command and provide `stream_url`. 2. Telnyx opens a WebSocket connection to the configured `stream_url`. 3. Telnyx sends a `connected` frame, followed by a `start` frame that identifies the call and media format. 4. Telnyx sends `media` frames with base64-encoded RTP payloads for the requested track or tracks. 5. If bidirectional streaming is enabled, the connected application can send `media`, `mark`, and `clear` frames back to Telnyx. 6. Telnyx sends `dtmf`, `mark`, `error`, and `stop` frames as applicable. ## Bidirectional Media Bidirectional streaming is enabled through Call Control by setting `stream_bidirectional_mode` to `rtp` for RTP payloads, or by sending base64-encoded MP3 media frames for media-file playback. RTP media chunks sent back to Telnyx can contain 20 milliseconds to 30 seconds of audio. MP3 media frames are queued and played in submission order, with a one-message-per-second rate limit. ## Ordering Media frame order is not guaranteed. Use `media.chunk`, `media.timestamp`, and `sequence_number` to order frames when required. # Stream speech to text over WebSocket Source: https://developers.telnyx.com/api-reference/websockets/stream-speech-to-text-over-websocket AsyncAPI specification for the Telnyx Speech-to-Text WebSocket endpoint. Real-time speech transcription by streaming audio and receiving transcript frames. ## Supported Engines - `Azure` - Microsoft Azure Speech Services - `Deepgram` - Deepgram Nova models - `Google` - Google Cloud Speech-to-Text - `Telnyx` - Telnyx native transcription (OpenAI Whisper models) - `xAI` - xAI Grok STT - `AssemblyAI` - AssemblyAI Universal-Streaming ## Connection Flow 1. Open WebSocket connection to `wss://api.telnyx.com/v2/speech-to-text/transcription` with query parameters. 2. Send binary audio frames (mp3 or wav format). 3. Receive JSON transcript frames with `transcript`, `is_final`, and `confidence` fields. 4. Close connection when done. ## Authentication Requires authentication via a Bearer token (Telnyx API v2 key). # Stream text to speech over WebSocket Source: https://developers.telnyx.com/api-reference/websockets/stream-text-to-speech-over-websocket AsyncAPI specification for the Telnyx Text-to-Speech WebSocket endpoint. Real-time speech synthesis by streaming text and receiving audio chunks. ## Supported Providers - `telnyx` - Telnyx native voices (Natural, NaturalHD, Qwen3TTS) - `aws` - Amazon Polly - `azure` - Microsoft Azure TTS - `elevenlabs` - ElevenLabs voices - `minimax` - MiniMax voices - `rime` - Rime voices - `resemble` - Resemble AI voices - `xai` - xAI voices (Eve, Ara, Rex, Sal, Leo) - `inworld` - Inworld AI voices ## Connection Flow 1. Open WebSocket connection to `wss://api.telnyx.com/v2/text-to-speech/speech` with query parameters. 2. Send an initial handshake message `{"text": " "}` (single space) with optional `voice_settings`. 3. Send text messages as `{"text": "Hello world"}`. 4. Receive audio chunks as JSON frames with base64-encoded audio. 5. A final frame with `isFinal: true` indicates the end of audio for the current text. ## Authentication Requires authentication via a Bearer token (Telnyx API v2 key). # Delete a Whatsapp Business Account Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/delete-a-whatsapp-business-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml delete /whatsapp/business_accounts/{id} # Get a single Whatsapp Business Account Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/get-a-single-whatsapp-business-account https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/business_accounts/{id} # Get WABA settings Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/get-waba-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/business_accounts/{id}/settings # List phone numbers for a WABA Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/list-phone-numbers-for-a-waba https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/business_accounts/{id}/phone_numbers # List Whatsapp Business Accounts Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/list-whatsapp-business-accounts https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/business_accounts # Update WABA settings Source: https://developers.telnyx.com/api-reference/whatsapp-business-accounts/update-waba-settings https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml patch /whatsapp/business_accounts/{id}/settings # Create a Whatsapp message template Source: https://developers.telnyx.com/api-reference/whatsapp-message-templates/create-a-whatsapp-message-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml post /whatsapp/message_templates # Delete a Whatsapp message template Source: https://developers.telnyx.com/api-reference/whatsapp-message-templates/delete-a-whatsapp-message-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml delete /whatsapp/message_templates/{id} # Get a Whatsapp message template by ID Source: https://developers.telnyx.com/api-reference/whatsapp-message-templates/get-a-whatsapp-message-template-by-id https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/message_templates/{id} # List Whatsapp message templates Source: https://developers.telnyx.com/api-reference/whatsapp-message-templates/list-whatsapp-message-templates https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/message_templates # Update a Whatsapp message template Source: https://developers.telnyx.com/api-reference/whatsapp-message-templates/update-a-whatsapp-message-template https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml patch /whatsapp/message_templates/{id} # Send a Whatsapp message Source: https://developers.telnyx.com/api-reference/whatsapp-messaging/send-a-whatsapp-message https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/messaging/messages.yml post /messages/whatsapp # Delete a Whatsapp phone number Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/delete-a-whatsapp-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml delete /whatsapp/phone_numbers/{phone_number} # Delete Whatsapp profile photo Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/delete-whatsapp-profile-photo https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml delete /whatsapp/phone_numbers/{phone_number}/profile/photo # Enable or disable Whatsapp calling for a phone number Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/enable-or-disable-whatsapp-calling-for-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml patch /whatsapp/phone_numbers/{phone_number}/calling_settings # Get calling settings for a phone number Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-calling-settings-for-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/phone_numbers/{phone_number}/calling_settings # Get phone number business profile Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-phone-number-business-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/phone_numbers/{phone_number}/profile # Get Whatsapp profile photo Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/get-whatsapp-profile-photo https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/phone_numbers/{phone_number}/profile/photo # Initialize Whatsapp phone number verification Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/initialize-whatsapp-phone-number-verification https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml post /whatsapp/business_accounts/{id}/phone_numbers # List Whatsapp phone numbers Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/list-whatsapp-phone-numbers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml get /whatsapp/phone_numbers # Resend verification code Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/resend-verification-code https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml post /whatsapp/phone_numbers/{phone_number}/resend_verification # Submit verification code for a phone number Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/submit-verification-code-for-a-phone-number https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml post /whatsapp/phone_numbers/{phone_number}/verify # Update phone number business profile Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/update-phone-number-business-profile https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml patch /whatsapp/phone_numbers/{phone_number}/profile # Upload Whatsapp profile photo Source: https://developers.telnyx.com/api-reference/whatsapp-phone-numbers/upload-whatsapp-profile-photo https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/whatsapp/management.yml post /whatsapp/phone_numbers/{phone_number}/profile/photo # Create a WireGuard Interface Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/create-a-wireguard-interface https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /wireguard_interfaces Create a new WireGuard Interface. Current limitation of 10 interfaces per user can be created. # Create a WireGuard Peer Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/create-a-wireguard-peer https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml post /wireguard_peers Create a new WireGuard Peer. Current limitation of 5 peers per interface can be created. # Delete a WireGuard Interface Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/delete-a-wireguard-interface https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /wireguard_interfaces/{id} Delete a WireGuard Interface. # Delete the WireGuard Peer Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/delete-the-wireguard-peer https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml delete /wireguard_peers/{id} Delete the WireGuard peer. # List all WireGuard Interfaces Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/list-all-wireguard-interfaces https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /wireguard_interfaces List all WireGuard Interfaces. # List all WireGuard Peers Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/list-all-wireguard-peers https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /wireguard_peers List all WireGuard peers. # Retrieve a WireGuard Interfaces Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/retrieve-a-wireguard-interfaces https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /wireguard_interfaces/{id} Retrieve a WireGuard Interfaces. # Retrieve the WireGuard Peer Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/retrieve-the-wireguard-peer https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /wireguard_peers/{id} Retrieve the WireGuard peer. # Retrieve Wireguard config template for Peer Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/retrieve-wireguard-config-template-for-peer https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml get /wireguard_peers/{id}/config Retrieve Wireguard config template for Peer # Update the WireGuard Peer Source: https://developers.telnyx.com/api-reference/wireguard-interfaces/update-the-wireguard-peer https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/networking/networking.yml patch /wireguard_peers/{id} Update the WireGuard peer. # Create a Wireless Blocklist Source: https://developers.telnyx.com/api-reference/wireless-blocklists/create-a-wireless-blocklist https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml post /wireless_blocklists Create a Wireless Blocklist to prevent SIMs from connecting to certain networks. # Delete a Wireless Blocklist Source: https://developers.telnyx.com/api-reference/wireless-blocklists/delete-a-wireless-blocklist https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml delete /wireless_blocklists/{id} Deletes the Wireless Blocklist. # Get a Wireless Blocklist Source: https://developers.telnyx.com/api-reference/wireless-blocklists/get-a-wireless-blocklist https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /wireless_blocklists/{id} Retrieve information about a Wireless Blocklist. # Get all possible wireless blocklist values Source: https://developers.telnyx.com/api-reference/wireless-blocklists/get-all-possible-wireless-blocklist-values https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /wireless_blocklist_values Retrieve all wireless blocklist values for a given blocklist type. # Get all Wireless Blocklists Source: https://developers.telnyx.com/api-reference/wireless-blocklists/get-all-wireless-blocklists https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml get /wireless_blocklists Get all Wireless Blocklists belonging to the user. # Update a Wireless Blocklist Source: https://developers.telnyx.com/api-reference/wireless-blocklists/update-a-wireless-blocklist https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/wireless/sim-cards-configuration.yml patch /wireless_blocklists/{id} Update a Wireless Blocklist. # Agent Skills Source: https://developers.telnyx.com/development/agent-skills/index Agent Skills enable Claude Code and other AI coding agents to build Telnyx integrations using natural language. They support all 36 Telnyx products including Messaging, Voice, Numbers, IoT, and AI. ## Installation Quickstart Choose your setup method: The Skills CLI works with Codex, Cursor, OpenClaw, Gemini CLI, GitHub Copilot, and more. ```bash theme={null} npx skills add team-telnyx/skills --skill --agent ``` **Example:** ```bash theme={null} npx skills add team-telnyx/skills --skill telnyx-voice-python --agent codex ``` ### Agent-specific commands ```bash theme={null} npx skills add team-telnyx/skills --skill --agent codex ``` ```bash theme={null} npx skills add team-telnyx/skills --skill --agent claude-code ``` ```bash theme={null} npx skills add team-telnyx/skills --skill --agent cursor ``` ```bash theme={null} npx skills add team-telnyx/skills --skill --agent openclaw ``` ```bash theme={null} npx skills add team-telnyx/skills --skill --agent gemini-cli ``` ```bash theme={null} 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 theme={null} /plugin marketplace add team-telnyx/skills ``` **Step 2.** Install a plugin: ```bash theme={null} /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 theme={null} /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 theme={null} 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. # API error codes Source: https://developers.telnyx.com/development/api-fundamentals/api-errors/index Comprehensive reference of all Telnyx API error codes with descriptions and solutions. When working with the Telnyx API, you may encounter various error codes. This page provides a complete reference of all error codes returned by the Telnyx API. | 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 and characters long, but was . | | 10026 | Invalid parameter type | The parameter must be of type , but 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\[] is invalid. | | 10032 | Invalid enumerated value | The value must be one of | | 10033 | Value outside of range | The value is outside of allowed range to | | 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](https://telnyx.com/upgrade). | | 10039 | Feature limited | A limit for this feature has been reached at this account level. See [https://telnyx.com/upgrade](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 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 to due to an existing block rule. | | 40301 | Unsupported message type for the 'to' address | Sending messages from to is currently unsupported. | | 40302 | Message too large | The SMS message would be divided into parts. The maximum is . | | 40303 | Message not found | The message with 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 does not match the one configured on the profile | | 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 for the destination 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 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 (with success rate and spam rejection rate ) 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 to is not possible. | | 40320 | Temporarily unusable 'from' address | The sending number 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. Messages over 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 | - | | 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 / and higher | | 50008 | Can not delete IP from source | Can not delete IP from 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 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 () 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' | # API Authentication Source: https://developers.telnyx.com/development/api-fundamentals/authentication/index Authentication methods and security best practices for all Telnyx APIs. 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 theme={null} 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 theme={null} // 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 # Create and Manage API Keys Source: https://developers.telnyx.com/development/api-fundamentals/create-api-keys/index Step-by-step guide to create, manage, and secure your Telnyx API keys for all services. 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 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 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 theme={null} 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 theme={null} curl -X GET \ --header "Authorization: Bearer YOUR_API_KEY" \ "https://api.telnyx.com/v2/endpoint" ``` ### SDKs ```javascript theme={null} // 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" ``` # Parameters & Field Names Source: https://developers.telnyx.com/development/api-fundamentals/data-standards/parameters-fields Comprehensive guide to Telnyx API parameter and field naming conventions, data types, and formatting standards. 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 theme={null} { "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 theme={null} HEADERS Total-Pages:13 ``` Response: ```json theme={null} { "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 theme={null} 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 theme={null} 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 theme={null} 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 theme={null} 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 theme={null} GET /phone_numbers?filter[tag][]=tag_one&filter[tag][]=tag_two HTTP/1.1 ``` Or an example using comments: ```bash theme={null} 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 theme={null} 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 theme={null} { "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 theme={null} GET /phone_numbers?filter[voice.connection_name]=conn_one HTTP/1.1 ``` Similarly by connection ID: ```bash theme={null} 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 theme={null} { "id": "d460a653-8pp6-4061-ae9a-5b8a57339fb4", "name": "conn_one", "record_type": "connection", ... } ``` then the query would be: ```bash theme={null} 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 theme={null} GET /phone_numbers?filter[purchased_at][lt]=2018-02-21 HTTP/1.1 ``` If using `eq` then: ```bash theme={null} GET /phone_numbers?filter[purchased_at][eq]=2018-02-21 HTTP/1.1 ``` and: ```bash theme={null} 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 theme={null} GET /phone_numbers?filter[voice.connection_name][contains]=conn HTTP/1.1 ``` # API Reliability & Retries Source: https://developers.telnyx.com/development/api-fundamentals/reliability/command-retries Best practices for handling API errors, implementing retries, and building resilient integrations across all Telnyx services. 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 # Rate Limiting Source: https://developers.telnyx.com/development/api-fundamentals/reliability/rate-limiting Understanding Telnyx API rate limits, headers, and best practices for handling rate limit responses across all services. 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 theme={null} { "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](mailto: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/index) and [Message Encoding](/docs/messaging/messages/message-encoding/index) for messaging-specific limits * **10DLC**: See [10DLC rate limits](/docs/messaging/10dlc/10dlc-rate-limits/index) for campaign-specific limits * **Voice API**: Standard API rate limits apply to call control endpoints * **Cloud Storage**: Rate limits apply to S3-compatible operations # Request & Response Handling Source: https://developers.telnyx.com/development/api-fundamentals/request-response/index Universal patterns for making requests and handling responses across all Telnyx APIs. 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 theme={null} 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 theme={null} 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 theme={null} PATCH /v2/messaging_profiles/{id} # Update profile PATCH /v2/phone_numbers/{id} # Update phone number settings ``` ### **DELETE** - Remove Resources Used to delete resources: ```bash theme={null} 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 theme={null} Content-Type: application/json ``` For file uploads or form data: ```bash theme={null} Content-Type: multipart/form-data Content-Type: application/x-www-form-urlencoded ``` ### Request Structure ```bash theme={null} 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 theme={null} { "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 theme={null} { "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](/development/api-fundamentals/api-errors/index). 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 theme={null} 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 theme={null} 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 theme={null} GET /v2/messages?page[number]=2&page[size]=50 ``` ### Response Metadata ```json theme={null} { "data": [...], "meta": { "page_number": 2, "page_size": 50, "total_pages": 10, "total_results": 500 } } ``` ## Filtering and Sorting ### Common Filter Patterns ```bash theme={null} # 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 # Webhook Fundamentals - Complete Guide to Telnyx Webhooks Source: https://developers.telnyx.com/development/api-fundamentals/webhooks/receiving-webhooks Learn how to receive, handle, and secure webhooks from Telnyx APIs. Complete guide covering setup, security, payload structure, and best practices for Voice, SMS, and Fax webhooks. 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/index) 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/index) section goes into a bit more detail on how SMS and MMS webhooks work. ## Universal Webhook Behavior Across all Telnyx services, webhooks follow consistent patterns: * **Primary/Failover URLs**: Webhooks are delivered to the primary URL specified in your application configuration. If that URL doesn't respond successfully, the webhook is sent to the failover URL (if configured) * **Response Requirements**: Your endpoint must return a 2xx HTTP status code to indicate successful receipt * **Retry Logic**: Failed webhook deliveries are automatically retried with exponential backoff ## 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](/development/development-tools/ngrok-setup/index). 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 To minimize webhook delivery time across all services, Telnyx: * **Does not guarantee delivery order**: Webhooks may arrive out of sequence * **Implements automatic retries**: Failed deliveries are retried with exponential backoff * **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 All Telnyx webhooks contain common identification fields: * **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 of the webhook will vary by product, but not by type of event received. For example, Voice API webhooks have a different top-level structure than Messaging webhooks however, the webhook structure across all Voice API commands is consistent. The `payload` of the webhook contains the most valuable information for your application. ### Voice API top-level structure ```json theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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, your endpoint should return a `2xx` HTTP status code. Any other information returned in the request headers or request body is ignored. All response codes outside this range, including `3xx` codes, will indicate to Telnyx that you did not receive the webhook. URL redirection or a "Not Modified" response will be treated as a failure. ## Retries Webhooks will be retried to each of the supplied URLs if your application does not respond in 2000 milliseconds. ## Best practices If your webhook script performs complex logic or makes network calls, it's possible the script would timeout before Telnyx sees its complete execution. For that reason, you may want to have your webhook endpoint immediately acknowledge receipt by returning a `2xx` HTTP status code, and then perform the rest of its duties. Webhook endpoints may occasionally receive the same event more than once. We advise you to guard against duplicated event receipts by making your event processing idempotent. One way of doing this is logging the events you've processed, and then not processing already-logged events. Additionally, we recommend verifying webhook signatures to confirm that received events are being sent from Telnyx. ## 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 theme={null} 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](/development/sdk) for implementation examples in your preferred language. # Scripting & Automation Source: https://developers.telnyx.com/development/cli/general-usage/index Output formats, filtering, and scripting with the Telnyx CLI 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 theme={null} telnyx phone-numbers list ``` ### JSON Format Machine-readable output for scripting and automation: ```bash theme={null} telnyx phone-numbers list --format json ``` ### YAML Format Human-readable structured output: ```bash theme={null} telnyx phone-numbers list --format yaml ``` ### Pretty Format Indented, colorized JSON: ```bash theme={null} telnyx phone-numbers list --format pretty ``` ### Raw Format Unformatted API response: ```bash theme={null} 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 theme={null} # 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 theme={null} # 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 theme={null} # 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 theme={null} # 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 theme={null} #!/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 theme={null} #!/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 theme={null} #!/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 theme={null} 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 theme={null} 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 *** # CLI Authentication Source: https://developers.telnyx.com/development/cli/getting-started/authentication Configure your API key for the Telnyx CLI The Telnyx CLI authenticates using an API key set via environment variable. ## Setting Your API Key Set the `TELNYX_API_KEY` environment variable: ```bash theme={null} 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 theme={null} 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 theme={null} # 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 theme={null} telnyx-prod phone-numbers list telnyx-staging phone-numbers list ``` ### Option 2: Separate Terminal Sessions Set different API keys in different terminal windows: ```bash theme={null} # 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 theme={null} TELNYX_API_KEY=KEY_other_xxx telnyx balance retrieve ``` ## CI/CD Integration ### GitHub Actions ```yaml theme={null} 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 theme={null} 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 theme={null} #!/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 *** # Install the Telnyx CLI Source: https://developers.telnyx.com/development/cli/getting-started/install Install the Telnyx CLI on macOS, Windows, or Linux 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 theme={null} 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 theme={null} # 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 theme={null} 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 theme={null} go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` ## Alternative: Run Without Installing You can run the CLI directly without installing: ```bash theme={null} 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 theme={null} ls $(go env GOPATH)/bin/telnyx ``` 2. Add Go bin to your PATH: ```bash theme={null} export PATH="$PATH:$(go env GOPATH)/bin" ``` 3. Reload your shell config: ```bash theme={null} 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 theme={null} go version ``` 2. Clear Go's module cache and retry: ```bash theme={null} 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 *** # Telnyx CLI Quickstart Source: https://developers.telnyx.com/development/cli/getting-started/quickstart Get up and running with the Telnyx CLI in 5 minutes 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 theme={null} go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` Ensure Go's bin directory is in your PATH: ```bash theme={null} export PATH="$PATH:$(go env GOPATH)/bin" ``` Verify the installation: ```bash theme={null} 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 theme={null} 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 theme={null} telnyx balance retrieve ``` You should see your account balance information. ## Step 3: Run Your First Commands ### Check Your Balance ```bash theme={null} telnyx balance retrieve ``` ### List Your Phone Numbers ```bash theme={null} telnyx phone-numbers list ``` ### Search for Available Numbers ```bash theme={null} 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 theme={null} telnyx messages send \ --from +15551234567 \ --to +15559876543 \ --text "Hello from the Telnyx CLI!" ``` ## Step 4: Explore Commands ### Get Help ```bash theme={null} # 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 theme={null} # 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 theme={null} telnyx phone-numbers list --debug ``` ## Next Steps Learn about authentication options Output formats, scripting, and CI/CD integration *** # Telnyx CLI Source: https://developers.telnyx.com/development/cli/index Command-line interface for Telnyx APIs 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](/development/sdks) 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 theme={null} # 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 theme={null} 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) # Legacy CLI Authentication Source: https://developers.telnyx.com/development/cli/legacy/authentication Configure API keys and manage multiple profiles in the legacy CLI **This CLI is deprecated.** The new [Telnyx CLI](/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 theme={null} telnyx auth setup ``` You'll be prompted to enter your API key. Configuration is stored in `~/.config/telnyx/config.json`. ### 2. Environment Variable ```bash theme={null} export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` ### 3. Command-Line Flag ```bash theme={null} telnyx number list --api-key KEY_xxxxxxxxxxxxx ``` ## Verify Authentication ```bash theme={null} 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 theme={null} telnyx auth setup --profile production telnyx auth setup --profile staging ``` ### List Profiles ```bash theme={null} telnyx profile list ``` ### Use a Profile ```bash theme={null} telnyx number list --profile production telnyx billing balance --profile staging ``` ### Set Default Profile ```bash theme={null} telnyx profile set-default production ``` ### Delete a Profile ```bash theme={null} telnyx profile delete staging ``` ## Configuration File The CLI stores configuration in `~/.config/telnyx/config.json`: ```json theme={null} { "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 # Legacy CLI (@telnyx/api-cli) Source: https://developers.telnyx.com/development/cli/legacy/index Documentation for the deprecated Node.js CLI **This CLI is deprecated.** The `@telnyx/api-cli` package is no longer actively maintained. For new projects, use the [Telnyx CLI (Go)](/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 # Install Legacy CLI Source: https://developers.telnyx.com/development/cli/legacy/install Install the legacy Node.js CLI (@telnyx/api-cli) **This CLI is deprecated.** For new projects, use the [current Telnyx CLI](/development/cli/getting-started/install) instead. ## Requirements The legacy CLI requires **Node.js 20 or later**. ## Installation Install globally via npm: ```bash theme={null} npm install -g @telnyx/api-cli ``` This makes the `telnyx` command available from any directory. ## Verify Installation ```bash theme={null} telnyx --version ``` Expected output: ``` @telnyx/api-cli/1.1.0 darwin-arm64 node-v20.10.0 ``` ## Update To update to the latest version: ```bash theme={null} npm update -g @telnyx/api-cli ``` ## Troubleshooting ### "command not found: telnyx" If the command isn't found after installation: 1. Verify it installed: ```bash theme={null} npm list -g @telnyx/api-cli ``` 2. Check npm's global bin is in your PATH: ```bash theme={null} npm config get prefix # Add /bin to your PATH if needed ``` 3. Restart your terminal or reload your shell config: ```bash theme={null} 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 # Legacy Command Reference Source: https://developers.telnyx.com/development/cli/legacy/reference Complete reference for legacy CLI commands (@telnyx/api-cli) **This CLI is deprecated.** For the current CLI commands, see [Command Reference](/development/cli/reference). ## Authentication & Profiles ```bash theme={null} 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 theme={null} # 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 theme={null} 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 theme={null} # 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 theme={null} telnyx message list telnyx message list --direction outbound --limit 50 telnyx message list --from +15551234567 telnyx message get ``` ### Messaging Profiles ```bash theme={null} 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 theme={null} 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 theme={null} 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 theme={null} 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 theme={null} telnyx 10dlc wizard # Guided setup wizard ``` ### Brand Management ```bash theme={null} telnyx 10dlc brand list telnyx 10dlc brand get telnyx 10dlc brand create --display-name "My Company" --entity-type PRIVATE_PROFIT ``` ### Campaign Management ```bash theme={null} telnyx 10dlc campaign list telnyx 10dlc campaign get telnyx 10dlc campaign create --brand-id --use-case MARKETING ``` ## Billing ```bash theme={null} telnyx billing balance # Check account balance ``` ## Verification ```bash theme={null} telnyx verify start +15551234567 --channel sms telnyx verify check --code 123456 ``` ## Shell Autocomplete ```bash theme={null} 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](/development/cli/legacy) for a command mapping to the new Go-based CLI. # Command Reference Source: https://developers.telnyx.com/development/cli/reference Complete reference for all Telnyx CLI commands 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 theme={null} --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 theme={null} # 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 theme={null} # 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 theme={null} # 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 theme={null} 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-message) for full payload options. ### Send Messages ```bash theme={null} # 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 theme={null} telnyx messages retrieve --id ``` ### Messaging Profiles ```bash theme={null} 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 theme={null} telnyx messaging-optouts list ``` ## 10DLC (US A2P Messaging) See [10DLC documentation](/docs/messaging/10dlc/quickstart) for registration requirements. ### Brands ```bash theme={null} # 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 theme={null} # 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 theme={null} telnyx messaging-10dlc:campaign:usecase list ``` ### Phone Number Campaigns ```bash theme={null} telnyx messaging-10dlc:phone-number-campaigns list telnyx messaging-10dlc:phone-number-campaigns retrieve --phone-number +15551234567 ``` ## Voice / Call Control See [Call Control API](/api-reference/call-control) for advanced call flow options. ### Make Calls ```bash theme={null} # 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 theme={null} telnyx calls retrieve-status --call-control-id ``` ### Call Actions ```bash theme={null} # 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 theme={null} 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 theme={null} 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 theme={null} 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 theme={null} telnyx ai:chat create-completion --model meta-llama/Meta-Llama-3.1-8B-Instruct \ --messages '[{"role": "user", "content": "Hello!"}]' ``` ### AI Assistants ```bash theme={null} # 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 theme={null} # 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 theme={null} telnyx ai:embeddings create --input "Your text here" --model text-embedding-ada-002 ``` ### Conversations ```bash theme={null} 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 theme={null} 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 theme={null} # 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 theme={null} telnyx verifications:actions verify --verification-id --code 123456 ``` ## Fax ```bash theme={null} # 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 theme={null} telnyx number-lookup retrieve --phone-number +15551234567 ``` ## Billing ```bash theme={null} # 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 theme={null} # 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 theme={null} # 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 theme={null} # Presigned URLs for upload/download telnyx storage:buckets create-presigned-url --bucket-name my-bucket --key my-file.txt ``` ## Video Rooms ```bash theme={null} # 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 theme={null} 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 theme={null} telnyx global-ips list telnyx global-ips create telnyx global-ips retrieve --id telnyx global-ips delete --id ``` ## Getting Help ```bash theme={null} 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 ``` *** # Troubleshooting Source: https://developers.telnyx.com/development/cli/troubleshooting Common issues and solutions for the Telnyx CLI 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](/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 theme={null} echo $TELNYX_API_KEY ``` 2. Check the key format (should start with `KEY_`): ```bash theme={null} # 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 theme={null} telnyx balance retrieve ``` ### "No API key" Error **Causes:** * Environment variable not set * Environment variable not exported **Solutions:** 1. Set the environment variable: ```bash theme={null} export TELNYX_API_KEY=KEY_xxxxxxxxxxxxx ``` 2. Verify it's exported (not just set): ```bash theme={null} # 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 theme={null} 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 theme={null} 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 theme={null} 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 theme={null} 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](/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 theme={null} 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 theme={null} # Wrong telnyx messages send --to 5551234567 ... # Correct telnyx messages send --to +15551234567 ... ``` 2. Verify the number is valid: ```bash theme={null} 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 theme={null} ls $(go env GOPATH)/bin/telnyx ``` 2. Add Go bin to PATH: ```bash theme={null} export PATH="$PATH:$(go env GOPATH)/bin" ``` 3. Reinstall if needed: ```bash theme={null} go install github.com/team-telnyx/telnyx-cli/cmd/telnyx@latest ``` 4. Reload your shell config: ```bash theme={null} source ~/.bashrc # or ~/.zshrc ``` ### "command not found: go" **Causes:** * Go not installed **Solutions:** Install Go: ```bash theme={null} # 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 theme={null} # macOS brew upgrade go # Or download latest from go.dev ``` ### Build/compile errors **Solutions:** 1. Ensure you have Go 1.22+: ```bash theme={null} go version ``` 2. Clear module cache and retry: ```bash theme={null} 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 theme={null} 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 theme={null} telnyx phone-numbers list --debug ``` ### Check CLI Version Ensure you're on the latest version: ```bash theme={null} 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) *** # How to Register for 10DLC via CLI Source: https://developers.telnyx.com/development/cli/workflows/10dlc Register your business for US A2P messaging using the Telnyx CLI 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](/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 theme={null} 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 theme={null} # 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 theme={null} # 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 theme={null} # 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/10dlc/create-campaign). The CLI supports retrieving and managing existing campaigns. ### Step 4: Manage Campaigns ```bash theme={null} # 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 theme={null} # 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 theme={null} # 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 theme={null} telnyx messaging-10dlc:campaign submit-appeal --campaign-id ``` ### Deactivate a Campaign ```bash theme={null} 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 theme={null} 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 theme={null} 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 theme={null} #!/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 *** # ngrok Source: https://developers.telnyx.com/development/development-tools/ngrok-setup/index Telnyx's ngrok setup guide allows developers to easily create secure tunnels to their local development environment. 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 theme={null} 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! # Telnyx Node-RED Source: https://developers.telnyx.com/development/development-tools/node-red/index **(aka `@telnyx/node-red-telnyx`)** | Field | Value | | ---------- | ---------------------------------- | | **Name** | `Node-RED` | | **Author** | `OpenJS Foundation & Contributors` | | **URL** | `https://nodered.org` | node-red-telnyx ## 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 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, we encourage users to reach out to us through the GitHub issue reporting platform of the [node-red-telnyx](https://github.com/team-telnyx/node-red-telnyx) repository, where they can report any issues or seek help with our open source projects. # Postman Setup Source: https://developers.telnyx.com/development/development-tools/postman-setup/index Postman Setup for using Telnyx APIs 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 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 5. Go to Environments tab on the left and select `Telnyx Environment` Postman Environment 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 **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 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 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 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 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](/development/development-tools/postman-setup/collections-list) # Development Source: https://developers.telnyx.com/development/index Essential tools, SDKs, and resources for building with Telnyx APIs and services. ## 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](/development/mcp/local-mcp/index). ## Need product-specific guides? Looking for AI, Voice, or Messaging docs? Explore our product tabs above. # Development llms-full.txt Source: https://developers.telnyx.com/development/llms-txt-full/index Complete machine-readable documentation for AI agents and LLMs — Development # Development llms-full.txt The complete Development documentation in a single machine-readable file, following the [llms.txt convention](https://llmstxt.org/). **→ [Download llms-full.txt](/development/llms-full.txt)** This file contains the full content of all Development documentation pages — use it when you need actual implementation details without following individual URLs. For a lightweight index with links only, see [Development llms.txt](/development/llms.txt). For other products, see the [main documentation index](/llms.txt). # Development llms.txt Source: https://developers.telnyx.com/development/llms-txt/index Machine-readable documentation index for AI agents and LLMs — Development # Development llms.txt A concise, machine-readable index of all Development documentation, following the [llms.txt convention](https://llmstxt.org/). **→ [Download llms.txt](/development/llms.txt)** This file lists every Development documentation page with a brief description and link, designed for LLMs and AI agents to quickly discover what's available. For the complete documentation content, see [Development llms-full.txt](/development/llms-full.txt). For other products, see the [main documentation index](/llms.txt). # Telnyx Local Model Context Protocol (MCP) Server Source: https://developers.telnyx.com/development/mcp/local-mcp/index Integrate Telnyx services with Claude and other AI assistants. 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 1. Get your API key from the Telnyx Portal. 2. Install `uvx` (Python package manager), install with `curl -LsSf https://astral.sh/uv/install.sh | sh` , `brew install uv` or see the `uv` repo for additional install methods. 3. Go to Claude > Settings > Developer > Edit Config > claude\_desktop\_config.json to include the following: ```json theme={null} { "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 1. Get your API key from the Telnyx Portal. 2. Install `uvx` (Python package manager), install with `curl -LsSf https://astral.sh/uv/install.sh | sh` , `brew install uv` or see the `uv` repo for additional install methods. 3. **Clone the Git Repository**\ Use Git to download the Telnyx MCP Server locally: ```bash theme={null} git clone https://github.com/team-telnyx/telnyx-mcp-server.git cd telnyx-mcp-server ``` 4. **Configure and Run with uvx**\ In your Claude config, you can reference the local folder by using the `--from` argument. For example: ```json theme={null} { "mcpServers": { "Telnyx": { "command": "uvx", "args": ["--from", "/path/to/telnyx-mcp-server", "telnyx-mcp-server"], "env": { "TELNYX_API_KEY": "" } } } } ``` 5. This instructs Claude to run the server from the folder you cloned. Replace "/path/to/telnyx-mcp-server" with the actual location of the repository. ## 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" * "Send a WhatsApp template message to +18005551234 using the order\_confirmation template" * "List my WhatsApp message templates and show which ones are approved" * "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](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 [github.com/team-telnyx/telnyx-mcp-server](https://github.com/team-telnyx/telnyx-mcp-server) for more information. # Telnyx Remote Model Context Protocol (MCP) Source: https://developers.telnyx.com/development/mcp/remote-mcp/index Integrate Telnyx services with Claude and other AI assistants without running a local MCP server. ## Quickstart with Claude Desktop ### Connect via Portal Requires a Claude or Claude Desktop plan with access to Custom Connectors. Go to Claude > Settings > Connectors Claude Desktop Step 1 Claude Desktop Step 2 Claude Desktop Step 3 Grant access in the Telnyx Portal (must be logged in) Claude Desktop Step 4 Claude Desktop Step 5 For information previously shared on this page regarding connecting to our legacy MCP server, [see the legacy guide](/development/mcp/remote-mcp/legacy/index). # Call Control migration to Voice API Source: https://developers.telnyx.com/development/migration/call-control-migration-guide/index Telnyx's call control migration guide will help you transition from our v1 API to v2. The guide outlines the differences between the two APIs and provides tips for migrating your code. 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 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 theme={null} { "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 theme={null} { "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 #### 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](/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 to SMS/MMS API Source: https://developers.telnyx.com/development/migration/messaging-migration-guide/index Telnyx provides developers with an easy to follow messaging migration guide when upgrading from Api v1 to Api v2. The guide covers all aspects of the migration process, including the differences between the two APIs and how to migrate your code. 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](/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 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 theme={null} { "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 theme={null} { "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 #### 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](/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 Guide Source: https://developers.telnyx.com/development/migration/twilio-migration-guide/index Telnyx's Programmable Fax system for migrating from Twilio. Start building on Telnyx today. \| [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/index) 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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} 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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} $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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} 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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} $ 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 theme={null} 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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/index) 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 theme={null} { "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 theme={null} 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 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 theme={null} { "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 theme={null} { "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 theme={null} { "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 theme={null} { "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/" } } ``` # Go SDK Source: https://developers.telnyx.com/development/sdk/golang/index The official Telnyx Go library for server-side applications. # Telnyx Go API Library

Go Reference

The Telnyx Go library provides convenient access to the Telnyx REST API from applications written in Go. It is generated with [Stainless](https://www.stainless.com/). ## Installation ```go theme={null} import ( "github.com/team-telnyx/telnyx-go" // imported as telnyx ) ``` Or to pin the version: ```sh theme={null} go get -u 'github.com/team-telnyx/telnyx-go@v0.0.1' ``` ## Requirements This library requires Go 1.22+. ## Usage The full API of this library can be found in [api.md](https://github.com/team-telnyx/telnyx-go/tree/master/api.md). ```go theme={null} package main import ( "context" "fmt" "github.com/team-telnyx/telnyx-go" "github.com/team-telnyx/telnyx-go/option" ) func main() { client := telnyx.NewClient( option.WithAPIKey("My API Key"), // defaults to os.LookupEnv("TELNYX_API_KEY") ) response, err := client.Calls.Dial(context.TODO(), telnyx.CallDialParams{ ConnectionID: "conn12345", From: "+15557654321", To: telnyx.CallDialParamsToUnion{ OfString: telnyx.String("+15551234567"), }, WebhookURL: telnyx.String("https://your-webhook.url/events"), }) if err != nil { panic(err.Error()) } fmt.Printf("%+v\n", response.Data) } ``` ### Request fields The telnyx library uses the [`omitzero`](https://tip.golang.org/doc/go1.24#encodingjsonpkgencodingjson) semantics from the Go 1.24+ `encoding/json` release for request fields. Required primitive fields (`int64`, `string`, etc.) feature the tag \`json:"...,required"\`. These fields are always serialized, even their zero values. Optional primitive types are wrapped in a `param.Opt[T]`. These fields can be set with the provided constructors, `telnyx.String(string)`, `telnyx.Int(int64)`, etc. Any `param.Opt[T]`, map, slice, struct or string enum uses the tag \`json:"...,omitzero"\`. Its zero value is considered omitted. The `param.IsOmitted(any)` function can confirm the presence of any `omitzero` field. ```go theme={null} p := telnyx.ExampleParams{ ID: "id_xxx", // required property Name: telnyx.String("..."), // optional property Point: telnyx.Point{ X: 0, // required field will serialize as 0 Y: telnyx.Int(1), // optional field will serialize as 1 // ... omitted non-required fields will not be serialized }, Origin: telnyx.Origin{}, // the zero value of [Origin] is considered omitted } ``` To send `null` instead of a `param.Opt[T]`, use `param.Null[T]()`. To send `null` instead of a struct `T`, use `param.NullStruct[T]()`. ```go theme={null} p.Name = param.Null[string]() // 'null' instead of string p.Point = param.NullStruct[Point]() // 'null' instead of struct param.IsNull(p.Name) // true param.IsNull(p.Point) // true ``` Request structs contain a `.SetExtraFields(map[string]any)` method which can send non-conforming fields in the request body. Extra fields overwrite any struct fields with a matching key. For security reasons, only use `SetExtraFields` with trusted data. To send a custom value instead of a struct, use `param.Override[T](https://github.com/team-telnyx/telnyx-go/tree/master/value)`. ```go theme={null} // In cases where the API specifies a given type, // but you want to send something else, use [SetExtraFields]: p.SetExtraFields(map[string]any{ "x": 0.01, // send "x" as a float instead of int }) // Send a number instead of an object custom := param.Override[telnyx.FooParams](https://github.com/team-telnyx/telnyx-go/tree/master/12) ``` ### Request unions Unions are represented as a struct with fields prefixed by "Of" for each of it's variants, only one field can be non-zero. The non-zero field will be serialized. Sub-properties of the union can be accessed via methods on the union struct. These methods return a mutable pointer to the underlying data, if present. ```go theme={null} // Only one field can be non-zero, use param.IsOmitted() to check if a field is set type AnimalUnionParam struct { OfCat *Cat `json:",omitzero,inline` OfDog *Dog `json:",omitzero,inline` } animal := AnimalUnionParam{ OfCat: &Cat{ Name: "Whiskers", Owner: PersonParam{ Address: AddressParam{Street: "3333 Coyote Hill Rd", Zip: 0}, }, }, } // Mutating a field if address := animal.GetOwner().GetAddress(); address != nil { address.ZipCode = 94304 } ``` ### Response objects All fields in response structs are ordinary value types (not pointers or wrappers). Response structs also include a special `JSON` field containing metadata about each property. ```go theme={null} type Animal struct { Name string `json:"name,nullable"` Owners int `json:"owners"` Age int `json:"age"` JSON struct { Name respjson.Field Owner respjson.Field Age respjson.Field ExtraFields map[string]respjson.Field } `json:"-"` } ``` To handle optional data, use the `.Valid()` method on the JSON field. `.Valid()` returns true if a field is not `null`, not present, or couldn't be marshaled. If `.Valid()` is false, the corresponding field will simply be its zero value. ```go theme={null} raw := `{"owners": 1, "name": null}` var res Animal json.Unmarshal([]byte(raw), &res) // Accessing regular fields res.Owners // 1 res.Name // "" res.Age // 0 // Optional field checks res.JSON.Owners.Valid() // true res.JSON.Name.Valid() // false res.JSON.Age.Valid() // false // Raw JSON values res.JSON.Owners.Raw() // "1" res.JSON.Name.Raw() == "null" // true res.JSON.Name.Raw() == respjson.Null // true res.JSON.Age.Raw() == "" // true res.JSON.Age.Raw() == respjson.Omitted // true ``` These `.JSON` structs also include an `ExtraFields` map containing any properties in the json response that were not specified in the struct. This can be useful for API features not yet present in the SDK. ```go theme={null} body := res.JSON.ExtraFields["my_unexpected_field"].Raw() ``` ### Response Unions In responses, unions are represented by a flattened struct containing all possible fields from each of the object variants. To convert it to a variant use the `.AsFooVariant()` method or the `.AsAny()` method if present. If a response value union contains primitive values, primitive fields will be alongside the properties but prefixed with `Of` and feature the tag `json:"...,inline"`. ```go theme={null} type AnimalUnion struct { // From variants [Dog], [Cat] Owner Person `json:"owner"` // From variant [Dog] DogBreed string `json:"dog_breed"` // From variant [Cat] CatBreed string `json:"cat_breed"` // ... JSON struct { Owner respjson.Field // ... } `json:"-"` } // If animal variant if animal.Owner.Address.ZipCode == "" { panic("missing zip code") } // Switch on the variant switch variant := animal.AsAny().(type) { case Dog: case Cat: default: panic("unexpected type") } ``` ### RequestOptions This library uses the functional options pattern. Functions defined in the `option` package return a `RequestOption`, which is a closure that mutates a `RequestConfig`. These options can be supplied to the client or at individual requests. For example: ```go theme={null} client := telnyx.NewClient( // Adds a header to every request made by the client option.WithHeader("X-Some-Header", "custom_header_info"), ) client.NumberOrders.New(context.TODO(), ..., // Override the header option.WithHeader("X-Some-Header", "some_other_custom_header_info"), // Add an undocumented field to the request body, using sjson syntax option.WithJSONSet("some.json.path", map[string]string{"my": "object"}), ) ``` The request option `option.WithDebugLog(nil)` may be helpful while debugging. See the [full list of request options](https://pkg.go.dev/github.com/team-telnyx/telnyx-go/option). ### Pagination This library provides some conveniences for working with paginated list endpoints. You can use `.ListAutoPaging()` methods to iterate through items across all pages: Or you can use simple `.List()` methods to fetch a single page and receive a standard response object with additional helper methods like `.GetNextPage()`, e.g.: ### Errors When the API returns a non-success status code, we return an error with type `*telnyx.Error`. This contains the `StatusCode`, `*http.Request`, and `*http.Response` values of the request, as well as the JSON of the error body (much like other response objects in the SDK). To handle errors, we recommend that you use the `errors.As` pattern: ```go theme={null} _, err := client.NumberOrders.New(context.TODO(), telnyx.NumberOrderNewParams{ PhoneNumbers: []telnyx.NumberOrderNewParamsPhoneNumber{{ PhoneNumber: "+15558675309", }}, }) if err != nil { var apierr *telnyx.Error if errors.As(err, &apierr) { println(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request println(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response } panic(err.Error()) // GET "/number_orders": 400 Bad Request { ... } } ``` When other errors occur, they are returned unwrapped; for example, if HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`. ### Timeouts Requests do not time out by default; use context to configure a timeout for a request lifecycle. Note that if a request is [retried](#retries), the context timeout does not start over. To set a per-retry timeout, use `option.WithRequestTimeout()`. ```go theme={null} // This sets the timeout for the request, including all the retries. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() client.NumberOrders.New( ctx, telnyx.NumberOrderNewParams{ PhoneNumbers: []telnyx.NumberOrderNewParamsPhoneNumber{{ PhoneNumber: "+15558675309", }}, }, // This sets the per-retry timeout option.WithRequestTimeout(20*time.Second), ) ``` ### File uploads Request parameters that correspond to file uploads in multipart requests are typed as `io.Reader`. The contents of the `io.Reader` will by default be sent as a multipart form part with the file name of "anonymous\_file" and content-type of "application/octet-stream". The file name and content-type can be customized by implementing `Name() string` or `ContentType() string` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a file returned by `os.Open` will be sent with the file name on disk. We also provide a helper `telnyx.File(reader io.Reader, filename string, contentType string)` which can be used to wrap any `io.Reader` with the appropriate file name and content type. ```go theme={null} // A file from the file system file, err := os.Open("/path/to/file") telnyx.AIAudioTranscribeParams{ Model: telnyx.AIAudioTranscribeParamsModelDistilWhisperDistilLargeV2, File: file, } // A file from a string telnyx.AIAudioTranscribeParams{ Model: telnyx.AIAudioTranscribeParamsModelDistilWhisperDistilLargeV2, File: strings.NewReader("my file contents"), } // With a custom filename and contentType telnyx.AIAudioTranscribeParams{ Model: telnyx.AIAudioTranscribeParamsModelDistilWhisperDistilLargeV2, File: telnyx.File(strings.NewReader(`{"hello": "foo"}`), "file.go", "application/json"), } ``` ### Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. We retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors. You can use the `WithMaxRetries` option to configure or disable this: ```go theme={null} // Configure the default for all requests: client := telnyx.NewClient( option.WithMaxRetries(0), // default is 2 ) // Override per-request: client.NumberOrders.New( context.TODO(), telnyx.NumberOrderNewParams{ PhoneNumbers: []telnyx.NumberOrderNewParamsPhoneNumber{{ PhoneNumber: "+15558675309", }}, }, option.WithMaxRetries(5), ) ``` ### Accessing raw response data (e.g. response headers) You can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when you need to examine response headers, status codes, or other details. ```go theme={null} // Create a variable to store the HTTP response var response *http.Response numberOrder, err := client.NumberOrders.New( context.TODO(), telnyx.NumberOrderNewParams{ PhoneNumbers: []telnyx.NumberOrderNewParamsPhoneNumber{{ PhoneNumber: "+15558675309", }}, }, option.WithResponseInto(&response), ) if err != nil { // handle error } fmt.Printf("%+v\n", numberOrder) fmt.Printf("Status Code: %d\n", response.StatusCode) fmt.Printf("Headers: %+#v\n", response.Header) ``` ### Making custom/undocumented requests This library is typed for convenient access to the documented API. If you need to access undocumented endpoints, params, or response properties, the library can still be used. #### Undocumented endpoints To make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs. `RequestOptions` on the client, such as retries, will be respected when making these requests. ```go theme={null} var ( // params can be an io.Reader, a []byte, an encoding/json serializable object, // or a "…Params" struct defined in this library. params map[string]any // result can be an []byte, *http.Response, a encoding/json deserializable object, // or a model defined in this library. result *http.Response ) err := client.Post(context.Background(), "/unspecified", params, &result) if err != nil { … } ``` #### Undocumented request params To make requests using undocumented parameters, you may use either the `option.WithQuerySet()` or the `option.WithJSONSet()` methods. ```go theme={null} params := FooNewParams{ ID: "id_xxxx", Data: FooNewParamsData{ FirstName: telnyx.String("John"), }, } client.Foo.New(context.Background(), params, option.WithJSONSet("data.last_name", "Doe")) ``` #### Undocumented response properties To access undocumented response properties, you may either access the raw JSON of the response as a string with `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with `result.JSON.Foo.Raw()`. Any fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`. ### Middleware We provide `option.WithMiddleware` which applies the given middleware to requests. ```go theme={null} func Logger(req *http.Request, next option.MiddlewareNext) (res *http.Response, err error) { // Before the request start := time.Now() LogReq(req) // Forward the request to the next handler res, err = next(req) // Handle stuff after the request end := time.Now() LogRes(res, err, start - end) return res, err } client := telnyx.NewClient( option.WithMiddleware(Logger), ) ``` When multiple middlewares are provided as variadic arguments, the middlewares are applied left to right. If `option.WithMiddleware` is given multiple times, for example first in the client then the method, the middleware in the client will run first and the middleware given in the method will run next. You may also replace the default `http.Client` with `option.WithHTTPClient(client)`. Only one http client is accepted (this overwrites any previous client) and receives requests after any middleware has been applied. ## Semantic versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes to library internals which are technically public but not intended or documented for external use. *(Please open a GitHub issue to let us know if you are relying on such internals.)* 2. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. We are keen for your feedback; please open an [issue](https://www.github.com/team-telnyx/telnyx-go/issues) with questions, bugs, or suggestions. ## Contributing See [the contributing documentation](https://github.com/team-telnyx/telnyx-go/tree/master/./CONTRIBUTING.md). # Java SDK Source: https://developers.telnyx.com/development/sdk/java/index The official Telnyx Java library for server-side applications. # Telnyx Java API Library Maven Central javadoc The Telnyx Java SDK provides convenient access to the Telnyx REST API from applications written in Java. It is generated with [Stainless](https://www.stainless.com/). Javadocs are available on [javadoc.io](https://javadoc.io/doc/com.telnyx.sdk/telnyx-java/5.0.0). ## Installation ### Gradle ```kotlin theme={null} implementation("com.telnyx.sdk:telnyx-java:5.0.0") ``` ### Maven ```xml theme={null} com.telnyx.sdk telnyx-java 5.0.0 ``` ## Requirements This library requires Java 8 or later. ## Usage ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; import com.telnyx.sdk.models.calls.CallDialParams; import com.telnyx.sdk.models.calls.CallDialResponse; // Configures using the `telnyx.apiKey` and `telnyx.baseUrl` system properties // Or configures using the `TELNYX_API_KEY` and `TELNYX_BASE_URL` environment variables TelnyxClient client = TelnyxOkHttpClient.fromEnv(); CallDialParams params = CallDialParams.builder() .connectionId("conn12345") .from("+15557654321") .to("+15551234567") .webhookUrl("https://your-webhook.url/events") .build(); CallDialResponse response = client.calls().dial(params); ``` ## Client configuration Configure the client using system properties or environment variables: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; // Configures using the `telnyx.apiKey` and `telnyx.baseUrl` system properties // Or configures using the `TELNYX_API_KEY` and `TELNYX_BASE_URL` environment variables TelnyxClient client = TelnyxOkHttpClient.fromEnv(); ``` Or manually: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; TelnyxClient client = TelnyxOkHttpClient.builder() .apiKey("My API Key") .build(); ``` Or using a combination of the two approaches: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; TelnyxClient client = TelnyxOkHttpClient.builder() // Configures using the `telnyx.apiKey` and `telnyx.baseUrl` system properties // Or configures using the `TELNYX_API_KEY` and `TELNYX_BASE_URL` environment variables .fromEnv() .apiKey("My API Key") .build(); ``` See this table for the available options: | Setter | System property | Environment variable | Required | Default value | | --------- | ---------------- | -------------------- | -------- | ----------------------------- | | `apiKey` | `telnyx.apiKey` | `TELNYX_API_KEY` | true | - | | `baseUrl` | `telnyx.baseUrl` | `TELNYX_BASE_URL` | true | `"https://api.telnyx.com/v2"` | System properties take precedence over environment variables. > \[!TIP] > Don't create more than one client in the same application. Each client has a connection pool and > thread pools, which are more efficient to share between requests. ### Modifying configuration To temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; TelnyxClient clientWithOptions = client.withOptions(optionsBuilder -> { optionsBuilder.baseUrl("https://example.com"); optionsBuilder.maxRetries(42); }); ``` The `withOptions()` method does not affect the original client or service. ## Requests and responses To send a request to the Telnyx API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class. For example, `client.calls().dial(...)` should be called with an instance of `CallDialParams`, and it will return an instance of `CallDialResponse`. ## Immutability Each class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it. Each class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy. Because each class is immutable, builder modification will *never* affect already built class instances. ## Asynchronous execution The default client is synchronous. To switch to asynchronous execution, call the `async()` method: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; import com.telnyx.sdk.models.calls.CallDialParams; import com.telnyx.sdk.models.calls.CallDialResponse; import java.util.concurrent.CompletableFuture; // Configures using the `telnyx.apiKey` and `telnyx.baseUrl` system properties // Or configures using the `TELNYX_API_KEY` and `TELNYX_BASE_URL` environment variables TelnyxClient client = TelnyxOkHttpClient.fromEnv(); CallDialParams params = CallDialParams.builder() .connectionId("conn12345") .from("+15557654321") .to("+15551234567") .webhookUrl("https://your-webhook.url/events") .build(); CompletableFuture response = client.async().calls().dial(params); ``` Or create an asynchronous client from the beginning: ```java theme={null} import com.telnyx.sdk.client.TelnyxClientAsync; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClientAsync; import com.telnyx.sdk.models.calls.CallDialParams; import com.telnyx.sdk.models.calls.CallDialResponse; import java.util.concurrent.CompletableFuture; // Configures using the `telnyx.apiKey` and `telnyx.baseUrl` system properties // Or configures using the `TELNYX_API_KEY` and `TELNYX_BASE_URL` environment variables TelnyxClientAsync client = TelnyxOkHttpClientAsync.fromEnv(); CallDialParams params = CallDialParams.builder() .connectionId("conn12345") .from("+15557654321") .to("+15551234567") .webhookUrl("https://your-webhook.url/events") .build(); CompletableFuture response = client.calls().dial(params); ``` The asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s. ## File uploads The SDK defines methods that accept files. To upload a file, pass a [`Path`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html): ```java theme={null} import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams; import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse; import java.nio.file.Paths; AudioTranscribeParams params = AudioTranscribeParams.builder() .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2) .file(Paths.get("/path/to/file")) .build(); AudioTranscribeResponse response = client.ai().audio().transcribe(params); ``` Or an arbitrary [`InputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/InputStream.html): ```java theme={null} import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams; import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse; import java.net.URL; AudioTranscribeParams params = AudioTranscribeParams.builder() .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2) .file(new URL("https://example.com//path/to/file").openStream()) .build(); AudioTranscribeResponse response = client.ai().audio().transcribe(params); ``` Or a `byte[]` array: ```java theme={null} import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams; import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse; AudioTranscribeParams params = AudioTranscribeParams.builder() .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2) .file("content".getBytes()) .build(); AudioTranscribeResponse response = client.ai().audio().transcribe(params); ``` Note that when passing a non-`Path` its filename is unknown so it will not be included in the request. To manually set a filename, pass a [`MultipartField`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/Values.kt): ```java theme={null} import com.telnyx.sdk.core.MultipartField; import com.telnyx.sdk.models.ai.audio.AudioTranscribeParams; import com.telnyx.sdk.models.ai.audio.AudioTranscribeResponse; import java.io.InputStream; import java.net.URL; AudioTranscribeParams params = AudioTranscribeParams.builder() .model(AudioTranscribeParams.Model.DISTIL_WHISPER_DISTIL_LARGE_V2) .file(MultipartField.builder() .value(new URL("https://example.com//path/to/file").openStream()) .filename("/path/to/file") .build()) .build(); AudioTranscribeResponse response = client.ai().audio().transcribe(params); ``` ## Binary responses The SDK defines methods that return binary responses, which are used for API responses that shouldn't necessarily be parsed, like non-JSON data. These methods return [`HttpResponse`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/http/HttpResponse.kt): ```java theme={null} import com.telnyx.sdk.core.http.HttpResponse; import com.telnyx.sdk.models.documents.DocumentDownloadParams; HttpResponse response = client.documents().download("6a09cdc3-8948-47f0-aa62-74ac943d6c58"); ``` To save the response content to a file, use the [`Files.copy(...)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#copy-java.io.InputStream-java.nio.file.Path-java.nio.file.CopyOption...-) method: ```java theme={null} import com.telnyx.sdk.core.http.HttpResponse; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; try (HttpResponse response = client.documents().download(params)) { Files.copy( response.body(), Paths.get(path), StandardCopyOption.REPLACE_EXISTING ); } catch (Exception e) { System.out.println("Something went wrong!"); throw new RuntimeException(e); } ``` Or transfer the response content to any [`OutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html): ```java theme={null} import com.telnyx.sdk.core.http.HttpResponse; import java.nio.file.Files; import java.nio.file.Paths; try (HttpResponse response = client.documents().download(params)) { response.body().transferTo(Files.newOutputStream(Paths.get(path))); } catch (Exception e) { System.out.println("Something went wrong!"); throw new RuntimeException(e); } ``` ## Raw responses The SDK defines methods that deserialize responses into instances of Java classes. However, these methods don't provide access to the response headers, status code, or the raw response body. To access this data, prefix any HTTP method call on a client or service with `withRawResponse()`: ```java theme={null} import com.telnyx.sdk.core.http.Headers; import com.telnyx.sdk.core.http.HttpResponseFor; import com.telnyx.sdk.models.numberorders.NumberOrderCreateParams; import com.telnyx.sdk.models.numberorders.NumberOrderCreateResponse; NumberOrderCreateParams params = NumberOrderCreateParams.builder() .addPhoneNumber(NumberOrderCreateParams.PhoneNumber.builder() .phoneNumber("+15558675309") .build()) .build(); HttpResponseFor numberOrder = client.numberOrders().withRawResponse().create(params); int statusCode = numberOrder.statusCode(); Headers headers = numberOrder.headers(); ``` You can still deserialize the response into an instance of a Java class if needed: ```java theme={null} import com.telnyx.sdk.models.numberorders.NumberOrderCreateResponse; NumberOrderCreateResponse parsedNumberOrder = numberOrder.parse(); ``` ## Error handling The SDK throws custom unchecked exception types: * [`TelnyxServiceException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code: | Status | Exception | | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 400 | [`BadRequestException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/BadRequestException.kt) | | 401 | [`UnauthorizedException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/UnauthorizedException.kt) | | 403 | [`PermissionDeniedException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/PermissionDeniedException.kt) | | 404 | [`NotFoundException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/NotFoundException.kt) | | 422 | [`UnprocessableEntityException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/UnprocessableEntityException.kt) | | 429 | [`RateLimitException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/RateLimitException.kt) | | 5xx | [`InternalServerException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/InternalServerException.kt) | | others | [`UnexpectedStatusCodeException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/UnexpectedStatusCodeException.kt) | * [`TelnyxIoException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxIoException.kt): I/O networking errors. * [`TelnyxRetryableException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxRetryableException.kt): Generic error indicating a failure that could be retried by the client. * [`TelnyxInvalidDataException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that's supposed to be required, but the API unexpectedly omitted it from the response. * [`TelnyxException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class. ## Logging The SDK uses the standard [OkHttp logging interceptor](https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor). Enable logging by setting the `TELNYX_LOG` environment variable to `info`: ```sh theme={null} $ export TELNYX_LOG=info ``` Or to `debug` for more verbose logging: ```sh theme={null} $ export TELNYX_LOG=debug ``` ## ProGuard and R8 Although the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `telnyx-java-core` is published with a [configuration file](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/resources/META-INF/proguard/telnyx-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage). ProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary. ## Jackson The SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default. The SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config). If the SDK threw an exception, but you're *certain* the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`TelnyxOkHttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClient.kt) or [`TelnyxOkHttpClientAsync`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClientAsync.kt). > \[!CAUTION] > We make no guarantee that the SDK works correctly when the Jackson version check is disabled. ## Network options ### Retries The SDK automatically retries 2 times by default, with a short exponential backoff between requests. Only the following error types are retried: * Connection errors (for example, due to a network connectivity problem) * 408 Request Timeout * 409 Conflict * 429 Rate Limit * 5xx Internal The API may also explicitly instruct the SDK to retry or not retry a request. To set a custom number of retries, configure the client using the `maxRetries` method: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; TelnyxClient client = TelnyxOkHttpClient.builder() .fromEnv() .maxRetries(4) .build(); ``` ### Timeouts Requests time out after 1 minute by default. To set a custom timeout, configure the method call using the `timeout` method: ```java theme={null} import com.telnyx.sdk.models.calls.CallDialResponse; CallDialResponse response = client.calls().dial( params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build() ); ``` Or configure the default for all method calls at the client level: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; import java.time.Duration; TelnyxClient client = TelnyxOkHttpClient.builder() .fromEnv() .timeout(Duration.ofSeconds(30)) .build(); ``` ### Proxies To route requests through a proxy, configure the client using the `proxy` method: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; import java.net.InetSocketAddress; import java.net.Proxy; TelnyxClient client = TelnyxOkHttpClient.builder() .fromEnv() .proxy(new Proxy( Proxy.Type.HTTP, new InetSocketAddress( "https://example.com", 8080 ) )) .build(); ``` ### HTTPS > \[!NOTE] > Most applications should not call these methods, and instead use the system defaults. The defaults include > special optimizations that can be lost if the implementations are modified. To configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; TelnyxClient client = TelnyxOkHttpClient.builder() .fromEnv() // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa. .sslSocketFactory(yourSSLSocketFactory) .trustManager(yourTrustManager) .hostnameVerifier(yourHostnameVerifier) .build(); ``` ### Custom HTTP client The SDK consists of three artifacts: * `telnyx-java-core` * Contains core SDK logic * Does not depend on [OkHttp](https://square.github.io/okhttp) * Exposes [`TelnyxClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClient.kt), [`TelnyxClientAsync`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientAsync.kt), [`TelnyxClientImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientImpl.kt), and [`TelnyxClientAsyncImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientAsyncImpl.kt), all of which can work with any HTTP client * `telnyx-java-client-okhttp` * Depends on [OkHttp](https://square.github.io/okhttp) * Exposes [`TelnyxOkHttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClient.kt) and [`TelnyxOkHttpClientAsync`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClientAsync.kt), which provide a way to construct [`TelnyxClientImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientImpl.kt) and [`TelnyxClientAsyncImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientAsyncImpl.kt), respectively, using OkHttp * `telnyx-java` * Depends on and exposes the APIs of both `telnyx-java-core` and `telnyx-java-client-okhttp` * Does not have its own logic This structure allows replacing the SDK's default HTTP client without pulling in unnecessary dependencies. #### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html) > \[!TIP] > Try the available [network options](#network-options) before replacing the default client. To use a customized `OkHttpClient`: 1. Replace your [`telnyx-java` dependency](#installation) with `telnyx-java-core` 2. Copy `telnyx-java-client-okhttp`'s [`OkHttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/OkHttpClient.kt) class into your code and customize it 3. Construct [`TelnyxClientImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientImpl.kt) or [`TelnyxClientAsyncImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientAsyncImpl.kt), similarly to [`TelnyxOkHttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClient.kt) or [`TelnyxOkHttpClientAsync`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClientAsync.kt), using your customized client ### Completely custom HTTP client To use a completely custom HTTP client: 1. Replace your [`telnyx-java` dependency](#installation) with `telnyx-java-core` 2. Write a class that implements the [`HttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/http/HttpClient.kt) interface 3. Construct [`TelnyxClientImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientImpl.kt) or [`TelnyxClientAsyncImpl`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/client/TelnyxClientAsyncImpl.kt), similarly to [`TelnyxOkHttpClient`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClient.kt) or [`TelnyxOkHttpClientAsync`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-client-okhttp/src/main/kotlin/com/telnyx/sdk/client/okhttp/TelnyxOkHttpClientAsync.kt), using your new client class ## Undocumented API functionality The SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API. ### Parameters To set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class: ```java theme={null} import com.telnyx.sdk.core.JsonValue; import com.telnyx.sdk.models.calls.CallDialParams; CallDialParams params = CallDialParams.builder() .putAdditionalHeader("Secret-Header", "42") .putAdditionalQueryParam("secret_query_param", "42") .putAdditionalBodyProperty("secretProperty", JsonValue.from("42")) .build(); ``` These can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods. To set undocumented parameters on *nested* headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class: ```java theme={null} import com.telnyx.sdk.core.JsonValue; import com.telnyx.sdk.models.calls.CallDialParams; CallDialParams params = CallDialParams.builder() .answeringMachineDetectionConfig(CallDialParams.AnsweringMachineDetectionConfig.builder() .putAdditionalProperty("secretProperty", JsonValue.from("42")) .build()) .build(); ``` These properties can be accessed on the nested built object later using the `_additionalProperties()` method. To set a documented parameter or property to an undocumented or not yet supported *value*, pass a [`JsonValue`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/Values.kt) object to its setter: ```java theme={null} import com.telnyx.sdk.core.JsonValue; import com.telnyx.sdk.models.calls.CallDialParams; CallDialParams params = CallDialParams.builder() .connectionId(JsonValue.from(42)) .from("+15557654321") .to("+15551234567") .webhookUrl("https://your-webhook.url/events") .build(); ``` The most straightforward way to create a [`JsonValue`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/Values.kt) is using its `from(...)` method: ```java theme={null} import com.telnyx.sdk.core.JsonValue; import java.util.List; import java.util.Map; // Create primitive JSON values JsonValue nullValue = JsonValue.from(null); JsonValue booleanValue = JsonValue.from(true); JsonValue numberValue = JsonValue.from(42); JsonValue stringValue = JsonValue.from("Hello World!"); // Create a JSON array value equivalent to `["Hello", "World"]` JsonValue arrayValue = JsonValue.from(List.of( "Hello", "World" )); // Create a JSON object value equivalent to `{ "a": 1, "b": 2 }` JsonValue objectValue = JsonValue.from(Map.of( "a", 1, "b", 2 )); // Create an arbitrarily nested JSON equivalent to: // { // "a": [1, 2], // "b": [3, 4] // } JsonValue complexValue = JsonValue.from(Map.of( "a", List.of( 1, 2 ), "b", List.of( 3, 4 ) )); ``` Normally a `Builder` class's `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset. To forcibly omit a required parameter or property, pass [`JsonMissing`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/core/Values.kt): ```java theme={null} import com.telnyx.sdk.core.JsonMissing; import com.telnyx.sdk.models.calls.CallDialParams; CallDialParams params = CallDialParams.builder() .from("+18005550101") .to("+18005550100 or sip:username@sip.telnyx.com") .connectionId(JsonMissing.of()) .build(); ``` ### Response properties To access undocumented response properties, call the `_additionalProperties()` method: ```java theme={null} import com.telnyx.sdk.core.JsonValue; import java.util.Map; Map additionalProperties = client.calls().dial(params)._additionalProperties(); JsonValue secretPropertyValue = additionalProperties.get("secretProperty"); String result = secretPropertyValue.accept(new JsonValue.Visitor<>() { @Override public String visitNull() { return "It's null!"; } @Override public String visitBoolean(boolean value) { return "It's a boolean!"; } @Override public String visitNumber(Number value) { return "It's a number!"; } // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject` // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden }); ``` To access a property's raw JSON value, which may be undocumented, call its `_` prefixed method: ```java theme={null} import com.telnyx.sdk.core.JsonField; import java.util.Optional; JsonField connectionId = client.calls().dial(params)._connectionId(); if (connectionId.isMissing()) { // The property is absent from the JSON response } else if (connectionId.isNull()) { // The property was set to literal null } else { // Check if value was provided as a string // Other methods include `asNumber()`, `asBoolean()`, etc. Optional jsonString = connectionId.asString(); // Try to deserialize into a custom type MyClass myObject = connectionId.asUnknown().orElseThrow().convert(MyClass.class); } ``` ### Response validation In rare cases, the API may return a response that doesn't match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else. By default, the SDK will not throw an exception in this case. It will throw [`TelnyxInvalidDataException`](https://github.com/team-telnyx/telnyx-java/tree/master/telnyx-java-core/src/main/kotlin/com/telnyx/sdk/errors/TelnyxInvalidDataException.kt) only if you directly access the property. If you would prefer to check that the response is completely well-typed upfront, then either call `validate()`: ```java theme={null} import com.telnyx.sdk.models.calls.CallDialResponse; CallDialResponse response = client.calls().dial(params).validate(); ``` Or configure the method call to validate the response using the `responseValidation` method: ```java theme={null} import com.telnyx.sdk.models.calls.CallDialResponse; CallDialResponse response = client.calls().dial( params, RequestOptions.builder().responseValidation(true).build() ); ``` Or configure the default for all method calls at the client level: ```java theme={null} import com.telnyx.sdk.client.TelnyxClient; import com.telnyx.sdk.client.okhttp.TelnyxOkHttpClient; TelnyxClient client = TelnyxOkHttpClient.builder() .fromEnv() .responseValidation(true) .build(); ``` ## FAQ ### Why don't you use plain `enum` classes? Java `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value. ### Why do you represent fields using `JsonField` instead of just plain `T`? Using `JsonField` enables a few features: * Allowing usage of [undocumented API functionality](#undocumented-api-functionality) * Lazily [validating the API response against the expected shape](#response-validation) * Representing absent vs explicitly null values ### Why don't you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)? It is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don't want to introduce a breaking change every time we add a field to a class. ### Why don't you use checked exceptions? Checked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason. Checked exceptions: * Are verbose to handle * Encourage error handling at the wrong level of abstraction, where nothing can be done about the error * Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function) * Don't play well with lambdas (also due to the function coloring problem) ## Semantic versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes to library internals which are technically public but not intended or documented for external use. *(Please open a GitHub issue to let us know if you are relying on such internals.)* 2. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. We are keen for your feedback; please open an [issue](https://www.github.com/team-telnyx/telnyx-java/issues) with questions, bugs, or suggestions. ## 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()); } } } } ``` # Node.js SDK Source: https://developers.telnyx.com/development/sdk/node/index The official Telnyx Node.js library for server-side applications. # Telnyx TypeScript API Library NPM version ![npm bundle size](https://img.shields.io/bundlephobia/minzip/telnyx) This library provides convenient access to the Telnyx REST API from server-side TypeScript or JavaScript. The full API of this library can be found in [api.md](https://github.com/team-telnyx/telnyx-node/tree/master/api.md). It is generated with [Stainless](https://www.stainless.com/). ## Installation ```sh theme={null} npm install telnyx ``` ## Usage The full API of this library can be found in [api.md](https://github.com/team-telnyx/telnyx-node/tree/master/api.md). ```js theme={null} import Telnyx from 'telnyx'; const client = new Telnyx({ apiKey: process.env['TELNYX_API_KEY'], // This is the default and can be omitted }); const response = await client.calls.dial({ connection_id: 'conn12345', from: '+15557654321', to: '+15551234567', webhook_url: 'https://your-webhook.url/events', }); console.log(response.data); ``` ### Request & Response types This library includes TypeScript definitions for all request params and response fields. You may import and use them like so: ```ts theme={null} import Telnyx from 'telnyx'; const client = new Telnyx({ apiKey: process.env['TELNYX_API_KEY'], // This is the default and can be omitted }); const params: Telnyx.NumberOrderCreateParams = { phone_numbers: [{ phone_number: '+15558675309' }] }; const numberOrder: Telnyx.NumberOrderCreateResponse = await client.numberOrders.create(params); ``` Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. ## File uploads Request parameters that correspond to file uploads can be passed in many different forms: * `File` (or an object with the same structure) * a `fetch` `Response` (or an object with the same structure) * an `fs.ReadStream` * the return value of our `toFile` helper ```ts theme={null} import fs from 'fs'; import Telnyx, { toFile } from 'telnyx'; const client = new Telnyx(); // If you have access to Node `fs` we recommend using `fs.createReadStream()`: await client.ai.audio.transcribe({ model: 'distil-whisper/distil-large-v2', file: fs.createReadStream('/path/to/file'), }); // Or if you have the web `File` API you can pass a `File` instance: await client.ai.audio.transcribe({ model: 'distil-whisper/distil-large-v2', file: new File(['my bytes'], 'file'), }); // You can also pass a `fetch` `Response`: await client.ai.audio.transcribe({ model: 'distil-whisper/distil-large-v2', file: await fetch('https://somesite/file'), }); // Finally, if none of the above are convenient, you can use our `toFile` helper: await client.ai.audio.transcribe({ model: 'distil-whisper/distil-large-v2', file: await toFile(Buffer.from('my bytes'), 'file'), }); await client.ai.audio.transcribe({ model: 'distil-whisper/distil-large-v2', file: await toFile(new Uint8Array([0, 1, 2]), 'file'), }); ``` ## Handling errors When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `APIError` will be thrown: ```ts theme={null} const numberOrder = await client.numberOrders .create({ phone_numbers: [{ phone_number: '+15558675309' }] }) .catch(async (err) => { if (err instanceof Telnyx.APIError) { console.log(err.status); // 400 console.log(err.name); // BadRequestError console.log(err.headers); // {server: 'nginx', ...} } else { throw err; } }); ``` Error codes are as follows: | Status Code | Error Type | | ----------- | -------------------------- | | 400 | `BadRequestError` | | 401 | `AuthenticationError` | | 403 | `PermissionDeniedError` | | 404 | `NotFoundError` | | 422 | `UnprocessableEntityError` | | 429 | `RateLimitError` | | >=500 | `InternalServerError` | | N/A | `APIConnectionError` | ### Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors will all be retried by default. You can use the `maxRetries` option to configure or disable this: ```js theme={null} // Configure the default for all requests: const client = new Telnyx({ maxRetries: 0, // default is 2 }); // Or, configure per-request: await client.numberOrders.create({ phone_numbers: [{ phone_number: '+15558675309' }] }, { maxRetries: 5, }); ``` ### Timeouts Requests time out after 1 minute by default. You can configure this with a `timeout` option: ```ts theme={null} // Configure the default for all requests: const client = new Telnyx({ timeout: 20 * 1000, // 20 seconds (default is 1 minute) }); // Override per-request: await client.numberOrders.create({ phone_numbers: [{ phone_number: '+15558675309' }] }, { timeout: 5 * 1000, }); ``` On timeout, an `APIConnectionTimeoutError` is thrown. Note that requests which time out will be [retried twice by default](#retries). ## Advanced Usage ### Accessing raw Response data (e.g., headers) The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic. You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. Unlike `.asResponse()` this method consumes the body, returning once it is parsed. ```ts theme={null} const client = new Telnyx(); const response = await client.numberOrders .create({ phone_numbers: [{ phone_number: '+15558675309' }] }) .asResponse(); console.log(response.headers.get('X-My-Header')); console.log(response.statusText); // access the underlying Response object const { data: numberOrder, response: raw } = await client.numberOrders .create({ phone_numbers: [{ phone_number: '+15558675309' }] }) .withResponse(); console.log(raw.headers.get('X-My-Header')); console.log(numberOrder.data); ``` ### Logging > \[!IMPORTANT] > All log messages are intended for debugging only. The format and content of log messages > may change between releases. #### Log levels The log level can be configured in two ways: 1. Via the `TELNYX_LOG` environment variable 2. Using the `logLevel` client option (overrides the environment variable if set) ```ts theme={null} import Telnyx from 'telnyx'; const client = new Telnyx({ logLevel: 'debug', // Show all log messages }); ``` Available log levels, from most to least verbose: * `'debug'` - Show debug messages, info, warnings, and errors * `'info'` - Show info messages, warnings, and errors * `'warn'` - Show warnings and errors (default) * `'error'` - Show only errors * `'off'` - Disable all logging At the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies. Some authentication-related headers are redacted, but sensitive data in request and response bodies may still be visible. #### Custom logger By default, this library logs to `globalThis.console`. You can also provide a custom logger. Most logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue. When providing a custom logger, the `logLevel` option still controls which messages are emitted, messages below the configured level will not be sent to your logger. ```ts theme={null} import Telnyx from 'telnyx'; import pino from 'pino'; const logger = pino(); const client = new Telnyx({ logger: logger.child({ name: 'Telnyx' }), logLevel: 'debug', // Send all messages to pino, allowing it to filter }); ``` ### Making custom/undocumented requests This library is typed for convenient access to the documented API. If you need to access undocumented endpoints, params, or response properties, the library can still be used. #### Undocumented endpoints To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs. Options on the client, such as retries, will be respected when making these requests. ```ts theme={null} await client.post('/some/path', { body: { some_prop: 'foo' }, query: { some_query_arg: 'bar' }, }); ``` #### Undocumented request params To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you send will be sent as-is. ```ts theme={null} client.calls.dial({ // ... // @ts-expect-error baz is not yet public baz: 'undocumented option', }); ``` For requests with the `GET` verb, any extra params will be in the query, all other requests will send the extra param in the body. If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request options. #### Undocumented response properties To access undocumented response properties, you may access the response object with `// @ts-expect-error` on the response object, or cast the response object to the requisite type. Like the request params, we do not validate or strip extra properties from the response from the API. ### Customizing the fetch client By default, this library expects a global `fetch` function is defined. If you want to use a different `fetch` function, you can either polyfill the global: ```ts theme={null} import fetch from 'my-fetch'; globalThis.fetch = fetch; ``` Or pass it to the client: ```ts theme={null} import Telnyx from 'telnyx'; import fetch from 'my-fetch'; const client = new Telnyx({ fetch }); ``` ### Fetch options If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.) ```ts theme={null} import Telnyx from 'telnyx'; const client = new Telnyx({ fetchOptions: { // `RequestInit` options }, }); ``` #### Configuring proxies To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy options to requests: Node \[[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)] ```ts theme={null} import Telnyx from 'telnyx'; import * as undici from 'undici'; const proxyAgent = new undici.ProxyAgent('http://localhost:8888'); const client = new Telnyx({ fetchOptions: { dispatcher: proxyAgent, }, }); ``` Bun \[[docs](https://bun.sh/guides/http/proxy)] ```ts theme={null} import Telnyx from 'telnyx'; const client = new Telnyx({ fetchOptions: { proxy: 'http://localhost:8888', }, }); ``` Deno \[[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)] ```ts theme={null} import Telnyx from 'npm:telnyx'; const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } }); const client = new Telnyx({ fetchOptions: { client: httpClient, }, }); ``` ## Frequently Asked Questions ## Semantic versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. 2. Changes to library internals which are technically public but not intended or documented for external use. *(Please open a GitHub issue to let us know if you are relying on such internals.)* 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. We are keen for your feedback; please open an [issue](https://www.github.com/team-telnyx/telnyx-node/issues) with questions, bugs, or suggestions. ## Requirements TypeScript >= 4.9 is supported. The following runtimes are supported: * Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) * Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. * Deno v1.28.0 or higher. * Bun 1.0 or later. * Cloudflare Workers. * Vercel Edge Runtime. * Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). * Nitro v2.6 or greater. Note that React Native is not supported at this time. If you are interested in other runtime environments, please open or upvote an issue on GitHub. ## Contributing See [the contributing documentation](https://github.com/team-telnyx/telnyx-node/tree/master/./CONTRIBUTING.md). # PHP SDK Source: https://developers.telnyx.com/development/sdk/php/index The official Telnyx PHP library for server-side applications. # Telnyx PHP SDK [![Build Status](https://github.com/team-telnyx/telnyx-php/workflows/Composer/badge.svg)](https://github.com/team-telnyx/telnyx-php/actions) [![Latest Stable Version](https://poser.pugx.org/telnyx/telnyx-php/v/stable.svg)](https://packagist.org/packages/telnyx/telnyx-php) [![Total Downloads](https://poser.pugx.org/telnyx/telnyx-php/downloads.svg)](https://packagist.org/packages/telnyx/telnyx-php) [![License](https://poser.pugx.org/telnyx/telnyx-php/license.svg)](https://packagist.org/packages/telnyx/telnyx-php) [![Code Coverage](https://coveralls.io/repos/github/team-telnyx/telnyx-php/badge.svg?branch=master&)](https://coveralls.io/github/team-telnyx/telnyx-php?branch=master&) [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://joinslack.telnyx.com/) The Telnyx PHP library provides convenient access to the Telnyx API from applications written in PHP. It includes a pre-defined set of classes for API resources that initialize themselves dynamically from API responses. The library also provides other features. For example: * Easy configuration path for fast setup and use. * Helpers for pagination. * Built-in mechanisms for the serialization of parameters according to the expectations of Telnyx's API. You can sign up for a Telnyx account at [telnyx.com](https://telnyx.com). ## Requirements PHP 5.6.0 and later. ## Composer You can install the bindings via [Composer](http://getcomposer.org/). Run the following command: ```bash theme={null} $ composer require telnyx/telnyx-php ``` ## Manual Installation If you do not wish to use Composer, you can download the [latest release](https://github.com/team-telnyx/telnyx-php/releases). Then, to use the bindings, include the `init.php` file. ```php theme={null} require_once('/path/to/telnyx-php/init.php'); ``` ## Dependencies Some PHP extensions are required: * [`curl`](https://secure.php.net/manual/en/book.curl.php), although you can use your own non-cURL client if you prefer * [`json`](https://secure.php.net/manual/en/book.json.php) * [`mbstring`](https://secure.php.net/manual/en/book.mbstring.php) (Multibyte String) Composer will handle these dependencies. If you install manually, you'll want to make sure that these extensions are available. ## Getting Started Basic example: ```php theme={null} \Telnyx\Telnyx::setApiKey('YOUR_API_KEY_HERE'); // Get a list of messaging profiles $result = \Telnyx\MessagingProfile::all(); // Output list of messaging profiles print_r($result); ``` ## Documentation Please see [https://developers.telnyx.com/docs/api/v2/overview](https://developers.telnyx.com/docs/api/v2/overview) for up-to-date documentation. ## Custom Request Timeouts To modify request timeouts (connect or total, in seconds) you'll need to tell the API client to use a CurlClient other than its default. You'll set the timeouts in that CurlClient. ```php theme={null} // set up your tweaked Curl client $curl = new \Telnyx\HttpClient\CurlClient(); $curl->setTimeout(10); // default is Telnyx\HttpClient\CurlClient::DEFAULT_TIMEOUT $curl->setConnectTimeout(5); // default is Telnyx\HttpClient\CurlClient::DEFAULT_CONNECT_TIMEOUT echo $curl->getTimeout(); // 10 echo $curl->getConnectTimeout(); // 5 // tell Telnyx to use the tweaked client \Telnyx\ApiRequestor::setHttpClient($curl); // use the Telnyx API client as you normally would ``` ## Custom cURL Options (proxies) Need to set a proxy for your requests? Pass in the requisite `CURLOPT_*` array to the CurlClient constructor, using the same syntax as `curl_stopt_array()`. This will set the default cURL options for each HTTP request made by the SDK, though many more common options (e.g. timeouts; see above on how to set those) will be overridden by the client even if set here. ```php theme={null} // set up your tweaked Curl client $curl = new \Telnyx\HttpClient\CurlClient([CURLOPT_PROXY => 'proxy.local:80']); // tell Telnyx to use the tweaked client \Telnyx\ApiRequestor::setHttpClient($curl); ``` Alternately, a callable can be passed to the CurlClient constructor that returns the above array based on request inputs. See `testDefaultOptions()` in `tests/CurlClientTest.php` for an example of this behavior. Note that the callable is called at the beginning of every API request, before the request is sent. ## Configuring a Logger The library does minimal logging, but it can be configured with a [`PSR-3` compatible logger][psr3] so that messages end up there instead of `error_log`: ```php theme={null} \Telnyx\Telnyx::setLogger($logger); ``` ## Accessing Response Data You can access the data from the last API response on any object via `getLastResponse()`. ```php theme={null} $order = \Telnyx\NumberOrder::create(['phone_number' => '+18665552368']); print_r($order->getLastResponse()->headers); ``` ## SSL / TLS Compatibility issues Telnyx's API now requires that all connections use TLS 1.2. Some systems (most notably some older CentOS and RHEL versions) are capable of using TLS 1.2 but will use TLS 1.0 or 1.1 by default. The recommended course of action is to upgrade your cURL and OpenSSL packages so that TLS 1.2 is used by default, but if that is not possible, you might be able to solve the issue by setting the `CURLOPT_SSLVERSION` option to either `CURL_SSLVERSION_TLSv1` or `CURL_SSLVERSION_TLSv1_2`: ```php theme={null} $curl = new \Telnyx\HttpClient\CurlClient([CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1]); \Telnyx\ApiRequestor::setHttpClient($curl); ``` ## Per-request Configuration For apps that need to use multiple keys during the lifetime of a process it's also possible to set a per-request key and/or account: ```php theme={null} \Telnyx\NumberOrder::all([], [ 'api_key' => 'KEY0123...' ]); \Telnyx\NumberOrder::retrieve("12ade33a-21c0-473b-b055-b3c836e1c292", [ 'api_key' => 'KEY0123...' ]); ``` ## Automatic Retries The library can be configured to automatically retry requests that fail due to an intermittent network problem: ```php theme={null} \Telnyx\Telnyx::setMaxNetworkRetries(2); ``` ## Development Unit tests rely on a mock server so all unit tests are ran through docker. To run all unit tests execute: ``` docker-compose run --rm php composer test ``` Running unit tests with code coverage requires you build the docker container with XDEBUG=1 ``` docker-compose build --build-arg XDEBUG=1 ``` then run the unit tests as ``` docker-compose run --rm php composer test-coverage ``` ## Plugin Developers Are you writing a plugin that integrates Telnyx and embeds our library? Then please use the `setAppInfo` function to identify your plugin. For example: ```php theme={null} \Telnyx\Telnyx::setAppInfo("MyCustomPlugin", "1.2.3", "https://customplugin.yoursite.com"); ``` The method should be called once before any request is sent to the API. The second and third parameters are optional. ## SSL / TLS Configuration Option See the "SSL / TLS compatibility issues" paragraph above for full context. If you want to ensure that your plugin can be used on all systems, you should add a configuration option to let your users choose between different values for `CURLOPT_SSLVERSION`: none (default), `CURL_SSLVERSION_TLSv1` and `CURL_SSLVERSION_TLSv1_2`. ## Acknowledgments The contributors and maintainers of Telnyx PHP would like to extend their deep gratitude to the authors of [Stripe PHP][stripe-php], upon which this project is based. Thank you for developing such elegant, usable, and extensible code and for sharing it with the community. [stripe-php]: https://github.com/stripe/stripe-php [composer]: https://getcomposer.org/ [curl]: http://curl.haxx.se/docs/caextract.html [psr3]: http://www.php-fig.org/psr/psr-3/ ```php theme={null} $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; ?> ``` # Python SDK Source: https://developers.telnyx.com/development/sdk/python/index The official Telnyx Python library for server-side applications. # Telnyx Python API library [![PyPI version](https://img.shields.io/pypi/v/telnyx.svg?label=pypi%20\(stable\))](https://pypi.org/project/telnyx/) The Telnyx Python library provides convenient access to the Telnyx REST API from any Python 3.8+ application. The library includes type definitions for all request params and response fields, and offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx). It is generated with [Stainless](https://www.stainless.com/). ## Documentation The full API of this library can be found in [api.md](https://github.com/team-telnyx/telnyx-python/tree/master/api.md). ## Installation ```sh theme={null} # install from PyPI pip install telnyx ``` ## Usage The full API of this library can be found in [api.md](https://github.com/team-telnyx/telnyx-python/tree/master/api.md). ```python theme={null} import os from telnyx import Telnyx client = Telnyx( api_key=os.environ.get("TELNYX_API_KEY"), # This is the default and can be omitted ) response = client.calls.dial( connection_id="conn12345", from_="+15557654321", to="+15551234567", webhook_url="https://your-webhook.url/events", ) print(response.data) ``` While you can provide an `api_key` keyword argument, we recommend using [python-dotenv](https://pypi.org/project/python-dotenv/) to add `TELNYX_API_KEY="My API Key"` to your `.env` file so that your API Key is not stored in source control. ## Async usage Simply import `AsyncTelnyx` instead of `Telnyx` and use `await` with each API call: ```python theme={null} import os import asyncio from telnyx import AsyncTelnyx client = AsyncTelnyx( api_key=os.environ.get("TELNYX_API_KEY"), # This is the default and can be omitted ) async def main() -> None: response = await client.calls.dial( connection_id="conn12345", from_="+15557654321", to="+15551234567", webhook_url="https://your-webhook.url/events", ) print(response.data) asyncio.run(main()) ``` Functionality between the synchronous and asynchronous clients is otherwise identical. ### With aiohttp By default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend. You can enable this by installing `aiohttp`: ```sh theme={null} # install from PyPI pip install telnyx[aiohttp] ``` Then you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`: ```python theme={null} import asyncio from telnyx import DefaultAioHttpClient from telnyx import AsyncTelnyx async def main() -> None: async with AsyncTelnyx( api_key="My API Key", http_client=DefaultAioHttpClient(), ) as client: response = await client.calls.dial( connection_id="conn12345", from_="+15557654321", to="+15551234567", webhook_url="https://your-webhook.url/events", ) print(response.data) asyncio.run(main()) ``` ## Using types Nested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like: * Serializing back into JSON, `model.to_json()` * Converting to a dictionary, `model.to_dict()` Typed requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`. ## Nested params Nested parameters are dictionaries, typed using `TypedDict`, for example: ```python theme={null} from telnyx import Telnyx client = Telnyx() response = client.calls.dial( connection_id="7267xxxxxxxxxxxxxx", from_="+18005550101", to="+18005550100 or sip:username@sip.telnyx.com", answering_machine_detection_config={ "after_greeting_silence_millis": 1000, "between_words_silence_millis": 1000, "greeting_duration_millis": 1000, "greeting_silence_duration_millis": 2000, "greeting_total_analysis_time_millis": 50000, "initial_silence_millis": 1000, "maximum_number_of_words": 1000, "maximum_word_length_millis": 2000, "silence_threshold": 512, "total_analysis_time_millis": 5000, }, ) print(response.answering_machine_detection_config) ``` ## File uploads Request parameters that correspond to file uploads can be passed as `bytes`, or a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance or a tuple of `(filename, contents, media type)`. ```python theme={null} from pathlib import Path from telnyx import Telnyx client = Telnyx() client.ai.audio.transcribe( model="distil-whisper/distil-large-v2", file=Path("/path/to/file"), ) ``` The async client uses the exact same interface. If you pass a [`PathLike`](https://docs.python.org/3/library/os.html#os.PathLike) instance, the file contents will be read asynchronously automatically. ## Handling errors When the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `telnyx.APIConnectionError` is raised. When the API returns a non-success status code (that is, 4xx or 5xx response), a subclass of `telnyx.APIStatusError` is raised, containing `status_code` and `response` properties. All errors inherit from `telnyx.APIError`. ```python theme={null} import telnyx from telnyx import Telnyx client = Telnyx() try: client.number_orders.create( phone_numbers=[{"phone_number": "+15558675309"}], ) except telnyx.APIConnectionError as e: print("The server could not be reached") print(e.__cause__) # an underlying Exception, likely raised within httpx. except telnyx.RateLimitError as e: print("A 429 status code was received; we should back off a bit.") except telnyx.APIStatusError as e: print("Another non-200-range status code was received") print(e.status_code) print(e.response) ``` Error codes are as follows: | Status Code | Error Type | | ----------- | -------------------------- | | 400 | `BadRequestError` | | 401 | `AuthenticationError` | | 403 | `PermissionDeniedError` | | 404 | `NotFoundError` | | 422 | `UnprocessableEntityError` | | 429 | `RateLimitError` | | >=500 | `InternalServerError` | | N/A | `APIConnectionError` | ### Retries Certain errors are automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, and >=500 Internal errors are all retried by default. You can use the `max_retries` option to configure or disable retry settings: ```python theme={null} from telnyx import Telnyx # Configure the default for all requests: client = Telnyx( # default is 2 max_retries=0, ) # Or, configure per-request: client.with_options(max_retries=5).number_orders.create( phone_numbers=[{"phone_number": "+15558675309"}], ) ``` ### Timeouts By default requests time out after 1 minute. You can configure this with a `timeout` option, which accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object: ```python theme={null} from telnyx import Telnyx # Configure the default for all requests: client = Telnyx( # 20 seconds (default is 1 minute) timeout=20.0, ) # More granular control: client = Telnyx( timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0), ) # Override per-request: client.with_options(timeout=5.0).number_orders.create( phone_numbers=[{"phone_number": "+15558675309"}], ) ``` On timeout, an `APITimeoutError` is thrown. Note that requests that time out are [retried twice by default](#retries). ## Advanced ### Logging We use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module. You can enable logging by setting the environment variable `TELNYX_LOG` to `info`. ```shell theme={null} $ export TELNYX_LOG=info ``` Or to `debug` for more verbose logging. ### How to tell whether `None` means `null` or missing In an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`: ```py theme={null} if response.my_field is None: if 'my_field' not in response.model_fields_set: print('Got json like {}, without a "my_field" key present at all.') else: print('Got json like {"my_field": null}.') ``` ### Accessing raw response data (e.g. headers) The "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g., ```py theme={null} from telnyx import Telnyx client = Telnyx() response = client.number_orders.with_raw_response.create( phone_numbers=[{ "phone_number": "+15558675309" }], ) print(response.headers.get('X-My-Header')) number_order = response.parse() # get the object that `number_orders.create()` would have returned print(number_order.data) ``` These methods return an [`APIResponse`](https://github.com/team-telnyx/telnyx-python/tree/master/src/telnyx/_response.py) object. The async client returns an [`AsyncAPIResponse`](https://github.com/team-telnyx/telnyx-python/tree/master/src/telnyx/_response.py) with the same structure, the only difference being `await`able methods for reading the response content. #### `.with_streaming_response` The above interface eagerly reads the full response body when you make the request, which may not always be what you want. To stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods. ```python theme={null} with client.number_orders.with_streaming_response.create( phone_numbers=[{"phone_number": "+15558675309"}], ) as response: print(response.headers.get("X-My-Header")) for line in response.iter_lines(): print(line) ``` The context manager is required so that the response will reliably be closed. ### Making custom/undocumented requests This library is typed for convenient access to the documented API. If you need to access undocumented endpoints, params, or response properties, the library can still be used. #### Undocumented endpoints To make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other http verbs. Options on the client will be respected (such as retries) when making this request. ```py theme={null} import httpx response = client.post( "/foo", cast_to=httpx.Response, body={"my_param": True}, ) print(response.headers.get("x-foo")) ``` #### Undocumented request params If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request options. #### Undocumented response properties To access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You can also get all the extra fields on the Pydantic model as a dict with [`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra). ### Configuring the HTTP client You can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including: * Support for [proxies](https://www.python-httpx.org/advanced/proxies/) * Custom [transports](https://www.python-httpx.org/advanced/transports/) * Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality ```python theme={null} import httpx from telnyx import Telnyx, DefaultHttpxClient client = Telnyx( # Or use the `TELNYX_BASE_URL` env var base_url="http://my.test.server.example.com:8083", http_client=DefaultHttpxClient( proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0"), ), ) ``` You can also customize the client on a per-request basis by using `with_options()`: ```python theme={null} client.with_options(http_client=DefaultHttpxClient(...)) ``` ### Managing HTTP resources By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting. ```py theme={null} from telnyx import Telnyx with Telnyx() as client: # make requests here ... # HTTP client is now closed ``` ## Versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. 2. Changes to library internals which are technically public but not intended or documented for external use. *(Please open a GitHub issue to let us know if you are relying on such internals.)* 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. We are keen for your feedback; please open an [issue](https://www.github.com/team-telnyx/telnyx-python/issues) with questions, bugs, or suggestions. ### Determining the installed version If you've upgraded to the latest version but aren't seeing any new features you were expecting then your python environment is likely still using an older version. You can determine the version that is being used at runtime with: ```py theme={null} import telnyx print(telnyx.__version__) ``` ## Requirements Python 3.8 or higher. ## Contributing See [the contributing documentation](https://github.com/team-telnyx/telnyx-python/tree/master/./CONTRIBUTING.md). # Ruby SDK Source: https://developers.telnyx.com/development/sdk/ruby/index The official Telnyx Ruby library for server-side applications. # Telnyx Ruby API library The Telnyx Ruby library provides convenient access to the Telnyx REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/team-telnyx/telnyx-ruby#Sorbet) for usage with Sorbet. The standard library's `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem. It is generated with [Stainless](https://www.stainless.com/). ## Documentation Documentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/telnyx). ## Installation To use this gem, install via Bundler by adding the following to your application's `Gemfile`: ```ruby theme={null} gem "telnyx", "~> 4.2.0" ``` ## Usage ```ruby theme={null} require "bundler/setup" require "telnyx" telnyx = Telnyx::Client.new( api_key: ENV["TELNYX_API_KEY"] # This is the default and can be omitted ) response = telnyx.calls.dial( connection_id: "conn12345", from: "+15557654321", to: "+15551234567", webhook_url: "https://your-webhook.url/events" ) puts(response.data) ``` ### File uploads Request parameters that correspond to file uploads can be passed as raw contents, a [`Pathname`](https://rubyapi.org/3.2/o/pathname) instance, [`StringIO`](https://rubyapi.org/3.2/o/stringio), or more. ```ruby theme={null} require "pathname" # Use `Pathname` to send the filename and/or avoid paging a large file into memory: response = telnyx.ai.audio.transcribe(file: Pathname("/path/to/file")) # Alternatively, pass file contents or a `StringIO` directly: response = telnyx.ai.audio.transcribe(file: File.read("/path/to/file")) # Or, to control the filename and/or content type: file = Telnyx::FilePart.new(File.read("/path/to/file"), filename: "/path/to/file", content_type: "…") response = telnyx.ai.audio.transcribe(file: file) puts(response.text) ``` Note that you can also pass a raw `IO` descriptor, but this disables retries, as the library can't be sure if the descriptor is a file or pipe (which cannot be rewound). ### Handling errors When the library is unable to connect to the API, or if the API returns a non-success status code (i.e., 4xx or 5xx response), a subclass of `Telnyx::Errors::APIError` will be thrown: ```ruby theme={null} begin number_order = telnyx.number_orders.create(phone_numbers: [{phone_number: "+15558675309"}]) rescue Telnyx::Errors::APIConnectionError => e puts("The server could not be reached") puts(e.cause) # an underlying Exception, likely raised within `net/http` rescue Telnyx::Errors::RateLimitError => e puts("A 429 status code was received; we should back off a bit.") rescue Telnyx::Errors::APIStatusError => e puts("Another non-200-range status code was received") puts(e.status) end ``` Error codes are as follows: | Cause | Error Type | | ---------------- | -------------------------- | | HTTP 400 | `BadRequestError` | | HTTP 401 | `AuthenticationError` | | HTTP 403 | `PermissionDeniedError` | | HTTP 404 | `NotFoundError` | | HTTP 409 | `ConflictError` | | HTTP 422 | `UnprocessableEntityError` | | HTTP 429 | `RateLimitError` | | HTTP >= 500 | `InternalServerError` | | Other HTTP error | `APIStatusError` | | Timeout | `APITimeoutError` | | Network error | `APIConnectionError` | ### Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default. You can use the `max_retries` option to configure or disable this: ```ruby theme={null} # Configure the default for all requests: telnyx = Telnyx::Client.new( max_retries: 0 # default is 2 ) # Or, configure per-request: telnyx.number_orders.create( phone_numbers: [{phone_number: "+15558675309"}], request_options: {max_retries: 5} ) ``` ### Timeouts By default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this: ```ruby theme={null} # Configure the default for all requests: telnyx = Telnyx::Client.new( timeout: nil # default is 60 ) # Or, configure per-request: telnyx.number_orders.create( phone_numbers: [{phone_number: "+15558675309"}], request_options: {timeout: 5} ) ``` On timeout, `Telnyx::Errors::APITimeoutError` is raised. Note that requests that time out are retried by default. ## Advanced concepts ### BaseModel All parameter and response objects inherit from `Telnyx::Internal::Type::BaseModel`, which provides several conveniences, including: 1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax. 2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true. 3. Both instances and the classes themselves can be pretty-printed. 4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`. ### Making custom or undocumented requests #### Undocumented properties You can send undocumented parameters to any endpoint, and read undocumented response properties, like so: Note: the `extra_` parameters of the same name overrides the documented parameters. ```ruby theme={null} number_order = telnyx.number_orders.create( phone_numbers: [{phone_number: "+15558675309"}], request_options: { extra_query: {my_query_parameter: value}, extra_body: {my_body_parameter: value}, extra_headers: {"my-header": value} } ) puts(number_order[:my_undocumented_property]) ``` #### Undocumented request params If you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above. #### Undocumented endpoints To make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so: ```ruby theme={null} response = client.request( method: :post, path: '/undocumented/endpoint', query: {"dog": "woof"}, headers: {"useful-header": "interesting-value"}, body: {"hello": "world"} ) ``` ### Concurrency & connection pooling The `Telnyx::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests. Each instance of `Telnyx::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings. When all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout. Unless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure. ## Sorbet This library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime. You can provide typesafe request parameters like so: ```ruby theme={null} telnyx.calls.dial( connection_id: "conn12345", from: "+15557654321", to: "+15551234567", webhook_url: "https://your-webhook.url/events" ) ``` Or, equivalently: ```ruby theme={null} # Hashes work, but are not typesafe: telnyx.calls.dial( connection_id: "conn12345", from: "+15557654321", to: "+15551234567", webhook_url: "https://your-webhook.url/events" ) # You can also splat a full Params class: params = Telnyx::CallDialParams.new( connection_id: "conn12345", from: "+15557654321", to: "+15551234567", webhook_url: "https://your-webhook.url/events" ) telnyx.calls.dial(**params) ``` ### Enums Since this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime: ```ruby theme={null} # :ALL puts(Telnyx::Legacy::Reporting::UsageReports::NumberLookupCreateParams::AggregationType::ALL) # Revealed type: `T.all(Telnyx::Legacy::Reporting::UsageReports::NumberLookupCreateParams::AggregationType, Symbol)` T.reveal_type(Telnyx::Legacy::Reporting::UsageReports::NumberLookupCreateParams::AggregationType::ALL) ``` Enum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value: ```ruby theme={null} # Using the enum constants preserves the tagged type information: telnyx.legacy.reporting.usage_reports.number_lookup.create( aggregation_type: Telnyx::Legacy::Reporting::UsageReports::NumberLookupCreateParams::AggregationType::ALL, # … ) # Literal values are also permissible: telnyx.legacy.reporting.usage_reports.number_lookup.create( aggregation_type: :ALL, # … ) ``` ## Versioning This package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time. This package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes. ## Requirements Ruby 3.2.0 or higher. ## Contributing See [the contributing documentation](https://github.com/team-telnyx/telnyx-ruby/tree/master/CONTRIBUTING.md). # WebRTC Android SDK AI Voice Assistant Anonymous Login Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/anonymous-login/index Learn how to implement anonymous login for AI voice assistants with the Android Voice SDK # Anonymous Connection for AI Agents ## Overview The `connectAnonymously` method allows you to connect to AI assistants without traditional authentication credentials. This is the first step in establishing communication with a Telnyx AI Agent. ## Method Signature ```kotlin theme={null} fun connectAnonymously( providedServerConfig: TxServerConfiguration = TxServerConfiguration(), targetId: String, targetType: String = "ai_assistant", targetVersionId: String? = null, userVariables: Map? = null, reconnection: Boolean = false, logLevel: LogLevel = LogLevel.NONE, ) ``` ## Parameters | Parameter | Type | Required | Default | Description | | ---------------------- | --------------------- | -------- | ----------------------- | ----------------------------------------------------------------------- | | `providedServerConfig` | TxServerConfiguration | No | TxServerConfiguration() | Server configuration for connection | | `targetId` | String | Yes | - | The ID of your AI assistant | | `targetType` | String | No | "ai\_assistant" | The type of target | | `targetVersionId` | String? | No | null | Optional version ID of the target. If not provided, uses latest version | | `userVariables` | `Map?` | No | null | Optional user variables to include | | `reconnection` | Boolean | No | false | Whether this is a reconnection attempt | | `logLevel` | LogLevel | No | LogLevel.NONE | Logging level configuration | ## Usage Example ```kotlin theme={null} try { telnyxClient.connectAnonymously( targetId = "your_assistant_id", // targetType = "ai_assistant", // This is the default value // targetVersionId = "your_assistant_version_id", // Optional // userVariables = mapOf("user_id" to "12345"), // Optional user variables // logLevel = LogLevel.NONE // Optional log level configuration ) // You are now connected and can make a call to the AI Assistant. } catch (e: Exception) { // Handle connection error Log.e("TelnyxClient", "Connection failed: ${e.message}") } ``` ## Advanced Usage ### With User Variables ```kotlin theme={null} telnyxClient.connectAnonymously( targetId = "your_assistant_id", userVariables = mapOf( "user_id" to "12345", "session_context" to "support_chat", "language" to "en-US" ) ) ``` ### With Version Control ```kotlin theme={null} telnyxClient.connectAnonymously( targetId = "your_assistant_id", targetVersionId = "v1.2.0" // Use specific version ) ``` ### With Custom Server Configuration ```kotlin theme={null} telnyxClient.connectAnonymously( providedServerConfig = TxServerConfiguration( host = "your-custom-host", port = 443 ), targetId = "your_assistant_id" ) ``` ## Important Notes * **Call Routing**: After a successful anonymous connection, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant * **Session Lock**: The session becomes locked to the AI assistant until disconnection * **Version Control**: If `targetVersionId` is not provided, the SDK will use the latest available version * **Error Handling**: Monitor socket responses for authentication errors * **Server Configuration**: Custom server configuration can be provided through the `providedServerConfig` parameter ## Socket Response Handling Listen for connection responses using the socket response flow: ```kotlin theme={null} // Using SharedFlow (Recommended) lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.MESSAGERECEIVED -> { response.data?.let { data -> when (data.method) { SocketMethod.LOGIN.methodName -> { // Handle successful anonymous connection Log.i("TelnyxClient", "Anonymous connection successful") } } } } SocketStatus.ERROR -> { // Handle connection errors Log.e("TelnyxClient", "Connection error: ${response.errorMessage}") } } } } ``` ## Error Handling Common errors you might encounter: ```kotlin theme={null} lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> if (response.status == SocketStatus.ERROR) { when { response.errorMessage?.contains("authentication") == true -> { // Handle authentication error Log.e("TelnyxClient", "Invalid assistant ID or authentication failed") } response.errorMessage?.contains("network") == true -> { // Handle network error Log.e("TelnyxClient", "Network connection failed") } else -> { // Handle other errors Log.e("TelnyxClient", "Unexpected error: ${response.errorMessage}") } } } } } ``` ## Next Steps After successful anonymous connection: 1. [Start a conversation](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/starting-conversations) using `newInvite()` 2. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/transcript-updates) to receive real-time conversation data 3. [Send text messages](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/text-messaging) during active calls # WebRTC Android SDK AI Voice Assistant Introduction Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/introduction/index Introduction to building AI-powered voice assistants with the Android Voice SDK # AI Agent Usage The Android WebRTC SDK supports [Voice AI Agent](https://telnyx.com/products/voice-ai-agents) implementations. To get started, follow the steps [described here](https://telnyx.com/resources/ai-assistant-builder) to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps: ## Pre-developed AI Widget If you don't want to develop your own custom AI Agent interface from scratch, you can utilize our pre-developed AI Agent widget that provides a drop-in solution for voice AI interactions. ### Android Telnyx Voice AI Widget The **Android Telnyx Voice AI Widget** is a standalone, embeddable widget that provides a complete voice AI assistant interface using the Telnyx WebRTC SDK. **Repository**: [https://github.com/team-telnyx/android-telnyx-voice-ai-widget](https://github.com/team-telnyx/android-telnyx-voice-ai-widget) **Maven Central**: `com.telnyx:android-voice-ai-widget:1.0.0` ### Key Features * **Drop-in Solution**: Easy integration with minimal setup * **Multiple UI States**: Collapsed, loading, expanded, and transcript views * **Icon-Only Mode**: Floating action button-style interface for minimal UI footprint * **Audio Visualizer**: Real-time audio visualization during conversations * **Theme Support**: Light and dark theme compatibility * **Responsive Design**: Optimized for various screen sizes * **Voice Controls**: Mute/unmute and call management * **Transcript View**: Full conversation history with text input * **Customizable Modifiers**: Fine-tuned UI customization options ### Quick Integration ```kotlin theme={null} import com.telnyx.voiceai.widget.AIAssistantWidget @Composable fun MyScreen() { var showWidget by remember { mutableStateOf(false) } AIAssistantWidget( assistantId = "your-assistant-id", shouldInitialize = showWidget, modifier = Modifier.fillMaxWidth() ) } ``` ### Icon-Only Mode ```kotlin theme={null} AIAssistantWidget( assistantId = "your-assistant-id", shouldInitialize = true, iconOnly = true, // Enables floating action button mode modifier = Modifier.fillMaxWidth() ) ``` This widget handles all the complexity of AI Agent integration, providing a production-ready solution that you can customize to match your app's design. ## Documentation Structure This directory contains detailed documentation for AI Agent integration: * [Anonymous Login](anonymous-login.md) - How to connect to AI assistants without traditional authentication * [Starting Conversations](starting-conversations.md) - How to initiate calls with AI assistants * [Transcript Updates](transcript-updates.md) - Real-time conversation transcripts * [Text Messaging](text-messaging.md) - Send text messages during active calls ## Quick Start 1. **Anonymous Login**: Use `anonymousLogin()` to connect to your AI assistant 2. **Start Conversation**: Use `newInvite()` to initiate a call (destination is ignored) 3. **Receive Transcripts**: Listen to `transcriptUpdateFlow` for real-time conversation updates 4. **Send Text Messages**: Use `sendAIAssistantMessage()` to send text during active calls ## Key Features * **No Authentication Required**: Connect to AI assistants without SIP credentials * **Real-time Transcripts**: Get live conversation updates with role identification * **Mixed Communication**: Combine voice and text messaging in the same conversation * **Widget Settings**: Access AI conversation configuration settings * **Standard Call Controls**: Use existing call management methods (mute, hold, end call) ## Important Notes * After `anonymousLogin()`, all subsequent calls are routed to the specified AI assistant * Transcript functionality is only available for AI assistant conversations * AI assistants automatically answer calls - no manual answer required * Text messages appear in transcript updates alongside spoken conversation # WebRTC Android SDK AI Voice Assistant Starting Conversations Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/starting-conversations/index Learn how to start conversations with AI voice assistants using the Android Voice SDK # Starting Conversations with AI Assistants ## Overview After a successful `anonymousLogin`, you can initiate calls to your AI Assistant using the standard `newInvite` method. The session is locked to the AI Assistant, so the destination parameter is ignored. ## Method Usage ```kotlin theme={null} telnyxClient.newInvite( callerName: String, // Optional display name, not required to make call but is useful for log referencing callerNumber: String, // Optional caller number, not required but useful for log referencing destinationNumber: String, // Optional destination number, ignored after anonymous login. All calls will be routed to the AI assistant clientState: String, // Custom state information for your application customHeaders: Map = emptyMap(), // Optional SIP headers to pass context to the AI assistant in the form of dynamic variables ) ``` ## Parameters | Parameter | Type | Description | | ------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `callerName` | String | Your display name (passed to AI assistant) | | `callerNumber` | String | Your phone number (passed to AI assistant) | | `destinationNumber` | String | Ignored after anonymous login - can be empty string | | `clientState` | String | Custom state information for your application | | `customHeaders` | `Map` | Optional SIP headers to pass context to the AI assistant (mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables)) | Note that you can also provide `customHeaders` in the `newInvite` method. These headers need to start with the `X-` prefix and will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the AI assistant (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. ## Usage Example ```kotlin theme={null} // After a successful anonymousLogin... telnyxClient.call.newInvite( callerName = "John Doe", callerNumber = "+1234567890", destinationNumber = "", // Destination is ignored, can be empty clientState = "ai_conversation_session", customHeaders = mapOf( "X-Session-Context" to "support_request", "X-User-Tier" to "premium"), ) ``` ## Complete Flow Example ```kotlin theme={null} class AIAssistantManager(private val telnyxClient: TelnyxClient) { fun startAIConversation(assistantId: String) { // Step 1: Anonymous login telnyxClient.anonymousLogin( targetId = assistantId, ) // Step 2: Listen for login success, then start call lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.MESSAGERECEIVED -> { response.data?.let { data -> when (data.method) { SocketMethod.LOGIN.methodName -> { // Login successful, start the call startCall() } SocketMethod.ANSWER.methodName -> { // AI Assistant answered automatically Log.i("AI", "Connected to AI Assistant") } } } } } } } } private fun startCall() { telnyxClient.call.newInvite( callerName = "Customer", // callerNumber = "+1234567890", destinationNumber = "", // Ignored clientState = "ai_session", customHeaders = mapOf( "X-Session-Context" to "customer_support", "X-User-Tier" to "premium") ) } } ``` ## Important Notes * **Automatic Answer**: AI assistants automatically answer calls - no manual answer required * **Destination Ignored**: The `destinationNumber` parameter is ignored after anonymous login * **Call Routing**: All calls are routed to the AI assistant specified during login * **Standard Controls**: Use existing call management methods (mute, hold, end call) * **Custom Headers**: You can pass custom SIP headers to provide context to the AI assistant. They will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the portal. Hyphens in header names are converted to underscores in variable names, e.g. `X-Session-Context` header maps to `{{session_context}}` variable. ## Call State Management Monitor call states as you would with regular calls: ```kotlin theme={null} lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.MESSAGERECEIVED -> { response.data?.let { data -> when (data.method) { SocketMethod.INVITE.methodName -> { // Call invitation sent Log.i("AI", "Calling AI Assistant...") } SocketMethod.RINGING.methodName -> { // AI Assistant is "ringing" (brief moment) Log.i("AI", "AI Assistant ringing...") } SocketMethod.ANSWER.methodName -> { // AI Assistant answered Log.i("AI", "Connected to AI Assistant") // Start listening for transcripts setupTranscriptListener() } SocketMethod.BYE.methodName -> { // Call ended Log.i("AI", "AI conversation ended") } } } } } } } ``` ## Error Handling Handle call-related errors: ```kotlin theme={null} lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> if (response.status == SocketStatus.ERROR) { when { response.errorMessage?.contains("invite") == true -> { Log.e("AI", "Failed to start conversation with AI Assistant") } response.errorMessage?.contains("session") == true -> { Log.e("AI", "Session expired, need to login again") } else -> { Log.e("AI", "Call error: ${response.errorMessage}") } } } } } ``` ## Call Management Once connected, use standard call management methods: ```kotlin theme={null} // Get the active call val activeCall = telnyxClient.calls.values.firstOrNull() activeCall?.let { call -> // Mute/unmute call.onMuteUnmutePressed() // Hold/unhold call.onHoldUnholdPressed(call.callId) // End call call.endCall(call.callId) } ``` ## Next Steps After starting a conversation: 1. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/transcript-updates) to receive real-time conversation data 2. [Send text messages](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/text-messaging) during the active call 3. Use standard call controls for mute, hold, and end call operations # WebRTC Android SDK AI Voice Assistant Text Messaging Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/text-messaging/index Learn how to implement text messaging with AI voice assistants using the Android Voice SDK # Sending Text Messages to AI Agents ## Overview In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. ## Method Signature ```kotlin theme={null} fun sendAIAssistantMessage(message: String) ``` ## Parameters | Parameter | Type | Description | | --------- | ------ | -------------------------------------------- | | `message` | String | The text message to send to the AI Assistant | ## Basic Usage ```kotlin theme={null} // Send a text message to the AI Agent during an active call telnyxClient.sendAIAssistantMessage("Hello, can you help me with my account?") ``` ## Complete Example ```kotlin theme={null} class AIConversationActivity : AppCompatActivity() { private lateinit var messageInput: EditText private lateinit var sendButton: Button override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_ai_conversation) messageInput = findViewById(R.id.messageInput) sendButton = findViewById(R.id.sendButton) setupMessageSending() } private fun setupMessageSending() { sendButton.setOnClickListener { val message = messageInput.text.toString().trim() if (message.isNotEmpty()) { sendTextMessage(message) messageInput.text.clear() } } // Send on Enter key messageInput.setOnEditorActionListener { _, actionId, _ -> if (actionId == EditorInfo.IME_ACTION_SEND) { sendButton.performClick() true } else { false } } } private fun sendTextMessage(message: String) { try { telnyxClient.sendAIAssistantMessage(message) Log.d("AI", "Text message sent: $message") } catch (e: Exception) { Log.e("AI", "Failed to send text message: ${e.message}") showError("Failed to send message") } } } ``` ## Advanced Usage with Call State Checking ```kotlin theme={null} class AIMessageManager(private val telnyxClient: TelnyxClient) { fun sendMessage(message: String): Boolean { return if (isAICallActive()) { telnyxClient.sendAIAssistantMessage(message) true } else { Log.w("AI", "Cannot send message: No active AI call") false } } private fun isAICallActive(): Boolean { return telnyxClient.calls.values.any { call -> call.callState == CallState.ACTIVE } } fun sendMessageWithConfirmation(message: String, callback: (Boolean) -> Unit) { if (sendMessage(message)) { // Listen for confirmation in transcript updates listenForMessageConfirmation(message, callback) } else { callback(false) } } private fun listenForMessageConfirmation( sentMessage: String, callback: (Boolean) -> Unit ) { // Monitor transcript for the sent message appearing lifecycleScope.launch { telnyxClient.transcriptUpdateFlow.collect { transcript -> val userMessages = transcript.filter { it.role == TranscriptItem.ROLE_USER } if (userMessages.any { it.content.contains(sentMessage) }) { callback(true) } } } } } ``` ## UI Integration Example ```kotlin theme={null} class ConversationFragment : Fragment() { private lateinit var binding: FragmentConversationBinding override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { binding = FragmentConversationBinding.inflate(inflater, container, false) return binding.root } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupMessageInput() setupTranscriptDisplay() } private fun setupMessageInput() { binding.messageInput.addTextChangedListener(object : TextWatcher { override fun afterTextChanged(s: Editable?) { binding.sendButton.isEnabled = !s.isNullOrBlank() } override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {} override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {} }) binding.sendButton.setOnClickListener { sendCurrentMessage() } } private fun sendCurrentMessage() { val message = binding.messageInput.text.toString().trim() if (message.isNotEmpty()) { // Show message as "sending" in UI addPendingMessage(message) // Send to AI Assistant telnyxClient.sendAIAssistantMessage(message) // Clear input binding.messageInput.text.clear() } } private fun addPendingMessage(message: String) { // Add message to UI with "sending" indicator // This will be replaced when transcript updates arrive } } ``` ## Message Types and Formatting ```kotlin theme={null} class AIMessageHelper { fun sendQuestion(question: String) { telnyxClient.sendAIAssistantMessage("Question: $question") } fun sendCommand(command: String) { telnyxClient.sendAIAssistantMessage("Command: $command") } fun sendContextualMessage(message: String, context: Map) { val contextString = context.entries.joinToString(", ") { "${it.key}: ${it.value}" } telnyxClient.sendAIAssistantMessage("$message [Context: $contextString]") } fun sendFormattedMessage(message: String, format: MessageFormat) { val formattedMessage = when (format) { MessageFormat.URGENT -> "URGENT: $message" MessageFormat.QUESTION -> "❓ $message" MessageFormat.FEEDBACK -> "💬 $message" MessageFormat.PLAIN -> message } telnyxClient.sendAIAssistantMessage(formattedMessage) } } enum class MessageFormat { URGENT, QUESTION, FEEDBACK, PLAIN } ``` ## Error Handling ```kotlin theme={null} private fun sendTextMessageWithErrorHandling(message: String) { try { // Check if we have an active AI call val hasActiveCall = telnyxClient.calls.values.any { it.callState == CallState.ACTIVE } if (!hasActiveCall) { showError("No active AI conversation. Please start a call first.") return } // Send the message telnyxClient.sendAIAssistantMessage(message) // Show success feedback showMessageSent(message) } catch (e: Exception) { Log.e("AI", "Failed to send message: ${e.message}") showError("Failed to send message: ${e.message}") } } private fun showError(message: String) { Toast.makeText(this, message, Toast.LENGTH_SHORT).show() } private fun showMessageSent(message: String) { // Optional: Show brief confirmation Log.d("AI", "Message sent successfully: $message") } ``` ## Important Notes * **Active Call Required**: You must have an active call established before sending text messages * **AI Assistant Only**: The `sendAIAssistantMessage` method is only available during AI Assistant conversations * **Transcript Integration**: Text messages sent this way will appear in transcript updates alongside spoken conversation * **Processing**: The AI Agent will process and respond to text messages just like spoken input * **Mixed Communication**: Users can seamlessly switch between voice and text communication ## Best Practices 1. **Validate Input**: Always check that messages are not empty before sending 2. **Check Call State**: Verify an active AI call exists before sending messages 3. **User Feedback**: Provide visual feedback when messages are sent 4. **Error Handling**: Handle network errors and call state issues gracefully 5. **UI Updates**: Update the conversation UI immediately for better user experience ## Integration with Transcript Updates Text messages will appear in the transcript flow: ```kotlin theme={null} lifecycleScope.launch { telnyxClient.transcriptUpdateFlow.collect { transcript -> transcript.forEach { item -> when (item.role) { TranscriptItem.ROLE_USER -> { // This includes both spoken words and text messages displayUserMessage(item.content, item.timestamp) } TranscriptItem.ROLE_ASSISTANT -> { // AI responses to both voice and text displayAssistantMessage(item.content, item.timestamp) } } } } } ``` This feature enables rich conversational experiences where users can seamlessly switch between voice and text communication with the AI Assistant. # WebRTC Android SDK AI Voice Assistant Transcript Updates Source: https://developers.telnyx.com/development/webrtc/android-sdk/ai-voice-assistant/transcript-updates/index Learn how to handle transcript updates with AI voice assistants using the Android Voice SDK # Real-time Transcript Updates ## Overview During AI Assistant conversations, the SDK provides real-time transcript updates that include both the caller's speech and the AI Assistant's responses. This allows you to display a live conversation transcript in your application. ## Transcript Properties The SDK provides two main ways to access transcript data: ### SharedFlow for Real-time Updates ```kotlin theme={null} val transcriptUpdateFlow: SharedFlow> ``` ### Current Transcript Access ```kotlin theme={null} val transcript: List ``` ## TranscriptItem Structure ```kotlin theme={null} data class TranscriptItem( val id: String, // Unique identifier val role: String, // "user" or "assistant" val content: String, // The transcribed text val timestamp: Date, // When the item was created val isPartial: Boolean = false // Whether this is a partial response ) { companion object { const val ROLE_USER = "user" const val ROLE_ASSISTANT = "assistant" } } ``` ## Setting Up Transcript Updates ### Using SharedFlow (Recommended) ```kotlin theme={null} class AIConversationActivity : AppCompatActivity() { private val conversationTranscript = mutableListOf() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Set up transcript listener setupTranscriptListener() } private fun setupTranscriptListener() { lifecycleScope.launch { telnyxClient.transcriptUpdateFlow.collect { transcript -> // Update UI with new transcript updateConversationUI(transcript) } } } private fun updateConversationUI(transcript: List) { runOnUiThread { conversationTranscript.clear() conversationTranscript.addAll(transcript) // Update RecyclerView or other UI components conversationAdapter.notifyDataSetChanged() // Auto-scroll to bottom recyclerView.scrollToPosition(conversationTranscript.size - 1) } } } ``` ### Processing Individual Transcript Items ```kotlin theme={null} private fun updateConversationUI(transcript: List) { transcript.forEach { item -> when (item.role) { TranscriptItem.ROLE_USER -> { Log.d("Transcript", "User said: ${item.content}") // Display user message in UI addUserMessage(item.content, item.timestamp) } TranscriptItem.ROLE_ASSISTANT -> { Log.d("Transcript", "Assistant said: ${item.content}") // Display assistant message in UI addAssistantMessage(item.content, item.timestamp, item.isPartial) } } } } ``` ## Manual Transcript Access You can also manually retrieve the current transcript at any time: ```kotlin theme={null} // Get current transcript val currentTranscript = telnyxClient.transcript // Process the transcript currentTranscript.forEach { item -> println("${item.role}: ${item.content} (${item.timestamp})") } ``` ## Handling Partial Responses AI Assistant responses may come in chunks (partial responses). Handle these appropriately: ```kotlin theme={null} private fun addAssistantMessage(content: String, timestamp: Date, isPartial: Boolean) { if (isPartial) { // Update existing message or show typing indicator updateLastAssistantMessage(content) showTypingIndicator(true) } else { // Final message - hide typing indicator showTypingIndicator(false) finalizeAssistantMessage(content, timestamp) } } ``` ## Complete Example with RecyclerView ```kotlin theme={null} class ConversationAdapter( private val transcript: List ) : RecyclerView.Adapter() { class ViewHolder(view: View) : RecyclerView.ViewHolder(view) { val messageText: TextView = view.findViewById(R.id.messageText) val timestamp: TextView = view.findViewById(R.id.timestamp) val roleIndicator: View = view.findViewById(R.id.roleIndicator) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.conversation_item, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = transcript[position] holder.messageText.text = item.content holder.timestamp.text = SimpleDateFormat("HH:mm:ss", Locale.getDefault()) .format(item.timestamp) // Style based on role when (item.role) { TranscriptItem.ROLE_USER -> { holder.roleIndicator.setBackgroundColor(Color.BLUE) holder.messageText.gravity = Gravity.END } TranscriptItem.ROLE_ASSISTANT -> { holder.roleIndicator.setBackgroundColor(Color.GREEN) holder.messageText.gravity = Gravity.START // Show partial indicator if (item.isPartial) { holder.messageText.alpha = 0.7f } else { holder.messageText.alpha = 1.0f } } } } override fun getItemCount() = transcript.size } ``` ## Widget Settings Access Access AI conversation widget settings: ```kotlin theme={null} // Get current widget settings val widgetSettings = telnyxClient.currentWidgetSettings widgetSettings?.let { settings -> // Use widget settings to configure UI Log.d("Widget", "Settings: $settings") } ``` ## Important Notes * **AI Assistant Only**: Transcript updates are only available during AI Assistant conversations initiated through `anonymousLogin` * **Real-time Updates**: Transcripts update in real-time as the conversation progresses * **Partial Responses**: Assistant responses may come in chunks - handle `isPartial` flag appropriately * **Memory Management**: Transcripts are cleared when calls end or when disconnecting * **Thread Safety**: Always update UI on the main thread when processing transcript updates ## Error Handling ```kotlin theme={null} lifecycleScope.launch { try { telnyxClient.transcriptUpdateFlow.collect { transcript -> updateConversationUI(transcript) } } catch (e: Exception) { Log.e("Transcript", "Error processing transcript updates: ${e.message}") } } ``` ## Next Steps After setting up transcript updates: 1. [Send text messages](https://developers.telnyx.com/development/webrtc/android-sdk/ai-agent/text-messaging) to interact with the AI Assistant via text # WebRTC Call Reports Source: https://developers.telnyx.com/development/webrtc/android-sdk/call-reports/index Collect and send WebRTC call statistics for troubleshooting and monitoring # WebRTC Call Reports The Telnyx Android SDK automatically collects detailed call statistics during WebRTC calls and sends them to Telnyx for troubleshooting and monitoring purposes. This feature helps diagnose call quality issues, connection problems, and provides insights into call performance. ## Overview When enabled, the SDK collects: * **Call summary**: Call identifiers, timestamps, duration, and device information * **Connection metrics**: ICE states, DTLS states, signaling transitions * **Media statistics**: Packet loss, jitter, round-trip time, audio levels * **Network information**: Selected ICE candidates, transport details The data is automatically uploaded to Telnyx when a call ends, and can also be accessed locally for debugging. ## Enabling Call Reports Call reports are automatically enabled when you connect to the Telnyx WebRTC service. The SDK handles data collection and upload transparently. Call reports are sent automatically when a call ends. No additional configuration is required. ## Accessing Local Call Reports For debugging purposes, you can access the call report JSON file that is saved locally after each call: ```kotlin theme={null} // Get the path to the last generated call stats JSON file val jsonPath = telnyxClient.getLastCallStatsJsonPath() // Read and process the JSON file jsonPath?.let { path -> val file = File(path) if (file.exists()) { val jsonContent = file.readText() // Process the call stats JSON } } ``` Call stats files are saved to: `/call_stats/call_stats_.json` ## Call Report JSON Structure The call report JSON contains the following sections: ### Top-Level Identifiers ```json theme={null} { "call_id": "uuid-of-the-call", "call_report_id": "report-token-from-server", "telnyx_leg_id": "uuid-of-telnyx-leg", "telnyx_session_id": "uuid-of-telnyx-session", "voice_sdk_id": "websocket-session-id" } ``` ### Summary Section Contains high-level call information: ```json theme={null} { "summary": { "callId": "uuid-of-the-call", "callerNumber": "+1234567890", "destinationNumber": "+0987654321", "direction": "outbound", "durationSeconds": 120.5, "startTimestamp": "2026-03-23T12:00:00.000Z", "endTimestamp": "2026-03-23T12:02:00.500Z", "sdkVersion": "3.5.0", "state": "done", "telnyxLegId": "uuid", "telnyxSessionId": "uuid" } } ``` ### Stats Array Contains interval-based statistics captured during the call. Each interval (typically 5 seconds) includes: ```json theme={null} { "stats": [ { "audio": { "inbound": { "bytesReceived": 48000, "packetsReceived": 500, "packetsLost": 2, "packetsDiscarded": 0, "jitterAvg": 10.5, "jitterBufferDelay": 50.0, "concealedSamples": 100, "concealmentEvents": 1, "audioLevelAvg": 0.85 }, "outbound": { "bytesSent": 48000, "packetsSent": 500, "audioLevelAvg": 0.78 } }, "connection": { "bytesReceived": 50000, "bytesSent": 50000, "packetsReceived": 520, "packetsSent": 520, "roundTripTimeAvg": 45.2 }, "ice": { "local": { "candidateType": "host", "protocol": "udp", "address": "192.168.1.100", "port": 54321 }, "remote": { "candidateType": "srflx", "protocol": "udp", "address": "203.0.113.50", "port": 12345 }, "nominated": true, "state": "succeeded" }, "transport": { "dtlsState": "connected", "iceState": "connected", "srtpCipher": "AEAD_AES_128_GCM", "tlsVersion": "DTLS 1.2" }, "intervalStartUtc": "2026-03-23T12:00:00.000Z", "intervalEndUtc": "2026-03-23T12:00:05.000Z" } ] } ``` ### Android Extra Section Contains Android-specific debugging information: ```json theme={null} { "android_extra": { "deviceInfo": { "userAgent": "TelnyxAndroidSDK/3.5.0", "networkType": "WiFi", "osVersion": "Android 14 (API 34)", "deviceModel": "Google Pixel 8", "selectedCodec": "audio/opus", "permissions": { "microphone": true, "notifications": true } }, "connectionState": { "lastIceGatheringState": "complete", "lastIceConnectionState": "connected", "lastDtlsState": "connected", "lastSignalingState": "stable" }, "connectionTimeline": [ { "event": "ICE_CHECKING", "timestamp": "2026-03-23T12:00:00.100Z" }, { "event": "ICE_CONNECTED", "timestamp": "2026-03-23T12:00:00.500Z" }, { "event": "DTLS_CONNECTING", "timestamp": "2026-03-23T12:00:00.600Z" }, { "event": "DTLS_CONNECTED", "timestamp": "2026-03-23T12:00:01.200Z" } ], "iceCandidates": { "total": 6, "hostCount": 2, "srflxCount": 2, "relayCount": 2 } } } ``` ## Metrics Reference ### Audio Inbound Metrics | Metric | Description | | ------------------- | ----------------------------------- | | `bytesReceived` | Total bytes received | | `packetsReceived` | Total packets received | | `packetsLost` | Number of lost packets | | `packetsDiscarded` | Packets discarded by jitter buffer | | `jitterAvg` | Average jitter in milliseconds | | `jitterBufferDelay` | Jitter buffer delay in milliseconds | | `concealedSamples` | Number of concealed audio samples | | `concealmentEvents` | Number of concealment events | | `audioLevelAvg` | Average audio level (0.0 to 1.0) | ### Audio Outbound Metrics | Metric | Description | | --------------- | ----------------------------------------- | | `bytesSent` | Total bytes sent | | `packetsSent` | Total packets sent | | `audioLevelAvg` | Average outgoing audio level (0.0 to 1.0) | ### Connection Metrics | Metric | Description | | ------------------ | --------------------------------------- | | `roundTripTimeAvg` | Average round-trip time in milliseconds | | `bytesReceived` | Total transport bytes received | | `bytesSent` | Total transport bytes sent | ## Troubleshooting with Call Reports Call reports can help diagnose common issues: ### High Packet Loss Look at `packetsLost` in the audio inbound stats. Values above 1-2% may indicate network issues. ### Audio Quality Issues Check `jitterAvg` and `concealmentEvents`. High jitter (>30ms) or frequent concealment events indicate audio quality degradation. ### Connection Failures Review the `connectionTimeline` in `android_extra`. Look for: * `ICE_FAILED` - Network connectivity issues * `DTLS_FAILED` - TLS/security handshake failures * Long gaps between `ICE_CONNECTED` and `DTLS_CONNECTED` (>5 seconds) ### One-Way Audio Check if: * `packetsReceived` is 0 (not receiving audio) * `audioLevelAvg` is 0 (microphone not capturing) * Review microphone permissions in `deviceInfo.permissions` ## Privacy & Data Handling Call reports are sent securely to Telnyx and are used solely for: * Troubleshooting call quality issues * Monitoring service health * Improving SDK performance Call reports do not include actual audio content or personally identifiable information beyond call metadata. ## See Also * [WebRTC Stats](/development/webrtc/android-sdk/stats) - Real-time call quality metrics * [Error Handling](/development/webrtc/android-sdk/error-handling) - SDK error codes and handling * [Troubleshooting Guide](/docs/voice/webrtc/push-notifications/android/troubleshooting) - Common issues and solutions # WebRTC Android ChangeLog Source: https://developers.telnyx.com/development/webrtc/android-sdk/changelog/index A comprehensive record of all updates, enhancements, and bug fixes. Stay informed about the latest features and improvements to optimize your development experience. ## [3.5.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.5.0) (2026-03-20) ### Enhancement * WebRTC Call Stats and Troubleshooting Tool with JSON export and automatic upload to voice-sdk-proxy (WEBRTC-3227) * Add ICE candidate pair details to Call Stats including connection state, network type, and candidate info (WEBRTC-3346) * Add transport stats (dtlsState, iceState, srtpCipher, tlsVersion) to call report intervals (WEBRTC-3415) * Add audioLevelAvg for inbound/outbound audio per stats interval (WEBRTC-3414) * Add SDK latency measurement for WebRTC call establishment with milestone tracking (WEBRTC-3276) * Handle telnyx\_call\_control\_id in answer for Call Control integration (WEBRTC-3341) ### Bug Fixing * Fix clientState truncation when payload exceeds 57 bytes due to Base64.DEFAULT newline insertion (ENGDESK-50462) * Prevent SIGSEGV crash in WebRTCReporter stats timer after PeerConnection teardown ## [3.4.1](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.4.1) (2026-03-05) ### Enhancement * Add conversation\_id parameter to anonymous login methods for joining existing conversations (WEBRTC-3319) ### Bug Fixing * Fix CallState.CONNECTING emitted on active call when receiving a second incoming call ## [3.4.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.4.0) (2025-02-18) ### Enhancement * ICE Trickle Support for faster call setup * Port TURN/STUN server configuration changes with custom ICE servers support * Add DebugDataCollector for call debug logging * Call Connection Benchmarking support * Add answered\_device\_token parameter for push notification call answering * Add DEV\_TURN and DEV\_STUN constants for development environment * Support for starting calls with muted microphone (Invite/Answer muted) ### Bug Fixing * Fix incorrect client ready state on failed login * Retry with exponential backoff when server closes during reconnection ## [3.3.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.3.0) (2025-11-18) ### Enhancement * Support for base64 encoded images in AI assistant messages * Added AudioConstraints data class on invite and answer to allow for echoCancellation, noiseSuppression and autoGainControl ### Bug Fixing * When TxSocket is now closing by close() instead of cancel() to prevent onError callback ## [3.2.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.2.0) (2025-10-22) ### Enhancement * Connection State Exposure with DISCONNECTED, CONNECTED, RECONNECTING, CLIENT\_READY states * Expose Socket Connection Quality * ICE Candidates Renegotiation ### Bug Fixing * Preferred Audio Codec Implementation ## [3.1.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.1.0) (2025-08-27) ### Enhancement * Anonymous Login + AI Agent related features * Preferred Codec implementation ## [3.0.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/3.0.0) (2025-07-17) ### Enhancement * Implemented forceRelayCandidate parameter in Android WebRTC SDK. * Migration from LiveData to Flows. (LiveData still supported for backward compatibility however methods are marked as deprecated) ## [2.0.2](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/2.0.2) (2025-06-17) ### Enhancement * Add Region parameter available to be set. This allows developers to restrict connection only to some regions. * Add parameter for prefetching ice candidates during call initiation. ### Bug Fixing * Fixed an issue where the Termination Cause was always 'USER\_BUSY' regardless of current call state. Now, when terminating an active call, the state will be 'NORMAL\_CLEARING' and when rejecting an invite, the Termination Cause will be 'USER\_BUSY'. ## [2.0.1](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/2.0.1) (2025-06-08) ### Enhancement * Further enhance error handling by modifying SocketObserver's onError method signature to include the Error Code as well as the Message. ## [2.0.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/2.0.0) (2025-05-22) ### Enhancement * Expose Call Termination Reasons in SDK and Surface Error Messages and Codes outside of the SDK. This allows developers to handle call termination reasons and error messages more effectively in their applications. ## [1.7.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.7.0) (2025-05-08) ### Enhancement * Add Call Quality metrics to the SDK to provide insights into call performance and quality. This is handled on a per call basis via a debug parameter and is different to the debug parameter passed at a config level. ### Bug Fixing * Ice Candidate Collection is now handled in the call object rather than universally in TelnyxClient, allowing for concurrent outgoing calls to be made without interference. This change improves the handling of multiple calls and ensures that each call's ICE candidates are managed independently. * Connection is now recovered after Network lost ## [1.6.4](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.6.3) (2025-04-23) ### Bug Fixing * Natively use transceivers to handle audio and video tracks instead of using separate streams. This change improves the handling of audio and video tracks in WebRTC calls, ensuring better compatibility with various devices and networks. * Further enhance Ice Candidate Collection when answering calls to ensure more suitable candidates are used in the SDP. * SDP Munging is now handled natively in the WebRTC library, which improves the overall performance and reliability of the call setup process. ## [1.6.3](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.6.3) (2025-04-08) ### Bug Fixing * Enhanced Ice Candidate Collection when answering calls to ensure more suitable candidates are used in the SDP. ## [1.6.2](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.6.2) (2025-03-28) ### Bug Fixing * Provide proper feedback when codec error occurs through the `onError` callback. * Tag logs for easier identification. ## [1.6.1](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.6.1) (2025-03-20) ### Bug Fixing * Fixed an issue where we were including local candidates in the SDP offer, which was causing issues with some networks. * Adjusted the Peer class to also use the provided Logger when logging messages so that these can be used by a custom logger provided by the user (or our default logger if none is provided). ## [1.6.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.6.0) (2025-03-07) ### Enhancement * Added reconnect timeout functionality to handle call reconnection failures. ## [1.5.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.5.0) (2025-03-07) ### Enhancement * Disable Push Notification call is now simplified, no longer requiring parameters to be passed in the SDK. We instead use the last logged in user to disable push notifications. This Aligns with our iOS and Flutter implementations * Added the ability to pass your own custom logger when connecting to redirect logs to your own logging system or log using a different chosen library. * Added new CallStates to represent DROPPED and RECONNECTING states in regards to network drops while on a call. ### Bug Fixing * Fixed an issue where listeners declared before connecting to the SDK would not receive events. ## [1.4.4](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.4) (2025-02-04) ### Enhancement * Add Debug Stats ability by passing bool to Connection allowing you to see stats of calls in portal * Remove BugSnag from SDK to reduce size as it is no longer required ## [1.4.3](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.3) (2025-01-22) ### Bug Fixing * Fix missing STUN or TURN Candidates in SDP ## [1.4.2](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.2) (2024-11-18) ### Enhancement * ICE candidates are no longer added to the peer connection after the establishment of the call to prevent use of ICE candidates that are not negotiated in the SDP. ## [1.4.2-beta](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.2-beta) (2024-10-31) ### Enhancement * Implemented websocket and RTC peer reconnection logic in the event of a network disconnect or network switch. ## [1.4.1](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.1) (2024-10-31) ### Enhancement * Implemented websocket and RTC peer reconnection logic in the event of a network disconnect or network switch. ## [1.4.0](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.4.0) (2024-09-18) ### Enhancement * Updated WebRTC library and added reconnection logic for Socket and Voice-SDK-ID. ## [1.3.9](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.3.9) (2024-08-27) ### Bug Fixing * Fixed SSL error on Android 8.1. ## [1.3.8](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.3.8) (2024-08-15) ### Enhancement * Improved stability of WebRTC session reconnection logic. ## [1.3.7](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.3.7) (2024-08-01) ### Enhancement * Added new ICE server configuration and enhanced logging for troubleshooting. ## [1.3.6](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.3.6) (2024-07-20) ### Bug Fixing * Refactored audio handling logic for improved compatibility with low-end devices. ## [1.3.5](https://github.com/team-telnyx/telnyx-webrtc-android/releases/tag/1.3.5) - 2024-07-10 ### Bug Fixing * Fix JVM issue with the androidxlifecycle. The androidxlifecycle observer onChanged(..) method was updated to fun onChanged(value: T) which was previously fun onChanged(value: T) the cause of the issue. # WebRTC Android Call Source: https://developers.telnyx.com/development/webrtc/android-sdk/classes/call/index A Call is the representation of an audio or video call between two devices, SIP clients or phone numbers. ### Telnyx Call Class that represents a Call and handles all call related actions, including answering and ending a call. ### Creating a call invitation In order to make a call invitation, you need to provide your callerName, callerNumber, the destinationNumber (or SIP credential), and your clientState (any String value). ```kotlin theme={null} telnyxClient.call.newInvite(callerName, callerNumber, destinationNumber, clientState) ``` ### Accepting a call In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response as LiveData: ```kotlin theme={null} fun getSocketResponse(): LiveData>? = telnyxClient.getSocketResponse() ``` We can then use this method to create a listener that listens for an invitation - in this example we assume getSocketResponse is a method within a ViewModel. ```kotlin theme={null} mainViewModel.getSocketResponse() ?.observe(this, object : SocketObserver() { override fun onConnectionEstablished() { // Handle a succesfully established connection } override fun onMessageReceived(data: ReceivedMessageBody?) { when (data?.method) { SocketMethod.CLIENT_READY.methodName -> { // Fires once client has correctly been setup and logged into, you can now make calls. } SocketMethod.LOGIN.methodName -> { // Handle a successful login - Update UI or Navigate to new screen, etc. } SocketMethod.INVITE.methodName -> { // Handle an invitation Update UI or Navigate to new screen, etc. // Then, through an answer button of some kind we can accept the call with: val inviteResponse = data.result as InviteResponse mainViewModel.acceptCall(inviteResponse.callId, inviteResponse.callerIdNumber) } SocketMethod.ANSWER.methodName -> { //Handle a received call answer - Update UI or Navigate to new screen, etc. } SocketMethod.BYE.methodName -> { // Handle a call rejection or ending - Update UI or Navigate to new screen, etc. } SocketMethod.RINGING.methodName -> { // Client Can simulate ringing state } SocketMethod.RINGING.methodName -> { // Ringback tone is streamed to the caller // early Media - Client Can simulate ringing state } } } override fun onLoading() { // Show loading dialog } override fun onError(errorCode: Int?, message: String?) { // Handle errors - Update UI or Navigate to new screen, etc. // errorCode provides additional context about the error type } override fun onSocketDisconnect() { // Handle disconnect - Update UI or Navigate to login screen, etc. } }) ``` When we receive a call we will receive an InviteResponse data class that contains the details we need to accept the call. We can then call the acceptCall method in TelnyxClient from our ViewModel: ### Handling Multiple Calls The Telnyx WebRTC SDK allows for multiple calls to be handled at once. You can use the callId to differentiate the calls.. ```kotlin theme={null} import java.util.UUID // Retrieve all calls from the TelnyxClient val calls: Map = telnyxClient.calls // Retrieve a specific call by callId val currentCall: Call? = calls[callId] ``` With the current call object, you can perform actions such as: 1. Hold/UnHold `currentCall.onHoldUnholdPressed(callId: UUID)` 2. Mute/UnMute `currentCall.onMuteUnmutePressed()` 3. AcceptCall `currentCall.acceptCall(...)` 4. EndCall `currentCall.endCall(callId: UUID)` The `Call` class is a fundamental part of the Telnyx WebRTC SDK, representing an active or pending call session. It provides properties to observe the call's state and methods to control the call, such as ending it, muting/unmuting audio, and managing hold states. ## Key Properties * **`callId: UUID`**: A unique identifier for the call. * **`sessionId: String`**: The session ID associated with the Telnyx connection. * **`callStateFlow: StateFlow`**: A Kotlin Flow that emits updates to the call's current state. This is the primary way to observe real-time changes to the call. States include: * `CallState.NEW`: The call has been locally initiated but not yet sent. * `CallState.CONNECTING`: The call is in the process of connecting. * `CallState.RINGING`: The call invitation has been sent, and the remote party is being alerted. * `CallState.ACTIVE`: The call is established and active. * `CallState.HELD`: The call is on hold. * `CallState.DONE(reason: CallTerminationReason?)`: The call has ended. The optional `reason` parameter provides details about why the call terminated (e.g., normal hangup, call rejected, busy, SIP error). `CallTerminationReason` contains `cause`, `causeCode`, `sipCode`, and `sipReason`. * `CallState.ERROR`: An error occurred related to this call. * `CallState.DROPPED(reason: CallNetworkChangeReason)`: The call was dropped, typically due to network issues. The `reason` (`CallNetworkChangeReason.NETWORK_LOST` or `CallNetworkChangeReason.NETWORK_SWITCH`) provides context. * `CallState.RECONNECTING(reason: CallNetworkChangeReason)`: The SDK is attempting to reconnect the call after a network disruption. The `reason` provides context. * **`onCallQualityChange: ((CallQualityMetrics) -> Unit)?`**: A callback for real-time call quality metrics. * **`audioManager: AudioManager`**: Reference to the Android `AudioManager` for controlling audio settings. * **`peerConnection: Peer?`**: Represents the underlying WebRTC peer connection. ## Key Methods * **`newInvite(...)`**: (Typically initiated via `TelnyxClient`) Initiates a new outgoing call. * **`acceptCall(...)`**: (Typically initiated via `TelnyxClient`) Accepts an incoming call. * **`endCall(callId: UUID)`**: Terminates the call. This is usually called on the `TelnyxClient` which then manages the specific `Call` object. * **`onMuteUnmutePressed()`**: Toggles the microphone mute state. * **`onLoudSpeakerPressed()`**: Toggles the loudspeaker state. * **`onHoldUnholdPressed(callId: UUID)`**: Toggles the hold state for the call. * **`dtmf(callId: UUID, tone: String)`**: Sends DTMF tones. ## Observing Call State Applications should observe the `callStateFlow` to react to changes in the call's status and update the UI accordingly. For example, displaying call duration when `ACTIVE`, showing a "reconnecting" indicator when `RECONNECTING`, or presenting termination reasons when `DONE`. ```kotlin theme={null} // Example: Observing call state in a ViewModel or Composable viewModelScope.launch { myCall.callStateFlow.collect { state -> when (state) { is CallState.ACTIVE -> { // Update UI to show active call controls } is CallState.DONE -> { // Call has ended, update UI // Access state.reason for termination details val reasonDetails = state.reason?.let { "Cause: ${it.cause}, SIP Code: ${it.sipCode}" } ?: "No specific reason provided." Log.d("Call Ended", "Reason: $reasonDetails") } is CallState.DROPPED -> { // Call dropped, possibly show a message with state.reason.description Log.d("Call Dropped", "Reason: ${state.callNetworkChangeReason.description}") } is CallState.RECONNECTING -> { // Call is reconnecting, update UI Log.d("Call Reconnecting", "Reason: ${state.callNetworkChangeReason.description}") } // Handle other states like NEW, CONNECTING, RINGING, HELD, ERROR else -> { /* ... */ } } } } ``` For more details on specific parameters and advanced usage, refer to the SDK's source code and the main `TelnyxClient` documentation. # WebRTC Android Client Source: https://developers.telnyx.com/development/webrtc/android-sdk/classes/txclient/index The TelnyxClient connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls `TelnyxClient` is the main entry point for interacting with the Telnyx WebRTC SDK. It handles connection management, call creation, and responses from the Telnyx platform. ## Core Functionalities * **Connection Management**: Establishes and maintains a WebSocket connection to the Telnyx RTC platform. * **Authentication**: Supports authentication via SIP credentials or tokens. * **Call Control**: Provides methods to initiate (`newInvite`), accept (`acceptCall`), and end (`endCall`) calls. * **Event Handling**: Uses `TxSocketListener` to process events from the socket, such as incoming calls (`onOfferReceived`), call answers (`onAnswerReceived`), call termination (`onByeReceived`), and errors (`onErrorReceived`). * **State Exposure**: Exposes connection status, session information, and call events via `SharedFlow` (recommended: `socketResponseFlow`) and deprecated `LiveData` (e.g., `socketResponseLiveData`) for UI consumption. ## Key Components and Interactions * **`TxSocket`**: Manages the underlying WebSocket communication. * **`TxSocketListener`**: An interface implemented by `TelnyxClient` to receive and process socket events. Notably: * `onOfferReceived(jsonObject: JsonObject)`: Handles incoming call invitations. * `onAnswerReceived(jsonObject: JsonObject)`: Processes answers to outgoing calls. * `onByeReceived(jsonObject: JsonObject)`: Handles call termination notifications. The `jsonObject` now contains richer details including `cause`, `causeCode`, `sipCode`, and `sipReason`, allowing the client to populate `CallState.DONE` with a detailed `CallTerminationReason`. * `onErrorReceived(jsonObject: JsonObject)`: Manages errors reported by the socket or platform. * `onClientReady(jsonObject: JsonObject)`: Indicates the client is ready for operations after connection and initial setup. * `onGatewayStateReceived(gatewayState: String, receivedSessionId: String?)`: Provides updates on the registration status with the Telnyx gateway. * **`Call` Class**: Represents individual call sessions. `TelnyxClient` creates and manages instances of `Call`. * **`CallState`**: The client updates the `CallState` of individual `Call` objects based on socket events and network conditions. This includes states like `DROPPED(reason: CallNetworkChangeReason)`, `RECONNECTING(reason: CallNetworkChangeReason)`, and `DONE(reason: CallTerminationReason?)` which now provide more context. * **`socketResponseFlow: SharedFlow>`**: This SharedFlow stream is the recommended approach for applications. It emits `SocketResponse` objects that wrap messages received from the Telnyx platform. For `BYE` messages, the `ReceivedMessageBody` will contain a `com.telnyx.webrtc.sdk.verto.receive.ByeResponse` which is now enriched with termination cause details. * **`socketResponseLiveData: LiveData>`**: **\[DEPRECATED]** This LiveData stream is deprecated in favor of `socketResponseFlow`. It's maintained for backward compatibility but new implementations should use SharedFlow. ## Usage Example **Recommended approach using SharedFlow:** ```kotlin theme={null} // Initializing the client val telnyxClient = TelnyxClient(context) // Observing responses using SharedFlow (Recommended) lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.MESSAGERECEIVED -> { response.data?.let { when (it.method) { SocketMethod.INVITE.methodName -> { val invite = it.result as InviteResponse // Handle incoming call invitation } SocketMethod.BYE.methodName -> { val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse // Call ended by remote party, bye.cause, bye.sipCode etc. are available Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}") } // Handle other methods like ANSWER, RINGING, etc. } } } SocketStatus.ERROR -> { // Handle errors Log.e("TelnyxClient", "Error: ${response.errorMessage}") } // Handle other statuses: ESTABLISHED, LOADING, DISCONNECT } } } ``` **Deprecated approach using LiveData:** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") // Observing responses (including errors and BYE messages) telnyxClient.socketResponseLiveData.observe(lifecycleOwner, Observer { response -> when (response.status) { SocketStatus.MESSAGERECEIVED -> { response.data?.let { when (it.method) { SocketMethod.INVITE.methodName -> { val invite = it.result as InviteResponse // Handle incoming call invitation } SocketMethod.BYE.methodName -> { val bye = it.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse // Call ended by remote party, bye.cause, bye.sipCode etc. are available Log.d("TelnyxClient", "Call ended: ${bye.callId}, Reason: ${bye.cause}") } // Handle other methods like ANSWER, RINGING, etc. } } } SocketStatus.ERROR -> { // Handle errors Log.e("TelnyxClient", "Error: ${response.errorMessage}") } // Handle other statuses: ESTABLISHED, LOADING, DISCONNECT } }) // Connecting and Logging In (example with credentials) telnyxClient.connect( credentialConfig = CredentialConfig( sipUser = "your_sip_username", sipPassword = "your_sip_password", // ... other config ... ) ) // Making a call val outgoingCall = telnyxClient.newInvite( callerName = "My App", callerNumber = "+11234567890", destinationNumber = "+10987654321", clientState = "some_state" ) // Observing the specific call's state outgoingCall.callStateFlow.collect { state -> if (state is CallState.DONE) { Log.d("TelnyxClient", "Outgoing call ended. Reason: ${state.reason?.cause}") } // Handle other states } ``` Refer to the SDK's implementation and specific method documentation for detailed usage patterns and configuration options. ## Telnyx Client NOTE: Remember to add and handle INTERNET, RECORD\_AUDIO and ACCESS\_NETWORK\_STATE permissions

### Initialize To initialize the TelnyxClient you will have to provide the application context. ```kotlin theme={null} telnyxClient = TelnyxClient(context) ``` ### Connect Once an instance is created, you can call the one of two available .connect(....) method to connect to the socket. ```kotlin theme={null} fun connect( providedServerConfig: TxServerConfiguration = TxServerConfiguration(), credentialConfig: CredentialConfig, txPushMetaData: String? = null, autoLogin: Boolean = true, ) ``` Connects to the socket by credential and using this client as the listener. Will respond with 'No Network Connection' if there is no network available Parameters: * providedServerConfig, the TxServerConfiguration used to connect to the socket * txPushMetaData, the push metadata used to connect to a call from push (Get this from push notification - fcm data payload) required fot push calls to work * credentialConfig, represents a SIP user for login - credential based * autoLogin, if true, the SDK will automatically log in with the provided credentials on connection established. We recommend setting this to true. ```kotlin theme={null} fun connect( providedServerConfig: TxServerConfiguration = TxServerConfiguration(), tokenConfig: TokenConfig, txPushMetaData: String? = null, autoLogin: Boolean = true, ) ``` Connects to the socket by token and using this client as the listener. Will respond with 'No Network Connection' if there is no network available * providedServerConfig, the TxServerConfiguration used to connect to the socket * txPushMetaData, the push metadata used to connect to a call from push (Get this from push notification - fcm data payload) required fot push calls to work * tokenConfig, represents a SIP user for login - token based * autoLogin, if true, the SDK will automatically log in with the provided credentials on connection established. We recommend setting this to true. **Note:** **tokenConfig** and **credentialConfig** are data classes that represent login settings for the client to use. They belong to **TelnyxConfig** and can be found in Data part. ### Listening for events and reacting We need to react for a socket connection state or incoming calls. We do this by getting the Telnyx Socket Response callbacks from our TelnyxClient. **Recommended approach using SharedFlow:** ```kotlin theme={null} val socketResponseFlow: SharedFlow> ``` Returns the socket response in the form of SharedFlow (Kotlin Flows). The format of each message is provided in `SocketResponse` and `ReceivedMessageBody`. * @see \[SocketResponse] * @see \[ReceivedMessageBody] **Deprecated approach using LiveData:** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") fun getSocketResponse(): LiveData> = socketResponseLiveData ``` Returns the socket response in the form of LiveData. The format of each message is provided in `SocketResponse` and `ReceivedMessageBody`. * @see \[SocketResponse] * @see \[ReceivedMessageBody] Response can be observed by implementation of abstract class `SocketObserver`. In `onMessageReceived` we will receive objects of `ReceivedMessageBody` class. ```kotlin theme={null} abstract class SocketObserver : Observer> { abstract fun onConnectionEstablished() abstract fun onMessageReceived(data: T?) abstract fun onLoading() abstract fun onError(errorCode: Int?, message: String?) abstract fun onSocketDisconnect() override fun onChanged(value: SocketResponse) { when (value.status) { SocketStatus.ESTABLISHED -> onConnectionEstablished() SocketStatus.MESSAGERECEIVED -> onMessageReceived(value.data) SocketStatus.LOADING -> onLoading() SocketStatus.ERROR -> onError(value.errorCode, value.errorMessage) SocketStatus.DISCONNECT -> onSocketDisconnect() } } } ``` # WebRTC Android Config Source: https://developers.telnyx.com/development/webrtc/android-sdk/config/txconfig/index Telnyx Config handle the properties provided when logging into the TelnyxClient with SIP details ## Telnyx Config This is a sealed class to handle the properties provided when logging into the TelnyxClient with SIP details. The sealed class is either Credential or Token based. ```kotlin theme={null} sealed class TelnyxConfig ``` ### Credential Config Represents a SIP user for login - Credential based **sipUser** - The SIP username of the user logging in **sipPassword** - The SIP password of the user logging in **sipCallerIDName** - The user's chosen Caller ID Name (optional) **sipCallerIDNumber** - The user's Caller ID Number (optional) **fcmToken** - The user's Firebase Cloud Messaging device ID (optional) **ringtone** - The integer raw value or uri of the audio file to use as a ringtone. Supports only raw file or uri (optional) **ringBackTone** - The integer raw value of the audio file to use as a ringback tone (optional) **logLevel** - The log level that the SDK should use. Default value is `LogLevel.NONE` **customLogger** - Optional custom logger implementation to handle SDK logs **autoReconnect** - Whether or not to reattempt (3 times) the login in the instance of a failure to connect and register to the gateway with valid credentials. Default is `false` **debug** - Whether or not to send client debug reports. Default is `false` **reconnectionTimeout** - How long the app should try to reconnect to the socket server before giving up (in milliseconds). Default is `60000` **region** - The region to use for the connection. Default is `Region.AUTO`. See [Available Regions](#available-regions) for options **fallbackOnRegionFailure** - Whether or not to connect to default region if the selected region is not reachable. Default is `true` ```kotlin theme={null} data class CredentialConfig( val sipUser: String, val sipPassword: String, val sipCallerIDName: String?, val sipCallerIDNumber: String?, val fcmToken: String?, val ringtone: Any?, val ringBackTone: Int?, val logLevel: LogLevel = LogLevel.NONE, val customLogger: TxLogger? = null, val autoReconnect: Boolean = false, val debug: Boolean = false, val reconnectionTimeout: Long = 60000, val region: Region = Region.AUTO, val fallbackOnRegionFailure: Boolean = true ) : TelnyxConfig() ``` ### Token Config Represents a SIP user for login - Token based **sipToken** - The JWT token for the SIP user **sipCallerIDName** - The user's chosen Caller ID Name (optional) **sipCallerIDNumber** - The user's Caller ID Number (optional) **fcmToken** - The user's Firebase Cloud Messaging device ID (optional) **ringtone** - The integer raw value or uri of the audio file to use as a ringtone. Supports only raw file or uri (optional) **ringBackTone** - The integer raw value of the audio file to use as a ringback tone (optional) **logLevel** - The log level that the SDK should use. Default value is `LogLevel.NONE` **customLogger** - Optional custom logger implementation to handle SDK logs **autoReconnect** - Whether or not to reattempt (3 times) the login in the instance of a failure to connect and register to the gateway with valid token. Default is `true` **debug** - Whether or not to send client debug reports. Default is `false` **reconnectionTimeout** - How long the app should try to reconnect to the socket server before giving up (in milliseconds). Default is `60000` **region** - The region to use for the connection. Default is `Region.AUTO`. See [Available Regions](#available-regions) for options **fallbackOnRegionFailure** - Whether or not to connect to default region if the selected region is not reachable. Default is `true` ```kotlin theme={null} data class TokenConfig( val sipToken: String, val sipCallerIDName: String?, val sipCallerIDNumber: String?, val fcmToken: String?, val ringtone: Any?, val ringBackTone: Int?, val logLevel: LogLevel = LogLevel.NONE, val customLogger: TxLogger? = null, val autoReconnect: Boolean = true, val debug: Boolean = false, val reconnectionTimeout: Long = 60000, val region: Region = Region.AUTO, val fallbackOnRegionFailure: Boolean = true ) : TelnyxConfig() ``` ## Available Regions The `region` parameter accepts a `Region` enum value that determines which Telnyx data center region to connect to. This can help optimize connection quality and latency based on your geographic location. ### Region Options **Region.AUTO** - Automatically selects the best region based on network conditions (default) **Region.EU** - European region for users in Europe **Region.US\_CENTRAL** - US Central region for users in central United States **Region.US\_EAST** - US East region for users in eastern United States **Region.US\_WEST** - US West region for users in western United States **Region.CA\_CENTRAL** - Canada Central region for users in central Canada **Region.APAC** - Asia-Pacific region for users in Asia-Pacific areas ### Usage Example ```kotlin theme={null} // Using a specific region val credentialConfig = CredentialConfig( sipUser = "your_sip_user", sipPassword = "your_sip_password", sipCallerIDName = "Your Name", sipCallerIDNumber = "1234567890", region = Region.US_EAST, fallbackOnRegionFailure = true ) // Using automatic region selection (default) val tokenConfig = TokenConfig( sipToken = "your_jwt_token", sipCallerIDName = "Your Name", sipCallerIDNumber = "1234567890", region = Region.AUTO ) ``` ### Region Fallback When `fallbackOnRegionFailure` is set to `true` (default), the SDK will automatically fall back to the default region if the selected region is unreachable. This ensures better connection reliability while still attempting to use your preferred region first. # WebRTC Android SDK Error Handling Source: https://developers.telnyx.com/development/webrtc/android-sdk/error-handling/index A complete guide to error handling for the Android Voice SDK This document describes the error handling mechanisms and call state event details in the Telnyx WebRTC Android SDK. It is divided into a **Reference** section detailing possible errors and states, and a **Guide** section on how to consume and manage them. ## Error & Call State Reference This section provides a reference for the various error conditions and call states you might encounter when using the SDK. ### 1. Socket-Level Errors (via `SocketResponse`) These errors are typically reported through the `TelnyxClient.socketResponseFlow` (recommended) or the deprecated `TelnyxClient.socketResponseLiveData` when `SocketResponse.status` is `SocketStatus.ERROR`. The `SocketResponse` for errors now includes an optional `errorCode: Int?` field in addition to the `errorMessage: String?`. * **Gateway Registration Issues**: * `errorMessage`: "Gateway registration has timed out", `errorCode`: -32003 (Triggered if gateway status is not "REGED" e.g., `GatewayState.NOREG`, or `GatewayState.EXPIRED`). * `errorMessage`: "Gateway registration has failed", `errorCode`: -32004 (Triggered if gateway status is "FAILED" or results in `GatewayState.FAIL_WAIT`). * **WebSocket Error Messages from Server**: * The `errorMessage` will contain the server-provided message. * The `errorCode` will contain the server-provided error code (e.g., -32000 for token error, -32001 for credential error) if available in the JSON payload from the server. * **No Network Connection (on initial connect)**: * `errorMessage`: "No Network Connection", `errorCode`: `null` (Triggered if an attempt to connect is made when the device has no active network connection). * **Client-Side Reconnection Timeout**: * `errorMessage`: "Reconnection timeout after X seconds", `errorCode`: `null` (Triggered if the SDK's internal reconnection timer expires). ### 2. Call-Specific States & Reasons (via `Call.callStateFlow`) Individual `Call` objects emit their state changes through `callStateFlow`. Several states now include detailed reasons: * **`CallState.DROPPED(reason: CallNetworkChangeReason)`**: * Indicates a call was dropped, usually due to network problems. * `reason` (of type `CallNetworkChangeReason`) provides context: * `CallNetworkChangeReason.NETWORK_LOST`: Network connectivity was completely lost. * `CallNetworkChangeReason.NETWORK_SWITCH`: A network switch occurred (e.g., Wi-Fi to Cellular), and while reconnection might be attempted, this state can be hit if it ultimately fails in that context, or if it's a direct drop without a reconnect attempt. * **`CallState.RECONNECTING(reason: CallNetworkChangeReason)`**: * The SDK is attempting to reconnect a call after a network disruption. * `reason` (of type `CallNetworkChangeReason`) provides context: * `CallNetworkChangeReason.NETWORK_SWITCH`: Typically seen when the SDK tries to recover a call after a network handover. * **`CallState.DONE(reason: CallTerminationReason?)`**: * The call has ended. The optional `reason` parameter (of type `CallTerminationReason`) provides details about *why* the call terminated. * `CallTerminationReason` fields: * `cause: String?`: A high-level cause string (e.g., "CALL\_REJECTED", "USER\_BUSY", "NORMAL\_CLEARING"). * `causeCode: Int?`: A numerical code associated with the cause (e.g., 21 for CALL\_REJECTED, 17 for USER\_BUSY, 16 for NORMAL\_CLEARING). * `sipCode: Int?`: The SIP response code, if applicable (e.g., 403, 486, 404). * `sipReason: String?`: The SIP reason phrase, if applicable (e.g., "Forbidden", "Busy Here", "Not Found"). * **`CallState.ERROR`**: * A general error occurred related to this specific call (e.g., failure to create offer/answer, media negotiation issues). This state itself does not carry a detailed reason object; specific error details might be logged internally or manifest as a transition to `CallState.DONE` with a reason. ### 3. Enriched `ByeResponse` Details (via `socketResponseFlow`) When a call is terminated by the remote party, a `BYE` message is received. The `TxSocketListener.onByeReceived(jsonObject: JsonObject)` method is triggered, and `TelnyxClient` processes this. * The `com.telnyx.webrtc.sdk.verto.receive.ByeResponse` object, which is delivered as the `result` within `ReceivedMessageBody` (when `method` is `SocketMethod.BYE.methodName`) via `socketResponseFlow` (recommended) or the deprecated `socketResponseLiveData`, is now enriched. * It contains the same detailed termination fields as `CallTerminationReason`: `callId`, `cause`, `causeCode`, `sipCode`, and `sipReason`. ### 4. Error/Cause Code Reference Table This table provides common causes and codes. For a comprehensive list of SIP codes and detailed troubleshooting, always refer to the [Telnyx Troubleshooting Guide for Call Completion](https://support.telnyx.com/en/articles/5025298-troubleshooting-call-completion). | Error Source / Category | `errorMessage` (Example) / `cause` (Example) | `errorCode` (from `SocketResponse`) / `causeCode` (from `CallTerminationReason`) | `sipCode` (from `CallTerminationReason`) | `sipReason` (Example) | Description / Common Scenario | | ------------------------------------------------------------------ | -------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------------- | --------------------------- | ------------------------------------------------------ | | **SocketResponse Errors** | "Gateway registration has timed out" | `SocketError.GATEWAY_TIMEOUT_ERROR.errorCode` (-32003) | N/A | N/A | Gateway registration timed out. | | | "Gateway registration has failed" | `SocketError.GATEWAY_FAILURE_ERROR.errorCode` (-32004) | N/A | N/A | Gateway registration failed after retries. | | | "Login Incorrect" | `SocketError.CREDENTIAL_ERROR.errorCode` (-32001) (if from server JSON) | N/A | N/A | Credential authentication error. | | | "Invalid Token" | `SocketError.TOKEN_ERROR.errorCode` (-32000) (if from server JSON) | N/A | N/A | Token authentication error. | | | "No Network Connection" | `null` | N/A | N/A | Client-side detection: no network on connect. | | **CallTerminationReason (from `CallState.DONE` or `ByeResponse`)** | | | | | | | General Call Clearing | `NORMAL_CLEARING` | 16 | N/A | N/A | Call ended normally. | | | `USER_BUSY` | 17 | 486 | "Busy Here" | Called party is busy. | | | `CALL_REJECTED` | 21 | 403 | "Forbidden" | Call rejected (invalid caller ID, auth failure, etc.). | | | `UNALLOCATED_NUMBER` | 1 | 404 | "Not Found" | Dialed number does not exist. | | | `NO_ANSWER` | 19 | 480 | "Temporarily Unavailable" | Callee did not answer. | | | `INCOMPATIBLE_DESTINATION` | 88 | 488/606 | "Not Acceptable Here" | Media negotiation failure. | | | `RECOVERY_ON_TIMER_EXPIRE` | 102 | N/A (often 408) | "Request Timeout" | Necessary response not received in time. | | SDK Internal Errors | `AnswerError` (example `cause`) | N/A | N/A | "No SDP in answer response" | SDK specific error during call setup. | *Note: Not all fields (`cause`, `causeCode`, `sipCode`, `sipReason`, `errorCode`) will be present for every error or `DONE` state. Presence depends on the nature and source of the event.* More SIP codes and their meanings can be found in the [Telnyx SIP Response Codes Guide](https://support.telnyx.com/en/articles/4409457-telnyx-sip-response-codes). ## Guide: Consuming Errors and Call Events This section explains how to effectively use the error and state information provided by the SDK. ### Observing Socket Responses (for General SDK Events & Errors) **Recommended approach using SharedFlow:** `TelnyxClient.socketResponseFlow` is the recommended channel for general SDK events, including connection status, errors (now with `errorCode`), and messages like incoming `BYE`. ```kotlin theme={null} // In your Activity or ViewModel lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.ERROR -> { Log.e("TelnyxSDK", "General SDK Error: ${response.errorMessage}, Code: ${response.errorCode}") // Handle specific error codes when (response.errorCode) { -32003 -> { // Gateway registration timeout showUserMessage("Connection timeout. Please check your credentials and try again.") } -32004 -> { // Gateway registration failed showUserMessage("Login failed. Please verify your credentials.") } // Handle other error codes... } } SocketStatus.MESSAGERECEIVED -> { response.data?.let { data -> when (data.method) { SocketMethod.BYE.methodName -> { val byeResponse = data.result as com.telnyx.webrtc.sdk.verto.receive.ByeResponse Log.d("TelnyxSDK", "Call ${byeResponse.callId} ended by remote party. Cause: ${byeResponse.cause}, SIP Code: ${byeResponse.sipCode}") // Update UI to reflect call termination } // Handle other message types... } } } // Handle other statuses... } } } ``` **Deprecated approach using LiveData:** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") // In your Activity or ViewModel telnyxClient.socketResponseLiveData.observe(this, Observer { response -> when (response.status) { SocketStatus.ERROR -> { Log.e("TelnyxSDK", "General SDK Error: ${response.errorMessage}, Code: ${response.errorCode}") // Handle specific error codes when (response.errorCode) { -32003 -> { // Gateway registration timeout showUserMessage("Connection timeout. Please check your credentials and try again.") } -32004 -> { // Gateway registration failed showUserMessage("Login failed. Please verify your credentials.") } // Handle other error codes... } } SocketStatus.MESSAGERECEIVED -> { response.data?.let { receivedMessageBody -> if (receivedMessageBody.method == SocketMethod.BYE.methodName) { val byeResponse = receivedMessageBody.result as? com.telnyx.webrtc.sdk.verto.receive.ByeResponse byeResponse?.let { val terminationMessage = "Remote party ended call (${it.callId}). " + "Reason: ${it.cause ?: "N/A"} (${it.causeCode ?: "N/A"})" + (it.sipCode?.let { sc -> " (SIP: $sc ${it.sipReason ?: ""})" } ?: "") Log.i("TelnyxSDK_Bye", terminationMessage) // The specific Call object's callStateFlow will also transition to CallState.DONE with this reason. } } // Handle other methods like INVITE, ANSWER, LOGIN, CLIENT_READY etc. } } // Handle other statuses: ESTABLISHED, LOADING, DISCONNECT } }) ``` ### Observing `Call.callStateFlow` (for Per-Call State and Reasons) For each individual `Call` object, observe its `callStateFlow` to get detailed state transitions and associated reasons. ```kotlin theme={null} // Assuming 'myCall' is an active Call object myCall.callStateFlow.collect { state -> when (state) { is CallState.ACTIVE -> { Log.i("CallState", "Call ${myCall.callId} is ACTIVE") // Update UI for active call } is CallState.DONE -> { val reason = state.reason val message = "Call ${myCall.callId} ENDED. " + (reason?.let { "Cause: ${it.cause ?: "Unknown"} (${it.causeCode ?: "N/A"}), " + "SIP: ${it.sipCode ?: "N/A"} ${it.sipReason ?: ""}" } ?: "No specific reason provided.") Log.i("CallState_Done", message) // Display termination reason to user, clean up call UI } is CallState.DROPPED -> { Log.w("CallState", "Call ${myCall.callId} DROPPED. Reason: ${state.callNetworkChangeReason.description}") // Inform user, potentially offer retry or end call UI } is CallState.RECONNECTING -> { Log.i("CallState", "Call ${myCall.callId} RECONNECTING. Reason: ${state.callNetworkChangeReason.description}") // Show reconnecting indicator } is CallState.ERROR -> { Log.e("CallState", "Call ${myCall.callId} entered ERROR state.") // Display error to user, clean up call UI } // Handle other states: NEW, CONNECTING, RINGING, HELD else -> Log.d("CallState", "Call ${myCall.callId} is now ${state.javaClass.simpleName}") } } ``` ## Best Practices for Error and State Handling 1. **Observe Both Channels**: Use `socketResponseFlow` (recommended) or the deprecated `socketResponseLiveData` for global SDK status/errors (including `errorCode`) and `call.callStateFlow` for individual call lifecycle management. 2. **Log Extensively**: During development, log error messages (with codes), call states, and reasons to aid in debugging. 3. **Provide Clear User Feedback**: Translate technical error codes and states into user-understandable messages. * Use `SocketResponse.errorCode` to distinguish specific socket/gateway errors. * For `CallState.DONE` with a `reason`, use the `cause`, `sipCode`, and `sipReason` to provide specific feedback (e.g., "User Busy", "Invalid Number", "Call Rejected: Restricted Area"). Refer to the [Telnyx Troubleshooting Guide](https://support.telnyx.com/en/articles/5025298-troubleshooting-call-completion) for common interpretations. * For `CallState.DROPPED` or `CallState.RECONNECTING`, inform the user about network issues. 4. **Implement Recovery/Retry Logic**: For network-related drops or gateway issues (identified by specific error codes or call states), consider implementing reconnection attempts or prompting the user. 5. **Graceful Degradation**: If critical errors occur (e.g., persistent gateway failure - `errorCode` -32004), ensure your app handles this gracefully, perhaps by disabling calling features and informing the user. ## Additional Resources * [Telnyx WebRTC Android SDK GitHub Repository](https://github.com/team-telnyx/telnyx-webrtc-android) * [API Documentation](https://developers.telnyx.com/docs/v2/webrtc) * [Telnyx Troubleshooting Guide for Call Completion](https://support.telnyx.com/en/articles/5025298-troubleshooting-call-completion) (Essential for interpreting SIP codes and call failure reasons) * [Telnyx SIP Response Codes Guide](https://support.telnyx.com/en/articles/4409457-telnyx-sip-response-codes) (For a detailed list of SIP codes) # Android Voice Client SDK Source: https://developers.telnyx.com/development/webrtc/android-sdk/index Telnyx's Voice Android Client SDK # Telnyx Android WebRTC SDK JitPack Unit Tests Enable Telnyx real-time communication services on Android ## Table of Contents * [Project structure](#project-structure) * [Project Setup](#project-setup) * [SIP Credentials](#sip-credentials) * [Usage](#usage) * [Telnyx Client](#telnyx-client) * [Logging into Telnyx Client](#logging-into-telnyx-client) * [Creating a call invitation](#creating-a-call-invitation) * [Accepting a call](#accepting-a-call) * [Handling Multiple Calls](#handling-multiple-calls) * [Adding push notifications](#adding-push-notifications) * [Providing our SDK with the FCM Token to receive Push Notifications](#providing-our-sdk-with-the-fcm-token-to-receive-push-notifications) * [Custom Logging](#custom-logging) * [Call Quality Metrics](#call-quality-metrics) * [Enabling Call Quality Metrics](#enabling-call-quality-metrics) * [CallQualityMetrics Properties](#callqualitymetrics-properties) * [CallQuality Enum](#callquality-enum) * [Trickle Ice](#trickle-ice) * [AI Agent Usage](#ai-agent-usage) * [1. Logging in to communicate with the AI Agent](#1-logging-in-to-communicate-with-the-ai-agent) * [2. Starting a Conversation with the AI Assistant](#2-starting-a-conversation-with-the-ai-assistant) * [3. Receiving Transcript Updates](#3-receiving-transcript-updates) * [4. Sending a text message to the AI Agent](#4-sending-a-text-message-to-the-ai-agent) * [ProGuard changes](#proguard-changes) * [Additional Resources](#additional-resources) * [Questions? Comments?](#questions-comments) * [License](#license) ## Project structure: * SDK project: sdk module, containing all Telnyx SDK components as well as tests. * Demo application: app module, containing a sample demo application utilizing the sdk module.

## Project Setup: 1. Clone the repository 2. Open the cloned repository in Android Studio and hit the build button to build both the sdk and sample app:

3. Connect a device or start an emulated device and hit the run button

4. Enjoy 😎

## SIP Credentials In order to start making and receiving calls using the TelnyxRTC SDK you will need to get SIP Credentials: 1. Access to [https://portal.telnyx.com/](https://portal.telnyx.com/) 2. Sign up for a Telnyx Account. 3. Create a Credential Connection to configure how you connect your calls. 4. Create an Outbound Voice Profile to configure your outbound call settings and assign it to your Credential Connection. For more information on how to generate SIP credentials check the [Telnyx WebRTC quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart). ## Usage ### Telnyx Client NOTE: Remember to add and handle INTERNET, RECORD\_AUDIO and ACCESS\_NETWORK\_STATE permissions

To initialize the TelnyxClient you will have to provide the application context. Once an instance is created, you can call the .connect() method to connect to the socket. An error will appear as a socket response if there is no network available: ```kotlin theme={null} telnyxClient = TelnyxClient(context) telnyxClient.connect() ``` ### Logging into Telnyx Client To log into the Telnyx WebRTC client, you'll need to authenticate using a Telnyx SIP Connection. Follow our [quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart) to create **JWTs** (JSON Web Tokens) to authenticate. To log in with a token we use the tokinLogin() method. You can also authenticate directly with the SIP Connection `username` and `password` with the credentialLogin() method: ```kotlin theme={null} telnyxClient.tokenLogin(tokenConfig) //OR telnyxClient.credentialLogin(credentialConfig) ``` **Note:** **tokenConfig** and **credentialConfig** are data classes that represent login settings for the client to use. They look like this: ```kotlin theme={null} sealed class TelnyxConfig /** * Represents a SIP user for login - Credential based * * @property sipUser The SIP username of the user logging in * @property sipPassword The SIP password of the user logging in * @property sipCallerIDName The user's chosen Caller ID Name * @property sipCallerIDNumber The user's Caller ID Number * @property fcmToken The user's Firebase Cloud Messaging device ID * @property ringtone The integer raw value or uri of the audio file to use as a ringtone. Supports only raw file or uri * @property ringBackTone The integer raw value of the audio file to use as a ringback tone * @property logLevel The log level that the SDK should use - default value is none. * @property customLogger Optional custom logger implementation to handle SDK logs * @property autoReconnect whether or not to reattempt (3 times) the login in the instance of a failure to connect and register to the gateway with valid credentials * @property debug whether or not to send client debug reports * @property reconnectionTimeout how long the app should try to reconnect to the socket server before giving up * @property region the region to use for the connection * @property fallbackOnRegionFailure whether or not connect to default region if the select region is not reachable */ data class CredentialConfig( val sipUser: String, val sipPassword: String, val sipCallerIDName: String?, val sipCallerIDNumber: String?, val fcmToken: String?, val ringtone: Any?, val ringBackTone: Int?, val logLevel: LogLevel = LogLevel.NONE, val customLogger: TxLogger? = null, val autoReconnect: Boolean = false, val debug: Boolean = false, val reconnectionTimeout: Long = 60000, val region: Region = Region.AUTO, val fallbackOnRegionFailure: Boolean = true ) : TelnyxConfig() /** * Represents a SIP user for login - Token based * * @property sipToken The JWT token for the SIP user. * @property sipCallerIDName The user's chosen Caller ID Name * @property sipCallerIDNumber The user's Caller ID Number * @property fcmToken The user's Firebase Cloud Messaging device ID * @property ringtone The integer raw value or uri of the audio file to use as a ringtone. Supports only raw file or uri * @property ringBackTone The integer raw value of the audio file to use as a ringback tone * @property logLevel The log level that the SDK should use - default value is none. * @property customLogger Optional custom logger implementation to handle SDK logs * @property autoReconnect whether or not to reattempt (3 times) the login in the instance of a failure to connect and register to the gateway with a valid token * @property debug whether or not to send client debug reports * @property reconnectionTimeout how long the app should try to reconnect to the socket server before giving up * @property region the region to use for the connection * @property fallbackOnRegionFailure whether or not connect to default region if the select region is not reachable */ data class TokenConfig( val sipToken: String, val sipCallerIDName: String?, val sipCallerIDNumber: String?, val fcmToken: String?, val ringtone: Any?, val ringBackTone: Int?, val logLevel: LogLevel = LogLevel.NONE, val customLogger: TxLogger? = null, val autoReconnect: Boolean = true, val debug: Boolean = false, val reconnectionTimeout: Long = 60000, val region: Region = Region.AUTO, val fallbackOnRegionFailure: Boolean = true ) : TelnyxConfig() ``` ### Creating a call invitation In order to make a call invitation, you need to provide your callerName, callerNumber, the destinationNumber (or SIP credential), and your clientState (any String value). ```kotlin theme={null} telnyxClient.call.newInvite(callerName, callerNumber, destinationNumber, clientState) ``` ### Accepting a call In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response. **Recommended approach using SharedFlow (Kotlin Flows):** ```kotlin theme={null} // In your ViewModel or Activity lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> // Handle socket responses } } ``` **Deprecated approach using LiveData:** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") fun getSocketResponse(): LiveData>? = telnyxClient.getSocketResponse() ``` We can then use this method to create a listener that listens for an invitation - in this example we assume getSocketResponse is a method within a ViewModel. **Using SharedFlow (Recommended):** ```kotlin theme={null} // In your ViewModel or Activity lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> when (response.status) { SocketStatus.ESTABLISHED -> { // Handle a successfully established connection } SocketStatus.MESSAGERECEIVED -> { response.data?.let { data -> when (data.method) { SocketMethod.CLIENT_READY.methodName -> { // Fires once client has correctly been setup and logged into, you can now make calls. } SocketMethod.LOGIN.methodName -> { // Handle a successful login - Update UI or Navigate to new screen, etc. } SocketMethod.INVITE.methodName -> { // Handle an invitation Update UI or Navigate to new screen, etc. // Then, through an answer button of some kind we can accept the call with: val inviteResponse = data.result as InviteResponse telnyxClient.acceptCall(inviteResponse.callId, inviteResponse.callerIdNumber) } SocketMethod.ANSWER.methodName -> { // Handle a received call answer - Update UI or Navigate to new screen, etc. } SocketMethod.BYE.methodName -> { // Handle a call rejection or ending - Update UI or Navigate to new screen, etc. } SocketMethod.RINGING.methodName -> { // Client Can simulate ringing state } } } } SocketStatus.LOADING -> { // Show loading dialog } SocketStatus.ERROR -> { // Handle errors - Update UI or Navigate to new screen, etc. // response.errorCode provides additional context about the error type } SocketStatus.DISCONNECT -> { // Handle disconnect - Update UI or Navigate to login screen, etc. } } } } ``` **Using LiveData (Deprecated):** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") mainViewModel.getSocketResponse() ?.observe(this, object : SocketObserver() { override fun onConnectionEstablished() { // Handle a succesfully established connection } override fun onMessageReceived(data: ReceivedMessageBody?) { when (data?.method) { SocketMethod.CLIENT_READY.methodName -> { // Fires once client has correctly been setup and logged into, you can now make calls. } SocketMethod.LOGIN.methodName -> { // Handle a successful login - Update UI or Navigate to new screen, etc. } SocketMethod.INVITE.methodName -> { // Handle an invitation Update UI or Navigate to new screen, etc. // Then, through an answer button of some kind we can accept the call with: val inviteResponse = data.result as InviteResponse mainViewModel.acceptCall(inviteResponse.callId, inviteResponse.callerIdNumber) } SocketMethod.ANSWER.methodName -> { //Handle a received call answer - Update UI or Navigate to new screen, etc. } SocketMethod.BYE.methodName -> { // Handle a call rejection or ending - Update UI or Navigate to new screen, etc. } SocketMethod.RINGING.methodName -> { // Client Can simulate ringing state } SocketMethod.RINGING.methodName -> { // Ringback tone is streamed to the caller // early Media - Client Can simulate ringing state } } } override fun onLoading() { // Show loading dialog } override fun onError(errorCode: Int?, message: String?) { // Handle errors - Update UI or Navigate to new screen, etc. // errorCode provides additional context about the error type } override fun onSocketDisconnect() { // Handle disconnect - Update UI or Navigate to login screen, etc. } }) ``` When we receive a call we will receive an InviteResponse data class that contains the details we need to accept the call. We can then call the acceptCall method in TelnyxClient from our ViewModel: ### Handling Multiple Calls The Telnyx WebRTC SDK allows for multiple calls to be handled at once. You can use the callId to differentiate the calls.. ```kotlin theme={null} import java.util.UUID // Retrieve all calls from the TelnyxClient val calls: Map = telnyxClient.calls // Retrieve a specific call by callId val currentCall: Call? = calls[callId] ``` With the current call object, you can perform actions such as: 1. Hold/UnHold `currentCall.onHoldUnholdPressed(callId: UUID)` 2. Mute/UnMute `currentCall.onMuteUnmutePressed()` 3. AcceptCall `currentCall.acceptCall(...)` 4. EndCall `currentCall.endCall(callId: UUID)` ## Adding push notifications The Telnyx Android Client WebRTC SDK makes use of Firebase Cloud Messaging in order to deliver push notifications. If you want to receive notifications for incoming calls on your Android mobile device you have to enable Firebase Cloud Messaging within your application. In order to do this you need to: 1. Set up a Firebase console account 2. Create a Firebase project 3. Add Firebase to your Android Application 4. Setup a Push Credential within the Telnyx Portal 5. Generate a Firebase Cloud Messaging instance token 6. Send the token with your login message ### Providing our SDK with the FCM Token to receive Push Notifications You will need to provide the `connect(..)` method with a `CredentialConfig` or `TokenConfig` that contains an fcmToken value (received from FirebaseMessaging like in the above code snippet). Once the fcmToken has been provided, we can provide push notifications to the application when a call is received but the device is not actively connected to the socket. (eg. Killed or Backgrounded states) ```kotlin theme={null} telnyxClient = TelnyxClient(context) val credentialConfig = CredentialConfig( sipUser = username, sipPassword = password, fcmToken = fcmToken ) telnyxClient.connect( txPushMetaData = txPushMetaData, credentialConfig = credentialConfig, ) ``` For a detailed tutorial, please visit our official [Push Notification Docs](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/portal-setup) ## Custom Logging The Telnyx WebRTC SDK allows you to implement your own custom logging solution by providing a `TxLogger` implementation. This gives you full control over how logs are handled, allowing you to route them to your own logging frameworks or analytics services. ### Using Custom Logger 1. Create a class that implements the `TxLogger` interface: ```kotlin theme={null} class MyCustomLogger : TxLogger { override fun log(level: LogLevel, tag: String?, message: String, throwable: Throwable?) { // Implement your custom logging logic here // Example: Send logs to your analytics service MyAnalyticsService.log( level = level.name, tag = tag ?: "Telnyx", message = message, throwable = throwable ) } } ``` 2. Pass your custom logger when creating the configuration: ```kotlin theme={null} // For credential-based login val credentialConfig = CredentialConfig( sipUser = "your_sip_username", sipPassword = "your_sip_password", sipCallerIDName = "Your Name", sipCallerIDNumber = "Your Number", fcmToken = fcmToken, ringtone = R.raw.ringtone, ringBackTone = R.raw.ringbacktone, logLevel = LogLevel.ALL, // Set desired log level customLogger = MyCustomLogger() // Pass your custom logger ) // For token-based login val tokenConfig = TokenConfig( sipToken = "your_jwt_token", sipCallerIDName = "Your Name", sipCallerIDNumber = "Your Number", fcmToken = fcmToken, ringtone = R.raw.ringtone, ringBackTone = R.raw.ringbacktone, logLevel = LogLevel.ALL, // Set desired log level customLogger = MyCustomLogger() // Pass your custom logger ) ``` ### Default Behavior If no custom logger is provided, the SDK will use its default logging implementation based on Android's Log class. The `logLevel` parameter still controls which logs are generated, regardless of whether you're using a custom logger or the default one. ## Trickle ICE The SDK supports Trickle ICE, which enables faster call setup by sending ICE candidates incrementally as they are discovered, rather than waiting for all candidates before establishing the connection. ### Key Features * **Faster Call Establishment**: Candidates are sent immediately as discovered, reducing connection time * **Automatic Management**: No configuration required - the SDK handles Trickle ICE automatically * **Smart Queuing**: Answering side queues candidates until ANSWER is sent to prevent race conditions * **Candidate Cleaning**: WebRTC extensions are removed for maximum server compatibility ### How It Works **Outbound Calls**: Candidates are sent immediately as they are generated **Inbound Calls**: Candidates are queued until the call is answered, then flushed all at once followed by real-time sending of new candidates This approach prevents race conditions where candidates might arrive before the answer, ensuring reliable call setup. #### Important Notes * **Codec Negotiation**: The final codec used will be negotiated between your preferred codecs and what the remote party supports. * **Fallback Behavior**: If none of your preferred codecs are supported, the system will automatically fall back to a mutually supported codec. * **Order Matters**: Codecs are prioritized in the order you specify them in the list. * **Platform Support**: All codecs listed are supported by the Telnyx platform, but actual availability may depend on the remote party's capabilities. ## Best Practices ### Handling Push Notifications In order to properly handle push notifications, we recommend using a call type [Foreground Service](https://developer.android.com/develop/background-work/services/foreground-services) with a broadcast receiver to show push notifications. An answer or reject call intent with `telnyxPushMetaData` can then be passed to the MainActivity for processing. **Declining Push Notifications** The SDK now provides a simplified way to decline incoming calls from push notifications using the `connectWithDeclinePush()` method. This new approach automatically handles the decline process by: 1. Connecting to the socket with a `decline_push` parameter 2. Sending the appropriate decline message 3. Disconnecting automatically This eliminates the need for the complex flow of launching the app, waiting for invites, and manually sending bye messages. Use `connectWithDeclinePush()` instead of the standard `connect()` method when declining calls from push notifications. **Best Practices for Push Notifications** * Play a ringtone when a call is received from push notification using the `RingtoneManager` ```kotlin theme={null} val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) RingtoneManager.getRingtone(applicationContext, notification).play() ``` * Make Sure to set these flags for your pendingIntents, so the values get updated anytime when the notification is clicked ```kotlin theme={null} PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ``` ### Android 14 Requirements In order to receive push notifications on Android 14, you will need to add the following permissions to your AndroidManifest.xml file and request a few at runtime: ```xml theme={null} // Request this permission at runtime // If you need to use foreground services, you will need to add the following permissions // Configure foregroundservice and set the foreground service type // Remember to stopForegroundService when the call is answered or rejected ``` ### Handling Missed Call Notifications The backend sends a missed call notification when a call is ended while the socket is not yet connected. It comes with the `Missed call!` message. In order to handle missed call notifications, you can use the following code snippet in the FirebaseMessagingService class: ```kotlin theme={null} const val Missed_Call = "Missed call!" val params = remoteMessage.data val objects = JSONObject(params as Map<*, *>) val metadata = objects.getString("metadata") val isMissedCall: Boolean = objects.getString("message").equals(Missed_Call) if(isMissedCall){ Timber.d("Missed Call") val serviceIntent = Intent(this, NotificationsService::class.java).apply { putExtra("action", NotificationsService.STOP_ACTION) } serviceIntent.setAction(NotificationsService.STOP_ACTION) startMessagingService(serviceIntent) return } ``` ### Handling Multiple Calls The Telnyx WebRTC SDK allows for multiple calls to be handled at once. You can use the callId to differentiate the calls. ```kotlin theme={null} import java.util.UUID // Retrieve all calls from the TelnyxClient val calls: Map = telnyxClient.calls // Retrieve a specific call by callId val currentCall: Call? = calls[callId] ``` ## AI Agent Usage The Android WebRTC SDK supports [Voice AI Agent](https://telnyx.com/products/voice-ai-agents) implementations. To get started, follow the steps [described here](https://telnyx.com/resources/ai-assistant-builder) to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps: ### 1. Logging in to communicate with the AI Agent To connect with an AI Assistant, you can use the `connectAnonymously` method. This allows you to establish a connection without traditional authentication credentials. This method takes a `targetId` which is the ID of your AI assistant, and an optional `targetVersionId`. If a `targetVersionId` is not provided, the SDK will use the latest version available. **Note:** After a successful anonymous connection, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant. Here's an example of how to use it: ```kotlin theme={null} try { telnyxClient.connectAnonymously( targetId = "your_assistant_id", // targetType = "ai_assistant", // This is the default value // targetVersionId = "your_assistant_version_id", // Optional // userVariables = mapOf("user_id" to "12345"), // Optional user variables // logLevel = LogLevel.NONE // Optional log level configuration ) // You are now connected and can make a call to the AI Assistant. } catch (e: Exception) { // Handle connection error Log.e("TelnyxClient", "Connection failed: ${e.message}") } ``` Once connected, you can use the standard `newInvite` method to start a conversation with the AI Assistant. ### 2. Starting a Conversation with the AI Assistant After a successful `anonymousLogin`, you can initiate a call to your AI Assistant using the `newInvite` method. Because the session is now locked to the AI Assistant, the `destinationNumber` parameter in the `newInvite` method will be ignored. Any values provided for `callerName` and `callerNumber` will be passed on, but the call will always be routed to the AI Assistant specified during the login. Here is an example of how to start the call: ```kotlin theme={null} // After a successful anonymousLogin... telnyxClient.newInvite( callerName = "Your Name", callerNumber = "Your Number", destinationNumber = "", // Destination is ignored, can be an empty string clientState = "Your custom state", customHeaders = mapOf( "X-Session-Context" to "support_request", "X-User-Tier" to "premium"), ) ``` Note that you can also provide `customHeaders` in the `newInvite` method. These headers need to start with the `X-` prefix and will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the AI assistant (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. The call will be automatically answered by the AI Assistant. From this point on, the call flow is handled in the same way as any other answered call, allowing you to use standard call control methods like `endCall`, `mute`, etc. ### 3. Receiving Transcript Updates During an AI Assistant conversation, the SDK provides real-time transcript updates that include both the caller's speech and the AI Assistant's responses. This allows you to display a live conversation transcript in your application. To receive transcript updates, use the `transcriptUpdateFlow` SharedFlow on your `TelnyxClient` instance: ```kotlin theme={null} // Set up transcript listener lifecycleScope.launch { telnyxClient.transcriptUpdateFlow.collect { transcript -> // Handle the updated transcript transcript.forEach { item -> Log.d("Transcript", "${item.role}: ${item.content}") // item.role will be either "user" or "assistant" // item.content contains the spoken text // item.timestamp contains when the message was received } // Update your UI to display the conversation updateConversationUI(transcript) } } ``` The `TranscriptItem` contains the following properties: * `id`: Unique identifier for the transcript item * `role`: Either "user" (for the caller) or "assistant" (for the AI Agent) * `content`: The transcribed text content * `timestamp`: When the transcript item was created * `isPartial`: Whether this is a partial response (for streaming AI responses) You can also manually retrieve the current transcript at any time: ```kotlin theme={null} val currentTranscript = telnyxClient.transcript ``` **Note:** Transcript updates are only available during AI Assistant conversations initiated through `anonymousLogin`. Regular calls between users do not provide transcript functionality. ### 4. Sending a text message to the AI Agent In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. To send a text message to the AI Agent, use the `sendAIAssistantMessage` method: ```kotlin theme={null} // Send a text message to the AI Agent during an active call telnyxClient.sendAIAssistantMessage("Hello, can you help me with my account?") ``` **Important Notes:** * The `sendAIAssistantMessage` method is only available during AI Assistant conversations * Text messages sent this way will appear in the transcript updates alongside spoken conversation * The AI Agent will process and respond to text messages just like spoken input * You must have an active call established before sending text messages This feature enables rich conversational experiences where users can seamlessly switch between voice and text communication with the AI Assistant. For detailed documentation and advanced usage examples, see the [AI Agent documentation](docs-markdown/ai-agent/introduction.md). ## ProGuard changes NOTE: In the case that you need to modify your application's proguard settings in order to obfuscate your code, such as we have done below: **`app/build.gradle`** ```gradle theme={null} buildTypes { release { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' jniDebuggable true } debug { minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' debuggable true jniDebuggable true } } ``` please keep in mind that you will need to add the following rules to the proguard-rules.pro file in your app in order for the SDK to continue functioning **`app/proguard-rules.pro`** ```gradle theme={null} -keep class com.telnyx.webrtc.** { *; } -dontwarn kotlin.Experimental$Level -dontwarn kotlin.Experimental -dontwarn kotlinx.coroutines.scheduling.ExperimentalCoroutineDispatcher ``` *** ## Additional Resources * [Android Precompiled WebRTC Library](/docs/voice/webrtc/android-sdk/precompiled-library) - For developers who need more control over WebRTC implementation * [WebRTC Official Documentation](https://webrtc.org/getting-started/overview) * [Official SDK Documentation](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/quickstart) Questions? Comments? Building something rad? Join our Slack channel and share. ## License [`MIT Licence`](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/LICENSE) © [Telnyx](https://github.com/team-telnyx) # Android Push Notification Setup Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/app-setup/index A step-by-step guide to setting up push notifications in Android. Learn how to configure and implement notifications to ensure seamless communication in your application. # Push Notification App Setup ### Multidevice Push Notifications Telnyx WebRTC supports multidevice push notifications. A single user can have up to 5 device tokens (either iOS - APNS or Android - FCM). When a user logs into the socket and provides a push token, our services will register this token to that user - allowing it to receive push notifications for incoming calls. If a 6th registration is made, the least recently used token will be removed. This effectivly means that you can have up to 5 devices that can receive push notifications for the same incoming call. ### Retrieving a Firebase Cloud Messaging Token If the portal setup is complete and when firebase is properly integrated into your application, you will be able to retrieve a token with a method such as this: ``` private fun getFCMToken() { FirebaseApp.initializeApp(this) FirebaseMessaging.getInstance().token.addOnCompleteListener { task -> if (!task.isSuccessful) { Timber.d("Fetching FCM registration token failed") } else if (task.isSuccessful){ // Get new FCM registration token try { token = task.result } catch (e: IOException) { Timber.d(e) } Timber.d("FCM token received: $token") } } } ``` ### Providing our SDK with the FCM Token to receive Push Notifications You will need to provide the `connect(..)` method with a `CredentialConfig` or `TokenConfig` that contains an fcmToken value (received from FirebaseMessaging like in the above code snippet). Once the fcmToken has been provided, we can provide push notifications to the application when a call is received but the device is not actively connected to the socket. (eg. Killed or Backgrounded states) ```kotlin theme={null} telnyxClient = TelnyxClient(context) val credentialConfig = CredentialConfig( sipUser = username, sipPassword = password, fcmToken = fcmToken ) telnyxClient.connect( txPushMetaData = txPushMetaData, credentialConfig = credentialConfig, ) ``` The final step is to create a MessagingService for your application. The MessagingService is the class that handles FCM messages and creates notifications for the device from these messages. You can read about the firebase messaging service class here: [https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService](https://firebase.google.com/docs/reference/android/com/google/firebase/messaging/FirebaseMessagingService) We have a sample implementation for you to take a look at here: [https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/app/src/main/java/com/telnyx/webrtc/sdk/utility/MyFirebaseMessagingService.kt](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/app/src/main/java/com/telnyx/webrtc/sdk/utility/MyFirebaseMessagingService.kt) Once this class is created, remember to update your manifest and specify the newly created service like so: [https://firebase.google.com/docs/cloud-messaging/android/client#manifest](https://firebase.google.com/docs/cloud-messaging/android/client#manifest) You are now ready to receive push notifications via Firebase Messaging Service. ### Handling Push Notifications once received - TxPushMetaData The Telnyx SDK provides a `TxPushMetaData` object that can be used to handle push notifications when a call is received. You can parse the `TxPushMetaData` object to get the call details that then need to be provided to the `connect` method when reconnecting to the socket as a result of reacting to a push notification. ```kotlin theme={null} override fun onMessageReceived(remoteMessage: RemoteMessage) { super.onMessageReceived(remoteMessage) Timber.d("Message Received From Firebase: ${remoteMessage.data}") Timber.d("Message Received From Firebase Priority: ${remoteMessage.priority}") Timber.d("Message Received From Firebase: ${remoteMessage.originalPriority}") val params = remoteMessage.data val objects = JSONObject(params as Map<*, *>) val metadata = objects.getString("metadata") val isMissedCall: Boolean = objects.getString("message").equals(Missed_Call) if(isMissedCall){ Timber.d("Missed Call") val serviceIntent = Intent(this, NotificationsService::class.java).apply { putExtra("action", NotificationsService.STOP_ACTION) } serviceIntent.setAction(NotificationsService.STOP_ACTION) startMessagingService(serviceIntent) return } val serviceIntent = Intent(this, NotificationsService::class.java).apply { putExtra("metadata", metadata) } startMessagingService(serviceIntent) } ``` You can see that in this case the TxPushMetaData is received from the 'metadata' field. This is then passed to our notification service for handling. A basic implementation of the Notification Service could look like so: ```kotlin theme={null} class NotificationsService : Service() { companion object { private const val CHANNEL_ID = "PHONE_CALL_NOTIFICATION_CHANNEL" private const val NOTIFICATION_ID = 1 const val STOP_ACTION = "STOP_ACTION" } override fun onCreate() { super.onCreate() createNotificationChannel() } private var ringtone:Ringtone? = null private fun playPushRingTone() { try { val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) ringtone = RingtoneManager.getRingtone(applicationContext, notification) ringtone?.play() } catch (e: NotFoundException) { Timber.e("playPushRingTone: $e") } } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { val stopAction = intent?.action if (stopAction != null && stopAction == STOP_ACTION) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { stopForeground(STOP_FOREGROUND_REMOVE) ringtone?.stop() } else { stopForeground(true) } return START_NOT_STICKY } val metadata = intent?.getStringExtra("metadata") val telnyxPushMetadata = Gson().fromJson(metadata, PushMetaData::class.java) telnyxPushMetadata?.let { showNotification(it) playPushRingTone() } return START_STICKY } override fun onBind(intent: Intent?): IBinder? { return null } private fun createNotificationChannel() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val name = "Phone Call Notifications" val description = "Notifications for incoming phone calls" val importance = NotificationManager.IMPORTANCE_HIGH val channel = NotificationChannel(CHANNEL_ID, name, importance) channel.description = description val notificationManager = getSystemService(NotificationManager::class.java) channel.apply { lightColor = Color.RED enableLights(true) enableVibration(true) setSound(null, null) } notificationManager.createNotificationChannel(channel) } } private fun showNotification(txPushMetaData: PushMetaData) { val intent = Intent(this, MainActivity::class.java).apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_MUTABLE) val customSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) val rejectResultIntent = Intent(this, MainActivity::class.java) rejectResultIntent.action = Intent.ACTION_VIEW rejectResultIntent.putExtra( MyFirebaseMessagingService.EXT_KEY_DO_ACTION, MyFirebaseMessagingService.ACT_REJECT_CALL ) rejectResultIntent.putExtra( MyFirebaseMessagingService.TX_PUSH_METADATA, txPushMetaData.toJson() ) val rejectPendingIntent = PendingIntent.getActivity( this, MyFirebaseMessagingService.REJECT_REQUEST_CODE, rejectResultIntent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) val answerResultIntent = Intent(this, MainActivity::class.java) answerResultIntent.setAction(Intent.ACTION_VIEW) answerResultIntent.putExtra( MyFirebaseMessagingService.EXT_KEY_DO_ACTION, MyFirebaseMessagingService.ACT_ANSWER_CALL ) answerResultIntent.putExtra( MyFirebaseMessagingService.TX_PUSH_METADATA, txPushMetaData.toJson() ) val answerPendingIntent = PendingIntent.getActivity( this, MyFirebaseMessagingService.ANSWER_REQUEST_CODE, answerResultIntent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ) Timber.d("showNotification: ${txPushMetaData.toJson()}") val builder = NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_stat_contact_phone) .setContentTitle("Incoming Call : ${txPushMetaData.callerName}") .setContentText("Incoming call from: ${txPushMetaData.callerNumber} ") .setPriority(NotificationCompat.PRIORITY_MAX) .setContentIntent(pendingIntent) .setSound(customSoundUri) .addAction( R.drawable.ic_call_white, MyFirebaseMessagingService.ACT_ANSWER_CALL, answerPendingIntent ) .addAction( R.drawable.ic_call_end_white, MyFirebaseMessagingService.ACT_REJECT_CALL, rejectPendingIntent ) .setOngoing(true) .setAutoCancel(false) .setCategory(NotificationCompat.CATEGORY_CALL) .setFullScreenIntent(pendingIntent, true) startForeground( NOTIFICATION_ID, builder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_PHONE_CALL ) } } ``` Ultimately though reacting to the push notification should cause the application to connect again and pass the handled `TxPushMetaData` object to the `connect` method like so: ```kotlin theme={null} telnyxClient.connect( txPushMetaData = txPushMetaData, credentialConfig = credentialConfig, ) ``` If this is done correctly and you reconnect to the socket, you should receive the invite for the call on the socket as soon as you are reconnected ## Declining Push Notifications The SDK provides two approaches for declining incoming calls from push notifications: the legacy approach and a new simplified approach. ### Legacy Approach (Complex Flow) In the traditional approach, declining a push notification requires the following steps: 1. User taps decline on notification 2. App launches via PendingIntent 3. App connects to socket using the standard `connect()` method 4. App waits for invite message to be received 5. App calls `endCall()` to decline the call 6. App handles cleanup and remains open **Example implementation:** ```kotlin theme={null} // In your notification decline handler val intent = Intent(context, MainActivity::class.java).apply { putExtra("action", "decline_call") putExtra("metadata", txPushMetadata.toJson()) flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } context.startActivity(intent) // In MainActivity if (intent.getStringExtra("action") == "decline_call") { val metadata = intent.getStringExtra("metadata") val txPushMetadata = Gson().fromJson(metadata, PushMetaData::class.java) // Connect and wait for invite telnyxClient.connect( txPushMetaData = txPushMetadata, credentialConfig = credentialConfig ) // Listen for invite and then call endCall() telnyxClient.socketResponseLiveData.observe(this) { response -> if (response is SocketResponse.invite) { telnyxClient.endCall(response.callId) } } } ``` ### New Simplified Approach (Recommended) The SDK now provides a much simpler way to decline incoming calls using the `connectWithDeclinePush()` method. This approach eliminates the need to wait for invite messages and manually send bye messages. **How the New Flow Works:** 1. User taps decline on notification 2. App or background service calls `connectWithDeclinePush()` 3. SDK connects to socket with `decline_push: true` parameter 4. SDK automatically handles the decline process 5. SDK disconnects automatically 6. No need to wait for invites or manually call `endCall()` **Example implementation:** ```kotlin theme={null} // In your notification decline handler val txPushMetadata = // ... get from notification val credentialConfig = CredentialConfig( sipUser = username, sipPassword = password, fcmToken = fcmToken ) // Use the new decline method telnyxClient.connectWithDeclinePush( config = credentialConfig, txPushMetaData = txPushMetadata.toJson() ) // The SDK handles everything automatically - no need to wait for invites ``` ### Benefits of the New Approach * **Simplified implementation**: No need to handle complex invite/bye message flows * **Automatic handling**: SDK manages the entire decline process internally * **Reduced complexity**: No need to listen for socket events or manually call `endCall()` * **Consistent behavior**: Decline process is handled uniformly by the SDK ### Choosing the Right Approach * **Use the new approach** (`connectWithDeclinePush()`) for new implementations or when updating existing code * **Legacy approach** may still be needed if you have specific requirements for handling the decline flow manually * The new approach is recommended for most use cases as it reduces implementation complexity and potential errors ## Best Practices ### Handling Push Notifications In order to properly handle push notifications, we recommend using a call type (Foreground Service)\[[https://developer.android.com/develop/background-work/services/foreground-services](https://developer.android.com/develop/background-work/services/foreground-services)] with a broadcast receiver to show push notifications. An answer or reject call intent with `telnyxPushMetaData` can then be passed to the MainActivity for processing. * Play a ringtone when a call is received from push notification using the `RingtoneManager` ```kotlin theme={null} val notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE) RingtoneManager.getRingtone(applicationContext, notification).play() ``` * Make Sure to set these flags for your pendingIntents, so the values get updated anytime when the notification is clicked ```kotlin theme={null} PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT ``` ### Android 14 Requirements In order to receive push notifications on Android 14, you will need to add the following permissions to your AndroidManifest.xml file and request a few at runtime: ```xml theme={null} // Request this permission at runtime // If you need to use foreground services, you will need to add the following permissions // Configure foregroundservice and set the foreground service type // Remember to stopForegroundService when the call is answered or rejected ``` ### Handling Missed Call Notifications The backend sends a missed call notification when a call is ended while the socket is not yet connected. It comes with the `Missed call!` message. In order to handle missed call notifications, you can use the following code snippet in the FirebaseMessagingService class: ```kotlin theme={null} const val Missed_Call = "Missed call!" val params = remoteMessage.data val objects = JSONObject(params as Map<*, *>) val metadata = objects.getString("metadata") val isMissedCall: Boolean = objects.getString("message").equals(Missed_Call) // if(isMissedCall){ Timber.d("Missed Call") val serviceIntent = Intent(this, NotificationsService::class.java).apply { putExtra("action", NotificationsService.STOP_ACTION) } serviceIntent.setAction(NotificationsService.STOP_ACTION) startMessagingService(serviceIntent) return } ``` # Android Portal Setup Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/portal-setup/index A step-by-step guide to setting up push notifications in Android. Learn how to configure and implement notifications to ensure seamless communication in your application. The Telnyx Android Client WebRTC SDK makes use of Firebase Cloud Messaging to deliver push notifications. If you want to receive notifications when receiving calls on your Android mobile device you need to enable Firebase Cloud Messaging within your application. To do this you need to: * Set up a Firebase console account * Create a Firebase project * Add Firebase to your Android Application * Setup a Push Credential within the Telnyx Portal * Generate a Firebase Cloud Messaging instance token * Send the token with your login message Adding Firebase to your application is a simple process. Click on the Android icon on the home screen of the console to start: firebase-pn-screen Next, enter your application details and register your application add-firebase-to-app After your application is registered, Firebase will generate a google-services.json file for you which will need to be added to your project root directory: download-config-file-firebase After that, you can follow this guide on how to enable the Firebase products within your application [https://firebase.google.com/docs/android/setup#add-config-file](https://firebase.google.com/docs/android/setup#add-config-file) An alternative method is to add Firebase using the Firebase Assistant within Android Studio if it is set up within your IDE. You can view steps on how to register via this option here: [https://firebase.google.com/docs/android/setup#assistant](https://firebase.google.com/docs/android/setup#assistant) Once your application is set up within the Firebase Console, you will be able to access the server key required for portal setup. You can access the server key file in JSON format by going into your project overview -> project settings -> Service Account and selecting Generate New Private Key. generate-server-key The next step is to set up your Android VoIP credentials in the portal. 1. Go to portal.telnyx.com and log in. 2. Go to the API Keys section on the left panel. 3. From the top bar go to the Credentials tab and select “Add” >> Android Credential api-keys-pn 4. Enter the details required for your Android Push Credentials. This includes a Credential name and the generated server key in JSON format in the field Project Account json add-android-push-credential Save the new push credential by pressing the Add Push Credential button We can now attach this Android Push Credential to a SIP Connection: 1. Go to the SIP Connections section on the left panel. 2. Open the Settings menu of the SIP connection that you want to add a Push Credential to or [create a new SIP Connection](/docs/voice/sip-trunking/quickstart). 3. Select the WebRTC tab. 4. Go to the Android Section and select the PN credential you previously created. # Notification Quickstart for Android Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/quickstart/index Using the predeveloped telnyx_common module as a drop in push notification solution to your application # Push Notification Quickstart with telnyx\_common The `telnyx_common` module provides a comprehensive SDK implementation, including push notification handling for your Android application. This guide will help you quickly integrate Telnyx's push notification system using the ready-made components available in the `telnyx_common` module. ## Overview The `telnyx_common` module offers a complete solution for handling push notifications for incoming calls, including: * Receiving and parsing Firebase Cloud Messaging (FCM) notifications * Displaying appropriate notifications for incoming calls * Handling user interactions with notifications (answer, reject, end call) * Managing notification channels and importance levels * Supporting both modern CallStyle notifications and legacy notifications for backward compatibility Instead of implementing these features from scratch, you can leverage the notification components in the `telnyx_common` module as a drop-in solution for your application. ## Key Components ### MyFirebaseMessagingService `MyFirebaseMessagingService` is responsible for receiving and processing incoming Firebase Cloud Messaging (FCM) push notifications for calls. **Key Features:** * Parses incoming push notifications and extracts call metadata * Handles different types of notifications (incoming calls, missed calls) * Routes notifications to the appropriate handlers * Supports both modern CallStyle notifications and legacy notifications **Implementation:** 1. Register the service in your AndroidManifest.xml: ```xml theme={null} ``` ### CallNotificationService `CallNotificationService` handles the creation and management of call notifications using Android's modern CallStyle API. **Key Features:** * Creates and manages notification channels with appropriate importance levels * Displays incoming call notifications with answer/reject actions * Shows ongoing call notifications with end call action * Supports full-screen incoming call UI * Configures appropriate sounds, vibration patterns, and priority levels **Implementation:** The service is automatically used by `MyFirebaseMessagingService` when an incoming call is received. No additional setup is required if you're using the `telnyx_common` module. ### CallNotificationReceiver `CallNotificationReceiver` is a BroadcastReceiver that handles user interactions with call notifications. **Key Features:** * Processes answer, reject, and end call actions from notifications * Routes actions to the appropriate handlers in your application * Cancels notifications when actions are taken * **New**: Uses `BackgroundCallDeclineService` for simplified call rejection without app launch **Implementation:** 1. Register the receiver in your AndroidManifest.xml: ```xml theme={null} ``` ### BackgroundCallDeclineService `BackgroundCallDeclineService` is a new service that handles call decline operations without launching the main application. **Key Features:** * Declines incoming calls in the background without app launch * Connects to socket with `decline_push` parameter for simplified decline flow * Automatically disconnects after decline operation is complete * Includes timeout handling to prevent service from running indefinitely * Improves user experience by avoiding unnecessary app launches **How it works:** 1. User taps decline on push notification 2. `CallNotificationReceiver` starts `BackgroundCallDeclineService` 3. Service connects to socket using `connectWithDeclinePush()` 4. Service sends login with `decline_push: true` parameter 5. Service automatically disconnects and stops after decline is processed **Implementation:** The service is automatically used by `CallNotificationReceiver` when using the `telnyx_common` module. No additional setup is required. ### LegacyCallNotificationService `LegacyCallNotificationService` is a legacy notification service maintained for backward compatibility. **Key Features:** * Provides fallback notification handling for devices that don't support CallStyle * Creates and manages notification channels * Displays incoming call notifications with answer/reject actions * Handles ringtone playback for incoming calls **Implementation:** 1. Register the service in your AndroidManifest.xml and specify your main activity: ```xml theme={null} ``` ## Integration Steps To integrate push notifications using the `telnyx_common` module: 1. **Set up Firebase Cloud Messaging (FCM)** in your project: * Follow the [Firebase setup guide](https://firebase.google.com/docs/cloud-messaging/android/client) * Add the necessary dependencies to your app's build.gradle file * Configure your Firebase project and download the google-services.json file 2. **Register the notification components** in your AndroidManifest.xml: ```xml theme={null} ``` 3. **Handle push notification actions** in your main activity: ```kotlin theme={null} override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // ... // Check if the activity was launched from a push notification intent?.let { handlePushNotificationIntent(it) } } override fun onNewIntent(intent: Intent?) { super.onNewIntent(intent) // Handle push notification intents when the activity is already running intent?.let { handlePushNotificationIntent(it) } } private fun handlePushNotificationIntent(intent: Intent) { val action = intent.getStringExtra(MyFirebaseMessagingService.EXT_KEY_DO_ACTION) val metadataJson = intent.getStringExtra(MyFirebaseMessagingService.TX_PUSH_METADATA) if (action != null && metadataJson != null) { val pushMetadata = Gson().fromJson(metadataJson, PushMetaData::class.java) when (action) { MyFirebaseMessagingService.ACT_ANSWER_CALL -> { // Answer the call using TelnyxViewModel viewModel.answerIncomingPushCall(this, pushMetadata) } MyFirebaseMessagingService.ACT_REJECT_CALL -> { // Reject the call using TelnyxViewModel viewModel.rejectIncomingPushCall(this, pushMetadata) } MyFirebaseMessagingService.ACT_OPEN_TO_REPLY -> { // Show UI for incoming call // This is called when the user taps the notification itself } } } } ``` 4. **Configure the CallForegroundService** for ongoing calls: ```xml theme={null} ``` ## Sample App References You can refer to our sample apps for complete implementations: ### Compose Sample App The [Compose sample app](https://github.com/team-telnyx/telnyx-webrtc-android/tree/main/samples/compose_app) demonstrates how to integrate push notifications in a Jetpack Compose application: * [AndroidManifest.xml](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/samples/compose_app/src/main/AndroidManifest.xml) - Shows how to register the notification components * [MainActivity.kt](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/samples/compose_app/src/main/java/org/telnyx/webrtc/compose_app/MainActivity.kt) - Demonstrates handling push notification intents ### XML Sample App The [XML sample app](https://github.com/team-telnyx/telnyx-webrtc-android/tree/main/samples/xml_app) shows the integration in a traditional XML-based Android application: * [AndroidManifest.xml](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/samples/xml_app/src/main/AndroidManifest.xml) - Shows how to register the notification components * [MainActivity.kt](https://github.com/team-telnyx/telnyx-webrtc-android/blob/main/samples/xml_app/src/main/java/org/telnyx/webrtc/xml_app/MainActivity.kt) - Demonstrates handling push notification intents ## Push Notification Decline - Migration Guide ### New Simplified Approach (Recommended) If you're using the `telnyx_common` module, the new `BackgroundCallDeclineService` is automatically used for call rejections. This provides: * **Improved User Experience**: No app launch interruption when declining calls * **Better Performance**: Reduced battery usage and faster response times * **Simplified Implementation**: No need to handle complex invite/bye message flows ### Legacy Approach (For Custom Implementations) If you have a custom implementation that manually handles call decline, you may want to migrate to the new approach: **Old Flow:** ```kotlin theme={null} // User taps decline → Launch app → Connect → Wait for invite → Send bye intent.putExtra("action", "decline_call") startActivity(intent) // Launches main app ``` **New Flow:** ```kotlin theme={null} // User taps decline → Background service handles everything BackgroundCallDeclineService.startService(context, txPushMetadata) ``` ## Best Practices 1. **Permissions**: Ensure your app has the necessary permissions for notifications and foreground services: ```xml theme={null} ``` 2. **Notification Channels**: The `telnyx_common` module automatically creates appropriate notification channels, but you may want to customize them for your app's branding. 3. **Testing**: Test push notifications on different Android versions to ensure compatibility with both modern CallStyle notifications and legacy notifications. 4. **Background Processing**: Use the `CallForegroundService` to maintain calls when your app is in the background. 5. **Error Handling**: Implement proper error handling for push notification processing to ensure a smooth user experience. 6. **Call Decline**: Use the new `BackgroundCallDeclineService` for optimal user experience when declining calls from push notifications. ## Troubleshooting * If notifications are not appearing, check that notification permissions are granted and channels are properly configured. * For issues with Firebase Cloud Messaging, verify that your FCM setup is correct and that you have the latest version of the Firebase SDK. * If call notifications are not working correctly, ensure that the `activity_class_name` metadata in your AndroidManifest.xml points to the correct activity. * For notification sound issues, check the audio settings on the device and verify that the notification channel is configured with the correct sound settings. * Double-check the Telnyx portal to make sure push credentials are assigned properly. # Android Push Troubleshooting Source: https://developers.telnyx.com/development/webrtc/android-sdk/push-notification/troubleshooting/index A step-by-step guide on how to debug common issues related to push notifications on Android This guide helps you troubleshoot common issues that prevent push notifications from being delivered in the Telnyx WebRTC Android SDK. ## Common Points of Failure ### 1. FCM Token Not Passed to Login One of the most common issues is that the FCM token is not being passed correctly during the login process. **How to verify:** * Check your application logs to ensure the FCM token is being retrieved successfully * Verify that the login message contains the FCM token * Look for logs similar to: `FCM token received: [your-token]` **Solution:** * Make sure you're retrieving the FCM token as shown in the [App Setup](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/app-setup) guide * Ensure the token is passed to the `connect()` method within the [TelnyxConfig](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/config/txconfig) object (Ether Credential or Token) * Verify that the token is not null or empty before passing it ### 2. Incorrect google-services.json Configuration If your Firebase configuration file is incorrect or outdated, push notifications will not work properly. **How to verify:** * Check that the google-services.json file is in the correct location (app module root directory) * Verify that the package name in the google-services.json matches your application's package name **Solution:** * Download a fresh copy of the google-services.json file from the Firebase Console * Make sure you're using the correct Firebase project for your application * Follow the [Portal Setup](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/portal-setup) guide to properly configure Firebase ### 3. Wrong Push Credential Assigned to SIP Credential If the push credential is not correctly assigned to your SIP credential, the server won't know where to send push notifications. **How to verify:** * Log into the Telnyx Portal and check your SIP Connection settings * Verify that the correct Android push credential is selected in the WebRTC tab **Solution:** * Follow the steps in the [Portal Setup](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/portal-setup) guide to properly assign the push credential * Make sure you've selected the correct credential for your application ### 4. Incorrect Push Credential If your push credential contains incorrect information, push notifications will fail. **How to verify:** * Check the push credential in the Telnyx Portal * Verify that the server key JSON is correctly formatted and valid **Solution:** * Generate a new server key in the Firebase Console * Update your push credential in the Telnyx Portal with the new key * Test push notifications after updating the credential ### 5. Login Method Limitations The way you authenticate with the Telnyx WebRTC SDK can affect push notification functionality. **How to verify:** * Check which login method you're using: SIP Connection, Generated Credential, or Token * Refer to the [Dialing Registered Clients documentation](https://developers.telnyx.com/docs/voice/webrtc/sdk-commonalities#dialing-registered-clients) **Solution:** * Be aware that there are limitations on which registered clients can be called * Test direct socket-connected calls before attempting push notification calls * If using a token-based authentication, ensure the token has the necessary permissions ## Additional Troubleshooting Steps 1. **Check Firebase Console Logs** * Go to the Firebase Console > Your Project > Engage > Messaging * Check for any errors or failed deliveries 2. **Verify Android Manifest Configuration** * Ensure your AndroidManifest.xml has the correct permissions and service declarations * Check that your FirebaseMessagingService is properly registered 3. **Test with Firebase Test Notifications** * Use the Firebase Console to send a test notification to your device * This can help determine if the issue is with Firebase or with Telnyx 4. **Check Network Connectivity** * Ensure your device has a stable internet connection * Firebase Cloud Messaging requires network connectivity to receive notifications 5. **Verify Device Registration** * Make sure your device is properly registered with Firebase * Check that the FCM token is being refreshed when needed ## Testing VoIP Push Notifications To help troubleshoot push notification issues, we provide a command-line tool that can send test VoIP push notifications directly to your Android device. ### Push Notification Testing Tool The Telnyx VoIP Push Notification Tester is a Node.js tool located in the `push-notification-tool/` directory of the WebRTC Android SDK repository. This tool allows you to: * Send test VoIP push notifications using Firebase Cloud Messaging HTTP v1 API * Verify that your device can receive push notifications * Test different caller information and payload data * Work with any Firebase project (not limited to Telnyx projects) ### Using the Testing Tool 1. **Navigate to the tool directory:** ```bash theme={null} cd push-notification-tool ``` 2. **Install dependencies:** ```bash theme={null} npm install ``` 3. **Run the tool:** ```bash theme={null} npm start ``` 4. **Configure the tool with:** * Your device's FCM token * Firebase Project ID (your Firebase project) * Firebase Service Account JSON credentials * Caller name and phone number for testing The tool will guide you through an interactive setup process and save your configuration for future use. ### What This Tests This tool tests the push notification delivery path independently of the Telnyx WebRTC SDK. If notifications work with this tool but not through normal calls, the issue is likely in one of the following areas: * SIP Connection configuration in Telnyx Portal * Push credential assignment * FCM token registration during SDK login * Application's FirebaseMessagingService implementation If notifications don't work with this tool, the issue is likely: * Incorrect Firebase configuration * Invalid FCM token * Network connectivity issues * Device-specific notification settings ## Still Having Issues? If you've gone through all the troubleshooting steps and are still experiencing problems: 1. Check the Telnyx WebRTC SDK documentation for any updates or known issues 2. Contact Telnyx Support with detailed information about your setup and the issues you're experiencing 3. Include logs, error messages, and steps to reproduce the problem when contacting support # WebRTC Android Quickstart Source: https://developers.telnyx.com/development/webrtc/android-sdk/quickstart/index Using the predeveloped telnyx_common module as a drop in solution to your application # Telnyx Android Quickstart - the telnyx\_common module The `telnyx_common` module provides a ready-to-use implementation of the Telnyx WebRTC SDK for Android applications. This module is designed to be a drop-in solution for developers who want to quickly integrate Telnyx's voice calling capabilities into their Android applications without having to implement the low-level SDK interactions themselves. The `telnyx_common` module is currently used in both our [Compose](https://github.com/team-telnyx/telnyx-webrtc-android/tree/main/samples/compose_app) and [XML](https://github.com/team-telnyx/telnyx-webrtc-android/tree/main/samples/xml_app) sample apps - both of which can be used as references depending on how you are developing your application ## Overview The `telnyx_common` module serves as a bridge between your application and the `telnyx_rtc` module (the core SDK). It provides: 1. A complete implementation of common WebRTC calling features 2. User-friendly abstractions for authentication, call management, and notifications 3. Ready-to-use UI components and services for handling calls 4. Foreground service implementation for maintaining calls when the app is minimized ## Key Components ### TelnyxViewModel The `TelnyxViewModel` is the primary interface for interacting with the Telnyx WebRTC SDK. It provides methods for authentication, call management, and handling incoming calls. **Authentication Methods** * `credentialLogin(viewContext, profile, txPushMetaData, autoLogin)`: Authenticates a user using SIP credentials (username/password) * `tokenLogin(viewContext, profile, txPushMetaData, autoLogin)`: Authenticates a user using a SIP token * `connectWithLastUsedConfig(viewContext, txPushMetaData)`: Reconnects using the last successful authentication method * `disconnect(viewContext)`: Disconnects the current session **Call Management Methods** * `sendInvite(viewContext, destinationNumber)`: Initiates an outgoing call to the specified number * `answerCall(viewContext, callId, callerIdNumber)`: Answers an incoming call * `rejectCall(viewContext, callId)`: Rejects an incoming call * `endCall(viewContext)`: Ends the current active call * `holdUnholdCurrentCall(viewContext)`: Toggles hold state for the current call * `dtmfPressed(key)`: Sends DTMF tones during an active call **Push Notification Methods** * `answerIncomingPushCall(viewContext, txPushMetaData)`: Answers a call received via push notification with the metadata received from the push notification * `rejectIncomingPushCall(viewContext, txPushMetaData)`: Rejects a call received via push notification with the metadata received from the push notification * `disablePushNotifications(context)`: Disables push notifications for the current device **Profile Management Methods - Saving and Loading Credentials (SIP or Generated) or Tokens** * `setupProfileList(context)`: Initializes the list of user profiles * `addProfile(context, profile)`: Adds a new user profile * `deleteProfile(context, profile)`: Deletes an existing user profile * `setCurrentConfig(context, profile)`: Sets the active user profile ### CallForegroundService The `CallForegroundService` is a foreground service that keeps your call active when the app is minimized. This is essential for maintaining call audio and preventing the system from killing the call process. The 'CallForegroundService' also provides a persistent notification that allows users to control the call directly from the notification. This notification is in line with Android's guidelines for ongoing calls and uses their official Call Notification style. Key features: * Maintains a persistent notification during active calls in the official Call Notification style * Handles audio priority and routing when the app is in the background. Without this service, the system may kill the call process, causing the call to disconnect or audio to stop * Provides call control actions directly from the notification Usage: ```kotlin theme={null} // Start the service when a call begins CallForegroundService.startService(context, pushMetaData) // Stop the service when a call ends CallForegroundService.stopService(context) // Check if the service is running val isCallActive = CallForegroundService.isServiceRunning(context) ``` A more fleshed out example of how we use this is within `TelnyxCommon.kt` which is utilized by the TelnyxViewModel where we set the current call and start the service when a call is active and stop it when the call is ended. ```kotlin theme={null} internal fun setCurrentCall(context: Context, call: Call?) { call?.let { newCall -> telnyxClient?.getActiveCalls()?.get(newCall.callId)?.let { _currentCall = it // Start the CallForegroundService - if one is not already running startCallService(context, it) } } ?: run { _currentCall = null // if we have no active call, stop the CallForegroundService stopCallService(context) } } ``` ### Notifications The notification folder provides a complete implementation for handling call notifications, including: **CallNotificationService** Handles the creation and management of notifications for: * Incoming calls * Ongoing calls * Missed calls (When an invitation has been stopped on the callers side) The service creates appropriate notification channels and configures them with the correct importance levels, sounds, and vibration patterns. **CallNotificationReceiver** A `BroadcastReceiver` that handles user interactions with call notifications: * Answering calls from the notification * Rejecting calls from the notification * Ending ongoing calls from the notification **MyFirebaseMessagingService** Handles incoming Firebase Cloud Messaging (FCM) push notifications for calls: * Parses incoming push notifications and extracts the call metadata, which is required when answering or rejecting calls from the notification * Displays appropriate UI for incoming calls * Routes call information to the appropriate handlers ## Implementation Example Here's a very very basic example of how to use the `telnyx_common` module in an activity: ```kotlin theme={null} class CallActivity : AppCompatActivity() { private lateinit var viewModel: TelnyxViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_call) // Initialize the ViewModel viewModel = ViewModelProvider(this)[TelnyxViewModel::class.java] // Set up observers for call events viewModel.uiState.observe(this) { state -> when (state) { is TelnyxSocketEvent.OnClientReady -> handleClientReady() is TelnyxSocketEvent.OnIncomingCall -> handleIncomingCall(state.message) is TelnyxSocketEvent.OnCallAnswered -> handleCallAnswered(state.callId) is TelnyxSocketEvent.OnCallEnded -> handleCallEnded(state.message) // Handle other states... } } // Set up UI buttons dialButton.setOnClickListener { viewModel.sendInvite(this, phoneNumberInput.text.toString()) } endCallButton.setOnClickListener { viewModel.endCall(this) } // Login with credentials val profile = Profile( sipUsername = "your_username", sipPassword = "your_password", callerIdName = "Your Name", callerIdNumber = "your_number" ) viewModel.credentialLogin(this, profile, null) } override fun onDestroy() { super.onDestroy() // Clean up if needed } } ``` ## Best Practices 1. **Call Lifecycle Management**: Always ensure you properly handle the call lifecycle, especially ending calls when they're complete to free up resources. 2. **Background Processing**: Use the `CallForegroundService` to maintain calls when your app is in the background. 3. **Error Handling**: Observe the `uiState` flow to catch and handle any errors that might occur during calls. 4. **User Permissions**: Ensure your app has the necessary permissions (microphone, notifications) before initiating calls. ## Troubleshooting * If calls disconnect when the app is minimized, ensure the `CallForegroundService` is properly started. * For notification issues, check that notification permissions are granted and channels are properly configured. Also double check the portal to make sure the push credentials are assigned properly. * If authentication fails, verify the credentials and ensure the device has internet connectivity. ### Observe Call State Changes For each `Call` object obtained (e.g., from `telnyxClient.newInvite(...)` or from an incoming call event), you should observe its `callStateFlow` to react to state changes: ```kotlin theme={null} val ongoingCall = telnyxClient.newInvite(/* ... params ... */) // In your Activity or ViewModel scope lifecycleScope.launch { ongoingCall.callStateFlow.collect { callState -> when (callState) { is CallState.NEW -> { // Call object created locally updateUi("Call initializing...") } is CallState.CONNECTING -> { updateUi("Connecting call...") } is CallState.RINGING -> { updateUi("Ringing...") } is CallState.ACTIVE -> { updateUi("Call is active") // Start call timer, enable in-call controls, etc. } is CallState.DONE -> { // Call has ended val reason = callState.reason val endMessage = if (reason != null) { "Call ended: ${reason.cause ?: "Unknown cause"}" + (reason.sipCode?.let { " (SIP: $it ${reason.sipReason ?: ""})" } ?: "") } else { "Call ended." } updateUi(endMessage) showToast(endMessage) // Navigate back or reset UI } is CallState.HELD -> { updateUi("Call on hold") } is CallState.DROPPED -> { val dropMessage = "Call dropped: ${callState.callNetworkChangeReason.description}" updateUi(dropMessage) showToast(dropMessage) // Attempt to reconnect or inform user } is CallState.RECONNECTING -> { val reconnectMessage = "Call reconnecting: ${callState.callNetworkChangeReason.description}" updateUi(reconnectMessage) } is CallState.ERROR -> { updateUi("Error with call.") showToast("An error occurred with the call.") // Navigate back or reset UI } } } } ``` Remember to replace `updateUi` and `showToast` with your actual UI update logic. ### Handling Incoming Calls **Recommended approach using SharedFlow:** When `TelnyxClient.socketResponseFlow` emits a message with `SocketMethod.INVITE`, it signifies an incoming call. You would typically display an incoming call UI and provide options to accept or reject. ```kotlin theme={null} // Using SharedFlow (Recommended) lifecycleScope.launch { telnyxClient.socketResponseFlow.collect { response -> if (response.status == SocketStatus.MESSAGERECEIVED && response.data?.method == SocketMethod.INVITE.methodName) { val inviteResponse = response.data.result as InviteResponse val incomingCallId = inviteResponse.callId val callerIdName = inviteResponse.callerIdName val callerIdNumber = inviteResponse.callerIdNumber // Display incoming call screen showIncomingCallUi(callerIdName, callerIdNumber, incomingCallId) // Store the inviteResponse or callId to accept/reject later currentIncomingCallId = incomingCallId } } } // To accept the call: telnyxClient.acceptCall(currentIncomingCallId, "your_destination_number") // To reject the call: telnyxClient.endCall(currentIncomingCallId) // Or a specific reject method if available ``` **Deprecated approach using LiveData:** ```kotlin theme={null} @Deprecated("Use socketResponseFlow instead. LiveData is deprecated in favor of Kotlin Flows.") // Inside the observer for telnyxClient.socketResponseLiveData if (response.data?.method == SocketMethod.INVITE.methodName) { val inviteResponse = response.data.result as InviteResponse val incomingCallId = inviteResponse.callId val callerIdName = inviteResponse.callerIdName val callerIdNumber = inviteResponse.callerIdNumber // Display incoming call screen showIncomingCallUi(callerIdName, callerIdNumber, incomingCallId) // Store the inviteResponse or callId to accept/reject later currentIncomingCallId = incomingCallId } ``` This quickstart covers the basic setup and core functionalities. Explore the SDK's classes and methods for more advanced features like call hold, DTMF, and custom headers. # WebRTC Android ReceivedMessageBody Source: https://developers.telnyx.com/development/webrtc/android-sdk/socket/receivedmessagebody/index A data class the represents the structure of every message received via the socket connection ## ReceivedMessageBody A data class the represents the structure of every message received via the socket connection ```kotlin theme={null} data class ReceivedMessageBody(val method: String, val result: ReceivedResult?) ``` Where the params are: * method the Telnyx Message Method - ie. INVITE, BYE, MODIFY, etc. @see \[SocketMethod] * result the content of the actual message in the structure provided via `ReceivedResult` ### SocketMethod Enum class to detail the Method property of the response from the Telnyx WEBRTC client with the given \[methodName] ```kotlin theme={null} enum class SocketMethod(var methodName: String) { ANSWER("telnyx_rtc.answer"), ATTACH("telnyx_rtc.attach"), INVITE("telnyx_rtc.invite"), BYE("telnyx_rtc.bye"), MODIFY("telnyx_rtc.modify"), MEDIA("telnyx_rtc.media"), INFO("telnyx_rtc.info"), RINGING("telnyx_rtc.ringing"), PINGPONG("telnyx_rtc.ping"), CLIENT_READY("telnyx_rtc.clientReady"), GATEWAY_STATE("telnyx_rtc.gatewayState"), DISABLE_PUSH("telnyx_rtc.disable_push_notification"), ATTACH_CALL("telnyx_rtc.attachCalls"), LOGIN("login") } ``` * methodName is the Telnyx representation of the method, eg. telnyx\_rtc.answer -> ANSWER Method names: * ANSWER the call has been answered by the destination * INVITE send/receive an invitation that can then be answered or rejected * BYE a user has ended the call * MODIFY a modifier that allows the user to hold the call, etc * MEDIA received media from destination, such as a dialtone * MEDIA send information to the destination such as DTMF * LOGIN the response to a login request. The `ReceivedMessageBody` data class is a crucial part of the Telnyx WebRTC SDK, serving as a standardized wrapper for all messages received over the WebSocket connection. It provides a consistent structure for handling different types of Verto protocol messages. ## Structure ```kotlin theme={null} data class ReceivedMessageBody( val method: String, // The Telnyx Message Method (e.g., "telnyx_rtc.invite", "telnyx_rtc.bye") val result: ReceivedResult? // The content of the actual message ) ``` * **`method: String`**: This field indicates the type of message received. It corresponds to one of the `SocketMethod` enums (e.g., `SocketMethod.INVITE`, `SocketMethod.ANSWER`, `SocketMethod.BYE`). Your application will typically use this field in a `when` statement to determine how to process the `result`. * **`result: ReceivedResult?`**: This field holds the actual payload of the message. `ReceivedResult` is a sealed class, and the concrete type of `result` will depend on the `method`. For example: * If `method` is `SocketMethod.LOGIN.methodName`, `result` will be a `LoginResponse`. * If `method` is `SocketMethod.INVITE.methodName`, `result` will be an `InviteResponse`. * If `method` is `SocketMethod.ANSWER.methodName`, `result` will be an `AnswerResponse`. * If `method` is `SocketMethod.BYE.methodName`, `result` will be a `com.telnyx.webrtc.sdk.verto.receive.ByeResponse`. Importantly, this `ByeResponse` now includes detailed termination information such as `cause`, `causeCode`, `sipCode`, and `sipReason`, in addition to the `callId`. * Other `ReceivedResult` subtypes include `RingingResponse`, `MediaResponse`, and `DisablePushResponse`. ## Usage When you observe `TelnyxClient.socketResponseLiveData`, you receive a `SocketResponse`. If the status is `SocketStatus.MESSAGERECEIVED`, the `data` field of `SocketResponse` will contain the `ReceivedMessageBody`. ```kotlin theme={null} telnyxClient.socketResponseLiveData.observe(this, Observer { response -> if (response.status == SocketStatus.MESSAGERECEIVED) { response.data?.let { receivedMessageBody -> Log.d("SDK_APP", "Method: ${receivedMessageBody.method}") when (receivedMessageBody.method) { SocketMethod.LOGIN.methodName -> { val loginResponse = receivedMessageBody.result as? LoginResponse // Process login response } SocketMethod.INVITE.methodName -> { val inviteResponse = receivedMessageBody.result as? InviteResponse // Process incoming call invitation } SocketMethod.BYE.methodName -> { val byeResponse = receivedMessageBody.result as? com.telnyx.webrtc.sdk.verto.receive.ByeResponse byeResponse?.let { // Process call termination, access it.cause, it.sipCode, etc. Log.i("SDK_APP", "Call ${it.callId} ended. Reason: ${it.cause}, SIP Code: ${it.sipCode}") } } // Handle other methods... } } } }) ``` By checking the `method` and casting the `result` to its expected type, your application can effectively handle the diverse messages sent by the Telnyx platform. # WebRTC Android SocketResponse Source: https://developers.telnyx.com/development/webrtc/android-sdk/socket/socketresponse/index Data class used with communication between socket connection and TelnyxClient ## SocketResponse Data class used with communication between socket connection and TelnyxClient. ```kotlin theme={null} data class SocketResponse(var status: SocketStatus, val data: T?, val errorMessage: String?) ``` Where SocketStatus is a Enum class: ```kotlin theme={null} enum class SocketStatus { ESTABLISHED, MESSAGERECEIVED, ERROR, LOADING, DISCONNECT } ``` The SocketStatus can be one of the following * ESTABLISHED a connection to the socket has been established * MESSAGERECEIVED the socket has received a message * ERROR the socket has encountered an error * LOADING the socket is loading a connection * DISCONNECT when the socket is disconnect # WebRTC Stats Source: https://developers.telnyx.com/development/webrtc/android-sdk/stats/index A comprehensive record of all updates, enhancements, and bug fixes related to WebRTC statistics. ## WebRTC Statistics The SDK provides WebRTC statistics functionality to assist with troubleshooting and monitoring call quality. This feature is controlled through the `debug` flag in the `TxClient` configuration. ### Enabling WebRTC Statistics To enable WebRTC statistics logging: ```Kotlin theme={null} val credentialConfig = CredentialConfig( sipUser = sipUsername ?: "", sipPassword = sipPass ?: "", sipCallerIDName = this.callerIdName, sipCallerIDNumber = callerIdNumber, logLevel = LogLevel.ALL, debug = false // Enable debug mode for WebRTC statistics ) // or With Token Login val credentialConfig = TokenConfig( sipToken= sipToken ?: "", sipCallerIDName = this.callerIdName, sipCallerIDNumber = callerIdNumber, logLevel = LogLevel.ALL, debug = false ) ``` ### Understanding WebRTC Statistics When `debug: true` is configured: * WebRTC statistics logs are automatically collected during calls * Logs are sent to the Telnyx portal and are accessible in the Object Storage section * Statistics are linked to the SIP credential used for testing * The logs help the Telnyx support team diagnose issues and optimize call quality * All statistics are presented in the Telnyx portal under the Object Storage section ### Real-time Call Quality Monitoring The SDK provides real-time call quality metrics through the `onCallQualityChange` callback on the `Call` object. This allows you to monitor call quality in real-time and provide feedback to users. **Using onCallQualityChanged** ```Kotlin theme={null} // When creating a new call set debug to true for CallQualityMetrics val outgoingCall = telnyxClient.newInvite(callerName, callerNumber, destinationNumber, clientState, customHeaders, debug // debug value ) //When accepting a call val incomingCall = telnyxCommon.getTelnyxClient(context).acceptCall(callId, callerIdNumber, customHeaders, debug // debug value ) // Set the onCallQualityChange callback incomingCall.onCallQualityChange = { callQualityMetrics -> // Handle call quality metrics println("Call quality: ${callQualityMetrics.quality}") println("MOS score: ${callQualityMetrics.mos}") println("Jitter: ${callQualityMetrics.jitter} ms") println("Round-trip time: ${callQualityMetrics.rtt} ms") } } ``` **CallQualityMetrics Properties** The `CallQualityMetrics` object provides the following properties: | Property | Type | Description | | --------------------- | ------------------- | -------------------------------------------------------------- | | `jitter` | Double | Jitter in seconds (multiply by 1000 for milliseconds) | | `rtt` | Double | Round-trip time in seconds (multiply by 1000 for milliseconds) | | `mos` | Double | Mean Opinion Score (1.0-5.0) | | `quality` | CallQuality | Call quality rating based on MOS | | `inboundAudio` | `Map?` | Inbound audio statistics | | `outboundAudio` | `Map?` | Outbound audio statistics | | `remoteInboundAudio` | `Map?` | Remote inbound audio statistics | | `remoteOutboundAudio` | `Map?` | Remote outbound audio statistics | **CallQuality Enum** The `CallQuality` enum provides the following values: | Value | MOS Range | Description | | ------------ | ------------------- | --------------------------- | | `.excellent` | `MOS > 4.2` | Excellent call quality | | `.good` | `4.1 <= MOS <= 4.2` | Good call quality | | `.fair` | `3.7 <= MOS <= 4.0` | Fair call quality | | `.poor` | `3.1 <= MOS <= 3.6` | Poor call quality | | `.bad` | `MOS <= 3.0` | Bad call quality | | `.unknown` | N/A | Unable to calculate quality | **Best Practices for Call Quality Monitoring** 1. **User Feedback**: * Consider showing a visual indicator of call quality to users * For poor quality calls, provide suggestions (e.g., "Try moving to an area with better connectivity") 2. **Logging**: * Log quality metrics for later analysis * Track quality trends over time to identify patterns 3. **Adaptive Behavior**: * Implement adaptive behaviors based on call quality * For example, suggest switching to audio-only if video quality is poor 4. **Performance Considerations**: * The callback is triggered periodically (approximately every 2 seconds) ### Important Notes 1. **Log Access**: * If you run the app using SIP credential A with `debug: true`, the WebRTC logs will be available in the Telnyx portal account associated with credential A * Logs are stored in the Object Storage section of your Telnyx portal 2. **Troubleshooting Support**: * WebRTC statistics are primarily intended to assist the Telnyx support team * When requesting support, enable `debug: true` in `TxClient` for all instances * Provide the `debug ID` or `callId` when contacting support * Statistics logging is disabled by default to optimize performance 3. **Best Practices**: * Enable `debug: true` only when troubleshooting is needed * Remember to provide the `debug ID` or `callId` in support requests * Consider disabling debug mode in production unless actively investigating issues *** # WebRTC Flutter SDK AI Voice Assistant Anonymous Login Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/anonymous-login/index Learn how to implement anonymous login for AI voice assistants with the Flutter Voice SDK # Anonymous Login for AI Agents ## Overview The `anonymousLogin` method allows you to connect to AI assistants without traditional authentication credentials. This is the first step in establishing communication with a Telnyx AI Agent. ## Method Signature ```dart theme={null} Future anonymousLogin({ required String targetId, String targetType = 'ai_assistant', String? targetVersionId, Map? userVariables, bool reconnection = false, LogLevel logLevel = LogLevel.none, }) ``` ## Parameters | Parameter | Type | Required | Default | Description | | ----------------- | ----------------------- | -------- | --------------- | ----------------------------------------------------------------------- | | `targetId` | String | Yes | - | The ID of your AI assistant | | `targetType` | String | No | 'ai\_assistant' | The type of target | | `targetVersionId` | String? | No | null | Optional version ID of the target. If not provided, uses latest version | | `userVariables` | `Map?` | No | null | Optional user variables to include | | `reconnection` | bool | No | false | Whether this is a reconnection attempt | | `logLevel` | LogLevel | No | LogLevel.none | Log level for this session | ## Usage Example ```dart theme={null} try { await _telnyxClient.anonymousLogin( targetId: 'your_assistant_id', // targetType: 'ai_assistant', // This is the default value // targetVersionId: 'your_assistant_version_id' // Optional ); // You are now connected and can make a call to the AI Assistant. } catch (e) { // Handle login error print('Login failed: $e'); } ``` ## Advanced Usage ### With User Variables ```dart theme={null} await _telnyxClient.anonymousLogin( targetId: 'your_assistant_id', userVariables: { 'user_id': '12345', 'session_context': 'support_chat', 'language': 'en-US' } ); ``` ### With Logging ```dart theme={null} await _telnyxClient.anonymousLogin( targetId: 'your_assistant_id', logLevel: LogLevel.debug ); ``` ## Important Notes * **Call Routing**: After a successful `anonymousLogin`, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant * **Session Lock**: The session becomes locked to the AI assistant until disconnection * **Version Control**: If `targetVersionId` is not provided, the SDK will use the latest available version * **Error Handling**: Always wrap the call in a try-catch block to handle authentication errors ## Error Handling Common errors you might encounter: ```dart theme={null} try { await _telnyxClient.anonymousLogin(targetId: 'invalid_id'); } catch (e) { if (e.toString().contains('authentication')) { // Handle authentication error print('Invalid assistant ID or authentication failed'); } else if (e.toString().contains('network')) { // Handle network error print('Network connection failed'); } else { // Handle other errors print('Unexpected error: $e'); } } ``` ## Next Steps After successful anonymous login: 1. [Start a conversation](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/starting-conversations) using `newInvite()` 2. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/transcript-updates) to receive real-time conversation data 3. [Send text messages](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/text-messaging) during active calls # WebRTC Flutter SDK AI Voice Assistant Introduction Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/introduction/index Introduction to building AI-powered voice assistants with the Flutter Voice SDK # AI Agent Usage The Flutter Voice SDK supports [Voice AI Agent](https://telnyx.com/products/voice-ai-agents) implementations. To get started, follow the steps [described here](https://telnyx.com/resources/ai-assistant-builder) to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps: ## Pre-developed AI Widget If you don't want to develop your own custom AI Agent interface from scratch, you can utilize our pre-developed AI Agent widget that provides a drop-in solution for voice AI interactions. ### Flutter Telnyx Voice AI Widget The **Flutter Telnyx Voice AI Widget** is a standalone, embeddable widget that provides a complete voice AI assistant interface using the Telnyx WebRTC SDK. **Repository**: [https://github.com/team-telnyx/flutter-telnyx-voice-ai-widget](https://github.com/team-telnyx/flutter-telnyx-voice-ai-widget) **Package**: [https://pub.dev/packages/flutter\_telnyx\_voice\_ai\_widget](https://pub.dev/packages/flutter_telnyx_voice_ai_widget) ### Key Features * **Configurable Dimensions**: Set custom height and width for the widget * **Icon-Only Mode**: Floating action button-style interface for minimal UI footprint * **Multiple UI States**: Collapsed, connecting, expanded, and conversation views * **Agent Status Indicators**: Shows when the agent is thinking or waiting for interruption * **Audio Visualizer**: Animated bars that respond to call activity * **Theme Support**: Light and dark theme configurations * **Call Controls**: Built-in mute/unmute and end call functionality * **Conversation View**: Full transcript with message history * **Responsive Design**: Adapts to different screen sizes ### Quick Integration ```dart theme={null} import 'package:flutter_telnyx_voice_ai_widget/flutter_telnyx_voice_ai_widget.dart'; // Basic usage TelnyxVoiceAiWidget( height: 60, width: 300, assistantId: 'your-assistant-id', ) // Icon-only mode TelnyxVoiceAiWidget.iconOnly( assistantId: 'your-assistant-id', ) ``` This widget handles all the complexity of AI Agent integration, providing a production-ready solution that you can customize to match your app's design. ## Documentation Structure This directory contains detailed documentation for AI Agent integration: * [Anonymous Login](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/anonymous-login) - How to connect to AI assistants without traditional authentication * [Starting Conversations](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/starting-conversations) - How to initiate calls with AI assistants * [Transcript Updates](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/transcript-updates) - Real-time conversation transcripts * [Text Messaging](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/text-messaging) - Send text messages to AI agents during calls ## Quick Start 1. **Login**: Use `anonymousLogin()` to connect to your AI assistant 2. **Call**: Use `newInvite()` to start a conversation (destination ignored) 3. **Listen**: Set up `onTranscriptUpdate` callback for real-time transcripts 4. **Message**: Use `sendConversationMessage()` to send text during calls ## Important Notes * AI Agent features are only available after `anonymousLogin` * All calls after anonymous login are routed to the specified AI assistant * Transcript updates are real-time and include both user and assistant messages * Text messages appear in transcript updates alongside spoken conversation * Standard call controls (mute, hold, end) work with AI agent calls # WebRTC Flutter SDK AI Voice Assistant Starting Conversations Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/starting-conversations/index Learn how to start conversations with AI voice assistants using the Flutter Voice SDK # Starting Conversations with AI Assistants ## Overview After a successful `anonymousLogin`, you can initiate a call to your AI Assistant using the `newInvite` method. The AI assistant will automatically answer the call, and standard call controls will work normally. ## Method Usage ```dart theme={null} Call newInvite( String callerName, String callerNumber, String destinationNumber, String clientState, { Map customHeaders = const {}, List? preferredCodecs, bool debug = false, }) ``` ## Important Behavior * **Destination Ignored**: Because the session is locked to the AI Assistant, the `destinationNumber` parameter is ignored, but can still be useful for referencing logs. * **Automatic Answer**: The AI assistant automatically answers the call * **Standard Controls**: All normal call controls (mute, hold, end, etc.) work as expected * **Custom Headers**: You can pass custom SIP headers to provide context to the AI assistant. They will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the portal. Hyphens in header names are converted to underscores in variable names, e.g. `X-Session-Context` header maps to `{{session_context}}` variable. ## Basic Example ```dart theme={null} // After a successful anonymousLogin... Call aiCall = _telnyxClient.newInvite( 'Your Name', 'Your Number', '', // Destination is ignored, can be an empty string 'Your custom state', ); // The call will be automatically answered by the AI Assistant ``` ## Advanced Usage ### With Custom Headers ```dart theme={null} Call aiCall = _telnyxClient.newInvite( 'John Doe', '+1234567890', '', // Ignored 'customer_support_session', customHeaders: { 'X-Session-Context': 'billing_inquiry', 'X-User-Tier': 'premium' } ); ``` Note: The above headers will map to dynamic variables `{{session_context}}` and `{{user_tier}}` in the AI assistant portal settings ### With Preferred Audio Codecs ```dart theme={null} // Get supported codecs List supportedCodecs = _telnyxClient.getSupportedAudioCodecs(); // Use preferred codecs (Opus for high quality) Call aiCall = _telnyxClient.newInvite( 'Jane Smith', '+1987654321', '', 'technical_support', preferredCodecs: [ AudioCodec( mimeType: 'audio/opus', clockRate: 48000, channels: 2, sdpFmtpLine: 'minptime=10;useinbandfec=1', ), ] ); ``` ### With Debug Mode ```dart theme={null} Call aiCall = _telnyxClient.newInvite( 'Debug User', '+1555000123', '', 'debug_session', debug: true // Enables call quality metrics ); // Listen for call quality metrics aiCall.onCallQualityChange = (metrics) { print('Call quality: ${metrics.quality}'); print('MOS score: ${metrics.mos}'); }; ``` ## Call State Management The AI call follows the same state management as regular calls: ```dart theme={null} // Listen for call state changes aiCall.callHandler.onCallStateChanged = (CallState state) { switch (state) { case CallState.connecting: print('Connecting to AI assistant...'); break; case CallState.active: print('Connected to AI assistant'); break; case CallState.done: print('AI conversation ended'); break; // Handle other states... } }; ``` ## Call Control Examples ### Mute/Unmute ```dart theme={null} // Mute the microphone aiCall.onMuteUnmutePressed(); // Check mute status bool isMuted = aiCall.muted; ``` ### Hold/Unhold ```dart theme={null} // Put the call on hold aiCall.onHoldUnholdPressed(); // Check hold status bool isOnHold = aiCall.held; ``` ### Speaker Phone ```dart theme={null} // Enable speaker phone aiCall.enableSpeakerPhone(true); // Disable speaker phone aiCall.enableSpeakerPhone(false); ``` ### End Call ```dart theme={null} // End the AI conversation aiCall.endCall(); ``` ## Error Handling ```dart theme={null} try { Call aiCall = _telnyxClient.newInvite( 'User Name', 'User Number', '', 'session_state' ); // Set up error handling aiCall.callHandler.onCallStateChanged = (CallState state) { if (state == CallState.done) { // Check for call termination reason if (state.terminationReason?.cause == 'FAILED') { print('Call failed: ${state.terminationReason?.sipReason}'); } } }; } catch (e) { print('Failed to start AI conversation: $e'); } ``` ## Best Practices 1. **State Management**: Always set up call state listeners before initiating the call 2. **Error Handling**: Implement proper error handling for connection failures 3. **Resource Cleanup**: Ensure calls are properly ended to free resources 4. **User Feedback**: Provide clear UI feedback about connection status 5. **Debugging**: Use debug mode during development to monitor call quality ## Next Steps After starting a conversation: 1. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/transcript-updates) to receive real-time conversation data 2. [Send text messages](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/text-messaging) during the active call 3. Use standard call controls as needed # WebRTC Flutter SDK AI Voice Assistant Text Messaging Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/text-messaging/index Learn how to implement text messaging with AI voice assistants using the Flutter Voice SDK # Sending Text Messages to AI Agents ## Overview In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. ## Method Signature ```dart theme={null} void sendConversationMessage(String message, {String? base64Image}) ``` This method is available on the `Call` object during an active AI Assistant conversation. ### Parameters * `message` (String): The text message to send to the AI Agent * `base64Image` (String?, optional): A base64 encoded image string for vision-capable AI models **Note**: To provide images to your AI assistant, ensure you are using a vision-capable model. The `base64Image` parameter accepts either: * A complete data URL format: `data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ...` * A raw base64 string (will be automatically formatted as JPEG): `/9j/4AAQSkZJRgABAQAAAQ...` ## Basic Usage ### Getting the Active Call ```dart theme={null} // Get the active call instance (after successfully connecting and calling) Call? activeCall = _telnyxClient.calls.values.firstOrNull; if (activeCall != null) { // Send a text message to the AI Agent activeCall.sendConversationMessage("Hello, can you help me with my account?"); // Send a message with an image (for vision-capable models) activeCall.sendConversationMessage( "Can you analyze this image?", base64Image: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..." ); // Send only an image without text activeCall.sendConversationMessage( "", base64Image: "/9j/4AAQSkZJRgABAQAAAQ..." // Raw base64 (auto-formatted as JPEG) ); } ``` ## Important Notes * **AI Assistant Only**: The `sendConversationMessage` method is only available during AI Assistant conversations * **Transcript Integration**: Text messages sent this way will appear in the transcript updates alongside spoken conversation * **Processing**: The AI Agent will process and respond to text messages just like spoken input * **Active Call Required**: You must have an active call established before sending text messages * **Real-time**: Messages are sent in real-time and will be processed immediately by the AI agent * **Vision Models**: Base64 image support requires vision-capable AI models to be configured in your AI Assistant * **Image Formats**: Supported image formats include JPEG, PNG, GIF, and WebP * **Image Size**: Consider image file size and compression for optimal performance * **Multimodal**: You can send text and images together, or send images without text for pure visual analysis ## Troubleshooting ### Message Not Sent If messages aren't being sent: 1. Verify the call is active (`call.callState.isActive`) 2. Check that you're in an AI Assistant conversation (after `anonymousLogin`) 3. Ensure the call object is not null 4. Verify network connectivity ### Messages Not Appearing in Transcript If sent messages don't appear in the transcript: 1. Confirm `onTranscriptUpdate` callback is properly set 2. Check that the message was successfully sent 3. Wait a moment for the transcript to update ## Next Steps * [Learn about transcript updates](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/transcript-updates) to handle responses # WebRTC Flutter SDK AI Voice Assistant Transcript Updates Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-voice-assistant/transcript-updates/index Learn how to handle transcript updates with AI voice assistants using the Flutter Voice SDK # Real-time Transcript Updates ## Overview During an AI Assistant conversation, the SDK provides real-time transcript updates that include both the caller's speech and the AI Assistant's responses. This allows you to display a live conversation transcript in your application. ## Setting Up Transcript Updates To receive transcript updates, set up the `onTranscriptUpdate` callback on your `TelnyxClient` instance: ```dart theme={null} _telnyxClient.onTranscriptUpdate = (List transcript) { // Handle the updated transcript for (var item in transcript) { print('${item.role}: ${item.content}'); // item.role will be either 'user' or 'assistant' // item.content contains the spoken text // item.timestamp contains when the message was received } // Update your UI to display the conversation setState(() { _conversationTranscript = transcript; }); }; ``` ## TranscriptItem Properties The `TranscriptItem` class contains the following properties: | Property | Type | Description | | ----------- | -------- | ---------------------------------------------------------------- | | `id` | String | Unique identifier for the transcript item | | `role` | String | Either 'user' (for the caller) or 'assistant' (for the AI Agent) | | `content` | String | The transcribed text content | | `timestamp` | DateTime | When the transcript item was created | ## Manual Transcript Management ### Retrieving Current Transcript You can manually retrieve the current transcript at any time: ```dart theme={null} List currentTranscript = _telnyxClient.transcript; // Process the transcript for (var item in currentTranscript) { print('${item.timestamp}: [${item.role}] ${item.content}'); } ``` ### Clearing Transcript To clear the transcript (for example, when starting a new conversation): ```dart theme={null} _telnyxClient.clearTranscript(); ``` ## UI Implementation Examples ### Simple List View ```dart theme={null} class TranscriptWidget extends StatefulWidget { @override _TranscriptWidgetState createState() => _TranscriptWidgetState(); } class _TranscriptWidgetState extends State { List _transcript = []; @override void initState() { super.initState(); // Set up transcript updates _telnyxClient.onTranscriptUpdate = (List transcript) { setState(() { _transcript = transcript; }); }; } @override Widget build(BuildContext context) { return ListView.builder( itemCount: _transcript.length, itemBuilder: (context, index) { final item = _transcript[index]; return ListTile( leading: Icon( item.role == 'user' ? Icons.person : Icons.smart_toy, color: item.role == 'user' ? Colors.blue : Colors.green, ), title: Text(item.content), subtitle: Text( '${item.role} • ${item.timestamp.toString()}', style: TextStyle(fontSize: 12), ), ); }, ); } } ``` ### Chat Bubble Style ```dart theme={null} class ChatTranscriptWidget extends StatefulWidget { @override _ChatTranscriptWidgetState createState() => _ChatTranscriptWidgetState(); } class _ChatTranscriptWidgetState extends State { List _transcript = []; ScrollController _scrollController = ScrollController(); @override void initState() { super.initState(); _telnyxClient.onTranscriptUpdate = (List transcript) { setState(() { _transcript = transcript; }); // Auto-scroll to bottom WidgetsBinding.instance.addPostFrameCallback((_) { if (_scrollController.hasClients) { _scrollController.animateTo( _scrollController.position.maxScrollExtent, duration: Duration(milliseconds: 300), curve: Curves.easeOut, ); } }); }; } @override Widget build(BuildContext context) { return ListView.builder( controller: _scrollController, itemCount: _transcript.length, itemBuilder: (context, index) { final item = _transcript[index]; final isUser = item.role == 'user'; return Align( alignment: isUser ? Alignment.centerRight : Alignment.centerLeft, child: Container( margin: EdgeInsets.symmetric(vertical: 4, horizontal: 8), padding: EdgeInsets.all(12), decoration: BoxDecoration( color: isUser ? Colors.blue[100] : Colors.grey[200], borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( item.content, style: TextStyle(fontSize: 16), ), SizedBox(height: 4), Text( DateFormat('HH:mm:ss').format(item.timestamp), style: TextStyle(fontSize: 10, color: Colors.grey[600]), ), ], ), ), ); }, ); } @override void dispose() { _scrollController.dispose(); super.dispose(); } } ``` ## Real-time Processing ### Filtering Transcript Items ```dart theme={null} _telnyxClient.onTranscriptUpdate = (List transcript) { // Filter only user messages List userMessages = transcript .where((item) => item.role == 'user') .toList(); // Filter only assistant messages List assistantMessages = transcript .where((item) => item.role == 'assistant') .toList(); // Process latest message if (transcript.isNotEmpty) { TranscriptItem latestMessage = transcript.last; if (latestMessage.role == 'assistant') { // Handle new assistant response _handleAssistantResponse(latestMessage); } } }; ``` ### Saving Transcript Data ```dart theme={null} class TranscriptManager { static const String _storageKey = 'conversation_transcripts'; static Future saveTranscript( String conversationId, List transcript, ) async { final prefs = await SharedPreferences.getInstance(); // Convert to JSON List> transcriptJson = transcript .map((item) => { 'id': item.id, 'role': item.role, 'content': item.content, 'timestamp': item.timestamp.toIso8601String(), }) .toList(); // Save to storage Map allTranscripts = jsonDecode(prefs.getString(_storageKey) ?? '{}'); allTranscripts[conversationId] = transcriptJson; await prefs.setString(_storageKey, jsonEncode(allTranscripts)); } static Future?> loadTranscript( String conversationId, ) async { final prefs = await SharedPreferences.getInstance(); Map allTranscripts = jsonDecode(prefs.getString(_storageKey) ?? '{}'); if (!allTranscripts.containsKey(conversationId)) return null; List transcriptJson = allTranscripts[conversationId]; return transcriptJson.map((item) => TranscriptItem( id: item['id'], role: item['role'], content: item['content'], timestamp: DateTime.parse(item['timestamp']), )).toList(); } } ``` ## Important Notes * **AI Assistant Only**: Transcript updates are only available during AI Assistant conversations initiated through `anonymousLogin` * **Real-time Updates**: Transcripts are updated in real-time as the conversation progresses * **Persistent**: The transcript persists throughout the call duration * **Memory Management**: Consider clearing transcripts for long conversations to manage memory * **Text Messages**: Text messages sent via `sendConversationMessage` also appear in the transcript ## Troubleshooting ### No Transcript Updates If you're not receiving transcript updates: 1. Ensure you're using `anonymousLogin` (not regular authentication) 2. Verify the `onTranscriptUpdate` callback is set before starting the call 3. Check that the AI assistant is properly configured for transcription 4. Confirm the call is active and connected ### Missing Messages If some messages are missing from the transcript: 1. Check network connectivity during the call 2. Ensure the callback isn't being overridden 3. Verify the AI assistant is configured to provide transcripts ## Next Steps * [Send text messages](https://developers.telnyx.com/development/webrtc/flutter-sdk/ai-agent/text-messaging) to the AI agent during calls # WebRTC Flutter ChangeLog Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/changelog/index A comprehensive record of all updates, enhancements, and bug fixes. Stay informed about the latest features and improvements to optimize your development experience. ## [4.1.0](https://pub.dev/packages/telnyx_webrtc/versions/4.1.0) (2026-03-08) ### Enhancement * Added `conversationId` parameter to the `anonymousLogin` method, allowing users to join an existing conversation by providing a valid conversation ID. This enables seamless continuation of AI assistant conversations. * Added automatic call reporting for every call to enhance customer call debugging. Logs are sent via post request at the end of call to avoid cluttering web socket. * Added `call-control-id` as a parameter that can be fetched when a call uses call control. Exposed in TelnyxClient * Adjustments to TURN/STUN server configuration to include UDP ## [4.0.1](https://pub.dev/packages/telnyx_webrtc/versions/4.0.1) (2026-02-12) ### Bug Fixing * fix web outbound calling and build by including answered device token and improved SDP handling ## [4.0.0](https://pub.dev/packages/telnyx_webrtc/versions/4.0.0) (2026-02-05) ### Breaking * Using version 4.0.0 will adjust how Push Notifications are handled on iOS devices. Using 4.0.0 allows iOS devices to received `MISSED CALL` notifications - signifying that a call was either missed, or an existing ongoing invitation that was not yet reacted to has been cancelled. Please make sure you are handling these `MISSED CALL` notifications appropriately if necessary or don't update. ### Bug Fixing * Align jitter source with Android/iOS Native SDKs for consistent MOS calculation when using Stats. ### Enhancement * Send an answered `answered_device_token` parameter for push notification calls, allowing us to send `MISSED CALL` notifications to all registered devices except the one that answered if users are using multiple devices ## [3.4.2](https://pub.dev/packages/telnyx_webrtc/versions/3.4.2) (2026-01-15) ### Bug Fixing * Fixed an issue where `CallState.active` was not called for outbound calls, and users could only rely on `SocketMethod.answer` to determine when a call was active. ## [3.4.1](https://pub.dev/packages/telnyx_webrtc/versions/3.4.1) (2026-01-09) ### Bug Fixing * Fixed an issue where the Web peer class did not match the mobile peer class causing build errors on Web and breaking the initial mute state of the call. ## [3.4.0](https://pub.dev/packages/telnyx_webrtc/versions/3.4.0) (2026-01-08) ### Enhancement * Added `Trickle Ice` option on `newInvite` and `acceptCall` methods to allow users to enable or disable Trickle ICE for calls. By default, Trickle ICE is disabled. * Added Call Connection Time Benchmarking to measure the time taken to establish a call connection. This can be useful for performance monitoring and optimization, and is logged automatically when a call is connected. ### Bug Fixing * Adjustments to Call Connection Establishment logic resulting from Connection Time Benchmark findings to improve call setup times and reliability. ## [3.3.0](https://pub.dev/packages/telnyx_webrtc/versions/3.3.0) (2025-12-15) ### Enhancement * Added `EchoCanellation`, `NoiseSuppression` and `AutoGainControl` MediaConstraints as AudioConstraints that can be passed on `newInvite` and `acceptCall` * Added a new parameter on `newInvite` and `acceptCall` called `mutedMicOnStart`, allowing users to join a call muted. * Added `tx_server_configuration.dart` allowing users to specify a specific server connection including host, port, turn and stun. ### Bug Fixing * Further tweaking and refining of the Ice Candidate Gathering and Peer disposal logic to improve call quality and memory usage ## [3.2.0](https://pub.dev/packages/telnyx_webrtc/versions/3.2.0) (2025-11-18) ### Enhancement * AI Agent Conversation Message Enhancements * Added support for sending multiple Base64 encoded images via the `sendConversationMessage()` method on the Call object. This allows users to send images to the AI agent for analysis or context during conversations. * Added configurable push notification timeout parameter on the `Config ` class. This allows users to specify how long the SDK should wait for a push notification to be accepted before timing out. The default value is 10 seconds. * Additionally, the timeout can be configured per call via the `pushAnswerTimeoutMs ` parameter on the `handlePushNotification() ` method. This will override the global timeout set in the Config class for that specific call. ### Bug Fixing * Fixed an issue where speakerphone state was not persisted after reconnection on Android devices. Now, the speakerphone state will be maintained correctly after network interruptions and reconnections. ## [3.1.0](https://pub.dev/packages/telnyx_webrtc/versions/3.1.0) (2025-10-20) ### Enhancement * Socket Connection Quality Callback * Added OnConnectionMetricsUpdate callback to the TelnyxClient class to provide real-time updates on the quality of the WebSocket connection. This can help users monitor and respond to network conditions affecting call quality. * AI Agent Enhancements * Allow for Base64 encoded images that can be sent via sendConversationMessage() on the Call object. * ICE Candidate Renegotiation process implemented to enhance call stability during network changes. * Supported Codecs no longer return a static list of codecs, but instead will return the actual codecs supported by the current device. ### Bug Fixing * Fixed an issue where preferred codecs were not being respected when specified during call initiation. * Fixed how stat metrics were being calculated and sent via the socket, causing some graphs during the debug view to be missing * Fixed an issue where the SDK version was not being parsed correctly in release builds, causing issues with backend logging and debugging. ## [3.0.0](https://pub.dev/packages/telnyx_webrtc/versions/3.0.0) (2025-08-25) ### Enhancement * Added support for AI Agent Usage. * Login to your specific AI agent by providing the agent ID from the portal to the anonymous login method. * Any call made via the newInvite method will be routed to the AI agent. * Transcription and AI responses will be available via the onTranscriptUpdate callback * Added PreferredCodec parameter to the newInvite and acceptCall methods to allow users to specify their preferred audio codec for the call. Note that if the chosen codec is not supported, the call will default to the first codec supported in the SDP. * You can retrieve the list of supported codecs via the getSupportedAudioCodecs method on the TelnyxClient class, however for now these are static and it is possible that some devices may not support all codecs listed - the SDK will fallback to a supported codec in this case. ### Bug Fixing * Fixed an issue where log levels were not being respected with the default logger (Specifically the NONE log level). Now, the default logger will respect the log level set in the Config class. * Fixed an issue where, for Android, the default speakerphone state was enabled when a call was initiated. Now, the speakerphone will only be enabled if the user explicitly enables it. ## [2.0.1](https://pub.dev/packages/telnyx_webrtc/versions/2.0.1) (2025-06-26) ### Enhancement * Added Region Selection support as a parameter on the Config class. This allows users to specify the region for their WebSocket connection, enhancing performance and reliability based on geographical location. It will default to 'auto' if not specified, which will automatically select the best region based on the user's location. There is also a fallbackOnRegionFailure parameter that defaults to true, which will automatically fallback to the 'auto' region if the specified region fails to connect if set to true. * Added a 10 second answer timeout for accepted push notifications. This ensures that if a user accepts a push notification but does not receive an invite on the socket once connected within 10 seconds, the call will be automatically ended with an ORIGINATOR\_CANCELLED termination reason. This prevents situations where a user accepts a call but does not receive the invite due to network issues or other delays potentially causing infinite loading states in implementations. ### Bug Fixing * Fixed an issue where the Termination Cause was always 'USER\_BUSY' regardless of current call state. Now, when terminating an active call, the state will be 'NORMAL\_CLEARING' and when rejecting an invite, the Termination Cause will be 'USER\_BUSY'. ## [2.0.0](https://pub.dev/packages/telnyx_webrtc/versions/2.0.0) (2025-06-13) ### Enhancement * Enhanced call state reporting to include more detailed information about the call state changes. * Enhanced error reporting to provide more context on errors encountered during call handling. * Simplified push notification decline process. ### Bug Fixing * Fixed an issue where, on the Android and iOS clients, we weren't checking if the socket was open before sending messages. This could lead to 'StreamSink is closed' errors in niche edge cases. ## [1.2.0](https://pub.dev/packages/telnyx_webrtc/versions/1.2.0) (2025-05-12) ### Enhancement * Added WebRTC Call Quality Metrics for each initiated call (enabled via debug bool on invite or accept) * Adjusted logging to be more clear for connection process and websocket messages ## [1.1.3](https://pub.dev/packages/telnyx_webrtc/versions/1.1.3) (2025-04-24) ### Bug Fixing * Clear Push Metadata in more places to prevent issue where a call is attempting to be attached based on previously stored push metadata. You can also now manually clear the push metadata by calling `clearPushMetadata` method on the `TelnyxViewModel` class. * Bump negotiation timeout to from 300ms to 500ms (per ice candidate) ## [1.1.2](https://pub.dev/packages/telnyx_webrtc/versions/1.1.2) (2025-04-09) ### Bug Fixing * CodecError fix. Enhanced Ice Candidate Collection when answering calls to ensure more suitable candidates are used in the SDP. ## [1.1.1](https://pub.dev/packages/telnyx_webrtc/versions/1.1.1) (2025-03-25) ### Enhancement * Added timemout for reconnection logic. ## [1.1.0](https://pub.dev/packages/telnyx_webrtc/versions/1.1.0) (2025-02-26) ### Enhancement * Added method to disable push notifications on the SDK via `disablePushNotifications` method. * Added a new parameter to the login configuration that allows users to provide their own `CustomLogger` to the SDK. This is useful for users that want to log the SDK's output in their own way or redirect logs to a server. * Added a new CallStates 'dropped' and 'reconnecting' to the `CallState` enum. This will allow users to know when a call has been dropped or is in the process of reconnecting. There will be a `NetworkReason` provided for both of these states to give more context on why the call was dropped or is reconnecting. ## [1.0.2](https://pub.dev/packages/telnyx_webrtc/versions/1.0.2) (2025-02-14) ### Bug Fixing * Fixed an issue where the call states were not being updated correctly, identifying a call as active when it was still connecting (ICE Gathering). This caused a scenario where users thought a call was active but couldn't hear anything. ## [1.0.1](https://pub.dev/packages/telnyx_webrtc/versions/1.0.1) (2025-02-10) ### Bug Fixing * Fixed an issue where running stats on calls could cause a call to end if the description was not set. * Fixed the web version of the SDK that was having issues working on Safari. ## [1.0.0](https://pub.dev/packages/telnyx_webrtc/versions/1.0.0) (2025-01-29) ### Enhancement - Breaking Changes * Call ID no longer required when ending call or using DTMF. As these methods belong to a call object, the call ID is inferred from the call object itself. This means users only need to keep track of the call objects that are in use and call the relevant methods on the call object itself. ### Bug Fixing * Fixed an issue where the Bye Params (such as cause = USER\_BUSY) were not being included in the ReceivedMessage. ## [0.1.4](https://pub.dev/packages/telnyx_webrtc/versions/0.1.4) (2025-01-28) ### Enhancement * Update UUID dependency to latest version to avoid conflicts with implementers of the SDK ## [0.1.3](https://pub.dev/packages/telnyx_webrtc/versions/0.1.3) (2025-01-06) ### Enhancement * Updated WebRTC to latest Flutter WebRTC version containing a hotfix for audio route issues on iOS ### Bug Fixing * Fixed an issue where audio would not loop for ringtones or ringback tones ## [0.1.2](https://pub.dev/packages/telnyx_webrtc/versions/0.1.2) (2024-12-20) ### Bug Fixing * Fixed an issue where, when accepting a an invite, the destination number was being set to name instead of number. ## [0.1.1](https://pub.dev/packages/telnyx_webrtc/versions/0.1.1) (2024-12-12) ### Enhancement * Improve IceCandidate handling to skip candidates when call is active * Improve PushNotification support on callkit for iOS ### Bug Fixing * General bug fixes and import cleanups. ## [0.1.0](https://pub.dev/packages/telnyx_webrtc/versions/0.1.0) (2024-11-07) ### Enhancement * Implemented WebSocket and RTC peer reconnection logic to ensure seamless recovery during network disconnects or switches. ## [0.0.18](https://pub.dev/packages/telnyx_webrtc/versions/0.0.18) (2024-09-25) ### Bug Fixing * General bug fixes related to imports and how they work and switch between Mobile / Web ## [0.0.17](https://pub.dev/packages/telnyx_webrtc/versions/0.0.17) (2024-08-12) ### Feature * Added support to include login credentials for the `connect` method. ## [0.0.16](https://pub.dev/packages/telnyx_webrtc/versions/0.0.16) (2024-08-01) ### Feature * Implemented push notifications mechanism for both background and foreground states. ### Bug Fixing * Fixed one-way audio issue. * Enhanced call state handling mechanism. ## [0.0.15](https://pub.dev/packages/telnyx_webrtc/versions/0.0.15) (2024-06-27) ### Bug Fixing * Fixed disposal of audio tracks to release iOS/Android microphones properly. ## [0.0.14](https://pub.dev/packages/telnyx_webrtc/versions/0.0.14) (2024-03-20) ### Bug Fixing * Fixed iOS push notification handling and reliability. ## [0.0.13](https://pub.dev/packages/telnyx_webrtc/versions/0.0.13) (2024-03-07) ### Bug Fixing * Resolved issues with Android push notifications. ## [0.0.12](https://pub.dev/packages/telnyx_webrtc/versions/0.0.12) (2024-02-27) ### Bug Fixing * Fixed audio issues for the web platform. ## [0.0.11](https://pub.dev/packages/telnyx_webrtc/versions/0.0.11) (2024-02-07) ### Bug Fixing * Fixed ringing state behavior. ## [0.0.10](https://pub.dev/packages/telnyx_webrtc/versions/0.0.10) (2024-01-04) ### Bug Fixing * Fixed gateway timeout issues. ## [0.0.9](https://pub.dev/packages/telnyx_webrtc/versions/0.0.9) (2022-10-22) ### Feature * Updated the sample app with a new disconnect functionality. ### Bug Fixing * Fixed disconnect functionality to allow subsequent logins. ## [0.0.8](https://pub.dev/packages/telnyx_webrtc/versions/0.0.8) (2022-10-05) ### Enhancement * Added Ping/Pong socket functionality to keep sockets alive. ### Bug Fixing * Fixed serialized variable names for better backend functionality. * Improved code formatting for readability. ## [0.0.7](https://pub.dev/packages/telnyx_webrtc/versions/0.0.7) (2022-09-21) ### Bug Fixing * General bug fixes. * Improved code formatting for readability. ## [0.0.6](https://pub.dev/packages/telnyx_webrtc/versions/0.0.6) (2022-09-05) ### Feature * Enabled speaker mode toggle. ## [0.0.5](https://pub.dev/packages/telnyx_webrtc/versions/0.0.5) (2022-09-02) ### Feature * Enabled PSTN call integration using early SDP contained in Telnyx media messages. ### Bug Fixing * Fixed ICE candidate error that would add a local IP ICE candidate. ## [0.0.4](https://pub.dev/packages/telnyx_webrtc/versions/0.0.4) (2022-08-26) ### Bug Fixing * Improved stability by providing a session ID to the backend immediately rather than waiting to set one. * Fixed gateway retry errors that continuously retried without a timeout. ## [0.0.3](https://pub.dev/packages/telnyx_webrtc/versions/0.0.3) (2022-08-03) ### Enhancement * Improved SDK stability with regular black-box tests. * Included an example folder with documentation. ### Bug Fixing * Resolved issues from static code analysis. ## [0.0.2](https://pub.dev/packages/telnyx_webrtc/versions/0.0.2) (2022-07-22) ### Enhancement * Simplified SDK usage by removing unnecessary parameters from various calls. * Added reference links for Pub.dev listing. ## [0.0.1](https://pub.dev/packages/telnyx_webrtc/versions/0.0.1) (2022-07-18) ### Initial Release * Initial release with basic functionality. # WebRTC Flutter Call Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/call/index A Call is the representation of an audio or video call between two devices, SIP clients or phone numbers. ### Call The Call class is used to manage the call state and call actions. It is used to accept, decline, end, mute, hold, and send DTMF tones during a call. ### Accept Call In order to accept a call, we simply retrieve the instance of the call and use the .acceptCall(callID) method: ```dart theme={null} _telnyxClient.call.acceptCall(_incomingInvite?.callID); ``` ### Decline / End Call In order to end a call, we can get a stored instance of Call and call the .endCall(callID) method. To decline an incoming call we first create the call with the .createCall() method and then call the .endCall(callID) method: ```dart theme={null} if (_ongoingCall) { _telnyxClient.call.endCall(_telnyxClient.call.callId); } else { _telnyxClient.createCall().endCall(_incomingInvite?.callID); } ``` ### DTMF (Dual Tone Multi Frequency) In order to send a DTMF message while on a call you can call the .dtmf(callID, tone), method where tone is a String value of the character you would like pressed: ```dart theme={null} _telnyxClient.call.dtmf(_telnyxClient.call.callId, tone); ``` ### Mute a call To mute a call, you can simply call the .onMuteUnmutePressed() method: ```dart theme={null} _telnyxClient.call.onMuteUnmutePressed(); ``` ### Toggle loud speaker To toggle loud speaker, you can simply call .enableSpeakerPhone(bool): ```dart theme={null} _telnyxClient.call.enableSpeakerPhone(true); ``` ### Put a call on hold To put a call on hold, you can simply call the .onHoldUnholdPressed() method: ```dart theme={null} _telnyxClient.call.onHoldUnholdPressed(); ``` # Flutter WebRTC SDK Message Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/messages/telnyx-message/index The TelnyxRTC Flutter Message represents a message received from the Telnyx Socket that the client can react to. ### TelnyxMessage This class is used to represent a message received from the Telnyx Socket. It contains a `socketMethod` which is a string representing the type of message received and a `ReceivedMessage` which contains the message data. ```dart theme={null} class TelnyxMessage { String socketMethod; ReceivedMessage message; TelnyxMessage({required this.socketMethod, required this.message}); } ``` ### Socket Methods The socket method can be one of the following: ```dart theme={null} class SocketMethod { static const answer = 'telnyx_rtc.answer'; static const invite = 'telnyx_rtc.invite'; static const bye = 'telnyx_rtc.bye'; static const modify = 'telnyx_rtc.modify'; static const media = 'telnyx_rtc.media'; static const info = 'telnyx_rtc.info'; static const ringing = 'telnyx_rtc.ringing'; static const clientReady = 'telnyx_rtc.clientReady'; static const gatewayState = 'telnyx_rtc.gatewayState'; static const ping = 'telnyx_rtc.ping'; static const login = 'login'; static const attachCall = 'telnyx_rtc.attachCalls'; static const attach = 'telnyx_rtc.attach'; } ``` ### ReceivedMessage The received message contains the data of the message received from the Telnyx Socket. It will contain the actual message as well as the state of the Call, client and SDK. # Flutter WebRTC SDK Socket Error Message Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/messages/telnyx-socket-error/index The TelnyxRTC Flutter Error represents an error received from the Telnyx Socket that the client can react and handle. ### TelnyxSocketError This class is used to represent an error received from the Telnyx Socket. It contains an `errorCode` which is an integer representing the error code and an `errorMessage` which is a string representing the error message. ```dart theme={null} class TelnyxSocketError { int errorCode = 0; String errorMessage = ''; TelnyxSocketError({required this.errorCode, required this.errorMessage}); TelnyxSocketError.fromJson(Map json) { errorCode = json['code'] ?? 0; errorMessage = json['message'] ?? ''; } } ``` ### Error Codes The error code can be one of the following: ```dart theme={null} class TelnyxErrorConstants { static const tokenError = 'Token registration error'; static const tokenErrorCode = -32000; static const credentialError = 'Credential registration error'; static const credentialErrorCode = -32001; static const gatewayTimeoutError = 'Gateway registration timeout'; static const gatewayTimeoutErrorCode = -32003; static const gatewayFailedError = 'Gateway registration failed'; static const gatewayFailedErrorCode = -32004; static const callNotFound = 'Call not found'; } ``` # WebRTC Flutter Client Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/classes/txclient/index The TelnyxRTC client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls ### Telnyx Client TelnyxClient() is the core class of the SDK, and can be used to connect to our backend socket connection, create calls, check state and disconnect, etc. Once an instance is created, you can call the .connect() method to connect to the socket with either a token or credentials (see below). An error will appear as a socket response if there is no network available: ```dart theme={null} TelnyxClient _telnyxClient = TelnyxClient(); ``` ### Logging into Telnyx Client To log into the Telnyx WebRTC client, you'll need to authenticate using a Telnyx SIP Connection. Follow our [quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart) to create **JWTs** (JSON Web Tokens) to authenticate. To log in with a token we use the connectWithToken() method. You can also authenticate directly with the SIP Connection `username` and `password` with the connectWithCredential() method: ```dart theme={null} _telnyxClient.connectWithToken(tokenConfig) //OR _telnyxClient.connectWithCredential(credentialConfig) ``` **Note:** **tokenConfig** and **credentialConfig** are simple classes that represent login settings for the client to use they extend a base Config class with shared properties. They look like this: ```dart theme={null} /// Creates an instance of CredentialConfig which can be used to log in /// /// Uses the [sipUser] and [sipPassword] fields to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// legitimate credentials class CredentialConfig extends Config { CredentialConfig({ required this.sipUser, required this.sipPassword, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.debug, super.ringTonePath, super.ringbackPath, }); final String sipUser; final String sipPassword; } /// Creates an instance of TokenConfig which can be used to log in /// /// Uses the [sipToken] field to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// a legitimate token class TokenConfig extends Config { TokenConfig({ required this.sipToken, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.debug, super.ringTonePath, super.ringbackPath, }); final String sipToken; } ``` ### Listening for events and reacting - Accepting a Call In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response callbacks from our TelnyxClient: ```dart theme={null} // Observe Socket Messages Received _telnyxClient.onSocketMessageReceived = (TelnyxMessage message) { switch (message.socketMethod) { case SocketMethod.CLIENT_READY: { // Fires once client has correctly been setup and logged into, you can now make calls. break; } case SocketMethod.LOGIN: { // Handle a successful login - Update UI or Navigate to new screen, etc. break; } case SocketMethod.INVITE: { // Handle an invitation Update UI or Navigate to new screen, etc. // Then, through an answer button of some kind we can accept the call with: // This will return an instance of the Call class which can be used to interact with the call or monitor it's state. _incomingInvite = message.message.inviteParams; _call = _telnyxClient.acceptCall( _incomingInvite, "callerName", "000000000", "State"); break; } case SocketMethod.ANSWER: { // Handle a received call answer - Update UI or Navigate to new screen, etc. break; } case SocketMethod.BYE: { // Handle a call rejection or ending - Update UI or Navigate to new screen, etc. break; } } }; ``` # WebRTC Flutter Call State Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/enums/call-state/index CallState represents the state of the call # `CallState` `CallState` represents the state of the call ```dart theme={null} enum CallState { newCall, connecting, ringing, active, held, done, error, } ``` ## Cases ### `NEW` ```dart theme={null} newCall ``` New call has been created in the client. ### `CONNECTING` ```dart theme={null} connecting ``` The outbound call is being sent to the server. ### `RINGING` ```dart theme={null} ringing ``` Call is pending to be answered. Someone is attempting to call you. ### `ACTIVE` ```dart theme={null} active ``` Call is active when two clients are fully connected. ### `HELD` ```dart theme={null} held ``` Call has been held. ### `DONE` ```dart theme={null} done ``` Call has ended. ### `error` ```dart theme={null} error ``` An error has occured # WebRTC Flutter SDK Error Handling Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/error-handling/index A complete guide to error handling for the Flutter Voice SDK This document describes the error handling mechanisms in the Telnyx WebRTC Flutter SDK, specifically focusing on when and why error events are triggered and how they are processed through the SDK. ## Error Handling Architecture The Flutter SDK implements a structured approach to error handling through several key components: 1. **OnSocketErrorReceived Callback**: Defines a callback function that is triggered when socket errors occur 2. **TelnyxSocketError Class**: Provides a data structure for encapsulating error states 3. **TelnyxErrorConstants Class**: Defines standard error codes and messages used throughout the SDK 4. **Network Connectivity Monitoring**: Detects and handles network changes and connectivity issues 5. **Gateway State Management**: Monitors the gateway registration status and triggers errors when appropriate ## Error Scenarios ### 1. Gateway Registration Status The SDK monitors the gateway registration status and triggers errors in the following scenarios: * When the gateway status is "FAILED" after registration attempts * When the gateway registration times out * Location: `telnyx_client.dart` * This ensures that the client is properly connected to the Telnyx network Example: ```dart theme={null} case GatewayState.failed: GlobalLogger().i('GATEWAY REGISTRATION FAILED :: ${stateMessage.toString()}'); gatewayState = GatewayState.failed; final error = TelnyxSocketError( errorCode: TelnyxErrorConstants.gatewayFailedErrorCode, errorMessage: TelnyxErrorConstants.gatewayFailedError, ); onSocketErrorReceived(error); ``` ### 2. Gateway Registration Timeout The SDK handles gateway registration timeout: * When the gateway registration process takes too long to complete * Location: `telnyx_client.dart` * This helps applications handle situations where the gateway is unreachable Example: ```dart theme={null} GlobalLogger().i('GATEWAY REGISTRATION TIMEOUT'); final error = TelnyxSocketError( errorCode: TelnyxErrorConstants.gatewayTimeoutErrorCode, errorMessage: TelnyxErrorConstants.gatewayTimeoutError, ); onSocketErrorReceived(error); ``` ### 3. WebSocket Error Messages The SDK handles error messages received through the WebSocket connection: * When the server sends an error message via WebSocket * Location: `telnyx_client.dart` - `_onMessage` method * These errors typically indicate issues with the connection or server-side problems Example: ```dart theme={null} if (data.toString().trim().contains('error')) { final errorJson = jsonEncode(data.toString()); _logger.log( LogLevel.info, 'Received WebSocket message - Contains Error :: $errorJson', ); try { final ReceivedResult errorResult = ReceivedResult.fromJson(jsonDecode(data.toString())); onSocketErrorReceived.call(errorResult.error!); } on Exception catch (e) { GlobalLogger().e('Error parsing JSON: $e'); } } ``` ### 4. Network Connectivity Issues The SDK detects network connectivity problems and reports them as errors: * When network is lost during an active session * When network type changes (e.g., from WiFi to mobile data) * Location: `telnyx_client.dart` - `_handleNetworkLost` method * These errors help applications handle offline scenarios gracefully Example: ```dart theme={null} void _handleNetworkLost() { for (var call in activeCalls().values) { call.callHandler.onCallStateChanged .call(CallState.dropped.withReason(NetworkReason.networkLost)); } } ``` ## TelnyxSocketError Implementation The `TelnyxSocketError` class provides a standardized way to handle errors throughout the SDK: ```dart theme={null} /// Represents an error that occurred during WebSocket communication with Telnyx. class TelnyxSocketError { /// The error code for the socket error. int errorCode = 0; /// The error message for the socket error. String errorMessage = 'Generic error. Source unknown.'; /// The constructor for the TelnyxSocketError. TelnyxSocketError({required this.errorCode, required this.errorMessage}); /// The constructor for the TelnyxSocketError from a JSON object. TelnyxSocketError.fromJson(Map json) { errorCode = json['code'] ?? 0; errorMessage = json['message'] ?? ''; } } ``` This class encapsulates: * An error code that identifies the type of error * An error message describing what went wrong ## Error Constants The SDK defines standard error constants in the `TelnyxErrorConstants` class: ```dart theme={null} /// Contains constant error messages and codes used in Telnyx WebRTC communication. class TelnyxErrorConstants { /// The error message for token registration errors. static const tokenError = 'Token registration error'; /// The error code for token registration errors. static const tokenErrorCode = -32000; /// The error message for credential registration errors. static const credentialError = 'Credential registration error'; /// The error code for credential registration errors. static const credentialErrorCode = -32001; /// The error message for codec errors. static const codecError = 'Codec error'; /// The error code for codec errors. static const codecErrorCode = -32002; /// The error message for gateway registration timeout errors. static const gatewayTimeoutError = 'Gateway registration timeout'; /// The error code for gateway registration timeout errors. static const gatewayTimeoutErrorCode = -32003; /// The error message for gateway registration failed errors. static const gatewayFailedError = 'Gateway registration failed'; /// The error code for gateway registration failed errors. static const gatewayFailedErrorCode = -32004; /// The error message for call not found errors. static const callNotFound = 'Call not found'; } ``` These constants provide consistent error reporting across the SDK. ## Call State Error Handling The SDK uses the `CallState` enum to track the state of calls, including error states: ```dart theme={null} enum CallState { // Other states... /// [reconnecting] The call is reconnecting - for this state a [NetworkReason] is provided. reconnecting, /// [dropped] The call has been dropped - for this state a [NetworkReason] is provided. dropped, /// [error] there was an issue creating the call. error; // Methods to handle reasons... } ``` When network issues occur, calls can transition to the `dropped` or `reconnecting` states with an associated `NetworkReason`: ```dart theme={null} enum NetworkReason { /// The network has been switched. networkSwitch('Network switched'), /// The network has been lost. networkLost('Network lost'), /// The network has adjusted due to Airplane mode. airplaneMode('Airplane mode enabled'); /// The message associated with the network reason. final String message; const NetworkReason(this.message); } ``` ## Consuming Errors in Your Application To handle errors in your application, you should implement the `onSocketErrorReceived` callback: ```dart theme={null} telnyxClient.onSocketErrorReceived = (TelnyxSocketError error) { // Log the error print('Telnyx Socket Error: ${error.errorMessage} (${error.errorCode})'); // Handle specific error types switch (error.errorCode) { case TelnyxErrorConstants.gatewayFailedErrorCode: // Handle gateway registration failure attemptReconnection(); break; case TelnyxErrorConstants.gatewayTimeoutErrorCode: // Handle gateway timeout showTimeoutMessage(); break; default: // Handle other types of errors showErrorToUser(error.errorMessage); break; } }; ``` ## Error Handling Best Practices When implementing error handling for the Telnyx WebRTC Flutter SDK: 1. **Always implement the onSocketErrorReceived callback**: This is the primary channel for receiving error notifications 2. **Log errors for debugging purposes**: Capture error messages for troubleshooting 3. **Implement appropriate error recovery mechanisms**: Different errors may require different recovery strategies 4. **Display user-friendly error messages**: Translate technical error messages into user-friendly notifications 5. **Implement reconnection logic when appropriate**: For network or gateway issues, automatic reconnection may be appropriate 6. **Monitor call state changes**: Watch for `dropped`, `reconnecting`, and `error` states to handle call-specific issues ## Common Error Scenarios and Solutions ### Gateway Registration Failure * **Cause**: Network connectivity issues or invalid credentials * **Solution**: Check network connection and credential validity, then attempt reconnection ### Gateway Registration Timeout * **Cause**: Server unreachable or network latency issues * **Solution**: Implement retry mechanism with exponential backoff ### WebSocket Connection Errors * **Cause**: Network interruption or server issues * **Solution**: Implement automatic reconnection with exponential backoff ### Network Connectivity Changes * **Cause**: Device switching between WiFi and mobile data, or losing connectivity * **Solution**: Monitor network state changes and implement appropriate UI feedback and reconnection logic ## Additional Resources * [Telnyx WebRTC Flutter SDK GitHub Repository](https://github.com/team-telnyx/flutter-voice-sdk) * [API Documentation](https://developers.telnyx.com/docs/v2/webrtc) # Flutter WebRTC SDK Socket Error Handler Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/event-handlers/on-socket-error-received/index The event handler that is used as a callback function when errors are received from the Telnyx Websocket Connection. ### onSocketErrorReceived The `onSocketErrorReceived` event handler is called when an error is received from the WebSocket connection. ```dart theme={null} typedef OnSocketErrorReceived = void Function(TelnyxSocketError message); ``` ### TelnyxSocketError This class is used to represent an error received from the Telnyx Socket. It contains an `errorCode` which is an integer representing the error code and an `errorMessage` which is a string representing the error message. ```dart theme={null} class TelnyxSocketError { int errorCode = 0; String errorMessage = ''; TelnyxSocketError({required this.errorCode, required this.errorMessage}); TelnyxSocketError.fromJson(Map json) { errorCode = json['code'] ?? 0; errorMessage = json['message'] ?? ''; } } ``` ### Error Codes The error code can be one of the following: ```dart theme={null} class TelnyxErrorConstants { static const tokenError = 'Token registration error'; static const tokenErrorCode = -32000; static const credentialError = 'Credential registration error'; static const credentialErrorCode = -32001; static const gatewayTimeoutError = 'Gateway registration timeout'; static const gatewayTimeoutErrorCode = -32003; static const gatewayFailedError = 'Gateway registration failed'; static const gatewayFailedErrorCode = -32004; static const callNotFound = 'Call not found'; } ``` # Flutter WebRTC SDK Socket Message Handler Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/event-handlers/on-socket-message-received/index The event handler that is used as a callback function when messages are received from the Telnyx Websocket Connection. ### OnSocketMethodReceived The `OnSocketMethodReceived` event handler is a callback function that is called when a message is received from the Telnyx WebSocket connection. The message is passed as a parameter to the callback function. ```dart theme={null} typedef OnSocketMessageReceived = void Function(TelnyxMessage message); ``` ### TelnyxMessage This class is used to represent a message received from the Telnyx Socket. It contains a `socketMethod` which is a string representing the type of message received and a `ReceivedMessage` which contains the message data. ```dart theme={null} class TelnyxMessage { String socketMethod; ReceivedMessage message; TelnyxMessage({required this.socketMethod, required this.message}); } ``` ### Socket Methods The socket method can be one of the following: ```dart theme={null} class SocketMethod { static const answer = 'telnyx_rtc.answer'; static const invite = 'telnyx_rtc.invite'; static const bye = 'telnyx_rtc.bye'; static const modify = 'telnyx_rtc.modify'; static const media = 'telnyx_rtc.media'; static const info = 'telnyx_rtc.info'; static const ringing = 'telnyx_rtc.ringing'; static const clientReady = 'telnyx_rtc.clientReady'; static const gatewayState = 'telnyx_rtc.gatewayState'; static const ping = 'telnyx_rtc.ping'; static const login = 'login'; static const attachCall = 'telnyx_rtc.attachCalls'; static const attach = 'telnyx_rtc.attach'; } ``` ### ReceivedMessage The received message contains the data of the message received from the Telnyx Socket. It will contain the actual message as well as the state of the Call, client and SDK. # Flutter Voice Client SDK Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/index Telnyx's Flutter / Dart Client SDK Pub Version Flutter Test # Telnyx Flutter Voice SDK Enable Telnyx real-time communication services on Flutter applications (Android / iOS / Web) 📞 🔥 ## Quick Start with Telnyx Common (Beta) **Looking for a faster implementation?** Check out [Telnyx Common](https://github.com/team-telnyx/flutter-voice-commons) - available on [pub.dev](https://pub.dev/packages/telnyx_common). Telnyx Common is a comprehensive Flutter package that abstracts away the complexity of implementing WebRTC voice calling functionality. It sits on top of the lower-level `telnyx_webrtc` package and provides a unified, easy-to-use API for developers who want to integrate voice calling capabilities into their Flutter applications without dealing with the intricate details of WebRTC, push notifications, and platform-specific implementations. This is the quickest way to implement the SDK with minimal setup and configuration. > **Note:** Telnyx Common is currently in beta. While it significantly simplifies implementation, you may encounter some limitations or changes as the library evolves. ## Table of Contents * [Features](#features) * [Usage](#usage) * [SIP Credentials](#sip-credentials) * [Platform Specific Configuration](#platform-specific-configuration) * [Android](#android) * [iOS](#ios) * [Basic Usage](#basic-usage) * [Telnyx Client](#telnyx-client) * [Logging Configuration](#logging-configuration) * [Logging into Telnyx Client](#logging-into-telnyx-client) * [Creating a call invitation](#creating-a-call-invitation) * [Accepting a call](#accepting-a-call) * [Decline / End Call](#decline--end-call) * [DTMF (Dual Tone Multi Frequency)](#dtmf-dual-tone-multi-frequency) * [Mute a call](#mute-a-call) * [Toggle loud speaker](#toggle-loud-speaker) * [Put a call on hold](#put-a-call-on-hold) * [Call Quality Metrics](#call-quality-metrics) * [Enabling Call Quality Metrics](#enabling-call-quality-metrics) * [CallQualityMetrics Properties](#callqualitymetrics-properties) * [CallQuality Enum](#callquality-enum) * [Advanced Usage - Push Notifications](#advanced-usage---push-notifications) * [Adding push notifications - Android platform](#adding-push-notifications---android-platform) * [Best Practices for Push Notifications on Android](#best-practices-for-push-notifications-on-android) * [Adding push notifications - iOS platform](#adding-push-notifications---ios-platform) * [Handling Late Notifications](#handling-late-notifications) * [Best Practices for Push Notifications on iOS](#best-practices-for-push-notifications-on-ios) * [New Push Notification Features](#new-push-notification-features) * [AI Agent Usage](#ai-agent-usage) * [1. Logging in to communicate with the AI Agent](#1-logging-in-to-communicate-with-the-ai-agent) * [2. Starting a Conversation with the AI Assistant](#2-starting-a-conversation-with-the-ai-assistant) * [3. Receiving Transcript Updates](#3-receiving-transcript-updates) * [4. Sending a text message to the AI Agent](#4-sending-a-text-message-to-the-ai-agent) * [Additional Resources](#additional-resources) * [License](#license) ## Features * ✅ Create / Receive calls * ✅ Hold calls * ✅ Mute calls * ✅ Dual Tone Multi Frequency * ✅ Call quality metrics monitoring ## Usage ### SIP Credentials In order to start making and receiving calls using the TelnyxRTC SDK you will need to get SIP Credentials: SIP Credentials Screenshot 1. Access to [https://portal.telnyx.com/](https://portal.telnyx.com/) 2. Sign up for a Telnyx Account. 3. Create a Credential Connection to configure how you connect your calls. 4. Create an Outbound Voice Profile to configure your outbound call settings and assign it to your Credential Connection. For more information on how to generate SIP credentials check the [Telnyx WebRTC quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart). ### Platform Specific Configuration ## Android If you are implementing the SDK into an Android application it is important to remember to add the following permissions to your AndroidManifest in order to allow Audio and Internet permissions: ```html theme={null} ``` ## iOS on the iOS platform, you need to add the microphone permission to your Info.plist file: ```xml theme={null} NSMicrophoneUsageDescription $(PRODUCT_NAME) Microphone Usage! ``` ## Basic Usage ### Telnyx Client TelnyxClient() is the core class of the SDK, and can be used to connect to our backend socket connection, create calls, check state and disconnect, etc. Once an instance is created, you can call the .connect() method to connect to the socket with either a token or credentials (see below). An error will appear as a socket response if there is no network available: ```dart theme={null} TelnyxClient _telnyxClient = TelnyxClient(); ``` ### Logging Configuration The SDK provides a flexible logging system that allows you to control the verbosity of logs and even implement your own custom logging solution. There are two main aspects to configure: 1. **Log Level** The `LogLevel` enum determines which types of logs are displayed: ```dart theme={null} enum LogLevel { none, // Disable all logs (default) error, // Print error logs only warning, // Print warning logs only debug, // Print debug logs only info, // Print info logs only verto, // Print verto protocol messages all // Print all logs } ``` 2. **Custom Logger** You can implement your own logging solution by extending the `CustomLogger` abstract class: ```dart theme={null} class MyCustomLogger extends CustomLogger { @override log(LogLevel level, String message) { print('[$level] $message'); // Implement any extra logging logic you would like here (eg. Send to a server, write to a file, etc.) } } ``` Both the log level and custom logger can be configured in the `Config` class: ```dart theme={null} var config = CredentialConfig( sipUser: 'username', sipPassword: 'password', sipCallerIDName: 'Caller Name', sipCallerIDNumber: '1234567890', debug: true, // Enable debug mode which allows you to track call metrics and download them from the portal - this is different to the log level and custom logger logLevel: LogLevel.debug, // Set log level customLogger: MyCustomLogger(), // Optional: provide custom logger ); ``` ### Logging into Telnyx Client To log into the Telnyx WebRTC client, you'll need to authenticate using a Telnyx SIP Connection. Follow our [quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart) to create **JWTs** (JSON Web Tokens) to authenticate. To log in with a token we use the connectWithToken() method. You can also authenticate directly with the SIP Connection `username` and `password` with the connectWithCredential() method: ```dart theme={null} _telnyxClient.connectWithToken(tokenConfig) //OR _telnyxClient.connectWithCredential(credentialConfig) ``` **Note:** **tokenConfig** and **credentialConfig** are simple classes that represent login settings for the client to use they extend a base Config class with shared properties. They look like this: ```dart theme={null} /// Creates an instance of CredentialConfig which can be used to log in /// /// Uses the [sipUser] and [sipPassword] fields to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// legitimate credentials class CredentialConfig extends Config { CredentialConfig({ required this.sipUser, required this.sipPassword, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.debug, super.ringTonePath, super.ringbackPath, }); final String sipUser; final String sipPassword; } /// Creates an instance of TokenConfig which can be used to log in /// /// Uses the [sipToken] field to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// a legitimate token class TokenConfig extends Config { TokenConfig({ required this.sipToken, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.debug, super.ringTonePath, super.ringbackPath, }); final String sipToken; } ``` ### Creating a call invitation In order to make a call invitation, we first create an instance of the Call class with the .call instance. This creates a Call class which can be used to interact with calls (invite, accept, decline, etc). To then send an invite, we can use the .newInvite() method which requires you to provide your callerName, callerNumber, the destinationNumber (or SIP credential), and your clientState (any String value). ```dart theme={null} _telnyxClient .call .newInvite("callerName", "000000000", destination, "State"); ``` ### Accepting a call In order to be able to accept a call, we first need to listen for invitations. We do this by getting the Telnyx Socket Response callbacks: ```dart theme={null} // Observe Socket Messages Received _telnyxClient.onSocketMessageReceived = (TelnyxMessage message) { switch (message.socketMethod) { case SocketMethod.CLIENT_READY: { // Fires once client has correctly been setup and logged into, you can now make calls. break; } case SocketMethod.LOGIN: { // Handle a successful login - Update UI or Navigate to new screen, etc. break; } case SocketMethod.INVITE: { // Handle an invitation Update UI or Navigate to new screen, etc. // Then, through an answer button of some kind we can accept the call with: // This will return an instance of the Call class which can be used to interact with the call or monitor it's state. _incomingInvite = message.message.inviteParams; _call = _telnyxClient.acceptCall( _incomingInvite, "callerName", "000000000", "State"); break; } case SocketMethod.ANSWER: { // Handle a received call answer - Update UI or Navigate to new screen, etc. break; } case SocketMethod.BYE: { // Handle a call rejection or ending - Update UI or Navigate to new screen, etc. break; } } }; ``` We can then use this method to create a listener that listens for an invitation and, in this case, answers it straight away. A real implementation would be more suited to show some UI and allow manual accept / decline operations. ### Decline / End Call In order to end a call, we can get a stored instance of Call and call the .endCall(callID) method. To decline an incoming call we first create the call with the .createCall() method and then call the .endCall(callID) method: ```dart theme={null} if (_ongoingCall) { _telnyxClient.call.endCall(_telnyxClient.call.callId); } else { _telnyxClient.createCall().endCall(_incomingInvite?.callID); } ``` ### DTMF (Dual Tone Multi Frequency) In order to send a DTMF message while on a call you can call the .dtmf(callID, tone), method where tone is a String value of the character you would like pressed: ```dart theme={null} _telnyxClient.call.dtmf(_telnyxClient.call.callId, tone); ``` ### Mute a call To mute a call, you can simply call the .onMuteUnmutePressed() method: ```dart theme={null} _telnyxClient.call.onMuteUnmutePressed(); ``` ### Toggle loud speaker To toggle loud speaker, you can simply call .enableSpeakerPhone(bool): ```dart theme={null} _telnyxClient.call.enableSpeakerPhone(true); ``` ### Put a call on hold To put a call on hold, you can simply call the .onHoldUnholdPressed() method: ```dart theme={null} _telnyxClient.call.onHoldUnholdPressed(); ``` ## Call Quality Metrics The SDK provides real-time call quality metrics through the `onCallQualityChange` callback on the `Call` object. This allows you to monitor call quality in real-time and provide feedback to users. ### Enabling Call Quality Metrics To enable call quality metrics, set the `debug` parameter to `true` when creating or answering a call: ```dart theme={null} // When making a call call.newInvite( callerName: "John Doe", callerNumber: "+1234567890", destinationNumber: "+1987654321", clientState: "some-state", debug: true ); // When answering a call call.acceptCall( callId: callId, destinationNumber: "destination", debug: true ); // Listen for call quality metrics call.onCallQualityChange = (metrics) { // Access metrics.jitter, metrics.rtt, metrics.mos, metrics.quality print("Call quality: ${metrics.quality}"); print("MOS score: ${metrics.mos}"); print("Jitter: ${metrics.jitter * 1000} ms"); print("Round-trip time: ${metrics.rtt * 1000} ms"); }; ``` ### CallQualityMetrics Properties The `CallQualityMetrics` object provides the following properties: | Property | Type | Description | | --------------- | ----------------------- | -------------------------------------------------------------- | | `jitter` | double | Jitter in seconds (multiply by 1000 for milliseconds) | | `rtt` | double | Round-trip time in seconds (multiply by 1000 for milliseconds) | | `mos` | double | Mean Opinion Score (1.0-5.0) | | `quality` | CallQuality | Call quality rating based on MOS | | `inboundAudio` | `Map?` | Inbound audio statistics | | `outboundAudio` | `Map?` | Outbound audio statistics | ### CallQuality Enum The `CallQuality` enum provides the following values: | Value | MOS Range | Description | | ----------- | --------------- | --------------------------- | | `excellent` | MOS > 4.2 | Excellent call quality | | `good` | 4.1 ≤ MOS ≤ 4.2 | Good call quality | | `fair` | 3.7 ≤ MOS ≤ 4.0 | Fair call quality | | `poor` | 3.1 ≤ MOS ≤ 3.6 | Poor call quality | | `bad` | MOS ≤ 3.0 | Bad call quality | | `unknown` | N/A | Unable to calculate quality | ## Advanced Usage - Push Notifications ### Adding push notifications - Android platform The Android platform makes use of Firebase Cloud Messaging in order to deliver push notifications. To receive notifications when receiving calls on your Android mobile device you will have to enable Firebase Cloud Messaging within your application. For a detailed tutorial, please visit our official [Push Notification Docs](https://developers.telnyx.com/docs/v2/webrtc/push-notifications?type=Android). Note: for flutter, an easy way to add the firebase configuration after setting up the firebase project is to simply run the `flutterfire configure` command in the terminal. For example, if your firebase project is called `myproject` you would run `flutterfire configure myproject`. This will generate all the required files and configurations for your project. The Demo app uses the [FlutterCallkitIncoming](https://pub.dev/packages/flutter_callkit_incoming) plugin to show incoming calls. To show a notification when receiving a call, you can follow the steps below: 1. Listen for Background Push Notifications, Implement the `FirebaseMessaging.onBackgroundMessage` method in your `main` method ```dart theme={null} @pragma('vm:entry-point') Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (defaultTargetPlatform == TargetPlatform.android) { // Android Only - Push Notifications await Firebase.initializeApp(); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); await FirebaseMessaging.instance .setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); } runApp(const MyApp()); } ``` 2. Optionally Add the `metadata` to CallKitParams `extra` field ```dart theme={null} static Future showNotification(RemoteMessage message) { CallKitParams callKitParams = CallKitParams( android:..., ios:..., extra: message.data, ) await FlutterCallkitIncoming.showCallkitIncoming(callKitParams); } ``` 3. Handle the push notification in the `_firebaseMessagingBackgroundHandler` method ```dart theme={null} Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { //show notifcation showNotification(message); //Listen to action from FlutterCallkitIncoming FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async { switch (event!.event) { case Event.actionCallAccept: // Set the telnyx metadata for access when the app comes to foreground TelnyxClient.setPushMetaData( message.data, isAnswer: true, isDecline: false); break; case Event.actionCallDecline: /* * When the user declines the call from the push notification, the SDK now handles this automatically. * Simply set the decline flag and the SDK will handle the rest using the new push_decline method. * */ TelnyxClient.setPushMetaData( message.data, isAnswer: false, isDecline: true); break; }}); } ``` 4. Use the `TelnyxClient.getPushMetaData()` method to retrieve the metadata when the app comes to the foreground. This data is only available on 1st access and becomes `null` afterward. ```dart theme={null} Future _handlePushNotification() async { final data = await TelnyxClient.getPushMetaData(); PushMetaData? pushMetaData = PushMetaData.fromJson(data); if (pushMetaData != null) { _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); } } ``` 5. To Handle push calls on foreground, Listen for Call Events and invoke the `handlePushNotification` method ```dart theme={null} FlutterCallkitIncoming.onEvent.listen((CallEvent? event) { switch (event!.event) { case Event.actionCallIncoming: // retrieve the push metadata from extras final data = await TelnyxClient.getPushData(); ... _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); break; case Event.actionCallStart: .... break; case Event.actionCallAccept: ... logger.i('Call Accepted Attach Call'); break; }); ``` #### Best Practices for Push Notifications on Android 1. Request for Notification Permissions for android 13+ devices to show push notifications. More information can be found [here](https://developer.android.com/develop/ui/views/notifications/notification-permission) 2. Push Notifications only work in foreground for apps that are run in `debug` mode (You will not receive push notifications when you terminate the app while running in debug mode). 3. On Foreground calls, you can use the `FirebaseMessaging.onMessage.listen` method to listen for incoming calls and show a notification. ```dart theme={null} FirebaseMessaging.onMessage.listen((RemoteMessage message) { TelnyxClient.setPushMetaData(message.data); NotificationService.showNotification(message); mainViewModel.callFromPush = true; }); ``` 4. To handle push notifications on the background, use the `FirebaseMessaging.onBackgroundMessage` method to listen for incoming calls and show a notification and make sure to set the ` TelnyxClient.setPushMetaData` when user answers the call. ```dart theme={null} TelnyxClient.setPushMetaData( message.data, isAnswer: true, isDecline: false); ``` 5. When you call the `telnyxClient.handlePushNotification` it connects to the `telnyxClient`, make sure not to call the `telnyxClient.connect()` method after this. e.g an Edge case might be if you call `telnyxClient.connect()` on Widget `init` method it will always call the `connect` method 6. Early Answer/Decline : Users may answer/decline the call too early before a socket connection is established. To handle this situation, assert if the `IncomingInviteParams` is not null and only accept/decline if this is availalble. ```dart theme={null} bool waitingForInvite = false; void accept() { if (_incomingInvite != null) { // accept the call if the incomingInvite arrives on time _currentCall = _telnyxClient.acceptCall( _incomingInvite!, _localName, _localNumber, "State"); } else { // set waitingForInvite to true if we have an early accept waitingForInvite = true; } } _telnyxClient.onSocketMessageReceived = (TelnyxMessage message) { switch (message.socketMethod) { ... case SocketMethod.INVITE: { if (callFromPush) { // For early accept of call if (waitingForInvite) { //accept the call accept(); waitingForInvite = false; } callFromPush = false; } } ... } } ``` ### Adding push notifications - iOS platform The iOS Platform makes use of the Apple Push Notification Service (APNS) and Pushkit in order to deliver and receive push notifications For a detailed tutorial, please visit our official [Push Notification Docs](https://developers.telnyx.com/docs/v2/webrtc/push-notifications?lang=ios) 1. Register/Invalidate the push device token for iOS ```swift theme={null} func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { print(credentials.token) let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined() //Save deviceToken to your server SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken) } func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP("") } ``` 2. For foreground calls to work, you need to register with callkit on the restorationHandler delegate function. You can also choose to register with callkit using iOS official documentation on [CallKit](https://developer.apple.com/documentation/callkit/). ```swift theme={null} override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { let nameCaller = handleObj.getDecryptHandle()["nameCaller"] as? String ?? "" let handle = handleObj.getDecryptHandle()["handle"] as? String ?? "" let data = flutter_callkit_incoming.Data(id: UUID().uuidString, nameCaller: nameCaller, handle: handle, type: isVideo ? 1 : 0) //set more data... data.nameCaller = "dummy" SwiftFlutterCallkitIncomingPlugin.sharedInstance?.startCall(data, fromPushKit: true) } ``` 3. Listen for incoming calls in AppDelegate.swift class ```swift theme={null} func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { print("didReceiveIncomingPushWith") guard type == .voIP else { return } if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] { var callID = UUID.init().uuidString if let newCallId = (metadata["call_id"] as? String), !newCallId.isEmpty { callID = newCallId } let callerName = (metadata["caller_name"] as? String) ?? "" let callerNumber = (metadata["caller_number"] as? String) ?? "" let id = payload.dictionaryPayload["call_id"] as? String ?? UUID().uuidString let data = flutter_callkit_incoming.Data(id: id, nameCaller: callerName, handle: callerNumber, type: isVideo ? 1 : 0) data.extra = payload.dictionaryPayload as NSDictionary data.normalHandle = 1 let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName let uuid = UUID(uuidString: callID) data.uuid = uuid!.uuidString data.nameCaller = caller SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true) } } ``` 4. Listen for Call Events and invoke the `handlePushNotification` method ```dart theme={null} FlutterCallkitIncoming.onEvent.listen((CallEvent? event) { switch (event!.event) { case Event.actionCallIncoming: // retrieve the push metadata from extras PushMetaData? pushMetaData = PushMetaData.fromJson(event.body['extra']['metadata']); _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); break; case Event.actionCallStart: .... break; case Event.actionCallAccept: ... logger.i('Call Accepted Attach Call'); break; }); ``` ### Handling Late Notifications If notifications arrive very late due to no internet connectivity, It is good to always flag it as a missed call. You can do that using the code snippet below : ```dart theme={null} const CALL_MISSED_TIMEOUT = 60; DateTime nowTime = DateTime.now(); Duration? difference = nowTime?.difference(message.sentTime!); if (difference.inSeconds > CALL_MISSED_TIMEOUT) { NotificationService.showMissedCallNotification(message); return; } ``` #### Best Practices for Push Notifications on iOS 1. Push Notifications only work in foreground for apps that are run in `debug` mode (You will not receive push notifications when you terminate the app while running in debug mode). Make sure you are in `release` mode. Preferably test using Testfight or Appstore. To test if push notifications are working, disconnect the telnyx client (while app is in foreground) and make a call to the device. You should receive a push notification. ### New Push Notification Features #### Simplified Push Decline Method The SDK now includes a simplified method for declining push notifications. Previously, you needed to log back into the socket, listen for events, wait for an invite, and manually send a bye message. **New Approach**: The SDK automatically handles call decline when you set the decline flag in `setPushMetaData`. The SDK will: * Connect to the socket * Send a login message with `decline_push: true` parameter * Automatically handle ending the call * Disconnect from the socket ```dart theme={null} // When declining a push notification, simply set the decline flag TelnyxClient.setPushMetaData(message.data, isAnswer: false, isDecline: true); // Then call handlePushNotification as usual _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); ``` #### 10-Second Answer Timeout The SDK now includes an automatic timeout mechanism for push notifications. When you accept a push notification but no INVITE message arrives on the socket within 10 seconds, the SDK will: * Automatically consider the call cancelled * Emit a bye message internally with `ORIGINATOR_CANCEL` termination reason (SIP code 487) * Prevent indefinite waiting for missing INVITE messages This timeout mechanism activates automatically when: 1. A push notification is accepted (`isAnswer: true`) 2. The SDK connects and waits for an INVITE message 3. No INVITE is received within 10 seconds **Normal Flow**: User accepts push → Timer starts → INVITE received → Timer cancelled → Call proceeds **Timeout Flow**: User accepts push → Timer starts → No INVITE received → Timer expires → Call terminated with ORIGINATOR\_CANCEL No additional code is required to use this feature - it's handled automatically by the SDK. ## AI Agent Usage The Flutter Voice SDK supports [Voice AI Agent](https://telnyx.com/products/voice-ai-agents) implementations. To get started, follow the steps [described here](https://telnyx.com/resources/ai-assistant-builder) to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps: ### 1. Logging in to communicate with the AI Agent. To connect with an AI Assistant, you can use the `anonymousLogin` method. This allows you to establish a connection without traditional authentication credentials. This method takes a `targetId` which is the ID of your AI assistant, and an optional `targetVersionId`. If a `targetVersionId` is not provided, the SDK will use the latest version available. **Note:** After a successful `anonymousLogin`, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant. Here's an example of how to use it: ```dart theme={null} try { await _telnyxClient.anonymousLogin( targetId: 'your_assistant_id', // targetType: 'ai_assistant', // This is the default value // targetVersionId: 'your_assistant_version_id' // Optional ); // You are now connected and can make a call to the AI Assistant. } catch (e) { // Handle login error } ``` Once connected, you can use the standard `newInvite` method to start a conversation with the AI Assistant. ### 2. Starting a Conversation with the AI Assistant After a successful `anonymousLogin`, you can initiate a call to your AI Assistant using the `newInvite` method. Because the session is now locked to the AI Assistant, the `destinationNumber` parameter in the `newInvite` method will be ignored. Any values provided for `callerName` and `callerNumber` will be passed on, but the call will always be routed to the AI Assistant specified during the login. Here is an example of how to start the call: ```dart theme={null} // After a successful anonymousLogin... _telnyxClient.newInvite( 'Your Name', 'Your Number', '', // Destination is ignored, can be an empty string 'Your custom state', customHeaders: {'X-Account-Number': '123', 'X-User-Name': 'JohnDoe'}, // Optional custom headers to be mapped to dynamic variables ); ``` Note that you can also provide `customHeaders` in the `newInvite` method. These headers need to start with the `X-` prefix and will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the AI assistant (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. The call will be automatically answered by the AI Assistant. From this point on, the call flow is handled in the same way as any other answered call, allowing you to use standard call control methods like `endCall`, `mute`, etc. ### 3. Receiving Transcript Updates During an AI Assistant conversation, the SDK provides real-time transcript updates that include both the caller's speech and the AI Assistant's responses. This allows you to display a live conversation transcript in your application. To receive transcript updates, set up the `onTranscriptUpdate` callback on your `TelnyxClient` instance: ```dart theme={null} _telnyxClient.onTranscriptUpdate = (List transcript) { // Handle the updated transcript for (var item in transcript) { print('${item.role}: ${item.content}'); // item.role will be either 'user' or 'assistant' // item.content contains the spoken text // item.timestamp contains when the message was received } // Update your UI to display the conversation setState(() { _conversationTranscript = transcript; }); }; ``` The `TranscriptItem` contains the following properties: * `id`: Unique identifier for the transcript item * `role`: Either 'user' (for the caller) or 'assistant' (for the AI Agent) * `content`: The transcribed text content * `timestamp`: When the transcript item was created You can also manually retrieve the current transcript at any time: ```dart theme={null} List currentTranscript = _telnyxClient.transcript; ``` To clear the transcript (for example, when starting a new conversation): ```dart theme={null} _telnyxClient.clearTranscript(); ``` **Note:** Transcript updates are only available during AI Assistant conversations initiated through `anonymousLogin`. Regular calls between users do not provide transcript functionality. ### 4. Sending a text message to the AI Agent In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. To send a text message to the AI Agent, use the `sendConversationMessage` method on the active call instance: ```dart theme={null} // Get the active call instance (after successfully connecting and calling) Call? activeCall = _telnyxClient.calls.values.firstOrNull; if (activeCall != null) { // Send a text message to the AI Agent activeCall.sendConversationMessage("Hello, can you help me with my account?"); } ``` You can also retrieve the call by its ID if you have it: ```dart theme={null} // If you have the call ID String callId = "your-call-id"; Call? call = _telnyxClient.getCallOrNull(callId); if (call != null) { call.sendConversationMessage("I need assistance with billing."); } ``` **Important Notes:** * The `sendConversationMessage` method is only available during AI Assistant conversations * Text messages sent this way will appear in the transcript updates alongside spoken conversation * The AI Agent will process and respond to text messages just like spoken input * You must have an active call established before sending text messages This feature enables rich conversational experiences where users can seamlessly switch between voice and text communication with the AI Assistant. ## Additional Resources * [Official SDK Documentation](https://developers.telnyx.com/docs/voice/webrtc/flutter-sdk) Questions? Comments? Building something rad? [Join our Slack channel](https://joinslack.telnyx.com/) and share. ## License [`MIT Licence`](https://github.com/team-telnyx/flutter-voice-sdk/blob/main/LICENSE) © [Telnyx](https://github.com/team-telnyx) # WebRTC Flutter Client Configuration Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/config/index This structure is intended to be used for Telnyx SDK configurations when connecting to the TelnyxClient on the Flutter SDK ### Config Config is used to log in and connect to the Telnyx WebRTC client. It contains the necessary fields to log in with either a token or credentials. The base Config class is represented like so: ```dart theme={null} class Config { final String sipCallerIDName; final String sipCallerIDNumber; final String? notificationToken; final bool? autoReconnect; final LogLevel logLevel; final bool debug; final CustomLogger? customLogger; final String? ringTonePath; final String? ringbackPath; int? reconnectionTimeout; final Region region; final bool fallbackOnRegionFailure; Config({ required this.sipCallerIDName, required this.sipCallerIDNumber, this.notificationToken, this.autoReconnect, this.logLevel = LogLevel.all, required this.debug, this.customLogger, this.ringTonePath, this.ringbackPath, this.reconnectionTimeout, this.region = Region.auto, this.fallbackOnRegionFailure = true, }); } ``` #### Config Parameters * **`sipCallerIDName`** (String, required): Name associated with the SIP account * **`sipCallerIDNumber`** (String, required): Number associated with the SIP account * **`notificationToken`** (String?, optional): Token used to register the device for notifications if required (FCM or APNS) * **`autoReconnect`** (bool?, optional): Flag to decide whether or not to attempt a reconnect (3 attempts) in the case of a login failure with legitimate credentials * **`logLevel`** (LogLevel, optional): Log level to set for SDK Logging (defaults to `LogLevel.all`) * **`debug`** (bool, required): Flag to enable debug logs * **`customLogger`** (CustomLogger?, optional): Custom logger to use for logging - if left null the default logger will be used which uses the Logger package * **`ringTonePath`** (String?, optional): Path to the ringtone file (audio to play when receiving a call) * **`ringbackPath`** (String?, optional): Path to the ringback file (audio to play when calling) * **`reconnectionTimeout`** (int?, optional): Reconnection timeout in milliseconds (Default 60 seconds). This is the maximum time allowed for a call to be in the RECONNECTING or DROPPED state * **`region`** (Region, optional): The region to use for the connection (defaults to `Region.auto`) * **`fallbackOnRegionFailure`** (bool, optional): Whether the SDK should default to AUTO after attempting and failing to connect to a specified region (defaults to `true`) #### Available Regions The `Region` enum provides the following options: * **`Region.auto`**: Automatically select the best region (default) * **`Region.eu`**: European region * **`Region.usCentral`**: US Central region * **`Region.usEast`**: US East region * **`Region.usWest`**: US West region * **`Region.caCentral`**: Canada Central region * **`Region.apac`**: Asia Pacific region The base Config class contains shared fields that are used by both the `TokenConfig` and `CredentialConfig` classes. These are the actual classes that you will use to log into the client. #### TokenConfig `TokenConfig` is used to log in with a token. It extends the base `Config` class and looks like this: ```dart theme={null} /// Creates an instance of TokenConfig which can be used to log in /// /// Uses the [sipToken] field to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// a legitimate token /// [logLevel] is the log level to set for SDK Logging /// [debug] flag to enable debug logs which will collect stats for each call and provide WebRTC stats to view in the portal /// [ringTonePath] is the path to the ringtone file (audio to play when receiving a call) /// [ringbackPath] is the path to the ringback file (audio to play when calling) /// [customLogger] is a custom logger to use for logging - if left null the default logger will be used which uses the Logger package /// [reconnectionTimeout] is the reconnection timeout in milliseconds (Default 60 seconds) /// [region] is the region to use for the connection (Auto by default) /// [fallbackOnRegionFailure] determines whether the SDK should default to AUTO after attempting and failing to connect to a specified region class TokenConfig extends Config { TokenConfig({ required this.sipToken, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.logLevel, required super.debug, super.ringTonePath, super.ringbackPath, super.customLogger, super.reconnectionTimeout, super.region = Region.auto, super.fallbackOnRegionFailure = true, }); final String sipToken; } ``` #### CredentialConfig `CredentialConfig` is used to log in with credentials. It extends the base `Config` class and looks like this: ```dart theme={null} /// Creates an instance of CredentialConfig which can be used to log in /// /// Uses the [sipUser] and [sipPassword] fields to log in /// [sipCallerIDName] and [sipCallerIDNumber] will be the Name and Number associated /// [notificationToken] is the token used to register the device for notifications if required (FCM or APNS) /// The [autoReconnect] flag decided whether or not to attempt a reconnect (3 attempts) in the case of a login failure with /// legitimate credentials /// [logLevel] is the log level to set for SDK Logging /// [debug] flag to enable debug logs which will collect stats for each call and provide WebRTC stats to view in the portal /// [ringTonePath] is the path to the ringtone file (audio to play when receiving a call) /// [ringbackPath] is the path to the ringback file (audio to play when calling) /// [customLogger] is a custom logger to use for logging - if left null the default logger will be used which uses the Logger package /// [reconnectionTimeout] is the reconnection timeout in milliseconds (Default 60 seconds) /// [region] is the region to use for the connection (Auto by default) /// [fallbackOnRegionFailure] determines whether the SDK should default to AUTO after attempting and failing to connect to a specified region class CredentialConfig extends Config { CredentialConfig({ required this.sipUser, required this.sipPassword, required super.sipCallerIDName, required super.sipCallerIDNumber, super.notificationToken, super.autoReconnect, required super.logLevel, required super.debug, super.ringTonePath, super.ringbackPath, super.customLogger, super.reconnectionTimeout, super.region = Region.auto, super.fallbackOnRegionFailure = true, }); final String sipUser; final String sipPassword; } ``` # WebRTC Flutter Incoming Invite Object Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/incoming-invite-params/index Contains the required information of the current Call that can be reacted to (answered, declined, etc.) ### IncomingInviteParams The `IncomingInviteParams` class represents the parameters for an incoming invite in a WebRTC session. It includes various details about the call and the participants. * **callID**: A unique identifier for the call. * **variables**: An instance of the `Variables` class containing additional event-related information. * **sdp**: The Session Description Protocol (SDP) data for the call. * **callerIdName**: The name of the caller. * **callerIdNumber**: The phone number of the caller. * **calleeIdName**: The name of the callee. * **calleeIdNumber**: The phone number of the callee. * **telnyxSessionId**: The session ID provided by Telnyx. * **telnyxLegId**: The leg ID provided by Telnyx. * **displayDirection**: The direction of the call display (e.g., inbound or outbound). ### Variables The `Variables` class contains various event-related details that are part of the incoming invite parameters. * **eventName**: The name of the event. * **coreUUID**: The UUID of the core. * **freeSWITCHHostname**: The hostname of the FreeSWITCH server. * **freeSWITCHSwitchname**: The switch name of the FreeSWITCH server. * **freeSWITCHIPv4**: The IPv4 address of the FreeSWITCH server. * **freeSWITCHIPv6**: The IPv6 address of the FreeSWITCH server. * **eventDateLocal**: The local date and time of the event. * **eventDateGMT**: The GMT date and time of the event. * **eventDateTimestamp**: The timestamp of the event. * **eventCallingFile**: The file from which the event was called. * **eventCallingFunction**: The function from which the event was called. * **eventCallingLineNumber**: The line number from which the event was called. * **eventSequence**: The sequence number of the event. ```dart theme={null} class IncomingInviteParams { String? callID; Variables? variables; String? sdp; String? callerIdName; String? callerIdNumber; String? calleeIdName; String? calleeIdNumber; String? telnyxSessionId; String? telnyxLegId; String? displayDirection; IncomingInviteParams({ this.callID, this.variables, this.sdp, this.callerIdName, this.callerIdNumber, this.calleeIdName, this.calleeIdNumber, this.telnyxSessionId, this.telnyxLegId, this.displayDirection, }); IncomingInviteParams.fromJson(Map json) { callID = json['callID']; variables = json['variables'] != null ? Variables.fromJson(json['variables']) : null; sdp = json['sdp']; callerIdName = json['caller_id_name']; callerIdNumber = json['caller_id_number']; calleeIdName = json['callee_id_name']; calleeIdNumber = json['callee_id_number']; telnyxSessionId = json['telnyx_session_id']; telnyxLegId = json['telnyx_leg_id']; displayDirection = json['display_direction']; } Map toJson() { final Map data = {}; data['callID'] = callID; if (variables != null) { data['variables'] = variables!.toJson(); } data['sdp'] = sdp; data['caller_id_name'] = callerIdName; data['caller_id_number'] = callerIdNumber; data['callee_id_name'] = calleeIdName; data['callee_id_number'] = calleeIdNumber; data['telnyx_session_id'] = telnyxSessionId; data['telnyx_leg_id'] = telnyxLegId; data['display_direction'] = displayDirection; return data; } } class Variables { String? eventName; String? coreUUID; String? freeSWITCHHostname; String? freeSWITCHSwitchname; String? freeSWITCHIPv4; String? freeSWITCHIPv6; String? eventDateLocal; String? eventDateGMT; String? eventDateTimestamp; String? eventCallingFile; String? eventCallingFunction; String? eventCallingLineNumber; String? eventSequence; Variables({ this.eventName, this.coreUUID, this.freeSWITCHHostname, this.freeSWITCHSwitchname, this.freeSWITCHIPv4, this.freeSWITCHIPv6, this.eventDateLocal, this.eventDateGMT, this.eventDateTimestamp, this.eventCallingFile, this.eventCallingFunction, this.eventCallingLineNumber, this.eventSequence, }); Variables.fromJson(Map json) { eventName = json['Event-Name']; coreUUID = json['Core-UUID']; freeSWITCHHostname = json['FreeSWITCH-Hostname']; freeSWITCHSwitchname = json['FreeSWITCH-Switchname']; freeSWITCHIPv4 = json['FreeSWITCH-IPv4']; freeSWITCHIPv6 = json['FreeSWITCH-IPv6']; eventDateLocal = json['Event-Date-Local']; eventDateGMT = json['Event-Date-GMT']; eventDateTimestamp = json['Event-Date-Timestamp']; eventCallingFile = json['Event-Calling-File']; eventCallingFunction = json['Event-Calling-Function']; eventCallingLineNumber = json['Event-Calling-Line-Number']; eventSequence = json['Event-Sequence']; } Map toJson() { final Map data = {}; data['Event-Name'] = eventName; data['Core-UUID'] = coreUUID; data['FreeSWITCH-Hostname'] = freeSWITCHHostname; data['FreeSWITCH-Switchname'] = freeSWITCHSwitchname; data['FreeSWITCH-IPv4'] = freeSWITCHIPv4; data['FreeSWITCH-IPv6'] = freeSWITCHIPv6; data['Event-Date-Local'] = eventDateLocal; data['Event-Date-GMT'] = eventDateGMT; data['Event-Date-Timestamp'] = eventDateTimestamp; data['Event-Calling-File'] = eventCallingFile; data['Event-Calling-Function'] = eventCallingFunction; data['Event-Calling-Line-Number'] = eventCallingLineNumber; data['Event-Sequence'] = eventSequence; return data; } } ``` # WebRTC Flutter Client Push Notifications Configuration Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/method-objects/push-metadata/index This class contains all the properties related to Push Notifications ### PushMetaData This class is used to represent the metadata received from a push notification. It contains a `callerName`, `callerNumber`, `callId`, `voiceSdkId`, `isAnswer` and `isDecline` which are strings representing the metadata received from the push notification. the `isAnswer` and `isDecline` are boolean values representing the state of the call. the `callerName`, `callerNumber`, `callId`, `voiceSdkId` are strings representing information about the caller and SDK. ```dart theme={null} class PushMetaData { PushMetaData({ this.callerName, this.callerNumber, this.callId, this.voiceSdkId, }); String? callerName; String? callerNumber; String? callId; String? voiceSdkId; bool? isAnswer; bool? isDecline; PushMetaData.fromJson(Map json) { callerName = json['caller_name']; callerNumber = json['caller_number']; callId = json['call_id']; voiceSdkId = json['voice_sdk_id']; isAnswer = json['isAnswer']; isDecline = json['isDecline']; } Map toJson() { final Map data = {}; data['caller_name'] = callerName; data['caller_number'] = callerNumber; data['call_id'] = callId; data['voice_sdk_id'] = voiceSdkId; data['isAnswer'] = isAnswer; data['isDecline'] = isDecline; return data; } } ``` # Flutter Push Notification App Setup Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/app-setup/index A step-by-step guide to setting up push notifications in Flutter. Learn how to configure and implement notifications to ensure seamless communication in your application. ## Introduction This document provides a guide on how to set up push notifications for incoming calls on the Telnyx Voice SDK Flutter Plugin. It is important to understand how push notifications work in general in relation to Telnyx services. When you connect to the TelnyxClient, you establish a socket connection that can receive and handle incoming calls. However, if your application is in the background or terminated, the socket connection closes and can no longer receive invitations. To address this limitation, the Telnyx Voice SDK uses push notifications to inform the device of incoming calls. When you log in to the TelnyxClient and provide an APNS or FCM token, the SDK sends a push notification to your device whenever an incoming call is received. Note that this notification only indicates that an invitation is on the way. Once you respond to a push notification—for example, by tapping "Accept"—you must handle the logic to launch and reconnect to the TelnyxClient. After reconnection, the socket connection is re-established, and the backend will send the actual invitation to your device. In this scenario, it may be helpful to store the fact that the push notification was accepted so that when the invitation arrives (as soon as the socket is connected), you can automatically accept the call. The following sections provide more detail on how to implement these steps. ## Multidevice Push Notifications Telnyx WebRTC supports multidevice push notifications. A single user can have up to 5 device tokens (either iOS - APNS or Android - FCM). When a user logs into the socket and provides a push token, our services will register this token to that user - allowing it to receive push notifications for incoming calls. If a 6th registration is made, the least recently used token will be removed. This effectivly means that you can have up to 5 devices that can receive push notifications for the same incoming call. ## Handling Foreground and Terminated Calls When the app is in the foreground you do not need to use push notifications to receive calls, however it still might be beneficial to use CallKit to show native UI for the calls. When the app is terminated you will need to use push notifications to receive calls as described below. ## Android The Android platform makes use of Firebase Cloud Messaging in order to deliver push notifications. To receive notifications when receiving calls on your Android mobile device you will have to enable Firebase Cloud Messaging within your application. The Demo app uses the [FlutterCallkitIncoming](https://pub.dev/packages/flutter_callkit_incoming) plugin to show incoming calls. To show a notification when receiving a call, you can follow the steps below: 1. Listen for Background Push Notifications, Implement the `FirebaseMessaging.onBackgroundMessage` method in your `main` method ```dart theme={null} @pragma('vm:entry-point') Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (defaultTargetPlatform == TargetPlatform.android) { // Android Only - Push Notifications await Firebase.initializeApp(); FirebaseMessaging.onBackgroundMessage(_firebaseMessagingBackgroundHandler); await FirebaseMessaging.instance .setForegroundNotificationPresentationOptions( alert: true, badge: true, sound: true, ); } runApp(const MyApp()); } ``` 2. Optionally Add the `metadata` to CallKitParams `extra` field ```dart theme={null} static Future showNotification(RemoteMessage message) { CallKitParams callKitParams = CallKitParams( android:..., ios:..., extra: message.data, ) await FlutterCallkitIncoming.showCallkitIncoming(callKitParams); } ``` 3. Handle the push notification in the `_firebaseMessagingBackgroundHandler` method ```dart theme={null} Future _firebaseMessagingBackgroundHandler(RemoteMessage message) async { // Show notifcation showNotification(message); // Listen to action from FlutterCallkitIncoming FlutterCallkitIncoming.onEvent.listen((CallEvent? event) async { switch (event!.event) { case Event.actionCallAccept: // Set the telnyx metadata for access when the app comes to foreground TelnyxClient.setPushMetaData( message.data, isAnswer: true, isDecline: false); break; case Event.actionCallDecline: /* * When the user declines the call from the push notification, the SDK now handles this automatically. * Simply set the decline flag and the SDK will handle the rest using the new push_decline method. * */ TelnyxClient.setPushMetaData( message.data, isAnswer: false, isDecline: true); break; }}); } ``` 4. **Create a High-Importance Notification Channel (Android 8.0+)** For Android 8.0 (API level 26) and higher, notifications must be assigned to a channel. To ensure incoming call notifications are treated with high priority (e.g., shown as heads-up notifications), you need to create a dedicated channel with maximum importance. First, add the `flutter_local_notifications` package to your `pubspec.yaml`: ```yaml theme={null} dependencies: flutter_local_notifications: ^ ``` **Gradle Setup (for Android):** The `flutter_local_notifications` plugin may require Java 8+ features. To enable support for these, you need to configure Core Library Desugaring in your Android project. In your `android/app/build.gradle` file, ensure the following configurations are present: ```groovy theme={null} // android/app/build.gradle (Groovy DSL) android { // ... other settings compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' } ``` For projects using **Kotlin DSL (`build.gradle.kts`):** ```kotlin theme={null} // android/app/build.gradle.kts (Kotlin DSL) android { // ... other settings defaultConfig { // multiDexEnabled = true // Only if you explicitly need multidex for other reasons } compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_1_8 // Or JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_1_8 // Or JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() // Or JavaVersion.VERSION_11.toString() } // ... other settings } dependencies { // ... other dependencies coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // Or a newer version like 2.1.4 for Java 11 } ``` *(Note: Adjust Java versions and `desugar_jdk_libs` version as needed. While `flutter_local_notifications` might show Java 11, Java 8 with `desugar_jdk_libs:2.0.4` is often sufficient. For Java 11, use `desugar_jdk_libs:2.1.4` or newer.)* Then, create the channel, typically during your app's initialization (e.g., in your `AndroidPushNotificationHandler.initialize` method): ```dart theme={null} import 'package:flutter_local_notifications/flutter_local_notifications.dart'; // Create high importance channel const AndroidNotificationChannel channel = AndroidNotificationChannel( 'telnyx_call_channel', // Unique ID for the channel 'Incoming Calls', // User-visible name description: 'Notifications for incoming Telnyx calls.', // User-visible description importance: Importance.max, // Crucial for heads-up display playSound: true, audioAttributesUsage: AudioAttributesUsage.notificationRingtone, // Use ringtone audio attributes // Add other properties like vibration pattern if desired ); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); try { await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation< AndroidFlutterLocalNotificationsPlugin>() ?.createNotificationChannel(channel); print('High importance notification channel created/updated.'); } catch (e) { print('Failed to create notification channel: $e'); } ``` Finally, tell the Firebase SDK to use this channel by default for incoming FCM notifications by adding the following meta-data inside the `` tag in your `android/app/src/main/AndroidManifest.xml`: ```html theme={null} ``` *(Note: The ID 'telnyx\_call\_channel' must match the ID used in the Dart code.)* 5. Use the `TelnyxClient.getPushMetaData()` method to retrieve the metadata when the app comes to the foreground. This data is only available on 1st access and becomes `null` afterward. ```dart theme={null} Future _handlePushNotification() async { final data = await TelnyxClient.getPushMetaData(); PushMetaData? pushMetaData = PushMetaData.fromJson(data); if (pushMetaData != null) { _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); } } ``` 6. To Handle push calls on foreground, Listen for Call Events and invoke the `handlePushNotification` method ```dart theme={null} FlutterCallkitIncoming.onEvent.listen((CallEvent? event) { switch (event!.event) { case Event.actionCallIncoming: // retrieve the push metadata from extras final data = await TelnyxClient.getPushData(); ... _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); break; case Event.actionCallStart: .... break; case Event.actionCallAccept: ... logger.i('Call Accepted Attach Call'); break; }); ``` #### Best Practices for Push Notifications on Android 1. Request for Notification Permissions for android 13+ devices to show push notifications. More information can be found [here](https://developer.android.com/develop/ui/views/notifications/notification-permission) 2. Push Notifications only work in foreground for apps that are run in `debug` mode (You will not receive push notifications when you terminate the app while running in debug mode). 3. On Foreground calls, you can use the `FirebaseMessaging.onMessage.listen` method to listen for incoming calls and show a notification. ```dart theme={null} FirebaseMessaging.onMessage.listen((RemoteMessage message) { TelnyxClient.setPushMetaData(message.data); NotificationService.showNotification(message); mainViewModel.callFromPush = true; }); ``` 4. To handle push notifications on the background, use the `FirebaseMessaging.onBackgroundMessage` method to listen for incoming calls and show a notification and make sure to set the ` TelnyxClient.setPushMetaData` when user answers the call. ```dart theme={null} TelnyxClient.setPushMetaData( message.data, isAnswer: true, isDecline: false); ``` 5. When you call the `telnyxClient.handlePushNotification` it connects to the `telnyxClient`, make sure not to call the `telnyxClient.connect()` method after this. e.g an Edge case might be if you call `telnyxClient.connect()` on Widget `init` method it will always call the `connect` method 6. Early Answer/Decline : Users may answer/decline the call too early before a socket connection is established. To handle this situation, assert if the `IncomingInviteParams` is not null and only accept/decline if this is available. ```dart theme={null} bool waitingForInvite = false; void accept() { if (_incomingInvite != null) { // accept the call if the incomingInvite arrives on time _currentCall = _telnyxClient.acceptCall( _incomingInvite!, _localName, _localNumber, "State"); } else { // set waitingForInvite to true if we have an early accept waitingForInvite = true; } } _telnyxClient.onSocketMessageReceived = (TelnyxMessage message) { switch (message.socketMethod) { ... case SocketMethod.INVITE: { if (callFromPush) { // For early accept of call if (waitingForInvite) { //accept the call accept(); waitingForInvite = false; } callFromPush = false; } } ... } } ``` ## iOS The iOS Platform makes use of the Apple Push Notification Service (APNS) and Pushkit in order to deliver and receive push notifications For a detailed tutorial, please visit our official [Push Notification Docs](https://developers.telnyx.com/docs/v2/webrtc/push-notifications?lang=ios) ## Native Swift Code Changes For a full example please view the [Demo Application Example](https://github.com/team-telnyx/flutter-voice-sdk/blob/main/ios/Runner/AppDelegate.swift) 1. In AppDelegate.swift setup the ability to receive VOIP push notifications by adding these lines to your application function ```swift theme={null} override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? ) -> Bool { GeneratedPluginRegistrant.register(with: self) //Setup VOIP let mainQueue = DispatchQueue.main let voipRegistry: PKPushRegistry = PKPushRegistry(queue: mainQueue) voipRegistry.delegate = self voipRegistry.desiredPushTypes = [PKPushType.voIP] RTCAudioSession.sharedInstance().useManualAudio = true RTCAudioSession.sharedInstance().isAudioEnabled = false return super.application(application, didFinishLaunchingWithOptions: launchOptions) } ``` Note: It is important to add the following lines to your `Info.plist` file to enable push notifications ```html theme={null} UIBackgroundModes processing remote-notification voip ``` Also, as we are using WebRTC we need to add the following lines to avoid a bug where there is no audio on iOS when using it with CallKit. Add the following lines to your `AppDelegate.swift` file in the application function as demonstrated above ```swift theme={null} RTCAudioSession.sharedInstance().useManualAudio = true RTCAudioSession.sharedInstance().isAudioEnabled = false ``` 2. Implement the CallkitIncomingAppDelegate within AppDelegate so that you can action on calls that are received. Callin action.fulfill() will allows us to listen to the events and act on them in our dart code. ```swift theme={null} @main @objc class AppDelegate: FlutterAppDelegate, PKPushRegistryDelegate, CallkitIncomingAppDelegate { func onAccept(_ call: flutter_callkit_incoming.Call, _ action: CXAnswerCallAction) { NSLog("onRunner :: Accept") action.fulfill() } func onDecline(_ call: flutter_callkit_incoming.Call, _ action: CXEndCallAction) { NSLog("onRunner :: Decline") action.fulfill() } func onEnd(_ call: flutter_callkit_incoming.Call, _ action: CXEndCallAction) { NSLog("onRunner :: onEnd") action.fulfill() } func onTimeOut(_ call: flutter_callkit_incoming.Call) { NSLog("onRunner :: TimeOut") } func didActivateAudioSession(_ audioSession: AVAudioSession) { NSLog("onRunner :: Activate Audio Session") RTCAudioSession.sharedInstance().audioSessionDidActivate(audioSession) RTCAudioSession.sharedInstance().isAudioEnabled = true } func didDeactivateAudioSession(_ audioSession: AVAudioSession) { NSLog(":: DeActivate Audio Session") RTCAudioSession.sharedInstance().audioSessionDidDeactivate(audioSession) RTCAudioSession.sharedInstance().isAudioEnabled = false } .... ``` Note: Notice for didActivateAudioSession and didDeactivateAudioSession that we are handling WebRTC manually. This is to handle the before mentioned bug where there is no audio on iOS when using it with CallKit. 1. Register / Invalidate the push device token for iOS within AppDelegate.swift class ```swift theme={null} func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { print(credentials.token) let deviceToken = credentials.token.map { String(format: "%02x", $0) }.joined() //Save deviceToken to your server SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP(deviceToken) } func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { SwiftFlutterCallkitIncomingPlugin.sharedInstance?.setDevicePushTokenVoIP("") } ``` 2. For foreground calls to work, you need to register with callkit on the restorationHandler delegate function. You can also choose to register with callkit using iOS official documentation on [CallKit](https://developer.apple.com/documentation/callkit/). ```swift theme={null} override func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool { let nameCaller = handleObj.getDecryptHandle()["nameCaller"] as? String ?? "" let handle = handleObj.getDecryptHandle()["handle"] as? String ?? "" let data = flutter_callkit_incoming.Data(id: UUID().uuidString, nameCaller: nameCaller, handle: handle, type: isVideo ? 1 : 0) //set more data... data.nameCaller = "dummy" SwiftFlutterCallkitIncomingPlugin.sharedInstance?.startCall(data, fromPushKit: true) } ``` 3. Listen for incoming calls in AppDelegate.swift class and grab the relevant metadata from the push payload to pass to showCallkitIncoming (eg. the callerName, callerNumber, callID, etc) ```swift theme={null} func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { print("didReceiveIncomingPushWith") guard type == .voIP else { return } if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] { var callID = UUID.init().uuidString if let newCallId = (metadata["call_id"] as? String), !newCallId.isEmpty { callID = newCallId } let callerName = (metadata["caller_name"] as? String) ?? "" let callerNumber = (metadata["caller_number"] as? String) ?? "" let id = payload.dictionaryPayload["call_id"] as? String ?? UUID().uuidString let data = flutter_callkit_incoming.Data(id: id, nameCaller: callerName, handle: callerNumber, type: isVideo ? 1 : 0) data.extra = payload.dictionaryPayload as NSDictionary data.normalHandle = 1 let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName let uuid = UUID(uuidString: callID) data.uuid = uuid!.uuidString data.nameCaller = caller SwiftFlutterCallkitIncomingPlugin.sharedInstance?.showCallkitIncoming(data, fromPushKit: true) DispatchQueue.main.asyncAfter(deadline: .now() + 1) { completion() } } } ``` Note: it is important to call completion() after showing the callkit incoming screen to avoid the app being terminated by the system. See the last line above. if you don't call completion() in pushRegistry(......, completion: @escaping () -> Void), there may be app crash by system when receiving voIP ## Dart / Flutter Code Changes 4. Listen for Call Events and invoke the `handlePushNotification` method ```dart theme={null} FlutterCallkitIncoming.onEvent.listen((CallEvent? event) { switch (event!.event) { case Event.actionCallIncoming: // retrieve the push metadata from extras PushMetaData? pushMetaData = PushMetaData.fromJson(event.body['extra']['metadata']); _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); break; case Event.actionCallStart: .... break; case Event.actionCallAccept: ... logger.i('Call Accepted Attach Call'); break; }); ``` 5. Sending an invitation on iOS when using Callkit. Because of the native changes we made in AppDelegate.swift related to WebRTC audio handling, we now need to start a callkit call whenever we send out an invitation so that we can have an active audio session. This simply means starting a callkit call whenever we send out an invitation. Your call() method could look something like: ```dart theme={null} void call(String destination) { _currentCall = telnyxClient.newInvite( _localName, _localNumber, destination, 'State', customHeaders: {'X-Header-1': 'Value1', 'X-Header-2': 'Value2'}, ); var params = CallKitParams( id: _currentCall?.callId, nameCaller: _localName, appName: 'My Calling App', handle: destination, ); FlutterCallkitIncoming.startCall(params); } ``` ### Handling Late Notifications If notifications arrive very late due to no internet connectivity, It is good to always flag it as a missed call. You can do that using the code snippet below : ```dart theme={null} const CALL_MISSED_TIMEOUT = 60; DateTime nowTime = DateTime.now(); Duration? difference = nowTime?.difference(message.sentTime!); if (difference.inSeconds > CALL_MISSED_TIMEOUT) { NotificationService.showMissedCallNotification(message); return; } ``` ## Handling Background Calls Background calls are handled slightly differently than terminated calls as the application is not disconnected and in a fresh state. The application is in the background and the socket connection is still active - meaning we can receive an invite on the socket but not be notified about it. We can get around this by listening to application lifecycle events and checking if the application is in the background, and if so disconnecting from the socket manually. This way we can listen to the push notification and reconnect to the socket when the user accepts the call. You can do this by either manually creating a lifecycle state listener in dart using the [WidgetsBindingObserver](https://api.flutter.dev/flutter/widgets/WidgetsBindingObserver-class.html) or using a library like [flutter\_fgbg](https://pub.dev/packages/flutter_fgbg) to listen to the application lifecycle events. An implementation could look like this: ```dart theme={null} @pragma('vm:entry-point') Future main() async { WidgetsFlutterBinding.ensureInitialized(); if (!AppInitializer()._isInitialized) { await AppInitializer() .initialize(); // handle any initialization here (setting up listeners, etc) } runApp( FGBGNotifier( onEvent: (FGBGType type) => switch (type) { FGBGType.foreground => { print('App in the foreground (FGBGNotifier)'), // Check if we are in the foreground as a result of a push notification, if we are do nothing, reconnection will happen there in handlePush. Otherwise connect if (telnyxClient.callFromPush) { telnyxClient.connectWithCredential(getCredentialConfig) }, }, FGBGType.background => { print('App in the background (FGBGNotifier)'), telnyxClient.disconnect(), } }, child: const MyApp()), ); } ``` Note: Notice that in the foreground event we check if we are in the foreground as a result of a push notification, if we are do nothing, reconnection will happen there in handlePush. Otherwise connect. This is because handlePushNotification will be called when the user accepts the call from the push notification and we will reconnect to the socket there. This also means however that when we are showing a notification, which on iOS can be full screen, we need to make sure that we don't disconnect when the notification is shown. We can do this with FGBG's ignoreWhile method like so: ```dart theme={null} Future showNotification(IncomingInviteParams message) async { // Temporarily ignore FGBG events while showing the CallKit notification FGBGEvents.ignoreWhile(() async { CallKitParams callKitParams = CallKitParams( id: message.callID, nameCaller: message.callerIdName, appName: 'Telnyx Flutter Demo', handle: message.callerIdNumber, type: 0, textAccept: 'Accept', textDecline: 'Decline', missedCallNotification: const NotificationParams( showNotification: false, isShowCallback: false, subtitle: 'Missed call', ), duration: 30000, extra: {}, headers: {'platform': 'flutter'}, ); await FlutterCallkitIncoming.showCallkitIncoming(callKitParams); }); } ``` #### Best Practices for Push Notifications on iOS 1. Push Notifications only work in foreground for apps that are run in `debug` mode (You will not receive push notifications when you terminate the app while running in debug mode). Make sure you are in `release` mode. Preferably test using Testfight or Appstore. To test if push notifications are working, disconnect the telnyx client (while app is in foreground) and make a call to the device. You should receive a push notification. ## New Push Notification Features ### Simplified Push Decline Method The Telnyx Flutter Voice SDK now includes a significantly simplified method for declining push notifications, eliminating the complex workflow previously required. #### Previous Method (Legacy) Previously, declining a push notification required: 1. Logging back into the socket 2. Listening for events 3. Waiting for an INVITE message 4. Manually sending a bye message to decline the call 5. Handling bye responses and cleanup #### New Simplified Method The SDK now handles push call decline automatically when you set the decline flag. The process is streamlined to: 1. **Set the decline flag** when the user declines the push notification: ```dart theme={null} case Event.actionCallDecline: TelnyxClient.setPushMetaData(message.data, isAnswer: false, isDecline: true); break; ``` 2. **Call handlePushNotification** as usual: ```dart theme={null} Future _handlePushNotification() async { final data = await TelnyxClient.getPushMetaData(); PushMetaData? pushMetaData = PushMetaData.fromJson(data); if (pushMetaData != null) { _telnyxClient.handlePushNotification(pushMetaData, credentialConfig, tokenConfig); } } ``` #### What Happens Internally When `isDecline: true` is set, the SDK automatically: * Connects to the Telnyx socket * Sends a login message with `decline_push: true` parameter * The backend handles the call termination * Automatically disconnects from the socket * No need to wait for INVITE messages or handle bye responses #### Benefits * **Simplified Implementation**: Reduces code complexity significantly * **Automatic Cleanup**: SDK handles all socket management and cleanup * **Reliable**: Eliminates potential race conditions and edge cases * **Consistent**: Works the same way across Android and iOS platforms ### 10-Second Answer Timeout Mechanism The SDK now includes an automatic timeout mechanism to handle cases where an INVITE message is missing after accepting a VoIP push notification. #### The Problem Sometimes after accepting a push notification, the INVITE message may not arrive due to: * Network connectivity issues * Server-side problems * Message delivery failures * Backend processing delays Previously, this would result in the app waiting indefinitely for an INVITE that might never come. #### The Solution The SDK now implements a 10-second timeout mechanism that: * Starts automatically when a push notification is accepted (`isAnswer: true`) * Monitors for incoming INVITE messages * Automatically terminates the call if no INVITE arrives within 10 seconds * Sends a bye message with `ORIGINATOR_CANCEL` termination reason (SIP code 487) #### How It Works **Normal Flow (INVITE Received)**: 1. User accepts push notification 2. SDK starts 10-second timer 3. INVITE message arrives on socket 4. Timer is cancelled 5. Call proceeds normally **Timeout Flow (No INVITE Received)**: 1. User accepts push notification 2. SDK starts 10-second timer 3. No INVITE message arrives within 10 seconds 4. Timer expires 5. SDK automatically sends bye message with `ORIGINATOR_CANCEL` 6. Call is terminated gracefully #### Implementation Details The timeout mechanism is completely automatic and requires no additional code. It activates when: * `TelnyxClient.setPushMetaData()` is called with `isAnswer: true` * `handlePushNotification()` is called * The SDK connects and waits for an INVITE #### Handling Timeout Events Your existing call event handlers will receive the termination event: ```dart theme={null} _telnyxClient.onSocketMessageReceived = (TelnyxMessage message) { switch (message.socketMethod) { case SocketMethod.bye: final byeMessage = message.message as ReceivedMessage; final byeParams = ReceiveByeMessageBody.fromJson(byeMessage.result); if (byeParams.terminationReason?.reason == CallTerminationReason.ORIGINATOR_CANCEL) { // Handle timeout case - call was cancelled due to missing INVITE print('Call terminated due to timeout - no INVITE received'); } break; // ... other cases } }; ``` #### Benefits * **Prevents Indefinite Waiting**: Ensures calls don't hang indefinitely * **Automatic Recovery**: No manual intervention required * **Clear Termination Reason**: Provides specific reason code for debugging * **Consistent Behavior**: Works across all platforms and scenarios * **User Experience**: Prevents users from waiting for calls that will never connect #### Configuration The timeout duration is fixed at 10 seconds and is not currently configurable. This duration was chosen to balance between: * Allowing sufficient time for normal INVITE delivery * Preventing excessive wait times for users * Accommodating network latency variations ### Migration Guide #### For Existing Decline Implementations If you have existing push decline logic, you can simplify it: **Before**: ```dart theme={null} case Event.actionCallDecline: // Complex logic to connect, wait for invite, send bye, etc. await connectAndDeclineCall(message.data); break; ``` **After**: ```dart theme={null} case Event.actionCallDecline: TelnyxClient.setPushMetaData(message.data, isAnswer: false, isDecline: true); break; ``` #### For Timeout Handling No migration is required for the timeout feature - it works automatically with existing code. However, you may want to add specific handling for `ORIGINATOR_CANCEL` termination reasons in your bye message handlers. ### Testing the New Features #### Testing Push Decline 1. Receive a push notification while app is terminated 2. Decline the call from the notification 3. Verify the call is declined without complex socket operations 4. Check logs to confirm `decline_push: true` parameter is sent #### Testing Answer Timeout 1. Accept a push notification 2. Simulate network issues or server problems that prevent INVITE delivery 3. Wait 10 seconds 4. Verify the call is automatically terminated with `ORIGINATOR_CANCEL` 5. Check that your app handles the termination gracefully ### Troubleshooting #### Push Decline Issues * Ensure you're setting `isDecline: true` in `setPushMetaData` * Verify `handlePushNotification` is called after setting the metadata * Check network connectivity for the decline message to be sent #### Timeout Issues * The timeout only applies to accepted push notifications (`isAnswer: true`) * Normal incoming calls (not from push) are not affected by this timeout * If INVITE arrives after timeout, it will be ignored as the call is already terminated # Flutter Push Notification Portal Setup Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/portal-setup/index A step-by-step guide to setting up push notifications in Flutter. Learn how to configure and implement notifications to ensure seamless communication in your application. ## Android The Telnyx Flutter Client WebRTC SDK uses Firebase Cloud Messaging (FCM) to deliver push notifications for Android devices. To enable notifications for incoming calls on your Android mobile device, you need to set up Firebase Cloud Messaging in your application. Follow these steps to configure Firebase Cloud Messaging for your Android application through the Telnyx portal: 1. Visit the [Portal Setup Android](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/portal-setup) to complete the setup process. ## ios The Telnyx Flutter Client WebRTC SDK uses Apple Push Notification Service (APNs) to deliver push notifications for iOS devices. To enable notifications for incoming calls on your iOS device, you need to set up APNs in your application. Follow these steps to configure Apple Push Notification Service (APNs) for your iOS application through the Telnyx portal: 1. Visit the [Portal Setup iOS](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/portal-setup) to complete the setup process. # Flutter Push Troubleshooting Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/push-notification/troubleshooting/index A step-by-step guide on how to debug common issues related to push notifications for Flutter This guide helps you troubleshoot common issues that prevent push notifications from being delivered in the Telnyx WebRTC Flutter SDK. ## Introduction Push notifications in Flutter applications require proper configuration on both the Flutter side and the native platform sides (iOS and Android). Since Flutter is a cross-platform framework, troubleshooting push notifications often involves checking platform-specific configurations. Common issues that affect both platforms: 1. **Push Token Not Passed to Login**: Ensure your push token is correctly retrieved and passed during login 2. **Wrong Push Credential Assigned to SIP Connection**: Verify your SIP connection has the correct push credential assigned 3. **Network Connectivity Issues**: Check that your device has a stable internet connection ## Android Troubleshooting ### 1. FCM Token Not Passed to Login One of the most common issues is that the FCM token is not being passed correctly during the login process. **How to verify:** * Check your application logs to ensure the FCM token is being retrieved successfully * Verify that the login message contains the FCM token * Look for logs similar to: `FCM token received: [your-token]` **Solution:** * Make sure you're retrieving the FCM token as shown in the [App Setup](https://developers.telnyx.com/docs/voice/webrtc/flutter-sdk/push-notification/app-setup) guide * Ensure the token is passed to the `connect()` method within the `TelnyxConfig` object * Verify that the token is not null or empty before passing it ### 2. Incorrect google-services.json Configuration If your Firebase configuration file is incorrect or outdated, push notifications will not work properly. **How to verify:** * Check that the google-services.json file is in the correct location (android/app/ directory) * Verify that the package name in the google-services.json matches your application's package name **Solution:** * Download a fresh copy of the google-services.json file from the Firebase Console * Make sure you're using the correct Firebase project for your application * Follow the [Portal Setup](https://developers.telnyx.com/docs/voice/webrtc/flutter-sdk/push-notification/portal-setup) guide to properly configure Firebase ### 3. Incorrect Push Credential If your push credential contains incorrect information, push notifications will fail. **How to verify:** * Check the push credential in the Telnyx Portal * Verify that the server key JSON is correctly formatted and valid **Solution:** * Generate a new server key in the Firebase Console * Update your push credential in the Telnyx Portal with the new key * Test push notifications after updating the credential ### 4. Delayed or Batched Notifications (Android 8+) **Symptom:** Notifications (especially for incoming calls) are not arriving immediately when the app is in the background or terminated. They might arrive in batches after some delay. **Cause:** Android includes power-saving features like Doze mode and App Standby that can defer background network access and job execution for apps using `normal` priority Firebase Cloud Messages (FCM). **Solutions:** 1. **Create High-Importance Notification Channel (Client-Side - For Display):** * While server-side priority affects *delivery speed*, a client-side Notification Channel with `Importance.max` is crucial for ensuring the notification is *displayed* promptly as a heads-up notification once delivered (on Android 8.0+). * Make sure you have created this channel using `flutter_local_notifications` during your app initialization, as described in the [App Setup Guide](https://developers.telnyx.com/docs/voice/webrtc/flutter-sdk/push-notification/app-setup). * **Verification Code Snippet:** ```dart theme={null} // Example (should be in your initialization code) import 'package:flutter_local_notifications/flutter_local_notifications.dart'; const AndroidNotificationChannel channel = AndroidNotificationChannel( 'telnyx_call_channel', 'Incoming Calls', description: 'Notifications for incoming Telnyx calls.', importance: Importance.max, playSound: true, audioAttributesUsage: AudioAttributesUsage.notificationRingtone, ); final FlutterLocalNotificationsPlugin flutterLocalNotificationsPlugin = FlutterLocalNotificationsPlugin(); await flutterLocalNotificationsPlugin .resolvePlatformSpecificImplementation() ?.createNotificationChannel(channel); ``` 2. **Check `AndroidManifest.xml`:** * Ensure you have added the `` tag inside your `` tag, where `your_channel_id` matches the ID used when creating the channel (e.g., `telnyx_call_channel`). This helps Firebase use the correct channel if it ever displays a notification directly. 3. **Enable Core Library Desugaring (Gradle Setup):** * If you encounter build failures like `CheckDebugAarMetadata` or runtime errors related to missing Java APIs after adding `flutter_local_notifications` or similar plugins, you likely need to enable Core Library Desugaring. * In your `android/app/build.gradle` (Groovy DSL): ```groovy theme={null} android { // ... compileOptions { coreLibraryDesugaringEnabled true sourceCompatibility JavaVersion.VERSION_1_8 // or VERSION_11 targetCompatibility JavaVersion.VERSION_1_8 // or VERSION_11 } kotlinOptions { jvmTarget = "1.8" // or "11" } // ... } dependencies { // ... coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4' // Or newer, e.g., 2.1.4 for Java 11 support } ``` * For projects using **Kotlin DSL (`build.gradle.kts`):** ```kotlin theme={null} // android/app/build.gradle.kts (Kotlin DSL) android { // ... other settings defaultConfig { // multiDexEnabled = true // Only if you explicitly need multidex for other reasons } compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_1_8 // Or JavaVersion.VERSION_11 targetCompatibility = JavaVersion.VERSION_1_8 // Or JavaVersion.VERSION_11 } kotlinOptions { jvmTarget = JavaVersion.VERSION_1_8.toString() // Or JavaVersion.VERSION_11.toString() } // ... other settings } dependencies { // ... other dependencies coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.0.4") // Or a newer version like 2.1.4 for Java 11 } ``` * This allows your app to use Java 8+ language APIs on older Android versions. Refer to the official [Android Java 8+ support documentation](https://developer.android.com/studio/write/java8-support) and the specific plugin's documentation (like `flutter_local_notifications`) for the recommended Java version and `desugar_jdk_libs` version. 4. **Foreground Service (Advanced):** * For maximum reliability, especially for critical call signaling, consider implementing an Android Foreground Service (using a plugin like `flutter_foreground_task`) to handle the incoming FCM message. This gives your background processing higher priority. Refer to Android best practices for call-related apps. ### 5. Additional Android Troubleshooting Steps 1. **Check Firebase Console Logs** * Go to the Firebase Console > Your Project > Engage > Messaging * Check for any errors or failed deliveries 2. **Test with Firebase Test Notifications** * Use the Firebase Console to send a test notification to your device * This can help determine if the issue is with Firebase or with Telnyx 3. **Verify Device Registration** * Make sure your device is properly registered with Firebase * Check that the FCM token is being refreshed when needed ## iOS Troubleshooting ### 1. VoIP Push Notification Certificate One of the most critical components for iOS push notifications is the VoIP Push Notification Certificate. A single VoIP Services Certificate supports both sandbox and production environments for the same bundle ID. **How to verify:** * Check that you have generated a valid VoIP Services Certificate in the Apple Developer Portal * Verify that the certificate is not expired * Ensure the certificate is generated for the correct bundle ID used in your app * Verify that the VoIP Services Certificate establishes connectivity between your notification server and both APNS sandbox and production environments **Solution:** * Follow [Apple's official documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns) to generate a new VoIP Services Certificate * Upload the certificate to the Telnyx Portal * Ensure the certificate matches your app's bundle ID * For different bundle IDs (e.g., com.myapp.dev, com.myapp), create separate VoIP Services Certificates * Note: A separate certificate is required for each app you distribute, but each certificate works for both sandbox and production ### 2. APNS Environment Mismatch iOS apps can target either the APNS Sandbox (development) or Production environment, and this must align with your build configuration. **How to verify:** * Check your build configuration (Debug vs Release) * Ensure that the APNS environment setting in your TxConfig (`pushEnvironment` property) is not being forced * Confirm that the correct VoIP Services Certificate, valid for both production and development, is uploaded to the Telnyx Portal **Solution:** * For Debug builds running from Xcode: * Use a Sandbox (development) certificate * Set `pushEnvironment` to `sandbox` in TelnyxConfig if needed * For Release builds or TestFlight: * Use a Production certificate * Set `pushEnvironment` to `production` in TelnyxConfig if needed * If generating an IPA: * Ensure it's signed with the correct profile (development or distribution) * Match the APNS environment to your signing profile ### 3. Info.plist Configuration Proper configuration in Info.plist is essential for push notifications to work. **How to verify:** * Check that push notifications are enabled in your app's capabilities * Verify that VoIP push notifications are properly configured * Ensure background modes are enabled for VoIP **Solution:** * Add the following to your Info.plist: ```html theme={null} UIBackgroundModes voip ``` * Enable "Voice over IP" and "Background fetch" in Xcode capabilities * Verify that your app has the required entitlements for push notifications ### 4. Additional iOS Troubleshooting Steps 1. **Check APNS Status** * Use Apple's developer tools to verify APNS connectivity * Monitor for any APNS feedback about invalid tokens or delivery failures 2. **Verify Bundle ID Configuration** * Ensure your bundle ID matches across: * Xcode project settings * Provisioning profiles * VoIP push certificates * Telnyx Portal configuration 3. **Test with Development Environment First** * Start testing with sandbox/development environment * Use debug builds and development certificates * Monitor system logs for push notification related messages ## Still Having Issues? If you've gone through all the troubleshooting steps and are still experiencing problems: 1. Check the Telnyx WebRTC Flutter SDK documentation for any updates or known issues 2. Contact Telnyx Support with detailed information about your setup and the issues you're experiencing 3. Include logs, error messages, and steps to reproduce the problem when contacting support 4. Provide your development environment details: * Flutter version * iOS/Android version * SDK version * Build configuration (Debug/Release) * Certificate type (Development/Production for iOS) # WebRTC Stats Source: https://developers.telnyx.com/development/webrtc/flutter-sdk/stats/index A comprehensive record of all updates, enhancements, and bug fixes related to WebRTC statistics. ## WebRTC Statistics The SDK provides WebRTC statistics functionality to assist with troubleshooting and monitoring call quality. This feature is controlled through the `debug` flag in the `TxClient` configuration. ### Enabling WebRTC Statistics To enable WebRTC statistics logging: ```dart theme={null} final credentialConfig = CredentialConfig( sipUser: sipUser, sipPassword: sipPassword, sipCallerIDName: sipCallerIDName, sipCallerIDNumber: sipCallerIDNumber, notificationToken: await getNotificationTokenForPlatform() ?? '', debug: true, // Enable debug mode ) // or With Token Login final tokenConfig = TokenConfig( sipToken= sipToken ?: "", sipCallerIDName = this.callerIdName, sipCallerIDNumber = callerIdNumber, logLevel = LogLevel.ALL, debug = false ) ``` ### Understanding WebRTC Statistics When `debug: true` is configured: * WebRTC statistics logs are automatically collected during calls * Logs are sent to the Telnyx portal and are accessible in the Object Storage section * Statistics are linked to the SIP credential used for testing * The logs help the Telnyx support team diagnose issues and optimize call quality * All statistics are presented in the Telnyx portal under the Object Storage section ### Real-time Call Quality Monitoring The SDK provides real-time call quality metrics through the `onCallQualityChange` callback on the `Call` object. This allows you to monitor call quality in real-time and provide feedback to users. #### Using onCallQualityChanged ```dart theme={null} // When creating a new call set debug to true for CallQualityMetrics val outgoingCall = telnyxClient.newInvite(callerName, callerNumber, destinationNumber, clientState, customHeaders, debug // debug value ) //When accepting a call _currentCall = _telnyxClient.acceptCall( invite, _localName, _localNumber, debug: true, // Enable debug mode ); // Set the onCallQualityChange callback _currentCall = _telnyxClient.newInvite( _localName, _localNumber, destination, debug: true, // Enable debug mode ); ``` #### CallQualityMetrics Properties The `CallQualityMetrics` object provides the following properties: | Property | Type | Description | | --------------------- | ------------------- | -------------------------------------------------------------- | | `jitter` | Double | Jitter in seconds (multiply by 1000 for milliseconds) | | `rtt` | Double | Round-trip time in seconds (multiply by 1000 for milliseconds) | | `mos` | Double | Mean Opinion Score (1.0-5.0) | | `quality` | CallQuality | Call quality rating based on MOS | | `inboundAudio` | `Map?` | Inbound audio statistics | | `outboundAudio` | `Map?` | Outbound audio statistics | | `remoteInboundAudio` | `Map?` | Remote inbound audio statistics | | `remoteOutboundAudio` | `Map?` | Remote outbound audio statistics | #### CallQuality Enum The `CallQuality` enum provides the following values: | Value | MOS Range | Description | | ------------ | ------------------- | --------------------------- | | `.excellent` | MOS > 4.2 | Excellent call quality | | `.good` | 4.1 \<= MOS \<= 4.2 | Good call quality | | `.fair` | 3.7 \<= MOS \<= 4.0 | Fair call quality | | `.poor` | 3.1 \<= MOS \<= 3.6 | Poor call quality | | `.bad` | MOS \<= 3.0 | Bad call quality | | `.unknown` | N/A | Unable to calculate quality | #### Best Practices for Call Quality Monitoring 1. **User Feedback**: * Consider showing a visual indicator of call quality to users * For poor quality calls, provide suggestions (e.g., "Try moving to an area with better connectivity") 2. **Logging**: * Log quality metrics for later analysis * Track quality trends over time to identify patterns 3. **Adaptive Behavior**: * Implement adaptive behaviors based on call quality * For example, suggest switching to audio-only if video quality is poor 4. **Performance Considerations**: * The callback is triggered periodically (approximately every 2 seconds) ### Important Notes 1. **Log Access**: * If you run the app using SIP credential A with `debug: true`, the WebRTC logs will be available in the Telnyx portal account associated with credential A * Logs are stored in the Object Storage section of your Telnyx portal 2. **Troubleshooting Support**: * WebRTC statistics are primarily intended to assist the Telnyx support team * When requesting support, enable `debug: true` in `TxClient` for all instances * Provide the `debug ID` or `callId` when contacting support * Statistics logging is disabled by default to optimize performance 3. **Best Practices**: * Enable `debug: true` only when troubleshooting is needed * Remember to provide the `debug ID` or `callId` in support requests * Consider disabling debug mode in production unless actively investigating issues *** # WebRTC iOS SDK AI Voice Assistant Anonymous Login Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/anonymous-login/index Learn how to implement anonymous login for AI voice assistants with the iOS Voice SDK # Anonymous Connection for AI Agents ## Overview The `anonymousLogin` method allows you to connect to AI assistants without traditional authentication credentials. This is the first step in establishing communication with a Telnyx AI Agent. ## Method Signature ```swift theme={null} public func anonymousLogin( targetId: String, targetType: String = "ai_assistant", targetVersionId: String? = nil, userVariables: [String: Any] = [:], reconnection: Bool = false, serverConfiguration: TxServerConfiguration = TxServerConfiguration() ) ``` ## Parameters | Parameter | Type | Required | Default | Description | | --------------------- | --------------------- | -------- | ----------------------- | ----------------------------------------------------------------------- | | `targetId` | String | Yes | - | The ID of your AI assistant | | `targetType` | String | No | "ai\_assistant" | The type of target | | `targetVersionId` | String? | No | nil | Optional version ID of the target. If not provided, uses latest version | | `userVariables` | \[String: Any] | No | \[:] | Optional user variables to include | | `reconnection` | Bool | No | false | Whether this is a reconnection attempt | | `serverConfiguration` | TxServerConfiguration | No | TxServerConfiguration() | Server configuration (signaling server URL and STUN/TURN servers) | ### TxServerConfiguration Properties | Property | Type | Description | | ------------------ | ---------------- | ----------------------------------------------------------- | | `signalingServer` | URL? | Custom signaling server URL (e.g., `wss://your-server.com`) | | `webRTCIceServers` | \[RTCIceServer]? | Custom STUN/TURN servers for WebRTC connections | ## Usage Example ```swift theme={null} do { client.anonymousLogin( targetId: "your_assistant_id", // targetType: "ai_assistant", // This is the default value // targetVersionId: "your_assistant_version_id", // Optional // userVariables: ["user_id": "12345"], // Optional user variables ) // You are now connected and can make a call to the AI Assistant. } catch { // Handle connection error print("Connection failed: \(error.localizedDescription)") } ``` ## Advanced Usage ### With User Variables ```swift theme={null} client.anonymousLogin( targetId: "your_assistant_id", userVariables: [ "user_id": "12345", "session_context": "support_chat", "language": "en-US" ] ) ``` ### With Version Control ```swift theme={null} client.anonymousLogin( targetId: "your_assistant_id", targetVersionId: "v1.2.0" // Use specific version ) ``` ### With Custom Server Configuration ```swift theme={null} import WebRTC // Example 1: Custom signaling server only let customSignalingServer = URL(string: "wss://your-custom-signaling-server.com")! let config1 = TxServerConfiguration(signalingServer: customSignalingServer) client.anonymousLogin( targetId: "your_assistant_id", serverConfiguration: config1 ) // Example 2: Custom STUN/TURN servers only let stunServer = RTCIceServer(urlStrings: ["stun:stun.example.com:3478"]) let turnServer = RTCIceServer( urlStrings: ["turn:turn.example.com:3478?transport=tcp"], username: "your-username", credential: "your-password" ) let config2 = TxServerConfiguration(webRTCIceServers: [stunServer, turnServer]) client.anonymousLogin( targetId: "your_assistant_id", serverConfiguration: config2 ) // Example 3: Full custom configuration (signaling server + STUN/TURN) let customConfig = TxServerConfiguration( signalingServer: customSignalingServer, webRTCIceServers: [stunServer, turnServer] ) client.anonymousLogin( targetId: "your_assistant_id", serverConfiguration: customConfig ) ``` ## Important Notes * **Call Routing**: After a successful anonymous connection, any subsequent call, regardless of the destination, will be directed to the specified AI Assistant * **Session Lock**: The session becomes locked to the AI assistant until disconnection * **Version Control**: If `targetVersionId` is not provided, the SDK will use the latest available version * **Error Handling**: Monitor delegate callbacks for authentication errors * **Server Configuration**: You can customize: * **Signaling Server**: Custom WebSocket server URL for SIP signaling (e.g., `wss://your-server.com`) * **ICE Servers**: Custom STUN/TURN servers for NAT traversal and media relay * **Default Configuration**: If no custom configuration is provided, the SDK uses Telnyx's default servers ## Delegate Response Handling Listen for connection responses using the delegate methods: ```swift theme={null} extension YourViewController: TxClientDelegate { func onClientReady() { // Handle successful anonymous connection print("Anonymous connection successful") } func onClientError(error: Error) { // Handle connection errors print("Connection error: \(error.localizedDescription)") } func onSocketDisconnected() { print("Disconnected from AI assistant") } } ``` ## Error Handling Common errors you might encounter: ```swift theme={null} func onClientError(error: Error) { if let txError = error as? TxError { switch txError { case .socketFailure: print("Invalid assistant ID or authentication failed") case .clientConfigurationFailure: print("Network connection failed") default: print("Unexpected error: \(txError)") } } } ``` ## Next Steps After successful anonymous connection: 1. [Start a conversation](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/starting-conversations) using `newCall()` 2. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/transcript-updates) to receive real-time conversation data 3. [Send text messages](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/text-messaging) during active calls # WebRTC iOS SDK AI Voice Assistant Introduction Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/introduction/index Introduction to building AI-powered voice assistants with the iOS Voice SDK # AI Agent Usage The iOS WebRTC SDK supports [Voice AI Agent](https://telnyx.com/products/voice-ai-agents) implementations. To get started, follow the steps [described here](https://telnyx.com/resources/ai-assistant-builder) to build your first AI Assistant. Once your AI Agent is up and running, you can use the SDK to communicate with your AI Agent with the following steps: ## Pre-developed AI Widget If you don't want to develop your own custom AI Agent interface from scratch, you can utilize our pre-developed AI Agent widget that provides a drop-in solution for voice AI interactions. ### iOS Telnyx Voice AI Widget The **iOS Telnyx Voice AI Widget** is a standalone, embeddable widget that provides a complete voice AI assistant interface using the Telnyx WebRTC SDK. **Repository**: [https://github.com/team-telnyx/ios-telnyx-voice-ai-widget](https://github.com/team-telnyx/ios-telnyx-voice-ai-widget) **Swift Package Manager**: `https://github.com/team-telnyx/ios-telnyx-voice-ai-widget.git` **CocoaPods**: `pod 'TelnyxVoiceAIWidget', '~> 1.0.0'` ### Key Features * **Drop-in Solution**: Easy integration with minimal setup * **Multiple UI States**: Collapsed, loading, expanded, and transcript views * **Icon-Only Mode**: Floating action button-style interface for minimal UI footprint * **Audio Visualizer**: Real-time audio visualization during conversations * **Theme Support**: Light and dark theme compatibility * **Responsive Design**: Optimized for various screen sizes * **Voice Controls**: Mute/unmute and call management * **Transcript View**: Full conversation history with text input * **Customizable Styling**: Fine-tuned UI customization options ### Quick Integration ```swift theme={null} import TelnyxVoiceAIWidget struct ContentView: View { @State private var showWidget = false var body: some View { AIAssistantWidget( assistantId: "your-assistant-id", shouldInitialize: showWidget ) } } ``` ### Icon-Only Mode ```swift theme={null} AIAssistantWidget( assistantId: "your-assistant-id", shouldInitialize: true, iconOnly: true // Enables floating action button mode ) ``` This widget handles all the complexity of AI Agent integration, providing a production-ready solution that you can customize to match your app's design. ## Documentation Structure This directory contains detailed documentation for AI Agent integration: * [Anonymous Login](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/anonymous-login) - How to connect to AI assistants without traditional authentication * [Starting Conversations](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/starting-conversations) - How to initiate calls with AI assistants * [Transcript Updates](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/transcript-updates) - Real-time conversation transcripts * [Text Messaging](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/text-messaging) - Send text messages during active calls ## Quick Start 1. **Anonymous Login**: Use `anonymousLogin()` to connect to your AI assistant 2. **Start Conversation**: Use `newCall()` to initiate a call (destination is ignored) 3. **Receive Transcripts**: Subscribe to transcript updates for real-time conversation updates 4. **Send Text Messages**: Use `sendAIAssistantMessage()` to send text during active calls ## Key Features * **No Authentication Required**: Connect to AI assistants without SIP credentials * **Real-time Transcripts**: Get live conversation updates with role identification * **Mixed Communication**: Combine voice and text messaging in the same conversation * **Widget Settings**: Access AI conversation configuration settings * **Standard Call Controls**: Use existing call management methods (mute, hold, end call) ## Important Notes * After `anonymousLogin()`, all subsequent calls are routed to the specified AI assistant * Transcript functionality is only available for AI assistant conversations * AI assistants automatically answer calls - no manual answer required * Text messages appear in transcript updates alongside spoken conversation # WebRTC iOS SDK AI Voice Assistant Starting Conversations Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/starting-conversations/index Learn how to start conversations with AI voice assistants using the iOS Voice SDK # Starting Conversations with AI Assistants ## Overview After a successful `anonymousLogin`, you can initiate calls to your AI Assistant using the standard `newCall` method. The session is locked to the AI Assistant, so the destination parameter is ignored. ## Method Usage ```swift theme={null} try client.newCall( callerName: String, // Display name (passed to AI assistant) callerNumber: String, // Caller number (passed to AI assistant) destinationNumber: String, // Ignored after anonymous login. All calls will be routed to the AI assistant callId: UUID, // Unique identifier for the call clientState: String? = nil, // Optional custom state information for your application customHeaders: [String: String] = [:] // Optional SIP headers to pass context to the AI assistant in the form of dynamic variables ) ``` ## Parameters | Parameter | Type | Description | | ------------------- | ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `callerName` | String | Your display name (passed to AI assistant) | | `callerNumber` | String | Your phone number (passed to AI assistant) | | `destinationNumber` | String | Ignored after anonymous login - can be empty string | | `callId` | UUID | Unique identifier for the call | | `clientState` | String? | Optional custom state information for your application | | `customHeaders` | \[String: String] | Optional SIP headers to pass context to the AI assistant (mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables)) | Note that you can also provide `customHeaders` in the `newCall` method. These headers need to start with the `X-` prefix and will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the AI assistant (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. ## Usage Example ```swift theme={null} // After a successful anonymousLogin... do { let call = try client.newCall( callerName: "John Doe", callerNumber: "+1234567890", destinationNumber: "", // Destination is ignored, can be empty callId: UUID(), clientState: "ai_conversation_session", customHeaders: [ "X-Session-Context": "support_request", "X-User-Tier": "premium" ] ) } catch { print("Failed to start call: \(error)") } ``` ## Complete Flow Example ```swift theme={null} class AIAssistantManager { private let client = TxClient() private var currentCall: Call? init() { client.delegate = self } func startAIConversation(assistantId: String) { // Step 1: Anonymous login client.anonymousLogin(targetId: assistantId) } private func startCall() { do { currentCall = try client.newCall( callerName: "Customer", callerNumber: "+1234567890", destinationNumber: "", // Ignored callId: UUID(), clientState: "ai_session", customHeaders: [ "X-Session-Context": "customer_support", "X-User-Tier": "premium" ] ) } catch { print("Failed to start call: \(error)") } } } extension AIAssistantManager: TxClientDelegate { func onClientReady() { // Login successful, start the call startCall() } func onCallStateUpdated(callState: CallState, callId: UUID) { guard currentCall?.callId == callId else { return } switch callState { case .NEW: print("Call invitation sent") case .RINGING: print("AI Assistant ringing...") case .ACTIVE: print("Connected to AI Assistant") // Start listening for transcripts case .DONE: print("AI conversation ended") default: break } } } ``` ## Important Notes * **Automatic Answer**: AI assistants automatically answer calls - no manual answer required * **Destination Ignored**: The `destinationNumber` parameter is ignored after anonymous login * **Call Routing**: All calls are routed to the AI assistant specified during login * **Standard Controls**: Use existing call management methods (mute, hold, end call) * **Custom Headers**: You can pass custom SIP headers to provide context to the AI assistant. They will be mapped to [dynamic variables](https://developers.telnyx.com/docs/inference/ai-assistants/dynamic-variables) in the portal. Hyphens in header names are converted to underscores in variable names, e.g. `X-Session-Context` header maps to `{{session_context}}` variable. ## Call State Management Monitor call states as you would with regular calls: ```swift theme={null} func onCallStateUpdated(callState: CallState, callId: UUID) { guard currentCall?.callId == callId else { return } switch callState { case .NEW: print("Calling AI Assistant...") case .RINGING: print("AI Assistant ringing...") case .ACTIVE: print("Connected to AI Assistant") // Start listening for transcripts setupTranscriptListener() case .DONE: print("AI conversation ended") default: break } } ``` ## Error Handling Handle call-related errors: ```swift theme={null} func onClientError(error: Error) { if let txError = error as? TxError { switch txError { case .callFailure: print("Failed to start conversation with AI Assistant") default: print("Call error: \(txError)") } } } ``` ## Call Management Once connected, use standard call management methods: ```swift theme={null} // Get the active call guard let activeCall = currentCall else { return } // Mute/unmute activeCall.muteUnmute() // Hold/unhold activeCall.holdUnhold() // End call activeCall.hangup() ``` ## Next Steps After starting a conversation: 1. [Set up transcript updates](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/transcript-updates) to receive real-time conversation data 2. [Send text messages](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/text-messaging) during the active call 3. Use standard call controls for mute, hold, and end call operations # WebRTC iOS SDK AI Voice Assistant Text Messaging Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/text-messaging/index Learn how to implement text messaging with AI voice assistants using the iOS Voice SDK # Sending Text Messages to AI Agents ## Overview In addition to voice conversation, you can send text messages directly to the AI Agent during an active call. This allows for mixed-mode communication where users can both speak and type messages to the AI Assistant. ## Method Signature ```swift theme={null} func sendAIAssistantMessage(_ message: String) -> Bool ``` ## Parameters | Parameter | Type | Description | | --------- | ------ | -------------------------------------------- | | `message` | String | The text message to send to the AI Assistant | ## Returns `Bool` - Returns `true` if the message was sent successfully, `false` otherwise ## Basic Usage ```swift theme={null} // Send a text message to the AI Agent during an active call let success = client.sendAIAssistantMessage("Hello, can you help me with my account?") if success { print("Message sent successfully") } else { print("Failed to send message") } ``` ## Complete Example ```swift theme={null} class AIConversationViewController: UIViewController { private let client = TxClient() @IBOutlet weak var messageTextField: UITextField! @IBOutlet weak var sendButton: UIButton! override func viewDidLoad() { super.viewDidLoad() setupMessageSending() } private func setupMessageSending() { sendButton.addTarget(self, action: #selector(sendButtonTapped), for: .touchUpInside) } @objc private func sendButtonTapped() { guard let message = messageTextField.text, !message.isEmpty else { showAlert("Please enter a message") return } sendTextMessage(message) } private func sendTextMessage(_ message: String) { let success = client.sendAIAssistantMessage(message) if success { print("Text message sent: \(message)") messageTextField.text = "" addMessageToUI(message, isUser: true) } else { showAlert("Failed to send message. Check connection.") } } private func addMessageToUI(_ message: String, isUser: Bool) { // Add message to conversation UI let messageView = createMessageBubble(text: message, isUser: isUser) conversationStackView.addArrangedSubview(messageView) scrollToBottom() } private func showAlert(_ message: String) { let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } } extension AIConversationViewController: TxClientDelegate { func onCallStateUpdated(callState: CallState, callId: UUID) { switch callState { case .ACTIVE: enableTextMessaging() case .DONE: disableTextMessaging() default: break } } private func enableTextMessaging() { messageTextField.isEnabled = true sendButton.isEnabled = true } private func disableTextMessaging() { messageTextField.isEnabled = false sendButton.isEnabled = false } } ``` ## Advanced Usage with Call State Checking ```swift theme={null} class AIMessageManager { private let client: TxClient init(client: TxClient) { self.client = client } func sendMessage(_ message: String) -> Bool { guard isAICallActive() else { print("Cannot send message: No active AI call") return false } return client.sendAIAssistantMessage(message) } private func isAICallActive() -> Bool { return client.calls.values.contains { $0.callState == .ACTIVE } } func sendMessageWithConfirmation(_ message: String, completion: @escaping (Bool) -> Void) { let success = sendMessage(message) completion(success) } } ``` ## Error Handling ```swift theme={null} private func sendTextMessageWithErrorHandling(_ message: String) { // Check if we have an active AI call guard hasActiveCall() else { showError("No active AI conversation. Please start a call first.") return } // Send the message let success = client.sendAIAssistantMessage(message) if success { showMessageSent(message) } else { showError("Failed to send message") } } private func hasActiveCall() -> Bool { return client.calls.values.contains { $0.callState == .ACTIVE } } private func showError(_ message: String) { let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default)) present(alert, animated: true) } private func showMessageSent(_ message: String) { print("Message sent successfully: \(message)") } ``` ## Important Notes * **Active Call Required**: You must have an active call established before sending text messages * **AI Assistant Only**: The `sendAIAssistantMessage` method is only available during AI Assistant conversations * **Transcript Integration**: Text messages sent this way will appear in transcript updates alongside spoken conversation * **Processing**: The AI Agent will process and respond to text messages just like spoken input * **Mixed Communication**: Users can seamlessly switch between voice and text communication ## Best Practices 1. **Validate Input**: Always check that messages are not empty before sending 2. **Check Call State**: Verify an active AI call exists before sending messages 3. **User Feedback**: Provide visual feedback when messages are sent 4. **Error Handling**: Handle network errors and call state issues gracefully 5. **UI Updates**: Update the conversation UI immediately for better user experience ## Integration with Transcript Updates Text messages will appear in the transcript updates: ```swift theme={null} cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { [weak self] transcript in DispatchQueue.main.async { transcript.forEach { item in switch item.role { case "user": // This includes both spoken words and text messages self?.displayUserMessage(item.content, item.timestamp) case "assistant": // AI responses to both voice and text self?.displayAssistantMessage(item.content, item.timestamp) default: break } } } } ``` This feature enables rich conversational experiences where users can seamlessly switch between voice and text communication with the AI Assistant. # WebRTC iOS SDK AI Voice Assistant Transcript Updates Source: https://developers.telnyx.com/development/webrtc/ios-sdk/ai-voice-assistant/transcript-updates/index Learn how to handle transcript updates with AI voice assistants using the iOS Voice SDK # Real-time Transcript Updates ## Overview During AI Assistant conversations, the SDK provides real-time transcript updates that include both the caller's speech and the AI Assistant's responses. This allows you to display a live conversation transcript in your application. ## Transcript Properties The SDK provides two main ways to access transcript data: ### Custom Publisher for Real-time Updates ```swift theme={null} // Subscribe to transcript updates using custom publisher let cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { transcripts in // Handle transcript updates } ``` ### Current Transcript Access ```swift theme={null} // Get current transcripts as property (read-only) let transcripts = client.aiAssistantManager.transcript // Or via method let transcripts = client.aiAssistantManager.getTranscriptions() ``` ## TranscriptionItem Structure ```swift theme={null} public struct TranscriptionItem { public let id: String // Unique identifier public let role: String // "user" or "assistant" public let content: String // The transcribed text public let timestamp: Date // When the item was created public let isPartial: Bool // Whether this is a partial response } ``` ## Setting Up Transcript Updates ### Using Custom Publisher (Recommended) ```swift theme={null} class AIConversationViewController: UIViewController { private let client = TxClient() private var transcriptCancellable: TranscriptCancellable? private var conversationTranscript: [TranscriptionItem] = [] override func viewDidLoad() { super.viewDidLoad() setupTranscriptListener() } private func setupTranscriptListener() { transcriptCancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { [weak self] transcript in // Updates are already dispatched on main thread by the publisher self?.updateConversationUI(transcript) } } private func updateConversationUI(_ transcript: [TranscriptionItem]) { conversationTranscript = transcript // Update UI conversationTableView.reloadData() // Auto-scroll to bottom if !transcript.isEmpty { let indexPath = IndexPath(row: transcript.count - 1, section: 0) conversationTableView.scrollToRow(at: indexPath, at: .bottom, animated: true) } } deinit { transcriptCancellable?.cancel() } } ``` ### Processing Individual Transcript Items ```swift theme={null} private func updateConversationUI(_ transcript: [TranscriptionItem]) { transcript.forEach { item in switch item.role { case "user": print("User said: \(item.content)") // Display user message in UI addUserMessage(item.content, item.timestamp) case "assistant": print("Assistant said: \(item.content)") // Display assistant message in UI addAssistantMessage(item.content, item.timestamp, item.isPartial) default: break } } } ``` ## Manual Transcript Access You can also manually retrieve the current transcript at any time: ```swift theme={null} // Get current transcript via property let currentTranscript = client.aiAssistantManager.transcript // Or via method let currentTranscript = client.aiAssistantManager.getTranscriptions() // Process the transcript currentTranscript.forEach { item in print("\(item.role): \(item.content) (\(item.timestamp))") } ``` ## Filtering Transcripts The SDK provides convenient methods to filter transcripts by role or status: ```swift theme={null} // Get only user transcriptions let userMessages = client.aiAssistantManager.getUserTranscriptions() // Get only assistant transcriptions let assistantMessages = client.aiAssistantManager.getAssistantTranscriptions() // Get only partial (in-progress) transcriptions let partialMessages = client.aiAssistantManager.getPartialTranscriptions() // Get only final (completed) transcriptions let finalMessages = client.aiAssistantManager.getFinalTranscriptions() // Get transcriptions by specific role let transcriptionsByRole = client.aiAssistantManager.getTranscriptionsByRole("user") ``` ## Handling Partial Responses AI Assistant responses may come in chunks (partial responses). Handle these appropriately: ```swift theme={null} private func addAssistantMessage(_ content: String, _ timestamp: Date, _ isPartial: Bool) { if isPartial { // Update existing message or show typing indicator updateLastAssistantMessage(content) showTypingIndicator(true) } else { // Final message - hide typing indicator showTypingIndicator(false) finalizeAssistantMessage(content, timestamp) } } ``` ## Complete Example with UITableView ```swift theme={null} class ConversationViewController: UIViewController, UITableViewDataSource { @IBOutlet weak var tableView: UITableView! private let client = TxClient() private var transcripts: [TranscriptionItem] = [] private var cancellable: TranscriptCancellable? override func viewDidLoad() { super.viewDidLoad() tableView.dataSource = self setupTranscripts() } private func setupTranscripts() { cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { [weak self] transcripts in DispatchQueue.main.async { self?.transcripts = transcripts self?.tableView.reloadData() } } } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return transcripts.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let transcript = transcripts[indexPath.row] let cell = tableView.dequeueReusableCell(withIdentifier: "TranscriptCell", for: indexPath) cell.textLabel?.text = transcript.content // Style based on role if transcript.role == "user" { cell.backgroundColor = .systemBlue cell.textLabel?.textColor = .white cell.textLabel?.textAlignment = .right } else { cell.backgroundColor = .systemGray6 cell.textLabel?.textColor = .label cell.textLabel?.textAlignment = .left } // Show partial indicator cell.textLabel?.alpha = transcript.isPartial ? 0.7 : 1.0 return cell } deinit { cancellable?.cancel() } } ``` ## Delegate Pattern (Alternative Approach) You can also use the delegate pattern to receive transcript updates: ```swift theme={null} class AIConversationViewController: UIViewController, AIAssistantManagerDelegate { private let client = TxClient() override func viewDidLoad() { super.viewDidLoad() client.aiAssistantManager.delegate = self } // MARK: - AIAssistantManagerDelegate func onTranscriptionUpdated(_ transcriptions: [TranscriptionItem]) { // Handle transcript updates updateConversationUI(transcriptions) } func onWidgetSettingsUpdated(_ settings: WidgetSettings) { // Handle widget settings updates print("Widget settings updated: \(settings)") } func onAIConversationMessage(_ message: [String: Any]) { // Handle raw AI conversation messages print("AI message received: \(message)") } func onAIAssistantConnectionStateChanged(isConnected: Bool, targetId: String?) { // Handle connection state changes print("AI Assistant connected: \(isConnected), targetId: \(targetId ?? "none")") } func onRingingAckReceived(callId: String) { // Handle ringing acknowledgment print("Ringing ack for call: \(callId)") } } ``` ## Widget Settings Access Access AI conversation widget settings: ```swift theme={null} // Get current widget settings if let widgetSettings = client.aiAssistantManager.widgetSettings { // Use widget settings to configure UI print("Widget settings: \(widgetSettings)") } ``` ## Connection State Monitoring Monitor the AI Assistant connection state: ```swift theme={null} // Check if AI Assistant is connected if client.aiAssistantManager.isAIAssistantConnected { print("AI Assistant is connected") } // Get the connected target ID if let targetId = client.aiAssistantManager.connectedTargetId { print("Connected to target: \(targetId)") } ``` ## Clearing Transcripts You can clear transcripts manually if needed: ```swift theme={null} // Clear all transcriptions client.aiAssistantManager.clearTranscriptions() // Clear transcriptions by specific role client.aiAssistantManager.clearTranscriptionsByRole("user") client.aiAssistantManager.clearTranscriptionsByRole("assistant") // Clear all AI Assistant data (including transcripts and widget settings) client.aiAssistantManager.clearAllData() ``` ## Important Notes * **AI Assistant Only**: Transcript updates are only available during AI Assistant conversations initiated through `anonymousLogin` * **Real-time Updates**: Transcripts update in real-time as the conversation progresses * **Partial Responses**: Assistant responses may come in chunks - handle `isPartial` flag appropriately * **Memory Management**: Transcripts are automatically cleared when calls end or when disconnecting * **Thread Safety**: Publisher updates are dispatched on the main thread automatically * **Multiple Subscribers**: You can have multiple subscribers to the same transcript updates ## Error Handling ```swift theme={null} cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { [weak self] transcripts in guard !transcripts.isEmpty else { print("Received empty transcript array") return } self?.updateConversationUI(transcripts) } // Always cancel subscriptions when done deinit { cancellable?.cancel() } ``` ## Next Steps After setting up transcript updates: 1. [Send text messages](https://developers.telnyx.com/development/webrtc/ios-sdk/ai-agent/text-messaging) to interact with the AI Assistant via text # WebRTC iOS ChangeLog Source: https://developers.telnyx.com/development/webrtc/ios-sdk/changelog/index A comprehensive record of all updates, enhancements, and bug fixes. Stay informed about the latest features and improvements to optimize your development experience. # CHANGELOG ## [3.2.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/3.2.0) (2026-03-06) ### Features * **Automatic Call Quality Reporting**: Implemented automatic collection and reporting of WebRTC statistics and call lifecycle events. The SDK now collects audio quality metrics (MOS, jitter, packet loss, RTT), connection stats, and structured debug logs during calls, then automatically posts comprehensive call reports to voice-sdk-proxy at call end for troubleshooting and quality analysis. Configurable via `TxConfig` with options for collection interval, log level filtering, and buffer limits. Enabled by default ([#325](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/325)) ## [3.1.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/3.1.0) (2026-02-26) ### Bug Fixes * **Call Reject Handling**: Fixed causeCode in bye message when rejecting incoming calls. Calls rejected in NEW state now properly send causeCode 17 (USER\_BUSY) instead of 16 (NORMAL\_CLEARING), preventing the backend from retrying call delivery indefinitely ([#327](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/327)) ### Features * **TURN Server Configuration**: Ported TURN server improvements from JS SDK for cross-platform consistency. Added UDP TURN servers as primary transport for lower latency, with TCP TURN servers as fallback for restrictive firewalls. Added Google STUN server (stun.l.google.com:19302) for redundancy. ICE server connection order: STUN → TURN UDP → TURN TCP ([#326](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/326)) ## [3.0.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/3.0.0) (2026-02-03) ### ⚠️ Breaking Changes **Missed Call Notification Handling Required** Starting in v3.0.0, you **must** handle missed call VoIP push notifications in your app. Failure to properly handle these notifications can lead to Apple disabling VoIP push notification delivery to your app, breaking incoming call functionality. **Action Required:** Implement the missed call notification handler as described in the migration guide (`docs-markdown/migrations/v2-to-v3.md`) before upgrading to v3.0.0. ### Features * **Trickle ICE Support**: Added support for Trickle ICE to improve connection establishment time and reliability. Enable by setting `useTrickleIce: true` in `TxConfig`. Candidates are sent immediately as discovered, reducing call setup latency ([#291](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/291)) * **Push Notification Call Decline**: Implemented proper call decline flow via push notifications. Calls can now be immediately rejected without waiting for full SDK connection, eliminating race conditions when CallKit notifications appear before SDK is ready. **Backward compatible** - no changes required in app implementation ([#236](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/236)) * **Missed Call Handling**: Added server-side support for missed call VoIP push notifications sent to iOS SDK v3.0.0+ clients. When a call is rejected remotely, Telnyx servers send a "Missed call!" push notification allowing your app to automatically dismiss the CallKit UI, preventing users from accepting stale notifications. **Implementation required** - See migration guide for handler implementation ([#254](https://github.com/team-telnyx/telnyx-webrtc-ios/pull/254)) ## [2.4.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.4.0) (2025-11-17) ### Features * **AI Agent Image Support**: Added ability to send Base64 encoded images to AI assistants during conversations through `sendAIAssistantMessage()` method with multi-image support ## [2.3.1](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.3.1) (2025-10-27) ### Bug Fixes * Fixed speaker state preservation during network reconnection and manual ACM (AudioDeviceModule) reset to prevent speakerphone from deactivating when switching networks ## [2.3.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.3.0) (2025-10-21) ### Features * **Preferred Audio Codecs**: Added support for preferred audio codec selection * `TxClient.getSupportedAudioCodecs()`: Query supported audio codecs available for calls * `Call.setPreferredCodecs()`: Set preferred audio codecs for individual calls ## [2.2.2](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.2.2) (2025-10-08) ### Features * **Anonymous Login for AI-Agent**: Added support for anonymous authentication specifically designed for AI-Agent integration, allowing connections without traditional credentials ### Bug Fixes * Fixed speaker restoration after ACM (AudioDeviceModule) buffer reset to maintain the previously selected audio route * Fixed User-Agent header formatting and content ## [2.2.1](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.2.1) (2025-09-23) ### Bug Fixes * Improve audio connection performance by removing unnecessary audio device resets during mute/unmute operations * Maintain audio route change subscriptions throughout the client lifecycle instead of unsubscribing on disconnect ## [2.2.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.2.0) (2025-09-19) ### Features * **ICE Renegotiation**: Enhanced ICE candidate renegotiation process to improve call quality during network fluctuations * **ACM Buffer Reset**: Implemented automatic AudioDeviceModule (ACM) buffer reset mechanism based on RTT monitoring to reduce audio delay. The ACM buffer is automatically reset when RTT exceeds 1000ms. Requires `debug: true` and `enableQualityMetrics: true` flags in `TxConfig` to enable RTT monitoring and automatic buffer reset functionality * **WebRTC Stats Control**: Added new `sendWebRTCStatsViaSocket` flag in `TxConfig` to control whether WebRTC statistics are sent via socket to Telnyx servers ## [2.1.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.1.0) (2025-07-31) ### Features * SDK Region Selection ### Enhancements * Improved reconnection logic for thread safety ## [2.0.2](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.0.2) (2025-05-26) ### Bug Fixes * Improved call quality metrics for real-time monitoring of call quality metrics * Fix cause codes for reject and normal clearing ## [2.0.1](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.0.1) (2025-05-26) ### Bug Fixes * Fixed initialization of `reconnectTimeOut` parameter in `TxConfig` that was not being properly assigned during configuration ## [2.0.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/2.0.0) (2025-05-21) ### Features * WEBRTC-2686: Expose Call Termination Reasons in SDK and Surface Error Messages ### Fixes * Fix Ringback Tone for parked calls ## [1.2.3](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.2.3) (2025-05-02) ### Enhancements * Implemented CallQuality metrics for real-time monitoring of call quality metrics including: * Jitter measurements * Packet loss statistics * Latency tracking * MOS (Mean Opinion Score) estimation ## [1.2.2](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.2.2) (2025-03-20) ### Enhancements * Improved call reconnection process for better reliability during network changes * Added configurable reconnection timeout for more control over network recovery ## [1.2.1](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.2.1) (2025-03-11) ### Bug Fixes * Disabled WebRTC stats during socket reconnection process to improve call reconnection speed. ## [1.2.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.2.0) (2025-03-01) ### Enhacement * **Custom Logs Support**: * Added support for custom logs in the SDK. You can now pass a customLogger in TxConfig to handle SDK logs. * If no custom logger is provided, logs will be printed to the console based on the configured logLevel (.none by default). ### Reconnection Enhancements * Improved call reconnection handling when switching networks (Wi-Fi / mobile data). * New CallState: Introduced a new DROPPED state to better track when a call is lost due to network issues. ```Swift theme={null} /// `CallState` represents the state of the call public enum CallState: Equatable { /// New call has been created in the client. case NEW /// The outbound call is being sent to the server. case CONNECTING /// Call is pending to be answered. Someone is attempting to call you. case RINGING /// Call is active when two clients are fully connected. case ACTIVE /// Call has been held. case HELD /// Call has ended. case DONE /// The active call is being recovered. Usually after a network switch or bad network case RECONNECTING(reason: Reason) /// The active call is dropped. Usually when the network is lost. case DROPPED(reason: Reason) /// Enum to represent reasons for reconnection or call drop. public enum Reason: String { case networkSwitch = "Network switched" case networkLost = "Network lost" case serverError = "Server error" } /// Helper function to get the reason for the state (if applicable). public func getReason() -> String? { switch self { case let .RECONNECTING(reason), let .DROPPED(reason): return reason.rawValue default: return nil } } } ``` ## [1.1.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.1.0) (2025-02-17) ### Bug Fixes * Fix callstate sequence for outgoing and incoming calls * Fix network switch for foreground calls ## [1.0.0](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/1.0.0) (2025-02-11) ### Enhacement * Added forceRelayCandidate configuration: * Allows control over local network access on iOS. * When set to true, the connection will only use TURN servers, preventing local network candidate gathering and avoiding the permission popup. * Enabled SDK support for simulators on Mac with M-series chips: Improved compatibility to allow testing the SDK on Apple Silicon simulators. ## [0.1.42](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.42) (2025-02-04) ### Bug Fixes * Removed Bugsnag dependency ## [0.1.41](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.41) (2025-01-27) ### Bug Fixes * Improved the CallKit speaker button behavior to ensure consistent functionality. The button now accurately reflects the current audio output state. Adjustments were made to the RTCAudioSession handling to resolve the issue. ## [0.1.40](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.40) (2025-01-22) ### Bug Fixes * Fix build on SPM: Added Foundation imports. ## [0.1.39](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.39) (2025-01-10) ### Enhacement * Enable/Disable WebRTC Statistics: You can now toggle WebRTC Statistics. When enabled, all WebRTC stats are uploaded to our servers. These statistics can be accessed via the Telnyx Portal under the Object Storage section associated with the account used to generate the credentials for the SDK login. ## [0.1.38](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.38) (2024-11-13) ### Bug Fixes * Prevent adding ICE candidates after negotiation ends or connection is established ## [0.1.37](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.37) (2024-10-29) ### Bug Fixes * Enhanced WebSocket and RTC peer reconnection logic to ensure seamless recovery during network disconnections or switches. ## [0.1.36](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.36) (2024-10-17) ### Bug Fixes * Resolved a race condition affecting the handling of early "Bye" messages. ## [0.1.35](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.35) (2024-09-19) ### Bug Fixes * Privacy Manifest improvements ## [0.1.34](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.34) (2024-09-04) ### Enhancement * WebRTC Debug Report: upload debug data. ### Bug Fixes * Reconnect when network disconnect * Generic Client Error Fix for Attach Call Method : If attach\_call call fails the sdk invokes the remoteCallEnded(..) method to identify and end the call ## [0.1.33](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.33) (2024-08-28) ### Enhancement * WebRTC Debug Report: added timestamp and data type. ## [0.1.31](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.31) (2024-07-24) ### Feature * WebRTC Debug Report: Collect debug statistics ## [0.1.30](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.30) (2024-07-24) ### Bug Fixing * Fix Package.Swift file to support Swift Package Manager. ## [0.1.29](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.29) (2024-06-26) ### Bug Fixing * Updated sdpSemantics to use `unifiedPlan` * Fix WebRTC Audio Session ## [0.1.28](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.28) (2024-05-14) ### Bug Fixing * Privacy Manifest improvements ## [0.1.28](https://github.com/team-telnyx/telnyx-webrtc-ios/releases/tag/0.1.27) (2024-05-09) ### Bug Fixing * Added Privacy Manifest # WebRTC iOS Call Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/call-extensions/index A Call is the representation of an audio or video call between two devices, SIP clients or phone numbers. **EXTENSION** # `Call` ```swift theme={null} extension Call ``` ## Methods ### `iceRestart(completion:)` ```swift theme={null} public func iceRestart(completion: @escaping (_ success: Bool, _ error: Error?) -> Void) ``` Performs ICE restart to renegotiate ICE candidates when network conditions change This helps resolve audio delay issues by establishing new network paths * Parameter completion: Callback indicating success or failure of the ICE restart #### Parameters | Name | Description | | ---------- | --------------------------------------------------------- | | completion | Callback indicating success or failure of the ICE restart | ### `hangup()` ```swift theme={null} public func hangup() ``` Hangup or reject an incoming call. ### Example: call.hangup() ### `answer(customHeaders:debug:)` ```swift theme={null} public func answer(customHeaders:[String:String] = [:], debug:Bool = false) ``` Starts the process to answer the incoming call. Use this method to accept an incoming call and establish the WebRTC connection. ### Examples: ```swift theme={null} // Basic answer call.answer() // Answer with custom headers call.answer(customHeaders: ["X-Custom-Header": "Value"]) // Answer with debug mode call.answer(debug: true) ``` * Parameters: * customHeaders: (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. * debug: (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the `onCallQualityChange` callback. #### Parameters | Name | Description | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | customHeaders | (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. | | debug | (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the `onCallQualityChange` callback. | ### `dtmf(dtmf:)` ```swift theme={null} public func dtmf(dtmf: String) ``` Sends a DTMF (Dual-Tone Multi-Frequency) signal during an active call. DTMF signals are used to send digits and symbols over a phone line, typically for interacting with automated systems, voicemail, or IVR menus. * Parameter dtmf: A string containing a single DTMF character. Valid characters are: * Digits: 0-9 * Special characters: \* (asterisk), # (pound) * Letters: A-D (less commonly used) ## Examples: ```swift theme={null} // Navigate an IVR menu currentCall?.dtmf("1") // Select option 1 currentCall?.dtmf("0") // Select option 0 // Special characters currentCall?.dtmf("*") // Send asterisk currentCall?.dtmf("#") // Send pound/hash ``` Note: The call must be in ACTIVE state for DTMF signals to be sent successfully. Each DTMF tone should be sent individually with appropriate timing between tones when sending multiple digits. #### Parameters | Name | Description | | ---- | ------------------------------------------------------------------ | | dtmf | A string containing a single DTMF character. Valid characters are: | ### `muteAudio()` ```swift theme={null} public func muteAudio() ``` Turns off audio output, i.e. makes it so other call participants cannot hear your audio. ### Example: call.muteAudio() ### `unmuteAudio()` ```swift theme={null} public func unmuteAudio() ``` Turns on audio output, i.e. makes it so other call participants can hear your audio. ### Example: call.unmuteAudio() ### `resetAudioDevice()` ```swift theme={null} public func resetAudioDevice() ``` Resets the audio device and clears accumulated buffers to resolve persistent audio delay issues. This method addresses iOS audio delay problems where: * AudioDeviceModule buffers stretch under poor network conditions * WebRTC audio pacing causes frame accumulation * iOS AudioUnit/AVAudioSession remains in large buffer state ### Example: call.resetAudioDevice() ### `hold()` ```swift theme={null} public func hold() ``` Holds the call. ### Example: call.hold() ### `unhold()` ```swift theme={null} public func unhold() ``` Removes hold from the call. ### Example: call.unhold() ### `toggleHold()` ```swift theme={null} public func toggleHold() ``` Toggles between `active` and `held` state of the call. ### Example: call.toggleHold() # WebRTC iOS Call Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/call/index A Call is the representation of an audio or video call between two devices, SIP clients or phone numbers. **CLASS** # `Call` ```swift theme={null} public class Call ``` A Call represents an audio or video communication session between two endpoints: WebRTC Clients, SIP clients, or phone numbers. The Call object manages the entire lifecycle of a call, from initiation to termination, handling both outbound and inbound calls. A Call object is created in two scenarios: 1. When you initiate a new outbound call using TxClient's newCall method 2. When you receive an inbound call through the TxClientDelegate's onIncomingCall callback ## Key Features * Audio and video call support * Call state management (NEW, CONNECTING, RINGING, ACTIVE, HELD, DONE) * Mute/unmute functionality * DTMF tone sending * Custom headers support for both INVITE and ANSWER messages * Call statistics reporting when debug mode is enabled ## Examples ### Creating an Outbound Call: ```swift theme={null} // Initialize the client self.telnyxClient = TxClient() self.telnyxClient?.delegate = self // Connect the client (see TxClient documentation for connection options) self.telnyxClient?.connect(....) // Create and initiate a call self.currentCall = try self.telnyxClient?.newCall( callerName: "John Doe", // The name to display for the caller callerNumber: "155531234567", // The caller's phone number destinationNumber: "18004377950", // The target phone number or SIP URI callId: UUID.init(), // Unique identifier for the call clientState: nil, // Optional client state information customHeaders: [:] // Optional custom SIP headers ) ``` ### Handling an Incoming Call: ```swift theme={null} class CallHandler: TxClientDelegate { var activeCall: Call? func initTelnyxClient() { let client = TxClient() client.delegate = self client.connect(....) } func onIncomingCall(call: Call) { // Store the call reference self.activeCall = call // Option 1: Auto-answer the call call.answer() // Option 2: Answer with custom headers call.answer(customHeaders: ["X-Custom-Header": "Value"]) // Option 3: Reject the call // call.hangup() } } ``` ## Properties ### `onCallQualityChange` ```swift theme={null} public var onCallQualityChange: ((CallQualityMetrics) -> Void)? ``` Callback for real-time call quality metrics This is triggered whenever new WebRTC statistics are available ### `inviteCustomHeaders` ```swift theme={null} public internal(set) var inviteCustomHeaders: [String:String]? ``` Custom headers received from the WebRTC INVITE message. These headers are passed during call initiation and can contain application-specific information. Format should be \["X-Header-Name": "Value"] where header names must start with "X-". ### `answerCustomHeaders` ```swift theme={null} public internal(set) var answerCustomHeaders: [String:String]? ``` Custom headers received from the WebRTC ANSWER message. These headers are passed during call acceptance and can contain application-specific information. Format should be \["X-Header-Name": "Value"] where header names must start with "X-". ### `sessionId` ```swift theme={null} public internal(set) var sessionId: String? ``` The unique session identifier for the current WebRTC connection. This ID is established during client connection and remains constant for the session duration. ### `telnyxSessionId` ```swift theme={null} public internal(set) var telnyxSessionId: UUID? ``` The unique Telnyx session identifier for this call. This ID can be used to track the call in Telnyx's systems and logs. ### `telnyxLegId` ```swift theme={null} public internal(set) var telnyxLegId: UUID? ``` The unique Telnyx leg identifier for this call. A call can have multiple legs (e.g., in call transfers). This ID identifies this specific leg. ### `debug` ```swift theme={null} public internal(set) var debug: Bool = false ``` Enables WebRTC statistics reporting for debugging purposes. When true, the SDK will collect and send WebRTC statistics to Telnyx servers. This is useful for troubleshooting call quality issues. ### `enableQualityMetrics` ```swift theme={null} public internal(set) var enableQualityMetrics: Bool = false ``` Enables CallQuality Metrics for Call ### `sendWebRTCStatsViaSocket` ```swift theme={null} public internal(set) var sendWebRTCStatsViaSocket: Bool = false ``` Controls whether the SDK should send WebRTC statistics via socket to Telnyx servers. When enabled, collected WebRTC stats will be sent to Telnyx servers for monitoring and debugging. This is independent of stats collection - stats can be collected without being sent via socket. ### `useTrickleIce` ```swift theme={null} public internal(set) var useTrickleIce: Bool = false ``` Controls whether the SDK should use trickle ICE for WebRTC signaling. When enabled, ICE candidates are sent individually as they are discovered, rather than waiting for all candidates to be gathered before sending the offer/answer. ### `forceRelayCandidate` ```swift theme={null} public internal(set) var forceRelayCandidate: Bool = false ``` Controls whether the SDK should force TURN relay for peer connections. When enabled, the SDK will only use TURN relay candidates for ICE gathering, which prevents the "local network access" permission popup from appearing. ### `enableCallReports` ```swift theme={null} public internal(set) var enableCallReports: Bool = true ``` Enable automatic call quality reporting to voice-sdk-proxy. When enabled, WebRTC stats are collected periodically during calls and posted to the voice-sdk-proxy /call\_report endpoint when the call ends. ### `callReportInterval` ```swift theme={null} public internal(set) var callReportInterval: TimeInterval = 5.0 ``` Interval in seconds for collecting call statistics. Stats are aggregated over each interval and stored locally until call end. ### `callReportLogLevel` ```swift theme={null} public internal(set) var callReportLogLevel: String = "debug" ``` Minimum log level to capture for call reports ("debug", "info", "warn", "error"). ### `callReportMaxLogEntries` ```swift theme={null} public internal(set) var callReportMaxLogEntries: Int = 1000 ``` Maximum number of log entries to buffer per call. ### `callInfo` ```swift theme={null} public var callInfo: TxCallInfo? ``` Contains essential information about the current call including: * callId: Unique identifier for this call * callerName: Display name of the caller * callerNumber: Phone number or SIP URI of the caller See `TxCallInfo` for complete details. ### `callState` ```swift theme={null} public var callState: CallState = .NEW ``` The current state of the call. Possible values: * NEW: Call object created but not yet initiated * CONNECTING: Outbound call is being established * RINGING: Incoming call waiting to be answered * ACTIVE: Call is connected and media is flowing * HELD: Call is temporarily suspended * DONE: Call has ended The state changes are notified through the `CallProtocol` delegate. ### `isMuted` ```swift theme={null} public var isMuted: Bool ``` Indicates whether the local audio is currently muted. * Returns: `true` if the call is muted (audio track disabled) * Returns: `false` if the call is not muted (audio track enabled) Use `muteAudio()` and `unmuteAudio()` to change the mute state. ### `localStream` ```swift theme={null} public var localStream: RTCMediaStream? ``` The local media stream containing audio and/or video tracks being sent to the remote party. This stream represents the media captured from the local device (microphone, camera). Can be used for audio visualization, local video preview, or other media processing. ## Examples ```swift theme={null} // Access local audio tracks for visualization if let localStream = call.localStream { let audioTracks = localStream.audioTracks // Use audio tracks for waveform visualization } ``` ### `remoteStream` ```swift theme={null} public var remoteStream: RTCMediaStream? ``` The remote media stream containing audio and/or video tracks received from the remote party. This stream represents the media being received from the other participant in the call. Can be used for audio visualization, remote video display, or other media processing. ## Examples ```swift theme={null} // Access remote audio tracks for visualization if let remoteStream = call.remoteStream { let audioTracks = remoteStream.audioTracks // Use audio tracks for waveform visualization } ``` # WebRTC iOS Client Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/txclient-extensions/index The TelnyxRTC client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls **EXTENSION** # `TxClient` ```swift theme={null} extension TxClient ``` ## Methods ### `getCall(callId:)` ```swift theme={null} public func getCall(callId: UUID) -> Call? ``` This function can be used to access any active call tracked by the SDK. A call will be accessible until has ended (transitioned to the DONE state). * Parameter callId: The unique identifier of a call. * Returns: The` Call` object that matches the requested `callId`. Returns `nil` if no call was found. #### Parameters | Name | Description | | ------ | -------------------------------- | | callId | The unique identifier of a call. | ### `newCall(callerName:callerNumber:destinationNumber:callId:clientState:customHeaders:preferredCodecs:debug:)` ```swift theme={null} public func newCall(callerName: String, callerNumber: String, destinationNumber: String, callId: UUID, clientState: String? = nil, customHeaders:[String:String] = [:], preferredCodecs: [TxCodecCapability]? = nil, debug:Bool = false) throws -> Call ``` Creates a new Call and starts the call sequence, negotiate the ICE Candidates and sends the invite. This method initiates an outbound call to the specified destination. The call will go through WebRTC negotiation, ICE candidate gathering, and SIP signaling to establish the connection. ### Examples: ```swift theme={null} // Basic call let call = try telnyxClient.newCall( callerName: "John Doe", callerNumber: "1234567890", destinationNumber: "18004377950", callId: UUID() ) // Call with preferred audio codecs let preferredCodecs = [ TxCodecCapability(mimeType: "audio/opus", clockRate: 48000, channels: 2), TxCodecCapability(mimeType: "audio/PCMU", clockRate: 8000, channels: 1) ] let call = try telnyxClient.newCall( callerName: "John Doe", callerNumber: "1234567890", destinationNumber: "18004377950", callId: UUID(), preferredCodecs: preferredCodecs ) // Call with codecs and debug mode enabled let call = try telnyxClient.newCall( callerName: "John Doe", callerNumber: "1234567890", destinationNumber: "18004377950", callId: UUID(), customHeaders: ["X-Custom-Header": "Value"], preferredCodecs: preferredCodecs, debug: true ) ``` * Parameters: * callerName: The caller name. This will be displayed as the caller name in the remote's client. * callerNumber: The caller Number. The phone number of the current user. * destinationNumber: The destination `SIP user address` (sip:[YourSipUser@sip.telnyx.com](mailto:YourSipUser@sip.telnyx.com)) or `phone number`. * callId: The current call UUID. * clientState: (optional) Custom state in string format encoded in base64 * customHeaders: (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. * preferredCodecs: (optional) Array of preferred audio codecs in priority order. The SDK will attempt to use these codecs in the specified order during negotiation. If none of the preferred codecs are available, WebRTC will fall back to its default codec selection. Use `getSupportedAudioCodecs()` to retrieve available codecs before setting preferences. See the [Preferred Audio Codecs Guide](https://github.com/team-telnyx/telnyx-webrtc-ios#preferred-audio-codecs) for more information. * debug: (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the call's `onCallQualityChange` callback. * Throws: * sessionId is required if user is not logged in * socket connection error if socket is not connected * destination number is required to start a call. * Returns: The call that has been created #### Parameters | Name | Description | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | callerName | The caller name. This will be displayed as the caller name in the remote’s client. | | callerNumber | The caller Number. The phone number of the current user. | | destinationNumber | The destination `SIP user address` (sip:[YourSipUser@sip.telnyx.com](mailto:YourSipUser@sip.telnyx.com)) or `phone number`. | | callId | The current call UUID. | | clientState | (optional) Custom state in string format encoded in base64 | | customHeaders | (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. | | preferredCodecs | (optional) Array of preferred audio codecs in priority order. The SDK will attempt to use these codecs in the specified order during negotiation. If none of the preferred codecs are available, WebRTC will fall back to its default codec selection. Use `getSupportedAudioCodecs()` to retrieve available codecs before setting preferences. See the for more information. | | debug | (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the call’s `onCallQualityChange` callback. | ### `getSupportedAudioCodecs()` ```swift theme={null} public func getSupportedAudioCodecs() -> [TxCodecCapability] ``` Returns the list of supported audio codecs available for use in calls * Returns: Array of TxCodecCapability objects representing available audio codecs This method reuses the shared RTCPeerConnectionFactory instance for efficiency. The codec list is queried from WebRTC's native capabilities and remains consistent throughout the application lifecycle. ### Example: ```swift theme={null} let supportedCodecs = telnyxClient.getSupportedAudioCodecs() for codec in supportedCodecs { print("Codec: \(codec.mimeType), Clock Rate: \(codec.clockRate)") } ``` ### `processVoIPNotification(txConfig:serverConfiguration:pushMetaData:)` ```swift theme={null} public func processVoIPNotification(txConfig: TxConfig, serverConfiguration: TxServerConfiguration,pushMetaData:[String: Any]) throws ``` Call this function to process a VoIP push notification of an incoming call. This function will be executed when the app was closed and the user executes an action over the VoIP push notification. You will need to * Parameters: * txConfig: The desired configuration to login to B2B2UA. User credentials must be the same as the * serverConfiguration : required to setup from VoIP push notification metadata. * pushMetaData : meta data payload from VOIP Push notification (this should be gotten from payload.dictionaryPayload\["metadata"] as? \[String: Any]) * Throws: Error during the connection process #### Parameters | Name | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | txConfig | The desired configuration to login to B2B2UA. User credentials must be the same as the | | serverConfiguration | required to setup from VoIP push notification metadata. | | pushMetaData | meta data payload from VOIP Push notification (this should be gotten from payload.dictionaryPayload\[“metadata”] as? \[String: Any]) | ### `setEarpiece()` ```swift theme={null} public func setEarpiece() ``` Select the internal earpiece as the audio output ### `setSpeaker()` ```swift theme={null} public func setSpeaker() ``` Select the speaker as the audio output # WebRTC iOS Client Source: https://developers.telnyx.com/development/webrtc/ios-sdk/classes/txclient/index The TelnyxRTC client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls **CLASS** # `TxClient` ```swift theme={null} public class TxClient ``` The `TelnyxRTC` client connects your application to the Telnyx backend, enabling you to make outgoing calls and handle incoming calls. ## Examples ### Connect and login: ``` // Initialize the client let telnyxClient = TxClient() // Register to get SDK events telnyxClient.delegate = self // Setup yor connection parameters. // Set the login credentials and the ringtone/ringback configurations if required. // Ringtone / ringback tone files are not mandatory. // You can user your sipUser and password let txConfigUserAndPassowrd = TxConfig(sipUser: sipUser, password: password, ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", //You can choose the appropriate verbosity level of the SDK. //Logs are disabled by default logLevel: .all) // Use a JWT Telnyx Token to authenticate (recommended) let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", //You can choose the appropriate verbosity level of the SDK. Logs are disabled by default logLevel: .all) do { // Connect and login // Use `txConfigUserAndPassowrd` or `txConfigToken` try telnyxClient.connect(txConfig: txConfigToken) } catch let error { print("ViewController:: connect Error \(error)") } // You can call client.disconnect() when you're done. Note: you need to relese the delegate manually when you are done. // Disconnecting and Removing listeners. telnyxClient.disconnect(); // Release the delegate telnyxClient.delegate = nil ``` ### Listen TxClient delegate events. ``` extension ViewController: TxClientDelegate { func onRemoteCallEnded(callId: UUID) { // Call has been removed internally. } func onSocketConnected() { // When the client has successfully connected to the Telnyx Backend. } func onSocketDisconnected() { // When the client from the Telnyx backend } func onClientError(error: Error) { // Something went wrong. } func onClientReady() { // You can start receiving incoming calls or // start making calls once the client was fully initialized. } func onSessionUpdated(sessionId: String) { // This function will be executed when a sessionId is received. } func onIncomingCall(call: Call) { // Someone is calling you. } // You can update your UI from here base on the call states. // Check that the callId is the same as your current call. func onCallStateUpdated(callState: CallState, callId: UUID) { DispatchQueue.main.async { switch (callState) { case .CONNECTING: break case .RINGING: break case .NEW: break case .ACTIVE: break case .DONE: break case .HELD: break } } } } ``` ## Properties ### `calls` ```swift theme={null} public internal(set) var calls: [UUID: Call] = [UUID: Call]() ``` Keeps track of all the created calls by theirs UUIDs ### `delegate` ```swift theme={null} public weak var delegate: TxClientDelegate? ``` Subscribe to TxClient delegate to receive Telnyx SDK events ### `aiAssistantManager` ```swift theme={null} public let aiAssistantManager = AIAssistantManager() ``` AI Assistant Manager for handling AI-related functionality ### `isSpeakerEnabled` ```swift theme={null} public private(set) var isSpeakerEnabled: Bool ``` ### `isAudioDeviceEnabled` ```swift theme={null} public var isAudioDeviceEnabled : Bool ``` Controls the audio device state when using CallKit integration. This property manages the WebRTC audio session activation and deactivation. When implementing CallKit, you must manually handle the audio session state: * Set to `true` in `provider(_:didActivate:)` to enable audio * Set to `false` in `provider(_:didDeactivate:)` to disable audio Example usage with CallKit: ```swift theme={null} extension CallKitProvider: CXProviderDelegate { func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { telnyxClient.isAudioDeviceEnabled = true } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { telnyxClient.isAudioDeviceEnabled = false } } ``` ### `isRegistered` ```swift theme={null} public var isRegistered: Bool ``` Client must be registered in order to receive or place calls. ## Methods ### `enableAudioSession(audioSession:)` ```swift theme={null} public func enableAudioSession(audioSession: AVAudioSession) ``` Enables and configures the audio session for a call. This method sets up the appropriate audio configuration and activates the session. * Parameter audioSession: The AVAudioSession instance to configure * Important: This method MUST be called from the CXProviderDelegate's `provider(_:didActivate:)` callback to properly handle audio routing when using CallKit integration. Example usage: ```swift theme={null} func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { print("provider:didActivateAudioSession:") self.telnyxClient.enableAudioSession(audioSession: audioSession) } ``` #### Parameters | Name | Description | | ------------ | ---------------------------------------- | | audioSession | The AVAudioSession instance to configure | ### `disableAudioSession(audioSession:)` ```swift theme={null} public func disableAudioSession(audioSession: AVAudioSession) ``` Disables and resets the audio session. This method cleans up the audio configuration and deactivates the session. * Parameter audioSession: The AVAudioSession instance to reset * Important: This method MUST be called from the CXProviderDelegate's `provider(_:didDeactivate:)` callback to properly clean up audio resources when using CallKit integration. Example usage: ```swift theme={null} func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { print("provider:didDeactivateAudioSession:") self.telnyxClient.disableAudioSession(audioSession: audioSession) } ``` #### Parameters | Name | Description | | ------------ | ------------------------------------ | | audioSession | The AVAudioSession instance to reset | ### `init()` ```swift theme={null} public init() ``` TxClient has to be instantiated. ### `deinit` ```swift theme={null} deinit ``` Deinitializer to ensure proper cleanup of resources ### `connect(txConfig:serverConfiguration:)` ```swift theme={null} public func connect(txConfig: TxConfig, serverConfiguration: TxServerConfiguration = TxServerConfiguration()) throws ``` Connects to the iOS cloglient to the Telnyx signaling server using the desired login credentials. * Parameters: * txConfig: The desired login credentials. See TxConfig docummentation for more information. * serverConfiguration: (Optional) To define a custom `signaling server` and `TURN/ STUN servers`. As default we use the internal Telnyx Production servers. * Throws: TxConfig parameters errors #### Parameters | Name | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | txConfig | The desired login credentials. See TxConfig docummentation for more information. | | serverConfiguration | (Optional) To define a custom `signaling server` and `TURN/ STUN servers`. As default we use the internal Telnyx Production servers. | ### `disconnect()` ```swift theme={null} public func disconnect() ``` Disconnects the TxClient from the Telnyx signaling server. ### `isConnected()` ```swift theme={null} public func isConnected() -> Bool ``` To check if TxClient is connected to Telnyx server. * Returns: `true` if TxClient socket is connected, `false` otherwise. ### `answerFromCallkit(answerAction:customHeaders:debug:)` ```swift theme={null} public func answerFromCallkit(answerAction: CXAnswerCallAction, customHeaders: [String:String] = [:], debug: Bool = false) ``` Answers an incoming call from CallKit and manages the active call flow. This method should be called from the CXProviderDelegate's `provider(_:perform:)` method when handling a `CXAnswerCallAction`. It properly integrates with CallKit to answer incoming calls. ### Examples: ```swift theme={null} extension CallKitProvider: CXProviderDelegate { func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { // Basic answer telnyxClient.answerFromCallkit(answerAction: action) // Answer with custom headers and debug mode telnyxClient.answerFromCallkit( answerAction: action, customHeaders: ["X-Custom-Header": "Value"], debug: true ) } } ``` * Parameters: * answerAction: The `CXAnswerCallAction` provided by CallKit's provider delegate. * customHeaders: (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. * debug: (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the call's `onCallQualityChange` callback. #### Parameters | Name | Description | | ------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | answerAction | The `CXAnswerCallAction` provided by CallKit’s provider delegate. | | customHeaders | (optional) Custom Headers to be passed over webRTC Messages. Headers should be in the format `X-key:Value` where `X-` prefix is required for custom headers. When calling AI Agents, headers with the `X-` prefix will be mapped to dynamic variables (e.g., `X-Account-Number` becomes `{{account_number}}`). Hyphens in header names are converted to underscores in variable names. | | debug | (optional) Enable debug mode for call quality metrics and WebRTC statistics. When enabled, real-time call quality metrics will be available through the call’s `onCallQualityChange` callback. | ### `endCallFromCallkit(endAction:callId:)` ```swift theme={null} public func endCallFromCallkit(endAction: CXEndCallAction, callId: UUID? = nil) ``` To end and control callKit active and conn ### `disablePushNotifications()` ```swift theme={null} public func disablePushNotifications() ``` To disable push notifications for the current user ### `getSessionId()` ```swift theme={null} public func getSessionId() -> String ``` Get the current session ID after logging into Telnyx Backend. * Returns: The current sessionId. If this value is empty, that means that the client is not connected to Telnyx server. ### `anonymousLogin(targetId:targetType:targetVersionId:userVariables:reconnection:serverConfiguration:)` ```swift theme={null} public func anonymousLogin( targetId: String, targetType: String = "ai_assistant", targetVersionId: String? = nil, userVariables: [String: Any] = [:], reconnection: Bool = false, serverConfiguration: TxServerConfiguration = TxServerConfiguration() ) ``` Performs an anonymous login to the Telnyx backend for AI assistant connections. This method allows connecting to AI assistants without traditional authentication. If the socket is already connected, the anonymous login message is sent immediately. If not connected, the socket connection process is started, and the anonymous login message is sent once the connection is established. * Parameters: * targetId: The target ID for the AI assistant * targetType: The target type (defaults to "ai\_assistant") * targetVersionId: Optional target version ID * userVariables: Optional user variables to include in the login * reconnection: Whether this is a reconnection attempt (defaults to false) * serverConfiguration: Server configuration to use for connection (defaults to TxServerConfiguration()) #### Parameters | Name | Description | | ------------------- | -------------------------------------------------------------------------------- | | targetId | The target ID for the AI assistant | | targetType | The target type (defaults to “ai\_assistant”) | | targetVersionId | Optional target version ID | | userVariables | Optional user variables to include in the login | | reconnection | Whether this is a reconnection attempt (defaults to false) | | serverConfiguration | Server configuration to use for connection (defaults to TxServerConfiguration()) | ### `sendRingingAck(callId:)` ```swift theme={null} public func sendRingingAck(callId: String) ``` Send a ringing acknowledgment message for a specific call * Parameter callId: The call ID to acknowledge #### Parameters | Name | Description | | ------ | -------------------------- | | callId | The call ID to acknowledge | ### `sendAIAssistantMessage(_:)` ```swift theme={null} public func sendAIAssistantMessage(_ message: String) -> Bool ``` Send a text message to AI Assistant during active call (mixed-mode communication) * Parameter message: The text message to send to AI assistant * Returns: True if message was sent successfully, false otherwise #### Parameters | Name | Description | | ------- | ---------------------------------------- | | message | The text message to send to AI assistant | ### `sendAIAssistantMessage(_:base64Images:imageFormat:)` ```swift theme={null} public func sendAIAssistantMessage(_ message: String, base64Images: [String]?, imageFormat: String = "jpeg") -> Bool ``` Send a text message with multiple Base64 encoded images to AI Assistant during active call * Parameters: * message: The text message to send to AI assistant * base64Images: Optional array of Base64 encoded image data (without data URL prefix) * imageFormat: Image format (jpeg, png, etc.). Defaults to "jpeg" * Returns: True if message was sent successfully, false otherwise #### Parameters | Name | Description | | ------------ | --------------------------------------------------------------------- | | message | The text message to send to AI assistant | | base64Images | Optional array of Base64 encoded image data (without data URL prefix) | | imageFormat | Image format (jpeg, png, etc.). Defaults to “jpeg” | # WebRTC iOS Call State Source: https://developers.telnyx.com/development/webrtc/ios-sdk/enums/call-state/index CallState represents the state of the call **ENUM** # `CallState` ```swift theme={null} public enum CallState: Equatable ``` `CallState` represents the state of the call ## Cases ### `NEW` ```swift theme={null} case NEW ``` New call has been created in the client. ### `CONNECTING` ```swift theme={null} case CONNECTING ``` The outbound call is being sent to the server. ### `RINGING` ```swift theme={null} case RINGING ``` Call is pending to be answered. Someone is attempting to call you. ### `ACTIVE` ```swift theme={null} case ACTIVE ``` Call is active when two clients are fully connected. ### `HELD` ```swift theme={null} case HELD ``` Call has been held. ### `DONE(reason:)` ```swift theme={null} case DONE(reason: CallTerminationReason? = nil) ``` Call has ended. ### `RECONNECTING(reason:)` ```swift theme={null} case RECONNECTING(reason: Reason) ``` The active call is being recovered. Usually after a network switch or bad network ### `DROPPED(reason:)` ```swift theme={null} case DROPPED(reason: Reason) ``` The active call is dropped. Usually when the network is lost. ## Methods ### `getReason()` ```swift theme={null} public func getReason() -> String? ``` Helper function to get the reason for the state (if applicable). ### `==(_:_:)` ```swift theme={null} public static func == (lhs: CallState, rhs: CallState) -> Bool ``` #### Parameters | Name | Description | | ---- | ------------------------- | | lhs | A value to compare. | | rhs | Another value to compare. | # WebRTC iOS SDK Error Handling Source: https://developers.telnyx.com/development/webrtc/ios-sdk/error-handling/index A comprehensive record of all updates, enhancements, and bug fixes. Stay informed about the latest features and improvements to optimize your development experience. ## Error Handling This document provides a comprehensive overview of error handling in the Telnyx WebRTC iOS SDK, including when the `onClientError` callback is triggered, the types of errors that can occur, and how the SDK handles reconnection attempts. ## Table of Contents 1. [Introduction](#introduction) 2. [Error Constants Reference](#error-constants-reference) 3. [Call Termination Reasons](#call-termination-reasons) 4. [The `onClientError` Callback](#the-onclienterror-callback) 5. [Error Types](#error-types) * [Server Errors](#server-errors) * [Local Errors](#local-errors) * [Socket Connection Errors](#socket-connection-errors) 6. [Reconnection Process](#reconnection-process) 7. [Best Practices](#best-practices) ## Introduction The Telnyx WebRTC iOS SDK provides robust error handling mechanisms to help developers manage various error scenarios that may occur during the lifecycle of a WebRTC connection. Understanding these error handling mechanisms is crucial for building reliable applications that can gracefully recover from failures. ## Error Constants Reference The following table lists all error constants used in the Telnyx WebRTC iOS SDK: | ERROR MESSAGE | ERROR CODE | DESCRIPTION | | ----------------------------- | ---------- | ------------------------------------ | | Token registration error | -32000 | Error during token registration | | Credential registration error | -32001 | Error during credential registration | | Codec error | -32002 | Error related to codec operation | | Gateway registration timeout | -32003 | Gateway registration timed out | | Gateway registration failed | -32004 | Gateway registration failed | | Call not found | N/A | The specified call cannot be found | ## Call Termination Reasons The SDK now provides detailed information about why a call has ended through the `CallState.DONE(reason: CallTerminationReason?)` state. The `CallTerminationReason` structure contains the following fields: | FIELD | TYPE | DESCRIPTION | | --------- | ------- | ---------------------------------------------------------------------------------- | | cause | String? | General cause description (e.g., "CALL\_REJECTED", "USER\_BUSY") | | causeCode | Int? | Numerical code for the cause (e.g., 21 for CALL\_REJECTED) | | sipCode | Int? | SIP response code (e.g., 403, 404) | | sipReason | String? | SIP reason phrase (e.g., "Dialed number is not included in whitelisted countries") | ### Common Cause Values | CAUSE | DESCRIPTION | | ------------------- | ---------------------------------------------- | | CALL\_REJECTED | The call was rejected by the remote party | | UNALLOCATED\_NUMBER | The dialed number is invalid or does not exist | | USER\_BUSY | The remote user is busy | | NORMAL\_CLEARING | Normal call termination | ### Example Usage ```swift theme={null} func onCallStateUpdated(callState: CallState) { switch callState { case .DONE(let reason): if let reason = reason { if let sipCode = reason.sipCode, let sipReason = reason.sipReason { // Handle specific SIP error print("Call failed with SIP code \(sipCode): \(sipReason)") } else if let cause = reason.cause { // Handle general cause print("Call ended: \(cause)") } } else { // Normal call end print("Call ended normally") } // Handle other states... default: break } } ``` ## The `onClientError` Callback The `onClientError` callback is part of the `TxClientDelegate` protocol and is triggered when an error occurs in the SDK. This callback provides a way for your application to be notified of errors and take appropriate action. ```swift theme={null} func onClientError(error: Error) ``` ### When is `onClientError` Called? The `onClientError` callback is triggered in the following scenarios: 1. **Gateway Registration Failure**: When the client fails to register with the Telnyx gateway after multiple retry attempts. * Error Type: `TxError.serverError(reason: .gatewayNotRegistered)` 2. **Server Error Messages**: When the server sends an error message through the WebSocket connection. * Error Type: `TxError.serverError(reason: .signalingServerError(message: String, code: String))` (Legacy) * Error Type: `TxError.signalingServerError(causeCode: Int, message: String)` (New) 3. **Socket Connection Errors**: When there are issues with the WebSocket connection. * These errors are propagated through the Socket class to the TxClient. ## Error Types The SDK uses the `TxError` enum to represent different types of errors that can occur. Understanding these error types can help you handle specific error scenarios appropriately. ### Server Errors Server errors are represented by the `TxError.serverError` case with a `ServerErrorReason` enum or the new `TxError.signalingServerError` case: ```swift theme={null} public enum ServerErrorReason { /// Any server signaling error. We get the message and code from the server case signalingServerError(message: String, code: String) /// Gateway is not registered. case gatewayNotRegistered } /// When the signaling server sends an error with a cause code and message case signalingServerError(causeCode: Int, message: String) ``` #### Signaling Server Errors These errors occur when the Telnyx signaling server returns an error response. The error includes: * A message describing the error * An error code (as an integer in the new format) Common signaling server errors include: | ERROR CODE | ERROR MESSAGE | DESCRIPTION | | ---------- | ----------------------------- | ------------------------------------ | | -32000 | Token registration error | Error during token registration | | -32001 | Credential registration error | Error during credential registration | | -32002 | Codec error | Error related to codec operation | | -32003 | Gateway registration timeout | Gateway registration timed out | | -32004 | Gateway registration failed | Gateway registration failed | | N/A | Call not found | The specified call cannot be found | These errors typically occur during authentication, call setup, or when interacting with the signaling server. #### Gateway Not Registered Errors This error occurs when the client fails to register with the Telnyx gateway after multiple retry attempts (default: 3 attempts). This can happen due to: * Network connectivity issues * Invalid credentials * Server-side issues ### Local Errors Local errors are errors that occur within the SDK itself, not directly related to server communication: 1. **Client Configuration Errors** (`TxError.clientConfigurationFailed`): * Missing username/password when using credential-based authentication * Missing token when using token-based authentication * Missing required configuration parameters 2. **Call Errors** (`TxError.callFailed`): * Missing destination number when placing an outbound call * Missing session ID when starting a call (indicates the client is not properly connected) ### Socket Connection Errors Socket connection errors are represented by the `TxError.socketConnectionFailed` case with a `SocketFailureReason` enum: ```swift theme={null} public enum SocketFailureReason { /// Socket is not connected. Check that you have an active connection. case socketNotConnected /// Socket connection was cancelled. case socketCancelled(nativeError: Error) } ``` These errors occur when: * The WebSocket connection cannot be established * The connection is interrupted or closed unexpectedly * The connection attempt is cancelled ## Reconnection Process The SDK includes an automatic reconnection mechanism to handle temporary network issues: 1. **Gateway Registration Retry**: * When the gateway state check fails, the SDK will retry up to 3 times (configurable via `MAX_REGISTER_RETRY`) * Each retry occurs after a fixed interval (default: 3 seconds, set by `DEFAULT_REGISTER_INTERVAL`) * If all retries fail, an `onClientError` with `gatewayNotRegistered` reason is triggered 2. **Network Monitoring**: * The SDK includes a `NetworkMonitor` class that continuously monitors network connectivity * When network state changes (e.g., from no connection to WiFi), the SDK attempts to reconnect automatically * Network state changes are handled in the `onNetworkStateChange` callback 3. **Call Reconnection**: * When network connectivity is lost during an active call, the call state is updated to `DROPPED` with a `networkLost` reason * When connectivity is restored, the SDK attempts to reconnect the client ## Best Practices To effectively handle errors in your application: 1. **Always implement the `onClientError` callback** in your `TxClientDelegate`: ```swift theme={null} func onClientError(error: Error) { if let txError = error as? TxError { switch txError { case .serverError(let reason): // Handle server errors switch reason { case .gatewayNotRegistered: // Handle gateway registration failure case .signalingServerError(let message, let code): // Handle signaling server errors (legacy format) } case .signalingServerError(let causeCode, let message): // Handle signaling server errors with cause code switch causeCode { case -32000: // Handle token registration error case -32001: // Handle credential registration error case -32002: // Handle codec error case -32003: // Handle gateway registration timeout case -32004: // Handle gateway registration failed default: // Handle other signaling server errors if message.contains("Call not found") { // Handle call not found error } } case .socketConnectionFailed(let reason): // Handle socket connection failures case .clientConfigurationFailed(let reason): // Handle configuration errors case .callFailed(let reason): // Handle call-specific errors } } // Update UI or take appropriate action } ``` 2. **Understand the difference between socket connection and client registration**: * **Socket Connection**: Represents the WebSocket connection to the Telnyx server * Managed through `onSocketConnected()` and `onSocketDisconnected()` callbacks * Only indicates that a network connection to the server exists * A connected socket does NOT mean the client is ready to make/receive calls * **Client Registration (Gateway State)**: Represents the SIP registration state * Managed through the `onClientReady()` callback * Only when this callback is triggered is the client fully registered and ready * The client must be in the `REGED` state to make/receive calls * Registration happens automatically after socket connection is established 3. **Handle the registration retry process**: * The SDK automatically attempts to register with the gateway up to 3 times (configurable via `MAX_REGISTER_RETRY`) * Each retry occurs after a fixed interval (default: 3 seconds) * If all retries fail, an `onClientError` with `gatewayNotRegistered` reason is triggered * Example implementation: ```swift theme={null} func onClientError(error: Error) { if let txError = error as? TxError, case .serverError(let reason) = txError, case .gatewayNotRegistered = reason { // Registration failed after multiple attempts showRegistrationFailureUI() // You might want to implement your own retry logic here DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) { // Attempt to reconnect after 5 seconds try? client.connect(txConfig: yourTxConfig) } } } ``` 4. **Handle call reconnection during network changes**: * The SDK includes network state monitoring that detects: * Network type changes (WiFi to cellular, etc.) * Airplane mode toggling * Network loss and recovery * **Call States During Reconnection**: * When network is lost during a call, the call state changes to `DROPPED` with reason `.networkLost` * During reconnection attempts, the call state changes to `RECONNECTING` with reason `.networkSwitch` * When a call ends with an error, the call state changes to `DONE` with a `CallTerminationReason` containing details * Your UI should reflect these states to keep users informed * Example implementation: ```swift theme={null} func onCallStateUpdated(callState: CallState, callId: UUID) { switch callState { case .RECONNECTING(let reason): if reason == .networkSwitch { // Show reconnecting UI showReconnectingIndicator() } case .DROPPED(let reason): if reason == .networkLost { // Show network lost UI showNetworkLostIndicator() } case .DONE(let terminationReason): if let reason = terminationReason { // Show call termination reason if let sipCode = reason.sipCode, let sipReason = reason.sipReason { showErrorMessage("Call failed: \(sipReason) (SIP \(sipCode))") } else if let cause = reason.cause { showErrorMessage("Call ended: \(cause)") } else { hideCallUI() } } else { // Normal call end hideCallUI() } case .ACTIVE: // Call is active again after reconnection hideReconnectingIndicator() default: break } } ``` 5. **Monitor socket and client states together**: * A client can be disconnected from the socket but still in an ongoing call reconnection process * Always check both the socket connection state and call states when making UI decisions * Example implementation: ```swift theme={null} func onSocketDisconnected() { // Only show disconnected UI if there are no active calls in reconnection if !hasActiveCallsInReconnection() { showDisconnectedUI() } else { showReconnectingUI() } } private func hasActiveCallsInReconnection() -> Bool { // Check if any calls are in RECONNECTING state return client.calls.values.contains { call in if case .RECONNECTING = call.callState { return true } return false } } ``` 6. **Log errors** for debugging purposes: * Use the error information provided in the callbacks to log detailed error information * Include error codes and messages in your logs to help with troubleshooting # Voice native iOS Client SDK Source: https://developers.telnyx.com/development/webrtc/ios-sdk/index Telnyx's Voice native iOS Client SDK # Telnyx-webrtc-ios Enable Telnyx real-time communication services on iOS. ## Project Structure * SDK project: Enable Telnyx WebRTC communications. * SDK Tests project. * Demo app project. ## Project Setup: 1. Clone the repository 2. Run the command `pod install` to install the dependencies inside the project root folder. 3. Open the Workspace : `TelnyxRTC.xcworkspace` 4. **Configure the Demo App (Optional):** * The `Config.xcconfig` file is included in the repository with default values * To use the Pre-call Diagnosis feature, edit `Config.xcconfig` and set a valid phone number: ``` PHONE_NUMBER = +15551234567 ``` * If you don't need Pre-call Diagnosis, you can leave `PHONE_NUMBER` empty 5. You will find 3 targets to build: * The SDK * The SDK Tests * The Demo App

Screen Shot 2021-05-04 at 18 34 45

5. Select the target `TelnyxRTC (TelnyxRTC Project)` to build the SDK

Screen Shot 2021-05-04 at 18 35 18

7. Select the target `TelnyxRTCTests` to run the tests. You will need to long press over the Run button and select `Build for testing`

Screen Shot 2021-03-03 at 10 04 05

7. Select target `TelnyxWebRTCDemo` to run the demo app. The SDK should be manually built in order to get the app running (Step 5) ## SIP Credentials In order to start making and receiving calls using the TelnyxRTC SDK you will need to get SIP Credentials: 1. Access to [https://portal.telnyx.com/](https://portal.telnyx.com/) 2. Sign up for a Telnyx Account. 3. Create a Credential Connection to configure how you connect your calls. 4. Create an Outbound Voice Profile to configure your outbound call settings and assign it to your Credential Connection. For more information on how to generate SIP credentials check the [Telnyx WebRTC quickstart guide](https://developers.telnyx.com/docs/v2/webrtc/quickstart). ## Region Selection The TelnyxRTC SDK supports connecting to different geographic regions to optimize call quality and reduce latency. The demo app includes a region selection feature that allows users to choose their preferred region. ### Available Regions * **Auto (Default)**: Automatically selects the best region based on network conditions * **US East**: East coast United States servers * **US Central**: Central United States servers * **US West**: West coast United States servers * **Canada Central**: Central Canada servers * **Europe**: European servers * **Asia Pacific**: Asia Pacific servers ### Using Region Selection 1. **In the Demo App**: Use the overflow menu (⋯) to access region selection. The current region is displayed as "Region: \[current-region]". 2. **In Your App**: Configure the region when creating a `TxServerConfiguration`: ```swift theme={null} // Set specific region let serverConfig = TxServerConfiguration( environment: .production, region: .usEast // or .eu, .usCentral, .usWest, .caCentral, .apac ) // Use auto region selection (default) let serverConfig = TxServerConfiguration( environment: .production, region: .auto ) try telnyxClient.connect(txConfig: txConfig, serverConfiguration: serverConfig) ``` ### Region Selection Behavior * **During Active Calls**: Region selection is automatically disabled during active calls to prevent connection disruption * **When Connected**: Region selection is disabled when the client is connected to prevent disrupting the established connection * **Fallback Logic**: If a regional server is unavailable, the SDK automatically falls back to the auto region * **Persistence**: The selected region persists across app sessions until manually changed ### Best Practices * Use **Auto** region for the best overall experience unless you have specific latency requirements * Select a region **geographically close** to your users for optimal call quality * Test different regions in your target deployment areas to determine the best performance ## Adding Telnyx SDK to your iOS Client Application: Currently the iOS SDK is supported using cocoapods. ### Cocoapods If your xcode project is not using [cocoapods](https://cocoapods.org/) yet, you will need to configure it. 1. Open your podfile and add the TelnyxRTC. ``` pod 'TelnyxRTC', '~> 0.1.0' ``` 2. Install your pods. You can add the flag --repo-update to ensure your cocoapods has the specs updated. ``` pod install --repo-update ``` 3. Open your .xcworkspace 4. Import TelnyxRTC at the top level of your class: ``` import TelnyxRTC ``` 5. Disable BITCODE (The GoogleWebRTC dependency has BITCODE disabled): Go to the Build Settings tab of your app target, search for “bitcode” and set it to “NO”

Screen Shot 2021-05-07 at 17 46 08

6. Enable VoIP and Audio background modes: Go to Signing & Capabilities tab, press the +Capability button and add those background modes:

Screen Shot 2021-05-07 at 17 46 54

7. Go to your Info.plist file and add the “Privacy - Microphone Usage Description” key with a description that your app requires microphone access in order to make VoIP calls.

Screen Shot 2021-05-07 at 17 48 17

8. You are all set! ### Swift Package Manager Xcode has a built-in support for Swift package manager. To add a package : 1. Select Files > Add Packages 2. On the Swift Package Manager Screen, Search for the [https://github.com/team-telnyx/telnyx-webrtc-ios.git](https://github.com/team-telnyx/telnyx-webrtc-ios.git) package. 3. Select the **main brach** and click Add Package

Screen Shot 2021-05-07 at 17 48 17

NB: if Add Package is stuck downloading try File > Packages > Reset Package Caches or Run the command `rm -rf ~/Library/Caches/org.swift.swiftpm/` in terminal Read more in [Apple documentation](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app) **Hint: Use either Cocoapods or Swift Package Manager for Individual Packages to avoid Duplicate binaries** ## Usage ### Telnyx client setup ```Swift theme={null} // Initialize the client let telnyxClient = TxClient() // Register to get SDK events telnyxClient.delegate = self // Setup yor connection parameters. // Set the login credentials and the ringtone/ringback configurations if required. // Ringtone / ringback tone files are not mandatory. // You can user your sipUser and password let txConfigUserAndPassowrd = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "DEVICE_APNS_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", // Force TURN relay to avoid local network access forceRelayCandidate: true, //You can choose the appropriate verbosity level of the SDK. //Logs are disabled by default logLevel: .all) // Or use a JWT Telnyx Token to authenticate let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN", pushDeviceToken: "DEVICE_APNS_TOKEN", ringtone: "incoming_call.mp3", ringBackTone: "ringback_tone.mp3", // Force TURN relay to avoid local network access forceRelayCandidate: true, //You can choose the appropriate verbosity level of the SDK. Logs are disabled by default logLevel: .all) do { // Connect and login // Use `txConfigUserAndPassowrd` or `txConfigToken` try telnyxClient.connect(txConfig: txConfigToken) } catch let error { print("ViewController:: connect Error \(error)") } // You can call client.disconnect() when you're done. Note: you need to release the delegate manually when you are done. // Disconnecting and Removing listeners. telnyxClient.disconnect(); // Release the delegate telnyxClient.delegate = nil ``` ### Telnyx client delegate You will need to instantiate the client and set the delegate. ```Swift theme={null} // Initialize the client let telnyxClient = TxClient() // Register to get SDK events telnyxClient.delegate = self ``` Then you will receive the following events: ```Swift theme={null} extension ViewController: TxClientDelegate { func onRemoteCallEnded(callId: UUID) { // Call has been removed internally. } func onSocketConnected() { // When the client has successfully connected to the Telnyx Backend. } func onSocketDisconnected() { // When the client from the Telnyx backend } func onClientError(error: Error) { // Something went wrong. } func onClientReady() { // You can start receiving incoming calls or // start making calls once the client was fully initialized. } func onSessionUpdated(sessionId: String) { // This function will be executed when a sessionId is received. } func onIncomingCall(call: Call) { // Someone is calling you. // This delegate method will be called when the app is in foreground and the Telnyx Client is connected. } func onPushCall(call: Call) { // If you have configured Push Notifications and app is in background or the Telnyx Client is disconnected // this delegate method will be called after the push notification is received. // Update the current call with the incoming call self.currentCall = call } // You can update your UI from here based on the call states. // Check that the callId is the same as your current call. func onCallStateUpdated(callState: CallState, callId: UUID) { // handle the new call state switch (callState) { case .CONNECTING: break case .RINGING: break case .NEW: break case .ACTIVE: break case .DONE(let reason): // The DONE state may include a termination reason with details about why the call ended if let reason = reason { print("Call ended with reason: \(reason.cause ?? "Unknown")") print("SIP code: \(reason.sipCode ?? 0), SIP reason: \(reason.sipReason ?? "None")") } break case .HELD: break case .RECONNECTING(let reason): print("Call reconnecting: \(reason.rawValue)") break case .DROPPED(let reason): print("Call dropped: \(reason.rawValue)") break } } } ``` ## Calls ### Outboud call ```Swift theme={null} // Create a client instance self.telnyxClient = TxClient() // Asign the delegate to get SDK events self.telnyxClient?.delegate = self // Connect the client (Check TxClient class for more info) self.telnyxClient?.connect(....) // Create the call and start calling self.currentCall = try self.telnyxClient?.newCall(callerName: "Caller name", callerNumber: "155531234567", // Destination is required and can be a phone number or SIP URI destinationNumber: "18004377950", callId: UUID.init()) ``` This is a general example: In order to fully support outbound calls you will need to implement CallKit to properly handle audio states. For more information check `Audio Session Handling WebRTC + CallKit` section. ### Inbound call How to answer an incoming call: ```Swift theme={null} //Init your client func initTelnyxClient() { // self.telnyxClient = TxClient() // Asign the delegate to get SDK events self.telnyxClient?.delegate = self // Connect the client (Check TxClient class for more info) self.telnyxClient?.connect(....) } extension ViewController: TxClientDelegate { //.... func onIncomingCall(call: Call) { // We are automatically answering any incoming call as an example, but // maybe you want to store a reference of the call, and answer the call after a button press. self.myCall = call.answer() } } ``` This is a general example: In order to fully support inbound calls you will need to implement PushKit + CallKit. For more information check `Setting up VoIP push notifications` section. *** ## AI Agent Integration The Telnyx iOS WebRTC SDK provides comprehensive support for AI Agent functionality, enabling intelligent voice applications with real-time conversation capabilities. ### Key Features * **Anonymous Authentication**: Connect to AI assistants without SIP credentials * **Real-time Transcripts**: Live conversation transcripts with role identification * **Mixed Communication**: Send text messages during voice calls * **Widget Settings**: Customizable AI assistant interface ### Quick Start ```swift theme={null} import TelnyxRTC class AIAgentViewController: UIViewController { private let client = TxClient() private var currentCall: Call? override func viewDidLoad() { super.viewDidLoad() client.delegate = self setupAIAgent() } private func setupAIAgent() { // Step 1: Anonymous login to AI assistant client.anonymousLogin( targetId: "your-ai-assistant-id", targetType: "ai_assistant" ) } private func startConversation() { // Step 2: Start conversation (destination ignored after anonymous login) currentCall = client.newInvite( callerName: "User", callerNumber: "user", destinationNumber: "ai-assistant", // Ignored after anonymous login callId: UUID() ) } private func sendTextMessage() { // Step 3: Send text message during call let success = client.sendAIAssistantMessage("Hello, can you help me?") print("Message sent: \(success)") } private func subscribeToTranscripts() { // Step 4: Listen to real-time transcripts let cancellable = client.aiAssistantManager.subscribeToTranscriptUpdates { transcripts in DispatchQueue.main.async { self.updateTranscriptUI(transcripts) } } // Store cancellable to manage subscription lifecycle } } extension AIAgentViewController: TxClientDelegate { func onClientReady() { print("Client ready - can start AI conversation") startConversation() } func onCallStateUpdated(callState: CallState, callId: UUID) { switch callState { case .ACTIVE: print("AI conversation active") subscribeToTranscripts() case .DONE: print("AI conversation ended") default: break } } } ``` ### Implementation Steps 1. **[Anonymous Login](docs-markdown/ai-agent/anonymous-login.md)** - Authenticate with AI assistants without SIP credentials 2. **[Starting Conversations](docs-markdown/ai-agent/starting-conversations.md)** - Initiate calls with AI agents 3. **[Transcript Updates](docs-markdown/ai-agent/transcript-updates.md)** - Handle real-time conversation transcripts 4. **[Text Messaging](docs-markdown/ai-agent/text-messaging.md)** - Send text messages during voice calls ### Complete Documentation For comprehensive AI Agent integration documentation, see: * **[AI Agent Introduction](docs-markdown/ai-agent/introduction.md)** - Overview and architecture * **[AIAssistantManager API](docs-markdown/classes/AIAssistantManager.md)** - Complete API reference * **[TranscriptionItem Structure](docs-markdown/structs/TranscriptionItem.md)** - Transcript data format * **[WidgetSettings Configuration](docs-markdown/structs/WidgetSettings.md)** - UI customization options *** ## Preferred Audio Codecs The SDK allows you to configure preferred audio codecs for your WebRTC calls. This feature enables you to prioritize specific codecs based on your application's requirements for audio quality, bandwidth usage, or network conditions. ### Getting Supported Codecs Query the list of audio codecs supported by the device and WebRTC framework: ```swift theme={null} // Get all supported audio codecs let supportedCodecs = telnyxClient.getSupportedAudioCodecs() // Print codec information for codec in supportedCodecs { print("Codec: \(codec.mimeType), Clock Rate: \(codec.clockRate) Hz") } ``` ### Setting Preferred Codecs **For Outbound Calls:** ```swift theme={null} // Define your preferred codecs in order of priority let preferredCodecs = [ TxCodecCapability(mimeType: "audio/opus", clockRate: 48000, channels: 2), TxCodecCapability(mimeType: "audio/PCMU", clockRate: 8000, channels: 1) ] // Create a call with preferred codecs let call = try telnyxClient.newCall( callerName: "John Doe", callerNumber: "1234567890", destinationNumber: "18004377950", callId: UUID(), preferredCodecs: preferredCodecs // Pass preferred codecs ) ``` **For Inbound Calls:** ```swift theme={null} func onIncomingCall(call: Call) { let preferredCodecs = [ TxCodecCapability(mimeType: "audio/opus", clockRate: 48000, channels: 2), TxCodecCapability(mimeType: "audio/PCMU", clockRate: 8000, channels: 1) ] // Answer with preferred codecs call.answer(preferredCodecs: preferredCodecs) } ``` ### Common Codec Configurations **High Quality Audio (VoIP apps):** ```swift theme={null} let preferredCodecs = [ TxCodecCapability(mimeType: "audio/opus", clockRate: 48000, channels: 2) ] ``` **Traditional Telephony Compatibility:** ```swift theme={null} let preferredCodecs = [ TxCodecCapability(mimeType: "audio/PCMU", clockRate: 8000, channels: 1), TxCodecCapability(mimeType: "audio/PCMA", clockRate: 8000, channels: 1) ] ``` **Low Bandwidth Optimization:** ```swift theme={null} let preferredCodecs = [ TxCodecCapability(mimeType: "audio/iLBC", clockRate: 8000), TxCodecCapability(mimeType: "audio/PCMU", clockRate: 8000) ] ``` For detailed documentation on codec selection, configuration options, and best practices, see the [Preferred Audio Codecs Guide](docs-markdown/audio-codecs/preferred-codecs.md). *** ## Call Termination Reasons When a call ends, the SDK provides detailed information about why the call was terminated through the `CallTerminationReason` structure. This information is available in the `DONE` state of the call. ### CallTerminationReason Structure The `CallTerminationReason` structure contains the following fields: * `cause`: A string describing the general cause of the call termination (e.g., "CALL\_REJECTED", "USER\_BUSY") * `causeCode`: A numerical code corresponding to the cause * `sipCode`: The SIP response code (e.g., 403, 404) * `sipReason`: The SIP reason phrase (e.g., "Dialed number is not included in whitelisted countries") ### Accessing Call Termination Reasons You can access the termination reason in the `onCallStateUpdated` delegate method: ```swift theme={null} func onCallStateUpdated(callState: CallState, callId: UUID) { switch callState { case .DONE(let reason): if let reason = reason { // Access termination details let cause = reason.cause let sipCode = reason.sipCode let sipReason = reason.sipReason // Display or log the information print("Call ended: \(cause ?? "Unknown"), SIP: \(sipCode ?? 0) \(sipReason ?? "")") } break // Handle other states... } } ``` ### Common Termination Causes The SDK provides various termination causes, including: * `NORMAL_CLEARING`: Call ended normally * `USER_BUSY`: The called party is busy * `CALL_REJECTED`: The call was rejected * `UNALLOCATED_NUMBER`: The dialed number is invalid * `INCOMPATIBLE_DESTINATION`: The destination cannot handle the call type ## WebRTC Statistics The SDK provides WebRTC statistics functionality to assist with troubleshooting and monitoring call quality. This feature is controlled through the `debug` flag in the `TxClient` configuration. ### Enabling WebRTC Statistics To enable WebRTC statistics logging: ```Swift theme={null} let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "DEVICE_APNS_TOKEN", debug: true) // Enable WebRTC statistics ``` ### Understanding WebRTC Statistics When `debug: true` is configured: * WebRTC statistics logs are automatically collected during calls * Logs are sent to the Telnyx portal and are accessible in the Object Storage section * Statistics are linked to the SIP credential used for testing * The logs help the Telnyx support team diagnose issues and optimize call quality ### Real-time Call Quality Monitoring The SDK provides real-time call quality metrics through the `onCallQualityChange` callback on the `Call` object. This allows you to monitor call quality in real-time and provide feedback to users. #### Using onCallQualityChanged ```Swift theme={null} // When creating a new call set debug to true for CallQualityMetrics let call = try telnyxClient.newCall(callerName: "Caller name", callerNumber: "155531234567", destinationNumber: "18004377950", callId: UUID.init(),debug:true) //When accepting a call telnyxClient?.answerFromCallkit(answerAction: action,debug:true) or call?.answer(debug:true) // Set the onCallQualityChange callback call.onCallQualityChange = { metrics in // Handle call quality metrics print("Call quality: \(metrics.quality.rawValue)") print("MOS score: \(metrics.mos)") print("Jitter: \(metrics.jitter * 1000) ms") print("Round-trip time: \(metrics.rtt * 1000) ms") // Update UI based on call quality switch metrics.quality { case .excellent, .good: // Show excellent/good quality indicator self.qualityIndicator.backgroundColor = .green case .fair: // Show fair quality indicator self.qualityIndicator.backgroundColor = .yellow case .poor, .bad: // Show poor/bad quality indicator self.qualityIndicator.backgroundColor = .red // Optionally show a message to the user case .unknown: // Quality couldn't be determined self.qualityIndicator.backgroundColor = .gray } } ``` #### CallQualityMetrics Properties The `CallQualityMetrics` object provides the following properties: | Property | Type | Description | | --------------------- | --------------- | -------------------------------------------------------------- | | `jitter` | Double | Jitter in seconds (multiply by 1000 for milliseconds) | | `rtt` | Double | Round-trip time in seconds (multiply by 1000 for milliseconds) | | `mos` | Double | Mean Opinion Score (1.0-5.0) | | `quality` | CallQuality | Call quality rating based on MOS | | `inboundAudio` | \[String: Any]? | Inbound audio statistics | | `outboundAudio` | \[String: Any]? | Outbound audio statistics | | `remoteInboundAudio` | \[String: Any]? | Remote inbound audio statistics | | `remoteOutboundAudio` | \[String: Any]? | Remote outbound audio statistics | #### CallQuality Enum | Value | MOS Range | Description | | ------------ | --------------- | --------------------------- | | `.excellent` | MOS > 4.2 | Excellent call quality | | `.good` | 4.1 ≤ MOS ≤ 4.2 | Good call quality | | `.fair` | 3.7 ≤ MOS ≤ 4.0 | Fair call quality | | `.poor` | 3.1 ≤ MOS ≤ 3.6 | Poor call quality | | `.bad` | MOS ≤ 3.0 | Bad call quality | | `.unknown` | N/A | Unable to calculate quality | #### Best Practices for Call Quality Monitoring 1. **User Feedback**: * Consider showing a visual indicator of call quality to users * For poor quality calls, provide suggestions (e.g., "Try moving to an area with better connectivity") 2. **Logging**: * Log quality metrics for later analysis * Track quality trends over time to identify patterns 3. **Adaptive Behavior**: * Implement adaptive behaviors based on call quality * For example, suggest switching to audio-only if video quality is poor 4. **Performance Considerations**: * The callback is triggered periodically (approximately every 2 seconds) ### Important Notes 1. **Log Access**: * If you run the app using SIP credential A with `debug: true`, the WebRTC logs will be available in the Telnyx portal account associated with credential A * Logs are stored in the Object Storage section of your Telnyx portal 2. **Troubleshooting Support**: * WebRTC statistics are primarily intended to assist the Telnyx support team * When requesting support, enable `debug: true` in `TxClient` for all instances * Provide the `debug ID` or `callId` when contacting support * Statistics logging is disabled by default to optimize performance 3. **Best Practices**: * Enable `debug: true` only when troubleshooting is needed * Remember to provide the `debug ID` or `callId` in support requests * Consider disabling debug mode in production unless actively investigating issues *** ## Custom Logging The SDK provides a flexible logging system that allows you to implement your own custom logger. This feature enables you to route SDK logs to your preferred logging framework or format. ### Implementing a Custom Logger To create a custom logger, implement the `TxLogger` protocol: ```Swift theme={null} class MyCustomLogger: TxLogger { func log(level: LogLevel, message: String) { // Implement your custom logging logic here // Example: Send logs to your analytics service MyAnalyticsService.log( level: level, message: message, ) } } ``` ### Using a Custom Logger To use your custom logger, pass it to the `TxConfig` when initializing the client: ```Swift theme={null} let customLogger = MyCustomLogger() let txConfig = TxConfig( sipUser: sipUser, password: password, logLevel: .all, // Set desired log level customLogger: customLogger // Pass your custom logger ) ``` ### Default Logger If no custom logger is provided, the SDK uses `TxDefaultLogger` which prints logs to the console with appropriate formatting and emojis for different log levels. ### Important Notes 1. **Log Levels**: * The `logLevel` parameter in `TxConfig` still controls which logs are processed * Custom loggers only receive logs that match the configured verbosity level 2. **Thread Safety**: * Ensure your custom logger implementation is thread-safe * Log callbacks may come from different threads 3. **Performance**: * Keep logging operations lightweight to avoid impacting call quality * Consider asynchronous logging for heavy operations 4. **Best Practices**: * Handle all log levels appropriately * Include timestamps for proper log sequencing * Consider log persistence for debugging * Handle errors gracefully within the logger *** ## Push Notifications Setup In order to receive incoming calls while the app is running in background or closed, you will need to perform a set of configurations over your Mission Control Portal Account and your application. For detailed documentation on setting up push notifications, see: * [App Setup](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/app-setup) - Configure your iOS app to receive VoIP push notifications * [Portal Setup](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/portal-setup) - Set up your Telnyx Portal account with VoIP push credentials * [Troubleshooting](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/troubleshooting) - Debug common push notification issues *** ## Trickle ICE The SDK supports Trickle ICE, which enables faster call setup by sending ICE candidates incrementally as they are discovered, rather than waiting for all candidates before establishing the connection. ### Key Features * **Faster Call Establishment**: Candidates are sent immediately as discovered, reducing connection time * **Automatic Management**: No configuration required - the SDK handles Trickle ICE automatically * **Smart Queuing**: Answering side queues candidates until ANSWER is sent to prevent race conditions * **Candidate Cleaning**: WebRTC extensions are removed for maximum server compatibility ### How It Works **Outbound Calls**: Candidates are sent immediately as they are generated **Inbound Calls**: Candidates are queued until the call is answered, then flushed all at once followed by real-time sending of new candidates This approach prevents race conditions where candidates might arrive before the answer, ensuring reliable call setup. For comprehensive documentation on Trickle ICE implementation, troubleshooting, and technical details, see the [Trickle ICE Guide](docs-markdown/trickle-ice/trickle-ice.md). ### Testing VoIP Push Notifications The repository includes a dedicated testing tool to help validate your VoIP push notification setup. This tool allows you to send test push notifications directly to your device using your own certificates and configuration. **Location**: `push-notification-tool/` in the repository root #### Quick Setup ```bash theme={null} cd push-notification-tool npm install npm run dev ``` #### What the Tool Does * **Validates Configuration**: Tests your certificate files, bundle ID, and device token * **Sends Test Pushes**: Generates VoIP notifications with SDK-compatible payload structure * **Provides Detailed Errors**: Clear error messages to help identify configuration issues * **Supports Continuous Testing**: Send multiple pushes, switch configurations, test different scenarios * **Smart Configuration Management**: Saves settings between sessions for faster iteration #### Perfect for Testing * Certificate and environment validation * Device token verification * Payload structure compatibility * Multi-device testing * Troubleshooting push delivery issues For complete setup instructions and usage examples, see the tool's [README](https://github.com/team-telnyx/telnyx-webrtc-ios/tree/main/push-notification-tool) or the [Troubleshooting Guide](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/troubleshooting#testing-voip-push-notifications). ### VoIP Push - Portal setup During this process you will learn how to create a VoIP push credential and assign the credential to a SIP Connection. This process requires: * A Mission Control Portal Account. * A SIP Connection. * Your Apple VoIP push certificate. For complete instructions on how to setup Push Notifications got to this [link](https://developers.telnyx.com/docs/v2/webrtc/push-notifications). ### VoIP Push - App Setup The following setup is required in your application to receive Telnyx VoIP push notifications: #### a. Add Push Notifications capability to your Xcode project 1. Open the xcode workspace associated with your app. 2. In the Project Navigator (the left-hand menu), select the project icon that represents your mobile app. 3. In the top-left corner of the right-hand pane in Xcode, select your app's target. 4. Press the +Capabilities button.

Screen Shot 2021-11-26 at 13 34 12

6. Enable Push Notifications

Screen Shot 2021-11-26 at 13 35 51

#### b. Configure PushKit into your app: 1. Import pushkit ```Swift theme={null} import PushKit ``` 2. Initialize PushKit: ```Swift theme={null} private var pushRegistry = PKPushRegistry.init(queue: DispatchQueue.main) ... func initPushKit() { pushRegistry.delegate = self pushRegistry.desiredPushTypes = Set([.voIP]) } ``` 3. Implement PKPushRegistryDelegate ```Swift theme={null} extension AppDelegate: PKPushRegistryDelegate { // New push notification token assigned by APNS. func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { if (type == .voIP) { // This push notification token has to be sent to Telnyx when connecting the Client. let deviceToken = credentials.token.reduce("", {$0 + String(format: "%02X", $1) }) UserDefaults.standard.savePushToken(pushToken: deviceToken) } } func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { if (type == .voIP) { // Delete incoming token in user defaults let userDefaults = UserDefaults.init() userDefaults.deletePushToken() } } /** This delegate method is available on iOS 11 and above. */ func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { if (payload.type == .voIP) { self.handleVoIPPushNotification(payload: payload) } if let version = Float(UIDevice.current.systemVersion), version >= 13.0 { completion() } } func handleVoIPPushNotification(payload: PKPushPayload) { if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] { let callId = metadata["call_id"] as? String let callerName = (metadata["caller_name"] as? String) ?? "" let callerNumber = (metadata["caller_number"] as? String) ?? "" let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName let uuid = UUID(uuidString: callId) // Re-connect the client and process the push notification when is received. // You will need to use the credentials of the same user that is receiving the call. let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "APNS_PUSH_TOKEN") //Call processVoIPNotification method try telnyxClient?.processVoIPNotification(txConfig: txConfig, serverConfiguration: serverConfig,pushMetaData: metadata) // Report the incoming call to CallKit framework. let callHandle = CXHandle(type: .generic, value: from) let callUpdate = CXCallUpdate() callUpdate.remoteHandle = callHandle callUpdate.hasVideo = false provider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in if let error = error { print("AppDelegate:: Failed to report incoming call: \(error.localizedDescription).") } else { print("AppDelegate:: Incoming call successfully reported.") } } } } ``` 4. If everything is correctly set-up when the app runs APNS should assign a Push Token. 5. In order to receive VoIP push notifications. You will need to send your push token when connecting to the Telnyx Client. ```Swift theme={null} let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "DEVICE_APNS_TOKEN", //You can choose the appropriate verbosity level of the SDK. logLevel: .all) // Or use a JWT Telnyx Token to authenticate let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN", pushDeviceToken: "DEVICE_APNS_TOKEN", //You can choose the appropriate verbosity level of the SDK. Logs are disabled by default logLevel: .all) ``` For more information about Pushkit you can check the official [Apple docs](https://developer.apple.com/documentation/pushkit]). ***Important***: * You will need to login at least once to send your device token to Telnyx before start getting Push notifications. * You will need to provide `pushMetaData` to `processVoIPNotification()` to get Push calls to work. * You will need to implement 'CallKit' to report an incoming call when there’s a VoIP push notification. On iOS 13.0 and later, if you fail to report a call to CallKit, the system will terminate your app. More information on [Apple docs](https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry) #### c. Configure CallKit into your App: `PushKit` requires you to use `CallKit` when handling VoIP calls. `CallKit` ensures that apps providing call-related services on a user’s device work seamlessly together on the user's device, and respect features like Do Not Disturb. `CallKit` also operates the system's call-related UIs, including the incoming or outgoing call screens. Use `CallKit` to present these interfaces and manage interactions with them. For more information about `CallKit` you can check the official [Apple docs](https://developer.apple.com/documentation/callkit]). ***General Setup:*** 1. Import CallKit: ```Swift theme={null} import CallKit ``` 2. Initialize CallKit ```Swift theme={null} func initCallKit() { let configuration = CXProviderConfiguration(localizedName: "TelnyxRTC") configuration.maximumCallGroups = 1 configuration.maximumCallsPerCallGroup = 1 callKitProvider = CXProvider(configuration: configuration) if let provider = callKitProvider { provider.setDelegate(self, queue: nil) } } ``` 3. Implement `CXProviderDelegate` methods. ***Audio Session Handling WebRTC + CallKit*** To get `CallKit` properly working with the `TelnyxRTC SDK` you need to set the audio device state based on the `CallKit` AudioSession state like follows: ```Swift theme={null} extension AppDelegate : CXProviderDelegate { ... func provider(_ provider: CXProvider, didActivate audioSession: AVAudioSession) { self.telnyxClient?.enableAudioSession(audioSession: audioSession) } func provider(_ provider: CXProvider, didDeactivate audioSession: AVAudioSession) { self.telnyxClient?.disableAudioSession(audioSession: audioSession) } } ``` ***Reporting calls with CallKit*** To properly report calls to callKit with right statuses, you need to invoke the following callKit methods at the right instances: 1. Starting A New Call : When ever you start a call, report to callkit using the `provider.reportCall()` method. ```Swift theme={null} let callUpdate = CXCallUpdate() callUpdate.remoteHandle = callHandle callUpdate.supportsDTMF = true callUpdate.supportsHolding = true callUpdate.supportsGrouping = false callUpdate.supportsUngrouping = false callUpdate.hasVideo = false provider.reportCall(with: uuid, updated: callUpdate) ``` 2. When user receives a Call : Use `provider.reportNewIncomingCall(with: uuid, update: callUpdate)` to report an incoming call. This sends a request to callKit the to provide the native call interface to the user. ```Swift theme={null} guard let provider = callKitProvider else { print("AppDelegate:: CallKit provider not available") return } let callHandle = CXHandle(type: .generic, value: from) let callUpdate = CXCallUpdate() callUpdate.remoteHandle = callHandle provider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in // handle error } ``` 3. When callee answers an outgoing call : Use `provider.reportOutgoingCall(with: callKitUUID, connectedAt:nil)` to report a connected outgoing call. This provides the time when the outgoing call goes to active to callKit. ```Swift theme={null} if let provider = self.callKitProvider, let callKitUUID = self.callKitUUID { let date = Date() provider.reportOutgoingCall(with: callKitUUID, connectedAt:date) } ``` NB : This should be used only when the call is outgoing. ### Best Practices when Using PushNotifications with Callkit. 1. When receiving calls from push notifications, it is always required to wait for the connection to the WebSocket before fulfilling the call answer action. This can be achieved by implementing the CXProviderDelegate in the following way (SDK version >=0.1.11): ```Swift theme={null} func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { self.telnyxClient?.answerFromCallkit(answerAction: action) } ``` When the `answerFromPush(answerAction: action)` is called, Callkit sets the call state to `connecting` to alert the user that the call is being connected. Once the call is active, the timer starts. | Connecting State | Active Call | | ---------------- | ----------- | | | | The previous SDK versions requires handling the websocket connection state on the client side. It can be done in the following way: ```Swift theme={null} var callAnswerPendingFromPush:Bool = false func provider(_ provider: CXProvider, perform action: CXAnswerCallAction) { print("AppDelegate:: ANSWER call action: callKitUUID [\(String(describing: self.callKitUUID))] action [\(action.callUUID)]") if(currentCall != nil){ self.currentCall?.answer() }else { self.callAnswerPendingFromPush = true } action.fulfill() } func onPushCall(call: Call) { print("AppDelegate:: TxClientDelegate onPushCall() \(call)") self.currentCall = call //Update the current call with the incoming call //Answer Call if call was answered from callkit //This happens when there's a race condition between login and receiving PN // when User answer's the call from PN and there's no Call or INVITE message yet. Set callAnswerPendingFromPush = true // Whilst we wait fot onPushCall Method to be called if(self.callAnswerPendingFromPush){ self.currentCall?.answer() self.callAnswerPendingFromPush = false } } ``` Likewise for ending calls, the `endCallFromCallkit(endAction:action)` method should be called from : ```Swift theme={null} func provider(_ provider: CXProvider, perform action: CXEndCallAction) { self.telnyxClient?.endCallFromCallkit(endAction:action) } ``` Calling this method solves the race condition, where call is ended before the client connects to the webserver. This way the call is ended on the callee side once a connection is established. 2. Logs on the receiver's end are essential for thorough debugging of issues related to push notifications. However, the debugger is not attached when the app is completely killed. To address this, you can simply put the app in the background. VOIP push notifications should then come through, and the debugger should capture all logs. ***Handling Multiple Calls*** To handle multiples, we can rely on the `CXProviderDelegate` delegate which invokes functions corresponding to what action was performed on the callkit user interface. 1. End and Accept or Decline : The **end and accept** button on the callkit user interface accepts the new call and ends the previous call. Callkit then invokes the `CXAnswerCallAction` and `CXEndCallAction` when the **end and accept** button is pressed. You can handle this scenario by ```Swift theme={null} var currentCall: Call? var previousCall: Call? //current calkit uuid var callKitUUID: UUID? func onIncomingCall(call: Call) { guard let callId = call.callInfo?.callId else { print("AppDelegate:: TxClientDelegate onIncomingCall() Error unknown call UUID") return } print("AppDelegate:: TxClientDelegate onIncomingCall() callKitUUID [\(String(describing: self.callKitUUID))] callId [\(callId)]") self.callKitUUID = call.callInfo?.callId //Update the previous call with the current call self.previousCall = self.currentCall //Update the current call with the incoming call self.currentCall = call .. } ``` Subsequently, when the user clicks on the End and Accept or Decline Button, you will need to determine which of these buttons was clicked. You can do that as follows: ```Swift theme={null} //Callkit invokes CXEndCallAction and CXAnswerCallAction delegate function for accept and answer func provider(_ provider: CXProvider, perform action: CXEndCallAction) { print("AppDelegate:: END call action: callKitUUID [\(String(describing: self.callKitUUID))] action [\(action.callUUID)]") // if the callKitUUID is the same as the one provided by the action // callkit expects you to end the current call if(self.callKitUUID == action.callUUID){ if let onGoingCall = self.previousCall { self.currentCall = onGoingCall self.callKitUUID = onGoingCall.callInfo?.callId } }else { // callkit expects you to end the previous call self.callKitUUID = self.currentCall?.callInfo?.callId } self.telnyxClient?.endCallFromCallkit(endAction:action) } ``` **Note** While handling multiple calls, you should report the **call end** to callkit properly with the right callUUID. This will keep your active calls with the callkit user interface until there are no more active sessions. 2. Hold and Accept or Decline: The **hold and accept** button on the callkit user interface accepts the new call and holds the previous call. Callkit then invokes the `CXSetHeldCallAction` when the **hold and accept** button is pressed. ```Swift theme={null} func provider(_ provider: CXProvider, perform action: CXSetHeldCallAction) { print("provider:performSetHeldAction:") //request to hold previous call, since we have both the current and previous calls previousCall?.hold() action.fulfill() } ``` Also, you will need to un-hold the previous call when the current call gets ended on `CXEndCallAction`. ```Swift theme={null} func provider(_ provider: CXProvider, perform action: CXEndCallAction) { if(previousCall?.callState == .HELD){ print("AppDelegate:: call held.. unholding call") previousCall?.unhold() } ... } ``` **Note** While handling multiple calls, you should report the **call end** to callkit properly with the right callUUID. This will keep your active calls with the callkit user interface until there are no more active sessions. ### Disable Push Notification Push notifications can be disabled for the current user by calling : ``` telnyxClient.disablePushNotifications() ``` Note : Signing back in, using same credentials will re-enable push notifications. ### Privacy Manifest Support for privacy manifest is added from version 0.1.26 ### Documentation: For more information you can: 1. Clone the repository 2. And check the exported documentation in: `docs/index.html` ## Support Find official documentation [here](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk) Questions? Comments? Building something rad? Join our Slack channel and share. ## License [`MIT Licence`](https://github.com/team-telnyx/telnyx-webrtc-ios/blob/main/LICENSE) © [Telnyx](https://github.com/team-telnyx) # WebRTC iOS TxClientDelegate Source: https://developers.telnyx.com/development/webrtc/ios-sdk/protocols/tx-client-delegate/index Defines methods for handling Telnyx Client events and updates, such as call state changes and backend connection status. **PROTOCOL** # `TxClientDelegate` ```swift theme={null} public protocol TxClientDelegate: AnyObject ``` The TxClientDelegate protocol defines methods for receiving events and updates from a TxClient instance. Implement this protocol to handle various states and events in your WebRTC-enabled application, including connection status, call state changes, and push notifications. ## Usage Example: ```swift theme={null} class CallHandler: TxClientDelegate { func onSocketConnected() { print("Connected to Telnyx backend") } func onIncomingCall(call: Call) { // Handle incoming call call.answer() } // Implement other required methods... } ``` ## Methods ### `onSocketConnected()` ```swift theme={null} func onSocketConnected() ``` Called when the WebSocket connection to Telnyx's backend is established. This indicates a successful network connection, but the client may not be fully ready yet. Wait for `onClientReady` before initiating calls. ### `onSocketDisconnected()` ```swift theme={null} func onSocketDisconnected() ``` Called when the WebSocket connection to Telnyx's backend is lost or closed. The client will automatically attempt to reconnect unless explicitly disconnected. ### `onClientError(error:)` ```swift theme={null} func onClientError(error: Error) ``` Called when an error occurs in the TxClient. * Parameter error: The error that occurred. Check the error type and message for details. Common errors include authentication failures and network connectivity issues. #### Parameters | Name | Description | | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | error | The error that occurred. Check the error type and message for details. Common errors include authentication failures and network connectivity issues. | ### `onClientReady()` ```swift theme={null} func onClientReady() ``` Called when the client has successfully connected AND authenticated. The client is now ready to make and receive calls. This is the appropriate time to enable UI elements for calling functionality. ### `onPushDisabled(success:message:)` ```swift theme={null} func onPushDisabled(success: Bool, message: String) ``` Called when push notification status changes for the current user. * Parameters: * success: Whether the push notification operation succeeded * message: Descriptive message about the operation result #### Parameters | Name | Description | | ------- | ------------------------------------------------- | | success | Whether the push notification operation succeeded | | message | Descriptive message about the operation result | ### `onSessionUpdated(sessionId:)` ```swift theme={null} func onSessionUpdated(sessionId: String) ``` Called when the client's session is updated, typically after a reconnection. * Parameter sessionId: The new session identifier for the connection. Store this ID if you need to track or debug connection issues. #### Parameters | Name | Description | | --------- | ------------------------------------------------------------------------------------------------------------- | | sessionId | The new session identifier for the connection. Store this ID if you need to track or debug connection issues. | ### `onCallStateUpdated(callState:callId:)` ```swift theme={null} func onCallStateUpdated(callState: CallState, callId: UUID) ``` Called whenever a call's state changes (e.g., ringing, answered, ended). * Parameters: * callState: The new state of the call (NEW, CONNECTING, RINGING, ACTIVE, HELD, DONE) * callId: The unique identifier of the affected call Use this to update your UI to reflect the current call state. #### Parameters | Name | Description | | --------- | -------------------------------------------------------------------------------------------------------- | | callState | The new state of the call (NEW, CONNECTING, RINGING, ACTIVE, HELD, DONE) | | callId | The unique identifier of the affected call Use this to update your UI to reflect the current call state. | ### `onIncomingCall(call:)` ```swift theme={null} func onIncomingCall(call: Call) ``` Called when a new incoming call is received. * Parameter call: The Call object representing the incoming call. You can use this object to answer or reject the call. #### Parameters | Name | Description | | ---- | ----------------------------------------------------------------------------------------------------- | | call | The Call object representing the incoming call. You can use this object to answer or reject the call. | ### `onRemoteCallEnded(callId:reason:)` ```swift theme={null} func onRemoteCallEnded(callId: UUID, reason: CallTerminationReason?) ``` Called when a remote party ends the call. * Parameters: * callId: The unique identifier of the ended call. * reason: Optional termination reason containing details about why the call ended. Use this to clean up any call-related UI elements or state and potentially display error messages. #### Parameters | Name | Description | | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | callId | The unique identifier of the ended call. | | reason | Optional termination reason containing details about why the call ended. Use this to clean up any call-related UI elements or state and potentially display error messages. | ### `onPushCall(call:)` ```swift theme={null} func onPushCall(call: Call) ``` Called when a push notification triggers an incoming call. * Parameter call: The Call object created from the push notification data. This is specifically for handling calls that arrive via push notifications when the app is in the background. #### Parameters | Name | Description | | ---- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | call | The Call object created from the push notification data. This is specifically for handling calls that arrive via push notifications when the app is in the background. | # iOS Push Notification Setup Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/app-setup/index A step-by-step guide to setting up push notifications in iOS. Learn how to configure and implement notifications to ensure seamless communication in your application. ## Push Notification App Setup ### VoIP Push - App Setup The following setup is required in your application to receive Telnyx VoIP push notifications: #### a. Add Push Notifications capability to your Xcode project 1. Open the xcode workspace associated with your app. 2. In the Project Navigator (the left-hand menu), select the project icon that represents your mobile app. 3. In the top-left corner of the right-hand pane in Xcode, select your app's target. 4. Press the +Capabilities button.

Screen Shot 2021-11-26 at 13 34 12

6. Enable Push Notifications

Screen Shot 2021-11-26 at 13 35 51

#### b. Configure PushKit into your app: 1. Import pushkit ```Swift theme={null} import PushKit ``` 2. Initialize PushKit: ```Swift theme={null} private var pushRegistry = PKPushRegistry.init(queue: DispatchQueue.main) ... func initPushKit() { pushRegistry.delegate = self pushRegistry.desiredPushTypes = Set([.voIP]) } ``` 3. Implement PKPushRegistryDelegate ```Swift theme={null} extension AppDelegate: PKPushRegistryDelegate { // New push notification token assigned by APNS. func pushRegistry(_ registry: PKPushRegistry, didUpdate credentials: PKPushCredentials, for type: PKPushType) { if (type == .voIP) { // This push notification token has to be sent to Telnyx when connecting the Client. let deviceToken = credentials.token.reduce("", {$0 + String(format: "%02X", $1) }) UserDefaults.standard.savePushToken(pushToken: deviceToken) } } func pushRegistry(_ registry: PKPushRegistry, didInvalidatePushTokenFor type: PKPushType) { if (type == .voIP) { // Delete incoming token in user defaults let userDefaults = UserDefaults.init() userDefaults.deletePushToken() } } /** This delegate method is available on iOS 11 and above. */ func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { if (payload.type == .voIP) { self.handleVoIPPushNotification(payload: payload) } if let version = Float(UIDevice.current.systemVersion), version >= 13.0 { completion() } } func handleVoIPPushNotification(payload: PKPushPayload) { if let metadata = payload.dictionaryPayload["metadata"] as? [String: Any] { let callId = metadata["call_id"] as? String let callerName = (metadata["caller_name"] as? String) ?? "" let callerNumber = (metadata["caller_number"] as? String) ?? "" let caller = callerName.isEmpty ? (callerNumber.isEmpty ? "Unknown" : callerNumber) : callerName let uuid = UUID(uuidString: callId) // Re-connect the client and process the push notification when is received. // You will need to use the credentials of the same user that is receiving the call. let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "APNS_PUSH_TOKEN") //Call processVoIPNotification method try telnyxClient?.processVoIPNotification(txConfig: txConfig, serverConfiguration: serverConfig,pushMetaData: metadata) // Report the incoming call to CallKit framework. let callHandle = CXHandle(type: .generic, value: from) let callUpdate = CXCallUpdate() callUpdate.remoteHandle = callHandle callUpdate.hasVideo = false provider.reportNewIncomingCall(with: uuid, update: callUpdate) { error in if let error = error { print("AppDelegate:: Failed to report incoming call: \(error.localizedDescription).") } else { print("AppDelegate:: Incoming call successfully reported.") } } } } ``` 4. If everything is correctly set-up when the app runs APNS should assign a Push Token. 5. In order to receive VoIP push notifications. You will need to send your push token when connecting to the Telnyx Client. ```Swift theme={null} let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "DEVICE_APNS_TOKEN", //You can choose the appropriate verbosity level of the SDK. logLevel: .all) // Or use a JWT Telnyx Token to authenticate let txConfigToken = TxConfig(token: "MY_JWT_TELNYX_TOKEN", pushDeviceToken: "DEVICE_APNS_TOKEN", //You can choose the appropriate verbosity level of the SDK. Logs are disabled by default logLevel: .all) ``` For more information about Pushkit you can check the official [Apple docs](https://developer.apple.com/documentation/pushkit]). ***Important***: * You will need to login at least once to send your device token to Telnyx before start getting Push notifications. * You will need to provide `pushMetaData` to `processVoIPNotification()` to get Push calls to work. * You will need to implement 'CallKit' to report an incoming call when there’s a VoIP push notification. On iOS 13.0 and later, if you fail to report a call to CallKit, the system will terminate your app. More information on [Apple docs](https://developer.apple.com/documentation/pushkit/pkpushregistrydelegate/2875784-pushregistry) ## Multidevice Push Notifications Telnyx WebRTC supports multidevice push notifications. A single user can have up to 5 device tokens (either iOS - APNS or Android - FCM). When a user logs into the socket and provides a push token, our services will register this token to that user - allowing it to receive push notifications for incoming calls. If a 6th registration is made, the least recently used token will be removed. This effectively means that you can have up to 5 devices that can receive push notifications for the same incoming call. ## Disable Push Notification Push notifications can be disabled for the current user by calling : ``` telnyxClient.disablePushNotifications() ``` Note : Signing back in, using same credentials will re-enable push notifications. # iOS Portal Setup Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/portal-setup/index A step-by-step guide to setting up push notifications in iOS. Learn how to configure and implement notifications to ensure seamless communication in your application. ## Push Notification Portal Setup The Telnyx iOS Client WebRTC SDK makes use of APNS in order to deliver push notifications. If you would like to receive notifications when receiving calls on your iOS mobile device you will have to configure a VoIP push certificate. ### Creating a VoIP push certificate For official Apple documentation, see [Create VoIP Services Certificates](https://developer.apple.com/help/account/certificates/create-voip-services-certificates). In order to generate VoIP push certificates you will need: * An Apple developer account * App BundleID * CSR (Certificate Signing Request): Explained on Step #7 1. Go to [https://developer.apple.com/](https://developer.apple.com/) and login with your credentials. 2. In the **Overview** section, select **"Certificates, Identifiers & Profiles"** 3. Press the blue "+" button to add a new Certificate. 4. Search for "**VoIP Services Certificate**" and Click "**Continue**". 5. Select the **BundleID** of the target application, and click "**Continue**" 6. Then, you will be requested to upload a CSR from your Mac. 7. In order to generate a CSR (for detailed instructions, see [Create a Certificate Signing Request](https://developer.apple.com/help/account/certificates/create-a-certificate-signing-request)): a. Open the KeyChain Access of your mac. b. Go to Keychain Access >> Certificate Assistance > Request a Certificate from a Certificate Authority. c. Add your email address and select "Save to disk" option, and click "**Continue**" d. Save the Certificate Signing Request (CSR) into your Mac. 8. Once you have created your CSR, press "Choose File" and select the certSign created on step #7. Click "**Continue**" and you are done. 9. The new Certificate has been created. Now you need to download it. 10. Search for the downloaded file (usually named voip\_services.cer) and double click on it to install it on your Mac. And that’s all for now! ### Obtain your Cert.pem and Key.pem files In order to allow the Telnyx VoIP push service to send notifications to your app, you will need to export the VoIP certificate and key: 1. Open Keychain Access on your Mac (where you have installed the VoIP certificate by following the "**Creating a VoIP push certificate**" instructions). 2. Search for "VoIP services" and verify that you have the certificate installed for the BundleID of your application. 3. Open the contextual menu and select "Export". 4. Save the .p12 file (A password will be requested before saving it). 5. Once the certificate is created you will need to run the following commands to obtain the **cert.pem** and **key.pem** files: ```bash theme={null} $ openssl pkcs12 -in PATH_TO_YOUR_P12 -nokeys -out cert.pem -nodes -legacy $ openssl pkcs12 -in PATH_TO_YOUR_P12 -nocerts -out key.pem -nodes -legacy $ openssl rsa -in key.pem -out key.pem ``` > **Note:** After pasting the above content, Kindly check and remove any new line added 6. Now you can go to your Portal account and configure your PN credential. ### Setup your iOS VoIP credentials on your Portal #### Create an iOS Push Credential: 1. Go to portal.telnyx.com and login. 2. Go to the **API Keys** section on the left panel. 3. From the top bar go to the **Credentials** tab and select "**Add**" >> **iOS Credential** 4. Set a credential name (You can use your app bundle ID to easy identify your PN credential) and then copy and paste the contents of your **cert.pem** and **key.pem** files into the defined sections (Notice that you need to copy from ---BEGIN ####--- to ---END--- sections including those marks). 5. Save the new push credential by pressing the **Add Push Credential** button. #### Assign your iOS Push Credential to a SIP Connection: 1. Go to the **SIP Connections** section on the left panel. 2. Open the Settings menu of the SIP connection that you want to add a Push Credential or [create a new SIP Connection](https://developers.telnyx.com/docs/voice/sip-trunking/quickstart). 3. Select the WEBRTC tab. 4. Go to the iOS Section and select the PN credential created on "**Create an iOS Push Credential**" That's done. You can now go to your code and start implementing **PushKit** and **Callkit** using the **TelnyxRTC SDK** and receive VoIP push notifications into your iOS device. # Troubleshooting Source: https://developers.telnyx.com/development/webrtc/ios-sdk/push-notification/troubleshooting/index A step-by-step guide to setting up push notifications in iOS. Learn how to configure and implement notifications to ensure seamless communication in your application. ## Push Notification Troubleshooting This guide helps you troubleshoot common issues that prevent push notifications from being delivered in the Telnyx WebRTC iOS SDK. ## Common Points of Failure ### 1. VoIP Push Notification Certificate One of the most critical components for iOS push notifications is the VoIP Push Notification Certificate. A single VoIP Services Certificate supports both sandbox and production environments for the same bundle ID. **How to verify:** * Check that you have generated a valid VoIP Services Certificate in the Apple Developer Portal * Verify that the certificate is not expired * Ensure the certificate is generated for the correct bundle ID used in your app * Verify that the VoIP Services Certificate establishes connectivity between your notification server and both APNS sandbox and production environments **Solution:** * Follow [Apple's official documentation](https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_certificate-based_connection_to_apns) to generate a new VoIP Services Certificate * Upload the certificate to the Telnyx Portal * Ensure the certificate matches your app's bundle ID * For different bundle IDs (e.g., com.myapp.dev, com.myapp), create separate VoIP Services Certificates * Note: A separate certificate is required for each app you distribute, but each certificate works for both sandbox and production ### 2. Push Token Not Passed to Login A common issue is that the push token is not being passed correctly during the login process. **How to verify:** * Check your application logs to ensure the push token is being retrieved successfully * Verify that the login message contains the push token * Look for logs similar to: `Push token received: [your-token]` **Solution:** * Make sure you're retrieving the push token as shown in the [App Setup](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/app-setup) guide * Ensure the token is passed to the `connect()` method within the [TelnyxConfig](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/structs/tx-config) object * Verify that the token is not null or empty before passing it ### 3. Wrong Push Credential Assigned to SIP Connection If the push credential is not correctly assigned to your SIP credential, the server won't know where to send push notifications. **How to verify:** * Log into the Telnyx Portal and check your SIP Connection settings * Verify that the correct iOS VoIP push credential is selected in the WebRTC tab **Solution:** * Follow the steps in the [Portal Setup](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/portal-setup) guide to properly assign the push credential * Make sure you've selected the correct credential for your application. * If using multiple environments, ensure each has its own SIP connection with the appropriate certificate ### 4. APNS Environment Mismatch OS apps can target either the APNS Sandbox (development) or Production environment, and this must align with your build configuration. **How to verify:** * Check your build configuration (Debug vs Release). * Ensure that the APNS environment setting in your TxConfig (`pushEnvironment` property) is not being forced. * Confirm that the correct VoIP Services Certificate, valid for both production and development, is uploaded to the Telnyx Portal. **Solution:** * For Debug builds running from Xcode: * Use a Sandbox (development) certificate * Set `pushEnvironment` to `sandbox` in TelnyxConfig if needed * For Release builds or TestFlight: * Use a Production certificate * Set `pushEnvironment` to `production` in TelnyxConfig if needed * If generating an IPA: * Ensure it's signed with the correct profile (development or distribution) * Match the APNS environment to your signing profile ### 5. Info.plist Configuration Proper configuration in Info.plist is essential for push notifications to work. **How to verify:** * Check that push notifications are enabled in your app's capabilities * Verify that VoIP push notifications are properly configured * Ensure background modes are enabled for VoIP **Solution:** * Add the following to your Info.plist: ```xml theme={null} UIBackgroundModes voip ``` * Enable "Voice over IP" and "Background fetch" in Xcode capabilities * Verify that your app has the required entitlements for push notifications ## Testing VoIP Push Notifications ### VoIP Push Notification Testing Tool To help validate your push notification setup, the repository includes a dedicated testing tool that allows you to send test VoIP push notifications directly to your device. **Location:** `push-notification-tool/` in the repository root ### Quick Setup 1. **Navigate to the tool directory:** ```bash theme={null} cd push-notification-tool ``` 2. **Install dependencies:** ```bash theme={null} npm install ``` 3. **Run the tool:** ```bash theme={null} npm run dev ``` ### What You'll Need * **Device Token**: 64-character hex string from your iOS app's VoIP registration * **Bundle ID**: Your app's identifier (e.g., `com.yourcompany.app`) * **Certificate Files**: `cert.pem` and `key.pem` from your VoIP push certificate * **Environment**: `sandbox` for development/TestFlight, `production` for App Store ### How It Works The tool generates VoIP push notifications with the exact payload structure expected by the Telnyx iOS SDK: ```json theme={null} { "metadata": { "voice_sdk_id": "12345678-abcd-1234-abcd-1234567890ab", "call_id": "87654321-dcba-4321-dcba-0987654321fe", "caller_name": "Test Caller", "caller_number": "+1234567890" } } ``` ### Testing Workflow 1. **Configure Once**: Enter your device token, bundle ID, certificate paths, and environment 2. **Send Test Push**: The tool sends a VoIP notification to your device 3. **Verify Receipt**: Check that your app receives the push and processes it correctly 4. **Continuous Testing**: Send multiple pushes, reconfigure settings, or test different scenarios 5. **Troubleshoot Issues**: Use detailed error responses to identify configuration problems ### Common Test Scenarios * **Certificate Validation**: Verify your cert.pem and key.pem files work * **Environment Testing**: Test both sandbox and production APNS environments * **Device Token Validation**: Confirm your app generates valid VoIP device tokens * **Payload Processing**: Ensure your app correctly handles the metadata structure * **Multiple Devices**: Quickly switch between different device tokens * **Reliability Testing**: Send multiple pushes to test consistency ### Troubleshooting with the Tool The tool provides detailed error responses that help identify issues: * **BadDeviceToken**: Device token is invalid or expired * **BadCertificate**: Certificate files are invalid or expired * **BadTopic**: Bundle ID doesn't match certificate * **DeviceTokenNotForTopic**: Device token doesn't match certificate bundle ID * **TopicDisallowed**: Certificate doesn't have VoIP permissions ### Integration Testing After successful push delivery, verify your app: 1. **Receives the Push**: Check that `pushRegistry:didReceiveIncomingPushWithPayload:` is called 2. **Processes Metadata**: Verify `voice_sdk_id` and `call_id` are extracted correctly 3. **Calls processVoIPNotification**: Ensure the SDK method is called with correct parameters 4. **Shows CallKit UI**: Confirm incoming call interface appears (if using CallKit) 5. **Establishes Connection**: Verify WebSocket connection to Telnyx servers ## Additional Troubleshooting Steps 1. **Check APNS Status** * Use Apple's developer tools to verify APNS connectivity * Monitor for any APNS feedback about invalid tokens or delivery failures 2. **Verify Bundle ID Configuration** * Ensure your bundle ID matches across: * Xcode project settings * Provisioning profiles * VoIP push certificates * Telnyx Portal configuration 3. **Test with Development Environment First** * Start testing with sandbox/development environment * Use debug builds and development certificates * Monitor system logs for push notification related messages 4. **Check Network Connectivity** * Ensure your device has a stable internet connection * Verify that your app can connect to APNS servers * Test both Wi-Fi and cellular connections 5. **Verify Certificate Validity** * Check the expiration date of your VoIP push certificate * Ensure the certificate is properly exported with private key * Verify the certificate is in the correct format when uploaded to Telnyx ## Still Having Issues? If you've gone through all the troubleshooting steps and are still experiencing problems: 1. Check the Telnyx WebRTC SDK documentation for any updates or known issues 2. Contact Telnyx Support with detailed information about your setup and the issues you're experiencing 3. Include logs, error messages, and steps to reproduce the problem when contacting support 4. Provide your development environment details: * Xcode version * iOS version * SDK version * Build configuration (Debug/Release) * Certificate type (Development/Production) # WebRTC Stats Source: https://developers.telnyx.com/development/webrtc/ios-sdk/stats/index A comprehensive record of all updates, enhancements, and bug fixes related to WebRTC statistics. ## WebRTC Statistics The SDK provides WebRTC statistics functionality to assist with troubleshooting and monitoring call quality. This feature is controlled through the `debug` flag in the `TxClient` configuration. ### Enabling WebRTC Statistics To enable WebRTC statistics logging: ```Swift theme={null} let txConfig = TxConfig(sipUser: sipUser, password: password, pushDeviceToken: "DEVICE_APNS_TOKEN", debug: true) // Enable WebRTC statistics ``` ### Understanding WebRTC Statistics When `debug: true` is configured: * WebRTC statistics logs are automatically collected during calls * Logs are sent to the Telnyx portal and are accessible in the Object Storage section * Statistics are linked to the SIP credential used for testing * The logs help the Telnyx support team diagnose issues and optimize call quality * All statistics are presented in the Telnyx portal under the Object Storage section ### Real-time Call Quality Monitoring The SDK provides real-time call quality metrics through the `onCallQualityChange` callback on the `Call` object. This allows you to monitor call quality in real-time and provide feedback to users. #### Using onCallQualityChanged ```Swift theme={null} // When creating a new call set debug to true for CallQualityMetrics let call = try telnyxClient.newCall(callerName: "Caller name", callerNumber: "155531234567", destinationNumber: "18004377950", callId: UUID.init(), debug:true) // Enable Call Quality //When accepting a call telnyxClient?.answerFromCallkit(answerAction: action, debug:true) // Enable Call Quality or call?.answer(debug:true) // Enable Call Quality // Set the onCallQualityChange callback call.onCallQualityChange = { metrics in // Handle call quality metrics print("Call quality: \(metrics.quality.rawValue)") print("MOS score: \(metrics.mos)") print("Jitter: \(metrics.jitter * 1000) ms") print("Round-trip time: \(metrics.rtt * 1000) ms") // Update UI based on call quality switch metrics.quality { case .excellent, .good: // Show excellent/good quality indicator self.qualityIndicator.backgroundColor = .green case .fair: // Show fair quality indicator self.qualityIndicator.backgroundColor = .yellow case .poor, .bad: // Show poor/bad quality indicator self.qualityIndicator.backgroundColor = .red // Optionally show a message to the user case .unknown: // Quality couldn't be determined self.qualityIndicator.backgroundColor = .gray } } ``` #### CallQualityMetrics Properties The `CallQualityMetrics` object provides the following properties: | Property | Type | Description | | --------------------- | --------------- | -------------------------------------------------------------- | | `jitter` | Double | Jitter in seconds (multiply by 1000 for milliseconds) | | `rtt` | Double | Round-trip time in seconds (multiply by 1000 for milliseconds) | | `mos` | Double | Mean Opinion Score (1.0-5.0) | | `quality` | CallQuality | Call quality rating based on MOS | | `inboundAudio` | \[String: Any]? | Inbound audio statistics | | `outboundAudio` | \[String: Any]? | Outbound audio statistics | | `remoteInboundAudio` | \[String: Any]? | Remote inbound audio statistics | | `remoteOutboundAudio` | \[String: Any]? | Remote outbound audio statistics | #### CallQuality Enum The `CallQuality` enum provides the following values: | Value | MOS Range | Description | | ------------ | ------------------- | --------------------------- | | `.excellent` | `MOS > 4.2` | Excellent call quality | | `.good` | `4.1 <= MOS <= 4.2` | Good call quality | | `.fair` | `3.7 <= MOS <= 4.0` | Fair call quality | | `.poor` | `3.1 <= MOS <= 3.6` | Poor call quality | | `.bad` | `MOS <= 3.0` | Bad call quality | | `.unknown` | N/A | Unable to calculate quality | #### Best Practices for Call Quality Monitoring 1. **User Feedback**: * Consider showing a visual indicator of call quality to users * For poor quality calls, provide suggestions (e.g., "Try moving to an area with better connectivity") 2. **Logging**: * Log quality metrics for later analysis * Track quality trends over time to identify patterns 3. **Adaptive Behavior**: * Implement adaptive behaviors based on call quality * For example, suggest switching to audio-only if video quality is poor 4. **Performance Considerations**: * The callback is triggered periodically (approximately every 2 seconds) ### Important Notes 1. **Log Access**: * If you run the app using SIP credential A with `debug: true`, the WebRTC logs will be available in the Telnyx portal account associated with credential A * Logs are stored in the Object Storage section of your Telnyx portal 2. **Troubleshooting Support**: * WebRTC statistics are primarily intended to assist the Telnyx support team * When requesting support, enable `debug: true` in `TxClient` for all instances * Provide the `debug ID` or `callId` when contacting support * Statistics logging is disabled by default to optimize performance 3. **Best Practices**: * Enable `debug: true` only when troubleshooting is needed * Remember to provide the `debug ID` or `callId` in support requests * Consider disabling debug mode in production unless actively investigating issues ***
# WebRTC iOS Call Info Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-call-info/index Contains the required information of the current Call **STRUCT** # `TxCallInfo` ```swift theme={null} public struct TxCallInfo ``` `TxCallInfo` contains the required information of the current Call ## Properties ### `callId` ```swift theme={null} public internal(set) var callId: UUID ``` The UUID of the call ### `callerName` ```swift theme={null} public internal(set) var callerName:String? ``` The caller name of the call ### `callerNumber` ```swift theme={null} public internal(set) var callerNumber: String? ``` The caller number of the call # WebRTC iOS Client Configuration Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-config/index This structure is intended to used for Telnyx SDK configurations. **STRUCT** # `TxConfig` ```swift theme={null} public struct TxConfig ``` This structure is intended to used for Telnyx SDK configurations. ## Properties ### `DEFAULT_TIMEOUT` ```swift theme={null} public static let DEFAULT_TIMEOUT = 60.0 ``` Default timeout value for reconnection attempts in seconds. After this period, if a call hasn't successfully reconnected, it will be terminated. ### `sipUser` ```swift theme={null} public internal(set) var sipUser: String? ``` ### `password` ```swift theme={null} public internal(set) var password: String? ``` ### `token` ```swift theme={null} public internal(set) var token: String? ``` ### `pushNotificationConfig` ```swift theme={null} public internal(set) var pushNotificationConfig: TxPushConfig? ``` ### `ringBackTone` ```swift theme={null} public internal(set) var ringBackTone: String? ``` ### `ringtone` ```swift theme={null} public internal(set) var ringtone: String? ``` ### `reconnectClient` ```swift theme={null} public internal(set) var reconnectClient: Bool = true ``` ### `pushEnvironment` ```swift theme={null} public internal(set) var pushEnvironment: PushEnvironment? ``` ### `debug` ```swift theme={null} public internal(set) var debug: Bool = false ``` Enables WebRTC communication statistics reporting to Telnyx servers. * Note: This flag is different from `logLevel`: * `debug`: When enabled, sends WebRTC communication statistics to Telnyx servers for monitoring and debugging purposes. See `WebRTCStatsReporter` class for details on the statistics collected. * `logLevel`: Controls console log output in Xcode when running the app in debug mode. * Important: The `debug` flag is disabled by default to minimize data usage. ### `forceRelayCandidate` ```swift theme={null} public internal(set) var forceRelayCandidate: Bool = false ``` Controls whether the SDK should force TURN relay for peer connections. When enabled, the SDK will only use TURN relay candidates for ICE gathering, which prevents the "local network access" permission popup from appearing. * Note: Enabling this may affect the quality of calls when devices are on the same local network, as all media will be relayed through TURN servers. * Important: This setting is disabled by default to maintain optimal call quality. ### `enableQualityMetrics` ```swift theme={null} public internal(set) var enableQualityMetrics: Bool = false ``` Controls whether the SDK should deliver call quality metrics ### `sendWebRTCStatsViaSocket` ```swift theme={null} public internal(set) var sendWebRTCStatsViaSocket: Bool = false ``` Controls whether the SDK should send WebRTC statistics via socket * Note: This flag is independent of `debug` and `enableQualityMetrics`: * `debug`: Enables WebRTC stats collection and real-time metrics * `enableQualityMetrics`: Enables call quality metrics calculation * `sendWebRTCStatsViaSocket`: Enables sending collected stats via socket to Telnyx servers * Important: This flag is disabled by default to minimize network traffic ### `reconnectTimeout` ```swift theme={null} public internal(set) var reconnectTimeout: Double = DEFAULT_TIMEOUT ``` Maximum time (in seconds) the SDK will attempt to reconnect a call after network disruption. * If a call is successfully reconnected within this time, the call continues normally. * If reconnection fails after this timeout period, the call will be terminated and a `reconnectFailed` error will be triggered. * Default value is 60 seconds (defined by `DEFAULT_TIMEOUT`). * This timeout helps prevent calls from being stuck in a "reconnecting" state indefinitely. ### `customLogger` ```swift theme={null} public internal(set) var customLogger: TxLogger? ``` Custom logger implementation for handling SDK logs If not provided, the default logger will be used ### `useTrickleIce` ```swift theme={null} public internal(set) var useTrickleIce: Bool = false ``` Controls whether the SDK should use trickle ICE for WebRTC signaling. When enabled, ICE candidates are sent individually as they are discovered, rather than waiting for all candidates to be gathered before sending the offer/answer. * Note: This improves call setup time by allowing ICE connectivity checks to start earlier. * Important: This setting is disabled by default to maintain compatibility with existing implementations. ### `enableCallReports` ```swift theme={null} public internal(set) var enableCallReports: Bool = true ``` Enable automatic call quality reporting to voice-sdk-proxy. When enabled, WebRTC stats are collected periodically during calls and posted to the voice-sdk-proxy /call\_report endpoint when the call ends. * Important: This setting is enabled by default. ### `callReportInterval` ```swift theme={null} public internal(set) var callReportInterval: TimeInterval = 5.0 ``` Interval in seconds for collecting call statistics. Stats are aggregated over each interval and stored locally until call end. * Important: Default is 5 seconds. ### `callReportLogLevel` ```swift theme={null} public internal(set) var callReportLogLevel: String = "debug" ``` Minimum log level to capture for call reports ("debug", "info", "warn", "error"). * Important: Default is "debug" to capture all logs. ### `callReportMaxLogEntries` ```swift theme={null} public internal(set) var callReportMaxLogEntries: Int = 1000 ``` Maximum number of log entries to buffer per call. * Important: Default is 1000 entries to prevent memory issues on long calls. ## Methods ### `init(sipUser:password:pushDeviceToken:ringtone:ringBackTone:pushEnvironment:logLevel:customLogger:reconnectClient:debug:forceRelayCandidate:enableQualityMetrics:sendWebRTCStatsViaSocket:reconnectTimeOut:useTrickleIce:enableCallReports:callReportInterval:callReportLogLevel:callReportMaxLogEntries:)` ```swift theme={null} public init(sipUser: String, password: String, pushDeviceToken: String? = nil, ringtone: String? = nil, ringBackTone: String? = nil, pushEnvironment: PushEnvironment? = nil, logLevel: LogLevel = .none, customLogger: TxLogger? = nil, reconnectClient: Bool = true, debug: Bool = false, forceRelayCandidate: Bool = false, enableQualityMetrics: Bool = false, sendWebRTCStatsViaSocket: Bool = false, reconnectTimeOut: Double = DEFAULT_TIMEOUT, useTrickleIce: Bool = false, enableCallReports: Bool = true, callReportInterval: TimeInterval = 5.0, callReportLogLevel: String = "debug", callReportMaxLogEntries: Int = 1000 ) ``` Constructor for the Telnyx SDK configuration using SIP credentials. * Parameters: * sipUser: The SIP username for authentication * password: The password associated with the SIP user * pushDeviceToken: (Optional) The device's push notification token, required for receiving inbound call notifications * ringtone: (Optional) The audio file name to play for incoming calls (e.g., "my-ringtone.mp3") * ringBackTone: (Optional) The audio file name to play while making outbound calls (e.g., "my-ringbacktone.mp3") * pushEnvironment: (Optional) The push notification environment (production or debug) * logLevel: (Optional) The verbosity level for SDK logs (defaults to `.none`) * customLogger: (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used * reconnectClient: (Optional) Whether the client should attempt to reconnect automatically. Default is true. * debug: (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. * forceRelayCandidate: (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. * enableQualityMetrics: (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. * sendWebRTCStatsViaSocket: (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. * reconnectTimeOut: (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. * useTrickleIce: (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. * enableCallReports: (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. * callReportInterval: (Optional) Interval in seconds for collecting call statistics. Default is 5.0. * callReportLogLevel: (Optional) Minimum log level to capture for call reports. Default is "debug". * callReportMaxLogEntries: (Optional) Maximum number of log entries to buffer per call. Default is 1000. #### Parameters | Name | Description | | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | sipUser | The SIP username for authentication | | password | The password associated with the SIP user | | pushDeviceToken | (Optional) The device’s push notification token, required for receiving inbound call notifications | | ringtone | (Optional) The audio file name to play for incoming calls (e.g., “my-ringtone.mp3”) | | ringBackTone | (Optional) The audio file name to play while making outbound calls (e.g., “my-ringbacktone.mp3”) | | pushEnvironment | (Optional) The push notification environment (production or debug) | | logLevel | (Optional) The verbosity level for SDK logs (defaults to `.none`) | | customLogger | (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used | | reconnectClient | (Optional) Whether the client should attempt to reconnect automatically. Default is true. | | debug | (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. | | forceRelayCandidate | (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. | | enableQualityMetrics | (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. | | sendWebRTCStatsViaSocket | (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. | | reconnectTimeOut | (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. | | useTrickleIce | (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. | | enableCallReports | (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. | | callReportInterval | (Optional) Interval in seconds for collecting call statistics. Default is 5.0. | | callReportLogLevel | (Optional) Minimum log level to capture for call reports. Default is “debug”. | | callReportMaxLogEntries | (Optional) Maximum number of log entries to buffer per call. Default is 1000. | ### `init(token:pushDeviceToken:ringtone:ringBackTone:pushEnvironment:logLevel:customLogger:reconnectClient:debug:forceRelayCandidate:enableQualityMetrics:sendWebRTCStatsViaSocket:reconnectTimeOut:useTrickleIce:enableCallReports:callReportInterval:callReportLogLevel:callReportMaxLogEntries:)` ```swift theme={null} public init(token: String, pushDeviceToken: String? = nil, ringtone: String? = nil, ringBackTone: String? = nil, pushEnvironment: PushEnvironment? = nil, logLevel: LogLevel = .none, customLogger: TxLogger? = nil, reconnectClient: Bool = true, debug: Bool = false, forceRelayCandidate: Bool = false, enableQualityMetrics: Bool = false, sendWebRTCStatsViaSocket: Bool = false, reconnectTimeOut: Double = DEFAULT_TIMEOUT, useTrickleIce: Bool = false, enableCallReports: Bool = true, callReportInterval: TimeInterval = 5.0, callReportLogLevel: String = "debug", callReportMaxLogEntries: Int = 1000 ) ``` Constructor for the Telnyx SDK configuration using JWT token authentication. * Parameters: * token: JWT token generated from [https://developers.telnyx.com/docs/v2/webrtc/quickstart](https://developers.telnyx.com/docs/v2/webrtc/quickstart) * pushDeviceToken: (Optional) The device's push notification token, required for receiving inbound call notifications * ringtone: (Optional) The audio file name to play for incoming calls (e.g., "my-ringtone.mp3") * ringBackTone: (Optional) The audio file name to play while making outbound calls (e.g., "my-ringbacktone.mp3") * pushEnvironment: (Optional) The push notification environment (production or debug) * logLevel: (Optional) The verbosity level for SDK logs (defaults to `.none`) * customLogger: (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used * reconnectClient: (Optional) Whether the client should attempt to reconnect automatically. Default is true. * debug: (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. * forceRelayCandidate: (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. * enableQualityMetrics: (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. * sendWebRTCStatsViaSocket: (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. * reconnectTimeOut: (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. * useTrickleIce: (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. * enableCallReports: (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. * callReportInterval: (Optional) Interval in seconds for collecting call statistics. Default is 5.0. * callReportLogLevel: (Optional) Minimum log level to capture for call reports. Default is "debug". * callReportMaxLogEntries: (Optional) Maximum number of log entries to buffer per call. Default is 1000. #### Parameters | Name | Description | | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- | | token | JWT token generated from [https://developers.telnyx.com/docs/v2/webrtc/quickstart](https://developers.telnyx.com/docs/v2/webrtc/quickstart) | | pushDeviceToken | (Optional) The device’s push notification token, required for receiving inbound call notifications | | ringtone | (Optional) The audio file name to play for incoming calls (e.g., “my-ringtone.mp3”) | | ringBackTone | (Optional) The audio file name to play while making outbound calls (e.g., “my-ringbacktone.mp3”) | | pushEnvironment | (Optional) The push notification environment (production or debug) | | logLevel | (Optional) The verbosity level for SDK logs (defaults to `.none`) | | customLogger | (Optional) Custom logger implementation for handling SDK logs. If not provided, the default logger will be used | | reconnectClient | (Optional) Whether the client should attempt to reconnect automatically. Default is true. | | debug | (Optional) Enables WebRTC communication statistics reporting to Telnyx servers. Default is false. | | forceRelayCandidate | (Optional) Controls whether the SDK should force TURN relay for peer connections. Default is false. | | enableQualityMetrics | (Optional) Controls whether the SDK should deliver call quality metrics. Default is false. | | sendWebRTCStatsViaSocket | (Optional) Whether to send WebRTC statistics via socket to Telnyx servers. Default is false. | | reconnectTimeOut | (Optional) Maximum time in seconds the SDK will attempt to reconnect a call after network disruption. Default is 60 seconds. | | useTrickleIce | (Optional) Controls whether the SDK should use trickle ICE for WebRTC signaling. Default is false. | | enableCallReports | (Optional) Enable automatic call quality reporting to voice-sdk-proxy. Default is true. | | callReportInterval | (Optional) Interval in seconds for collecting call statistics. Default is 5.0. | | callReportLogLevel | (Optional) Minimum log level to capture for call reports. Default is “debug”. | | callReportMaxLogEntries | (Optional) Maximum number of log entries to buffer per call. Default is 1000. | ### `validateParams()` ```swift theme={null} public func validateParams() throws ``` Validate if TxConfig parameters are valid * Throws: Throws TxConfig parameters errors # WebRTC iOS Client Push Notifications Configuration Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-push-config/index This class contains all the properties related to Push Notifications **STRUCT** # `TxPushConfig` ```swift theme={null} public struct TxPushConfig ``` This class contains all the properties related to Push Notifications ## Properties ### `PUSH_NOTIFICATION_PROVIDER` ```swift theme={null} public static let PUSH_NOTIFICATION_PROVIDER: String = "ios" ``` ### `pushDeviceToken` ```swift theme={null} public internal(set) var pushDeviceToken: String? ``` ### `pushNotificationProvider` ```swift theme={null} public internal(set) var pushNotificationProvider: String = PUSH_NOTIFICATION_PROVIDER ``` # WebRTC iOS Client Push IP Notifications Configuration Source: https://developers.telnyx.com/development/webrtc/ios-sdk/structs/tx-push-ip-config/index This structure contains all the properties related to Server Configuration from Push **STRUCT** # `TxPushIPConfig` ```swift theme={null} public struct TxPushIPConfig ``` This class contains all the properties related to Server Confuguration from Push ## Properties ### `rtc_ip` ```swift theme={null} public internal(set) var rtc_ip:String ``` ### `rtc_port` ```swift theme={null} public internal(set) var rtc_port:Int ``` ## Methods ### `init(rtc_ip:rtc_port:)` ```swift theme={null} public init(rtc_ip: String, rtc_port: Int) ``` # WebRTC JS ChangeLog Source: https://developers.telnyx.com/development/webrtc/js-sdk/changelog/index A comprehensive record of all updates, enhancements, and bug fixes. Stay informed about the latest features and improvements to optimize your development experience. ## [2.26.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.26.0...webrtc/v2.26.1) (2026-04-10) ### Structured Errors & Warnings * **Feat: wire structured errors and warnings across SDK** (#548) Comprehensive overhaul introducing typed error codes (`40xxx`–`49xxx`) and warning codes (`3xxxx`) throughout the SDK. Replaces previously swallowed errors with structured `TelnyxError` events and `ITelnyxWarning` notifications while maintaining backward compatibility. * **SDP errors (`400xx`):** offer, answer, local/remote description, and send failures * **Media errors (`420xx`):** microphone permission denied, device not found, general media failures * **Call-control errors (`440xx`):** hold failed, invalid parameters, BYE send failed, subscribe failed * **WebSocket/transport errors (`450xx`):** connection failed, reconnection exhausted, gateway failures * **Authentication errors (`460xx`):** login failed, invalid credentials, authentication required * **Network errors (`480xx`):** network offline * **Quality warnings (`310xx`):** high RTT, jitter, packet loss, low MOS * **Connection warnings (`320xx`):** low bytes received/sent * **ICE warnings (`330xx`):** connectivity lost, gathering timeout, peer connection failed, host-only candidates * **Auth warnings (`340xx`):** token expiring soon * **Session warnings (`350xx`):** session not reattached * **Chore: improve errors docs and export error/warning code constants** (#602) Restructured error-handling documentation for clarity. Exports `TELNYX_ERROR_CODES` and `TELNYX_WARNING_CODES` from the main package index so consumers can reference them directly. **Listening for errors and warnings:** ```ts theme={null} import { SwEvent, TelnyxError, TELNYX_ERROR_CODES, TELNYX_WARNING_CODES, } from '@telnyx/webrtc'; client.on(SwEvent.Error, (event) => { switch (event.error.code) { case TELNYX_ERROR_CODES.MICROPHONE_PERMISSION_DENIED: showMessage('Microphone access was denied.'); break; case TELNYX_ERROR_CODES.NETWORK_OFFLINE: showMessage('You appear to be offline.'); break; case TELNYX_ERROR_CODES.AUTHENTICATION_REQUIRED: showMessage('Session expired. Please re-authenticate.'); break; default: showMessage(event.error.message); } }); client.on(SwEvent.Warning, (event) => { if (event.warning.code === TELNYX_WARNING_CODES.PEER_CONNECTION_FAILED) { showBanner('Call connectivity degraded.'); } if (event.warning.code === TELNYX_WARNING_CODES.TOKEN_EXPIRING_SOON) { refreshToken(); } }); ``` ### Media Recovery * **Fix: interrupt call negotiation on media failure for non-receive-only peers** (#582) When media retrieval (e.g. microphone access) fails during peer initialization, the SDK now interrupts call negotiation immediately instead of continuing into SDP setup. Previously, media failures triggered hangup asynchronously, creating a race condition where an answer SDP could be created before hangup executed on inbound calls. Receive-only peers are unaffected since they do not require local media. **Media recovery on inbound calls:** ```ts theme={null} import { isMediaRecoveryErrorEvent } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: '...', mediaPermissionsRecovery: { enabled: true, timeout: 20000, onSuccess: () => console.log('Media recovered, call proceeding'), onError: (err) => console.error('Recovery failed', err), }, }); client.on(SwEvent.Error, (event) => { if (isMediaRecoveryErrorEvent(event)) { // Show a prompt so the user can grant microphone access // User need to implement it on their side showPermissionDialog({ deadline: event.retryDeadline, onAllow: () => event.resume(), // retries getUserMedia onDeny: () => event.reject(), // terminates the call }); } }); ``` * **Fix: remove trickleIce guard for attach method** (WEBRTC-3395) (#584) Removes the forced `trickleIce=false` override for the `attach` (reconnection) method. The guard was originally added for b2bua-rtc codec negotiation compatibility but is no longer needed. ### Call Teardown & Disconnect * **Fix: separate client.disconnect() and PUNT disconnect paths with correct BYE behavior** (#580) Distinguishes between client-initiated graceful disconnect and server-initiated disconnect (PUNT). `client.disconnect()` now sends BYE messages to active calls before purging; PUNT triggers `serverDisconnect()` which purges calls without BYE since the server connection is already gone. * **Feat: make hangup async, properly await BYE execution** (#581) **Breaking:** `hangup()` is now an **async** method returning `Promise` (previously synchronous/fire-and-forget). Callers can now `await hangup()` to ensure BYE messages are fully sent before proceeding, enabling clean call termination sequences. ```ts theme={null} // Before (fire-and-forget) call.hangup(); // After (await to ensure BYE is sent) await call.hangup(); ``` ### Features * **Feat: store source datacenter identifier from REGED message** (#583) The SDK now extracts and stores `dc` and `region` fields from the REGED WebSocket message, allowing consumers to identify which Telnyx regional infrastructure handled their connection. ### Bug Fixes * **fix(types):** point `types` field at `lib/src/index.d.ts` (#601) ### Documentation * **docs: Voice SDK Network Connectivity Requirements** (#564) New comprehensive guide covering signaling server endpoints, STUN/TURN addresses, media server IP subnets, port ranges (UDP 16384–32768), bandwidth requirements (Opus \~40 kbps, PCMU \~100 kbps), firewall configuration, and best practices for enterprise/VPN environments. ### CI / Chores * fix(ci): push release branch before pinning draft release target (#597) * fix(ci): pin draft target to bump SHA, publish from tag (#596) * fix(ci): single release-it call for bump + tag + draft (#593, #594) * fix(ci): allow non-immutable installs for draft release tagging step (#592) * fix(ci): drop lockfile update step, set YARN\_ENABLE\_IMMUTABLE\_INSTALLS=false (#591) * fix(ci): use --mode update-lockfile to avoid upgrading all deps (#589) * fix(ci): update lockfile after version bump in draft-release (#587) * fix(ci): create release tag after version bump commit (#586) * chore: include README.md in npm packages and remove Slack notifications (#578) ## [2.26.1-beta.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.26.1-beta.0...webrtc/v2.26.1-beta.2) (2026-04-08) * chore: release webrtc\@2.26.1-beta.1 (#595) * fix(ci): allow non-immutable installs for draft release tagging step (#592) * fix(ci): allow non-immutable installs for draft release tagging step * fix(ci): drop lockfile update step, set YARN\_ENABLE\_IMMUTABLE\_INSTALLS=false (#591) * fix(ci): use --mode update-lockfile to avoid upgrading all deps (#589) * fix(ci): update lockfile after version bump in draft-release (#587) * fix(ci): create release tag after version bump commit (#586) * Fix: interrupt call negotiation on media failure for non-receive-only peers (#582) * feat: make hangup async, properly await BYE execution (#581) * Feat: wire structured errors and warnings across SDK (#548) ## [2.26.1-beta.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.26.1-beta.0...webrtc/v2.26.1-beta.1) (2026-04-08) * fix(ci): allow non-immutable installs for draft release tagging step (#592) * fix(ci): allow non-immutable installs for draft release tagging step * fix(ci): drop lockfile update step, set YARN\_ENABLE\_IMMUTABLE\_INSTALLS=false (#591) * fix(ci): use --mode update-lockfile to avoid upgrading all deps (#589) * fix(ci): update lockfile after version bump in draft-release (#587) * fix(ci): create release tag after version bump commit (#586) * Fix: interrupt call negotiation on media failure for non-receive-only peers (#582) * feat: make hangup async, properly await BYE execution (#581) * Feat: wire structured errors and warnings across SDK (#548) ## [2.26.1-beta.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.26.0...webrtc/v2.26.1-beta.0) (2026-04-07) * docs: update ts docs * fix: read dc/region instead of local\_dc/local\_region from REGED params * refactor: rename localDc/localRegion to dc/region and use structured logging * feat: store local\_dc and local\_region from REGED message * feat: store source datacenter identifier from REGED message * chore: include README.md in npm packages and remove Slack notifications (#578) ## [2.26.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.29...webrtc/v2.26.0) (2026-03-31) * chore: upgrade Node.js to 24.5.0 (npm 11.5.1 for OIDC trusted publishing) (#576) ## [2.25.29](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.28...webrtc/v2.25.29) (2026-03-31) * fix: upgrade actions/setup-node from v4 to v6 for OIDC compatibility (#574) ## [2.25.28](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.27...webrtc/v2.25.28) (2026-03-31) * chore: upgrade Node.js from 18 to 22.14 across all workflows (#572) * chore: release webrtc\@2.25.27 (#571) ## [2.25.27](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.26...webrtc/v2.25.27) (2026-03-31) * chore: remove NODE\_AUTH\_TOKEN from publish steps for OIDC auth (#570) ## [2.25.26](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.26-beta.4...webrtc/v2.25.26) (2026-03-31) * fix: guard against null localDescription in \_onIceSdp (#557) * chore: consolidate publish workflows for npm trusted publisher OIDC (#567) * fix: reset keepalive on any inbound message to prevent false ping/pong warnings (#556) * fix: don't null global LogCollector on call cleanup (#555) * chore: add OIDC permissions and npm provenance to prerelease workflow (#566) * chore: add OIDC permissions and npm provenance to publish-release workflow (#565) ## [2.25.26-beta.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.25...webrtc/v2.25.26-beta.2) (2026-03-13) * docs: update ts docs * feat: add recoveredCallId to call object for recovery correlation (ENGDESK-50308) ## [2.25.25](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.24...webrtc/v2.25.25) (2026-03-11) * docs: update ts docs * fix: disable trickle ICE for attach (reconnection) (#550) * feat: add recvonly audio transceiver when audio=false (WEBRTC-3394) (#549) * feat(WEBRTC-3324): support target\_params in anonymous\_login (#542) * feat: auto-trigger developer docs update on JS SDK release (#545) ## [2.25.24](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.23...webrtc/v2.25.24) (2026-03-03) * docs: update ts docs * fix: handle getUserMedia failure gracefully (no microphone) (#541) * feat: add audioLevel + transport stats to call report (WEBRTC-3321) (#540) ## [2.25.23](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.22...webrtc/v2.25.23) (2026-02-27) * docs: update ts docs * feat: add ICE candidate pair stats to call report (WEBRTC-3302) (#538) * chore: release webrtc\@2.25.22 (#536) ## [2.25.22](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.21...webrtc/v2.25.22) (2026-02-26) * fix: retry once on network error when posting call report (#534) ## [2.25.21](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.20...webrtc/v2.25.21) (2026-02-25) * fix: send call reports for calls shorter than the collection interval (#532) ## [2.25.20](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.19...webrtc/v2.25.20) (2026-02-25) * fix: serialize log context to capture DOM Event properties in call reports (#520) * chore: update CODEOWNERS to @lucasassisrosa @ArtemPapazian (#530) * fix: set direction before setState on inbound invite (#527) * fix: use state-dependent hangup cause code (#528) ## [2.25.19](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.15...webrtc/v2.25.19) (2026-02-23) * fix: commit CHANGELOG.md before yarn release to avoid dirty worktree error (#524) * fix: strip localElement and remoteElement from dialogParams (#450) (#521) * fix: keep loglevel at debug so LogCollector captures all logs for call reports (#522) * feat: enable prefetchIceCandidates by default (#523) * fix: Apply safety timeout to all close() calls (#515) * chore: generate CHANGELOG.md in draft-release workflow (#519) * chore: use ubuntu-latest runner for draft-release workflow (#517) * feat: automatic call quality reporting to voice-sdk-proxy (#494) * fix: reuse single VertoHandler instance and convert static state to instance state (#509) * fix(WEBRTC-3267): Fire telnyx.ready event on reconnection (#513) * fix(WEBRTC-3266): Prevent race condition in network reconnection by deferring \_wasOffline reset (#511) * fix(ENGDESK-49463): use correct hangup code (16) instead of hardcoded USER\_BUSY (17) (#506) * fix: set TURN transport to udp as default and tcp as fallback (#495) * fix: stop debug reporter when peer connection is closing (#498) * fix: remove canary flag requirement for trickleIce (#507) * fix: remove trickle ICE support check that sends empty candidate on login (#500) * docs: add 4014 gateway down close code to error handling (#504) * chore: fix TelnyxRTC.md (#497) * fix: if we get attach always run reconnection flow (#503) * FIX: Reconnection flow (#492) * feat: getUserMedia fallback for device-specific errors (#490) * docs: add authentication error handling documentation (#491) * fix: documentation on event listening (#489) ## [2.25.18](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.17...webrtc/v2.25.18) (2026-02-10) * fix: use correct hangup code (16) instead of hardcoded USER\_BUSY (17) * fix: stop debug reporter when peer connection is closing * fix: remove canary flag requirement for trickleIce * fix: remove trickle ICE support check that sends empty candidate on login * fix: set TURN transport to udp as default and tcp as fallback * fix: if we get attach always run reconnection flow * docs: add 4014 gateway down close code to error handling * chore: fix TelnyxRTC.md * chore: add meta-dev.yml for GitHub access control ## [2.25.17](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.16...webrtc/v2.25.17) (2026-02-02) * fix: reconnection flow * feat: implement manual Login function * feat: getUserMedia fallback for device-specific errors ## [2.25.16](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.15...webrtc/v2.25.16) (2026-01-22) * fix: documentation on event listening * docs: add authentication error handling documentation * docs: document manual re-authentication with new token ## [2.25.15](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.14...webrtc/v2.25.15) (2026-01-12) * fix: recreate call if peer connection signaling state is closed * chore: restart debug stats reporter on session reconnect * chore: expose PeerConnectionSignalingStateClosed event * chore: update documentation for event and error handling * fix: remote stream assignment to properly persist (@maiconpavi) * fix: propagate session forceRelayCandidate option to call * fix: address race condition on peer creation during reconnect * fix: active call leg on reconnection with ice restart * fix: send hangup msg before reconnectionOnAttach flag activation * fix: avoid creating multiple calls on reconnection * fix: flag usage on attach handler nested condition * fix: hangup bye execute logic and buffer manipulation * feat: update documentation on flag optimistic behavior ## [2.25.14](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.13...webrtc/v2.25.14) (2025-12-16) * fix: make sure offerToReceiveAudio is set if call audio options is undefined ## [2.25.12](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.11...webrtc/v2.25.12) (2025-12-15) * feat: clear intervals setup on device sleep wake ## [2.25.11](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.10...webrtc/v2.25.11) (2025-12-15) ### Enhancements * normalize logging calls * improve debug logs and socket disconnect on retry * add device sleep mode detection code ### Fixes * address connection state not transitioning * maintain call state on peer connection signaling state change ## [2.25.10](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.9...webrtc/v2.25.10) (2025-12-04) * fix: consider `keepConnectionAliveOnSocketClose` in session call for Punt * fix: do not empty execution queue on `keepConnectionAliveOnSocketClose` to avoid old refs ## [2.25.9](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.8...webrtc/v2.25.9) (2025-12-02) ### Enhancements * move `mutedMicOnStart` from call to client options ## [2.25.8](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.7...webrtc/v2.25.8) (2025-11-28) ### Features * add `iceServers` to client options * add `mutedMicOnStart` to call options ## [2.25.7](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.6...webrtc/v2.25.7) (2025-11-25) ### Features * add `useCanaryRtcServer` to client options ### Enhancements * add `call_id` for debug\_report\_start and debug\_report\_stop messages ## [2.25.6](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.5...webrtc/v2.25.6) (2025-11-18) ### Fixes * received authentication required counter cleanup ## [2.25.5](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.4...webrtc/v2.25.5) (2025-11-13) ### Fixes * punt message handling logic on `keepConnectionAliveOnSocketClose` option set ### Enhancements * add SwEvent handling reference with session readiness, notifications, diagnostics, and telemetry docs * add SwEvent error reference to error handling docs ## [2.25.4](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.3...webrtc/v2.25.4) (2025-11-12) * fix: ws connection down case on reconnection * chore: update `keepConnectionAliveOnSocketClose` docs to point users to client options usage ## [2.25.3](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.2...webrtc/v2.25.3) (2025-11-12) * fix: called createWebRTCStatsReporter before use statsReporter ## [2.25.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.25.1...webrtc/v2.25.2) (2025-11-07) ### Enhancements * update audio constraints types in call options * update ts docs * log audio constraints applied to peer connection ### Fixes * correct typings declaration file export ## [2.25.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.24.2...webrtc/v2.25.1) (2025-11-05) ### Features * add `keepConnectionAliveOnSocketClose` to client options ### Enhancements * improve logs on peer connection failure * remove legacy code * keep alive check on ping messages ### Fixes * correct method scope in browser session * clear call and peer connection on unrecoverable state * add cleanup to network listeners * reconnect on false positive reged state from gateway * restart ice on offer peer only * do not disconnect session on punt if `keepConnectionAliveOnSocketClose` is set * hangup and recreate call if peer connection instance is destroyed ## [2.24.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.24.1...webrtc/v2.24.2) (2025-11-04) * chore: socket connection error handling documentation (#460) ## [2.24.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.24.0...webrtc/v2.24.1) (2025-10-30) * fix: update inner `voice_sdk_id` state on first trickle ice canary use (#459) ## [2.24.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.19...webrtc/v2.24.0) (2025-10-29) ### Features * true trickle ice implementation (#439) ### Enhancements * check for gateway trickle ice support and add fallback * improve logging on connection state changes * add trickle ice performance metrics * remove legacy video code ## [2.22.19](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.18...webrtc/v2.22.19) (2025-10-29) fix: enforce callID from call options to be string (#456) ## [2.22.18](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.17...webrtc/v2.22.18) (2025-10-23) fix: expose getIsRegistered (#448) fix: preferred codecs should only be enforced on INVITE, not on ANSWER (#452) ## [2.22.17](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.16...webrtc/v2.22.17) (2025-08-04) chore: add detailed performance measuring for invite (#438) ## [2.22.16](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.15...webrtc/v2.22.16) (2025-08-04) feat: add support for image attachments (#436) ## [2.22.15](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.14...webrtc/v2.22.15) (2025-07-24) feat: pass target\_version\_id for anonymous login (#434) ## [2.22.14](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.13...webrtc/v2.22.14) (2025-07-09) feat: send messages to AI agents (#432) ## [2.22.13](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.12...webrtc/v2.22.13) (2025-07-04) fix: improve p2p connection establishment time (#431) fix: export Call via relative path (#429) ## [2.22.12](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.11...webrtc/v2.22.12) (2025-05-20) chore: Tidy up exposed interfaces in entrypoint (#428) ## [2.22.11](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.10...webrtc/v2.22.11) (2025-05-14) ### Bug fixes fix: the pre-call diagnosis report sometimes doesn't resolve. (#426) ## [2.22.10](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.9...webrtc/v2.22.10) (2025-05-09) ### Bug fixes fix: debug report file is not generated (#425) ## [2.22.9](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.8...webrtc/v2.22.9) (2025-04-14) ### Features feat: anonymous login and ai\_agent calls (#420) ## [2.22.8](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.7...webrtc/v2.22.8) (2025-03-28) ### Features feat: regional subdomains for voice-sdk (#417) ## [2.22.7](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.6...webrtc/v2.22.7) (2025-03-06) ### Features feat: implement real time call quality metrics (#414) feat: implement pre-call diagnosis (#407) ### Bug fixes fix: disable automatic video response in favor of answer option (#413) ## [2.22.6](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.5...webrtc/v2.22.6) (2025-02-20) ### Bug fixes fix: attach with video when receiving m=video sdp (#409) ## [2.22.5](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.4...webrtc/v2.22.5) (2025-01-17) ### Bug Fixes fix(webrtc): Stop ringback tone when call is hung up (#406) ## [2.22.4](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.3...webrtc/v2.22.4) (2025-01-14) ### Bug fixes Fix inconsistency in reporting `addConnection` debug event through the websocket ## [2.22.3](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.2...webrtc/v2.22.3) (2024-12-03) ### Bug fixes fix: Fix compatibility with NextJS ### Features feat: add option to force usage of relay candidate (#400) ## [2.22.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.1...webrtc/v2.22.2) (2024-11-14) ### Enhancement * WebRTC Debug Report: Enhance collected data. ### Features * add an option to allow ice candidate prefetching (#396) ## [2.22.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.22.0...webrtc/v2.22.1) (2024-10-14) ### Bug Fixes Improve stability for ICE gathering process. (See [#391](https://github.com/team-telnyx/webrtc/pull/391)) ## [2.22.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.21.2...webrtc/v2.22.0) (2024-10-14) ### Features * add reconnection flag to login message ([#380](https://github.com/team-telnyx/webrtc/issues/380)) ([643e252](https://github.com/team-telnyx/webrtc/commit/643e25240ec34a3262811e53fe46d907a2c32390)) * change reconnection logic ([#383](https://github.com/team-telnyx/webrtc/issues/383)) ([8ac1d8c](https://github.com/team-telnyx/webrtc/commit/8ac1d8ca14293dc09dc57e7c89b45ef4e6a6b5ff)) * publish generated docs to gh pages ([#385](https://github.com/team-telnyx/webrtc/issues/385)) ([d3a3d37](https://github.com/team-telnyx/webrtc/commit/d3a3d37d59678a4ad292b72c19fe8954ea91b16b)) * set client\_state from bye message ([#382](https://github.com/team-telnyx/webrtc/issues/382)) ([b2c4611](https://github.com/team-telnyx/webrtc/commit/b2c461124ccc70cf5604d40a6d2708c6014c4f83)) ### [2.21.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.21.1...webrtc/v2.21.2) (2024-09-05) ### Bug Fixes * keep socket open for longer ([#379](https://github.com/team-telnyx/webrtc/issues/379)) ([89b92ec](https://github.com/team-telnyx/webrtc/commit/89b92ec7b6a92647da5f35a710d33206a170bacb)) * use npm publish ([#376](https://github.com/team-telnyx/webrtc/issues/376)) ([ca965c4](https://github.com/team-telnyx/webrtc/commit/ca965c4d6c998977f637b9d47edf549d56492308)) ### [2.21.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.21.0...webrtc/v2.21.1) (2024-08-22) ### Bug Fixes * add .yarn/install\_state.gz to .gitignore ([#369](https://github.com/team-telnyx/webrtc/issues/369)) ([7b2b7a4](https://github.com/team-telnyx/webrtc/commit/7b2b7a41a5ed6a1ea992732549fff25fdab093ac)) * query param is appended multiple times ([#368](https://github.com/team-telnyx/webrtc/issues/368)) ([14c2711](https://github.com/team-telnyx/webrtc/commit/14c2711549e6738e4f09a6489e76d5bc4c84b442)) * upgrade ci to use yarn v2 ([#370](https://github.com/team-telnyx/webrtc/issues/370)) ([cc46e49](https://github.com/team-telnyx/webrtc/commit/cc46e491b057c67d1a884e3678098ab0515bb09a)) ## [2.21.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.20.0...webrtc/v2.21.0) (2024-08-14) ### Features * attach reconnection token to host ([#367](https://github.com/team-telnyx/webrtc/issues/367)) ([27be846](https://github.com/team-telnyx/webrtc/commit/27be8463f59a00d8e3369c2826efc3d3d8236b70)) ## [2.20.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.19.0...webrtc/v2.20.0) (2024-08-01) ### Features * get registration state from the gateway ([#366](https://github.com/team-telnyx/webrtc/issues/366)) ([c5af08b](https://github.com/team-telnyx/webrtc/commit/c5af08bcd45f53ea1dba3861a0a53229cf2dbc54)) ## [2.19.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.18.0...webrtc/v2.19.0) (2024-06-20) ### Features * log ice events ([#363](https://github.com/team-telnyx/webrtc/issues/363)) ([f591bcb](https://github.com/team-telnyx/webrtc/commit/f591bcb360c395863155936b5686a1d0ca6d28df)) ### Bug Fixes * add debug typespec ([#362](https://github.com/team-telnyx/webrtc/issues/362)) ([479e745](https://github.com/team-telnyx/webrtc/commit/479e7459ca006ad6395c249794562e9b074fbfa5)) ## [2.18.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.17.0...webrtc/v2.18.0) (2024-06-10) ### Features * support caller codec preference ([#361](https://github.com/team-telnyx/webrtc/issues/361)) ([cac97ac](https://github.com/team-telnyx/webrtc/commit/cac97acf042d7820dd41e501b6b8281e0a67e80d)) ## [2.17.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.16.0...webrtc/v2.17.0) (2024-05-28) ### Features * propagate session id with error event ([#358](https://github.com/team-telnyx/webrtc/issues/358)) ([0f931ed](https://github.com/team-telnyx/webrtc/commit/0f931ede12f637b7ec6db265162deb73dd2f2ff1)) ## [2.16.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.15.0...webrtc/v2.16.0) (2024-05-14) ### Features * chunk debug log ([#356](https://github.com/team-telnyx/webrtc/issues/356)) ([70b6e5e](https://github.com/team-telnyx/webrtc/commit/70b6e5ed1bd5e04443885497dccd2288284092d4)) ## [2.15.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.14.0...webrtc/v2.15.0) (2024-04-30) ### Features * add custom headers on bye ([#353](https://github.com/team-telnyx/webrtc/issues/353)) ([a17781c](https://github.com/team-telnyx/webrtc/commit/a17781c0df72256aab38f386fa90eb521f4aa246)) ## [2.14.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.13.0...webrtc/v2.14.0) (2024-04-26) ### Features * implement debug output for file and websocket ([#352](https://github.com/team-telnyx/webrtc/issues/352)) ([8d1f8e6](https://github.com/team-telnyx/webrtc/commit/8d1f8e6c6a0874d9a4a4be21c101f81678084afb)) ## [2.13.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.12.0...webrtc/v2.13.0) (2024-04-22) ### Features * add probe to fetch webrtc statistics periodically ([#350](https://github.com/team-telnyx/webrtc/issues/350)) ([2a72b60](https://github.com/team-telnyx/webrtc/commit/2a72b60843599dd824ee40ef79bdce2d8ba1ce52)) ## [2.12.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.11.0...webrtc/v2.12.0) (2024-04-05) ### Features * add a faster work-around for ice gathering never completing ([#349](https://github.com/team-telnyx/webrtc/issues/349)) ([47e1863](https://github.com/team-telnyx/webrtc/commit/47e18633b142263d49ca061f8b0c29fd5d5edf2a)) ## [2.11.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.10.2...webrtc/v2.11.0) (2024-02-26) ### Features * **TELAPPS-4794:** expose user agent on login ([#343](https://github.com/team-telnyx/webrtc/issues/343)) ([a8b9606](https://github.com/team-telnyx/webrtc/commit/a8b96068255c4cec50d43d737a85fea267f3b52a)) ### Bug Fixes * **ENGDESK-23349:** bind telnyxids on ringing event for outbound calls ([#342](https://github.com/team-telnyx/webrtc/issues/342)) ([1b1df78](https://github.com/team-telnyx/webrtc/commit/1b1df782c3c4034d412be079b92019e661dbd5ce)) * **ENGDESK-28811:** call object direction is undefined upon receiving call ([#341](https://github.com/team-telnyx/webrtc/issues/341)) ([8ac5a3f](https://github.com/team-telnyx/webrtc/commit/8ac5a3f6626d67cde4cf14c541aa26085be19ae6)) ### [2.10.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.10.1...webrtc/v2.10.2) (2024-02-20) ### Bug Fixes * **ENGDESK-26922:** Make `login_token` optional ([#340](https://github.com/team-telnyx/webrtc/issues/340)) ([1c0b36a](https://github.com/team-telnyx/webrtc/commit/1c0b36a8daec1d2552da7dde7842763c1aa477ca)) ### [2.10.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.10.0...webrtc/v2.10.1) (2023-11-23) ### Bug Fixes * the params.customHeaders was not being destructuring correctly the values ([#339](https://github.com/team-telnyx/webrtc/issues/339)) ([b7e1c2a](https://github.com/team-telnyx/webrtc/commit/b7e1c2a4dcc974b36f32c59a54a6380a8cbd4d07)) ## [2.10.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.9.0...webrtc/v2.10.0) (2023-11-22) ### Features * **ENGDESK-26634:** add custom headers to invite and answer messages ([#338](https://github.com/team-telnyx/webrtc/issues/338)) ([69814b4](https://github.com/team-telnyx/webrtc/commit/69814b4f4123b7dba777813836551ac771e54892)) * **ENGDESK-27107:** Upgrade WebRTC library to support React 18 ([#321](https://github.com/team-telnyx/webrtc/issues/321)) ([66d0c0e](https://github.com/team-telnyx/webrtc/commit/66d0c0ee8bcd458b20e7fe67c0561663c3190417)) ## [2.9.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.8.2...webrtc/v2.9.0) (2023-01-31) ### Features * **ENGDESK-21003:** add beforeunload event to hang up active calls when the browser is closed or refreshed ([#304](https://github.com/team-telnyx/webrtc/issues/304)) ([5f4a899](https://github.com/team-telnyx/webrtc/commit/5f4a8992e128c9ca9b7c7d5b84412daae2636dcc)) ### [2.8.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.8.1...webrtc/v2.8.2) (2022-09-28) ### Bug Fixes * **ENGDESK-19054:** Voice SDK missing types when installed in TypeScript projects. ([#299](https://github.com/team-telnyx/webrtc/issues/299)) ([ae76c98](https://github.com/team-telnyx/webrtc/commit/ae76c984d57c423d8bcac935be680670cfa8614e)) ### [2.8.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.8.0...webrtc/v2.8.1) (2022-07-07) ## [2.8.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.6...webrtc/v2.8.0) (2022-05-25) ### Features * **WEBRTC-1798:** add ping request to the server to keep connected ([#287](https://github.com/team-telnyx/webrtc/issues/287)) ([95ce187](https://github.com/team-telnyx/webrtc/commit/95ce187758112edba9f66a4e904c56f9a749dee7)) ### [2.7.6](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.5...webrtc/v2.7.6) (2022-04-26) ### [2.7.5](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.4...webrtc/v2.7.5) (2022-04-26) ### [2.7.4](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.3...webrtc/v2.7.4) (2022-04-25) ### Bug Fixes * change timeout value of 500 to use a random number between 3000 ([#246](https://github.com/team-telnyx/webrtc/issues/246)) ([34a232a](https://github.com/team-telnyx/webrtc/commit/34a232a768683aa8e60c395b658ce9ac44db47a6)) * **WEBRTC-1705:** reverting dependabot updates to fix typedoc generation ([#278](https://github.com/team-telnyx/webrtc/issues/278)) ([5ac667d](https://github.com/team-telnyx/webrtc/commit/5ac667d8d01df418dcbbc814968628121631e4e7)) ### [2.7.3](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.2...webrtc/v2.7.3) (2021-12-14) ### Bug Fixes * change previousGatewayState only if gateWayState exist to avoid send many REGISTER messages ([#244](https://github.com/team-telnyx/webrtc/issues/244)) ([70c10fa](https://github.com/team-telnyx/webrtc/commit/70c10faae274e08e019fdf2187af839dd0ad744c)) ### [2.7.2](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.1...webrtc/v2.7.2) (2021-12-13) ### Bug Fixes * **ENGDESK-12851:** add code to avoid multiples REGED messages on the client side ([#235](https://github.com/team-telnyx/webrtc/issues/235)) ([86b3a0e](https://github.com/team-telnyx/webrtc/commit/86b3a0e98cd7b6f60bc00beb1fb21773cdcb2401)) ### [2.7.1](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.7.0...webrtc/v2.7.1) (2021-12-09) ### Bug Fixes * add stop stream after query it ([#233](https://github.com/team-telnyx/webrtc/issues/233)) ([0e4fba9](https://github.com/team-telnyx/webrtc/commit/0e4fba97cfd98fd464f2076d1c32f7366366e9f2)) ## [2.7.0](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.6.2...webrtc/v2.7.0) (2021-12-08) ### Features * **WEBRTC-558:** add slack notification ([#219](https://github.com/team-telnyx/webrtc/issues/219)) ([3925a82](https://github.com/team-telnyx/webrtc/commit/3925a822d5c42658a23a7e9fd1df8ff563a723a1)) ### Bug Fixes * **Hotfix:** package.lock update and node upgrade to 14 ([#228](https://github.com/team-telnyx/webrtc/issues/228)) ([29b7c27](https://github.com/team-telnyx/webrtc/commit/29b7c2789dfac30083a0cb62ae4677e943cb5767)) * **WEBRTC-746:** recursive call to getDevices when the browser does not support audiooutput like Safari and Firefox. ([#223](https://github.com/team-telnyx/webrtc/issues/223)) ([bbc2231](https://github.com/team-telnyx/webrtc/commit/bbc2231cc1a62a1bff62bbcb974c7f0231fef06e)) ### [2.2.7](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.2.7...webrtc/v2.2.7) (2021-01-08) ### [2.2.6](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.2.6...webrtc/v2.2.6) (2021-01-08) ### [2.2.5](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.2.5...webrtc/v2.2.5) (2021-01-06) ### [2.2.4](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.2.4...webrtc/v2.2.4) (2020-12-11) ### [2.2.3](https://github.com/team-telnyx/webrtc/compare/webrtc/v2.2.2...webrtc/v2.2.3) (2020-12-04) ### Changed * Updates to `docs` ## [2.2.2](https://github.com/team-telnyx/webrtc/compare/v2.2.1-50-g0d4d2364801153f2d24afdee90fc15c856b000df...webrtc/v2.2.2) (2020-11-19) ### Bug Fixes * **ENGDESK-7173:** change the STUN\_SERVER port from 3843 to 3478 ([#60](https://github.com/team-telnyx/webrtc/issues/60)) ([cc8f78f](https://github.com/team-telnyx/webrtc/commit/cc8f78f1454039efb55b921c0de54df5c1326e8f)) ## 2.1.6 - 2020-10-05 ### Changed * Added cause and causeCode when hangup the call ## 2.1.5 - 2020-08-26 ### Changed * Removed adapter-webrtc it was breaking the react-native SDK ### Added * Added improvements in production bundle code. ## 2.1.4 - 2020-08-26 ### Changed * Enabled multiple connections in multiple devices (browsers, tabs, and etc) * Changed localStorage to use sessionStorage on Login class to save `sessid` ## 2.1.3 - 2020-08-13 ### Added * Added `SipReason` `SipCode` and `SIP Call ID` to show friendly error messages. ### Changed * Changed the project structure to use monorepo yarn workspaces. ## 2.1.2 - 2020-08-06 ### Fixed * Fixed alert message about `Authentication required` ## 2.1.1 - 2020-08-03 ### Added * Added a new react video example to make video call. ### Updated * Updated storybook react example, removed deprecated methods, and added new ones. ### Fixed * Fixed audio call on Firefox v78. It only add `offerToReceiveAudio/offerToReceiveVideo` when provided in the `options` ### Security * Fixed vulnerabilities in some dev dependencies. ## 2.1.0 - 2020-07-09 ### Added * Added the property `ringbackFile` to provide a ringback audio file. * Added support to play ringback file when receive the event `telnyx_rtc.ringing`. * Added the property `login_token` to support login with ephemeral token. * Added CHANGELOG file. ### Changed * Changed the property `ringFile` to be `ringtoneFile`. ### Security * Fixed vulnerabilities in some dev dependencies. ## 2.0.3 - 2020-06-08 ### Added * Added `setStateTelnyx` method to `BaseCall.ts`. ## 2.0.2 - 2020-05-12 ### Added * Added support to react-native ## 2.0.1 - 2020-05-12 ## First Release! ## Release: WebRTC SDK V2.22.17 feat: add call initialization metrics # Authentication Architecture Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/authentication-architecture/index How the three Telnyx WebRTC authentication methods relate — Credential Connections, Telephony Credentials, and JWTs — and when to use each. # Authentication Architecture Telnyx WebRTC has three authentication methods. They're not interchangeable — they form a hierarchy, and using the wrong one is the most common cause of security issues and unexpected behavior. *** ## The Hierarchy ```mermaid theme={null} flowchart TD subgraph CC["Credential Connection"] direction TB subgraph TC["Telephony Credential"] direction TB JWT["JWT (Access Token)"] end end CC ---|has many| TC TC ---|generates many| JWT style CC fill:#e3f2fd,stroke:#1565c0 style TC fill:#f3e5f5,stroke:#7b1fa2 style JWT fill:#e8f5e9,stroke:#2e7d32 ``` * **One Credential Connection** can have **multiple Telephony Credentials** * **Each Telephony Credential** can generate **multiple JWTs** *** ## The Three Methods ### 1. Credential Connection (`login` + `password`) ```javascript theme={null} const client = new TelnyxRTC({ login: 'my_credential', password: 'my_password', }); ``` **What it is:** Direct username/password authentication to the SIP infrastructure. **When to use:** Local development and testing only. **Limitations:** * Credentials are long-lived — they remain valid until manually deleted * No per-user isolation — one credential = one SIP registration * No automatic rotation or refresh **Portal page:** [Credential Connections](/development/webrtc/js-sdk/how-to/authenticating-your-app) *** ### 2. Telephony Credential (credential-based login) ```javascript theme={null} const client = new TelnyxRTC({ login: 'credential_username', password: 'credential_password', // Same API, but using a Telephony Credential instead of Connection credential }); ``` **What it is:** A SIP identity (username + password) managed under a Credential Connection. **When to use:** Quick prototyping, testing with multiple identities. **One credential per user.** Never share a Telephony Credential across multiple users or browser tabs. Each credential = one SIP registration. If two tabs register with the same credential, only the most recent one receives incoming calls. **Portal page:** [Telephony Credentials](/development/webrtc/js-sdk/how-to/authenticating-your-app) *** ### 3. JWT (`login_token`) ```javascript theme={null} const client = new TelnyxRTC({ login_token: 'eyJhbGciOiJSUzI1NiIs...', // JWT string }); ``` **What it is:** A time-limited, cryptographically signed token that authenticates your client. **When to use:** Production. Always. This is the recommended method. **Why it's recommended:** * **Time-limited** — tokens expire 24 hours after creation (or when the parent credential expires, whichever comes first) * **Per-device** — each device should use its own credential → its own JWT, preventing registration conflicts * **Refresh-aware** — the SDK emits a `TOKEN_EXPIRING_SOON` warning (code 34001) before expiry, so your app can request a fresh token from your backend * **Multiple concurrent sessions** — different users/devices can each have their own JWT without overwriting each other's SIP registration **Portal page:** [JWT Authentication](/development/webrtc/js-sdk/how-to/authenticating-your-app) *** ## Comparison | | Credential Connection | Telephony Credential | JWT | | ------------------ | --------------------- | -------------------- | ------------------------------------- | | **SDK field** | `login` + `password` | `login` + `password` | `login_token` | | **Anonymous** | — | — | `anonymous_login` (object) | | **Lifetime** | Permanent | Permanent | 24 hours (or credential expiry) | | **In browser?** | Dev only | Dev only | Production-ready | | **Per-user** | No | Yes | Yes | | **Revocable** | Delete credential | Delete credential | Disable parent credential | | **Rotation** | Manual | Manual | App handles via TOKEN\_EXPIRING\_SOON | | **Incoming calls** | Single registration | Single registration | Multi-user | | **Setup effort** | Low | Low | Medium (needs backend) | *** ## The JWT Flow in Production ### Initial connection ```mermaid theme={null} sequenceDiagram participant B as Browser participant A as Your Backend participant T as Telnyx API participant V as VSP B->>A: 1. Request token A->>T: 2. POST /telnyx_rtc/access_tokens T-->>A: { token: "eyJ..." } A-->>B: Return login_token B->>V: 3. Connect with JWT V-->>B: telnyx.ready ✓ ``` ### Token refresh JWTs expire after 24 hours. The SDK warns you before expiry so you can refresh without disconnecting: ```mermaid theme={null} sequenceDiagram participant B as Browser participant A as Your Backend participant T as Telnyx API Note over B: TOKEN_EXPIRING_SOON (34001) B->>A: 4. Request new token A->>T: 5. POST /telnyx_rtc/access_tokens T-->>A: { token: "new_eyJ..." } A-->>B: Return new login_token Note over B: client.updateToken(newToken) Note over B: Session continues ✓ ``` **Your backend must:** 1. Have a Telnyx API key (`TELNYX_API_KEY`) 2. Expose an endpoint that creates tokens for a given telephony credential 3. Return the token to the browser 4. Handle token refresh requests when `TOKEN_EXPIRING_SOON` (34001) fires See [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app) for the full implementation. *** ## Why "One Credential Per User" Matters ### Wrong — shared credential ```mermaid theme={null} flowchart LR A[User A] -->|register shared credential| V[VSP] B[User B] -->|register shared credential| V V -->|overwrites A's registration| X[Only B rings] A -.- X style A fill:#ffcdd2 style B fill:#c8e6c9 style X fill:#ffcdd2 ``` When two users share one credential, the second registration overwrites the first. **User A never receives incoming calls.** ### Correct — separate JWTs ```mermaid theme={null} flowchart LR A[User A] -->|register JWT_A| V[VSP] B[User B] -->|register JWT_B| V V -->|A's registration| A2[A rings] V -->|B's registration| B2[B rings] style A fill:#c8e6c9 style B fill:#c8e6c9 style A2 fill:#c8e6c9 style B2 fill:#c8e6c9 ``` With JWTs, each token maps to a unique session. Multiple users can register concurrently without conflicts. *** ## Common Mistakes | Mistake | What Happens | Fix | | ------------------------------------------ | ----------------------------------------------------------- | ----------------------------------- | | Using `login`+`password` for production | Long-lived credential, no rotation, no per-device isolation | Use `login_token` (JWT) | | Sharing one credential across users | Only last user gets incoming calls | One credential/JWT per user | | Not handling `TOKEN_EXPIRING_SOON` (34001) | Token expires → disconnected after 24h | Implement token refresh in your app | | Generating JWT in the browser | API key in client code | Generate JWT on your backend only | *** ## See Also * [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app) — Full code examples for all three methods * [IClientOptions](/development/webrtc/js-sdk/reference/iclientoptions) — `login_token`, `login`, `password` fields # Call State Lifecycle Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/call-state-lifecycle/index Every state a Telnyx WebRTC call goes through, what triggers each transition, and what your app should do at each stage. # Call State Lifecycle A call is a state machine. Understanding every state and transition is essential for building a reliable UI and handling edge cases like reconnection, transfer, and one-way audio. *** ## State Diagram ```mermaid theme={null} stateDiagram-v2 [*] --> new: newCall() new --> ringing: INVITE sent/received ringing --> active: answer() / 200 OK ringing --> destroyed: hangup() / reject active --> held: hold() held --> active: unhold() active --> destroyed: hangup() / BYE received held --> destroyed: hangup() active --> reconnecting: ICE/DTLS failure reconnecting --> active: media restored reconnecting --> destroyed: timeout ``` *** ## All States | State | Direction | Description | What your app should do | | -------------- | --------- | ------------------------------------ | ----------------------------------- | | `new` | Outbound | Call object created, ICE gathering | Show "Connecting..." | | `ringing` | Outbound | Remote party's phone is ringing | Show ringing UI, play ringback tone | | `ringing` | Inbound | Incoming call waiting | Show incoming call UI, ring tone | | `active` | Both | Call connected, media flowing | Show in-call UI, start timer | | `held` | Both | Call on hold (sendonly) | Show held state, dim audio | | `reconnecting` | Both | Media path lost, attempting recovery | Show reconnecting banner | | `destroyed` | Both | Call ended | Show call ended, clean up UI | *** ## Outbound Call States (Detailed) ### `new` → `ringing` ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); // call.state === 'new' // SDK is: gathering ICE candidates, preparing SDP, sending INVITE ``` **What happens internally:** 1. SDK creates a PeerConnection 2. ICE gathering starts (host → srflx → relay candidates) 3. SDP offer created with codec preferences 4. INVITE sent over WebSocket to VSP 5. VSP translates to SIP INVITE → carrier **Your app:** Show "Calling..." with a spinner. Don't start the call timer yet. ### `ringing` ```javascript theme={null} // Remote party's phone is ringing // call.state === 'ringing' ``` **What happens:** * Remote phone is ringing (SIP 180 Ringing) * You may hear ringback tone (generated locally by the SDK or played from network) **Your app:** Play ringback tone if SDK doesn't auto-play it. Show "Ringing..." state. ### `ringing` → `active` ```javascript theme={null} // Remote party answered // call.state === 'active' ``` **What happens internally:** 1. SIP 200 OK received from carrier 2. SDP answer processed — codecs and ICE candidates agreed 3. DTLS handshake completes — media is encrypted 4. SRTP audio starts flowing in both directions 5. Audio element auto-created and attached to DOM **Your app:** Start call timer. Show in-call controls (mute, hold, hangup). Check audio is playing. *** ## Inbound Call States (Detailed) ### `ringing` (incoming) ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; if (call.state === 'ringing' && call.direction === 'inbound') { // Incoming call! const from = call.remotePartyNumber; const to = call.remotePartyName; showIncomingCallUI({ from, to, call }); } } }); ``` **What happens internally:** 1. VSP receives SIP INVITE from carrier 2. VSP pushes invite message to SDK over WebSocket 3. SDK creates a Call object with `state: 'ringing'` 4. `telnyx.notification` fires with `callUpdate` **Your app:** Show incoming call UI. Play ringtone. Offer Accept/Reject buttons. ### `ringing` → `active` (answer) ```javascript theme={null} // User clicks "Accept" call.answer(); // call.state → 'active' ``` **What happens internally:** 1. SDK sends 200 OK over WebSocket 2. getUserMedia() — browser requests microphone permission 3. ICE gathering starts 4. SDP answer sent 5. DTLS handshake 6. Media flows \*\* Important:\*\* `call.answer()` triggers `getUserMedia()`. If the user hasn't granted microphone permission, the browser will show a permission dialog. The call won't be fully active until permission is granted. ### `ringing` → `destroyed` (reject) ```javascript theme={null} // User clicks "Reject" call.hangup(); // call.state → 'destroyed' ``` **What happens:** SDK sends SIP 487 Request Terminated (or CANCEL if INVITE still in progress). *** ## Active Call States ### `active` → `held` ```javascript theme={null} call.hold(); // call.state → 'held' ``` **What happens:** 1. SDK sends re-INVITE with `sendonly` media direction 2. Remote party's audio continues (they hear hold music if configured) 3. Your audio stops sending (microphone muted at SIP level) 4. Remote party receives a `callUpdate` with their call state changing ### `held` → `active` ```javascript theme={null} call.unhold(); // call.state → 'active' ``` **What happens:** 1. SDK sends re-INVITE with `sendrecv` media direction 2. Two-way audio resumes *** ## Reconnecting State ```javascript theme={null} // Network interruption during call // call.state → 'reconnecting' ``` **What triggers it:** * ICE connectivity checks fail (network change) * DTLS session breaks * WebSocket still connected but media path lost **What the SDK does:** 1. ICE restart — re-gathers candidates 2. Attempts to re-establish DTLS 3. If successful → `call.state → 'active'` (call resumes) 4. If fails after timeout → `call.state → 'destroyed'` (call drops) **Your app:** Show a "Reconnecting..." banner. Don't hang up — let the SDK try to recover. See [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) for details. *** ## Destroyed State All calls end up here. It's terminal — no further transitions. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.call.state === 'destroyed') { const call = notification.call; console.log(`Call ended. Direction: ${call.direction}`); console.log(`Duration: ${call.duration}s`); console.log(`End reason: ${call.cause}`); // normal, hangup, timeout, error } }); ``` **Common causes:** | Cause | Direction | Why | | ------------------ | --------- | ------------------------------------------- | | `normal` | Both | Normal hangup — either party ended the call | | `originatorCancel` | Outbound | Caller hung up while ringing | | `timeOut` | Outbound | No answer within timeout period | | `rejected` | Inbound | Callee rejected the call | | `error` | Both | Network error, ICE failure, or server error | | `replaced` | Both | Call was replaced (attended transfer) | **Your app:** Clean up UI. Upload call report. Show call summary if applicable. *** ## State Transition Matrix | From | To | Trigger | Direction | | -------------- | -------------- | ----------------------------- | --------- | | `new` | `ringing` | INVITE sent/received | Outbound | | `ringing` | `active` | `answer()` / 200 OK | Both | | `ringing` | `destroyed` | `hangup()` / reject / timeout | Both | | `active` | `held` | `hold()` | Both | | `held` | `active` | `unhold()` | Both | | `active` | `destroyed` | `hangup()` / BYE | Both | | `held` | `destroyed` | `hangup()` | Both | | `active` | `reconnecting` | ICE/DTLS failure | Both | | `reconnecting` | `active` | Media restored | Both | | `reconnecting` | `destroyed` | Timeout | Both | *** ## Common Pitfalls ### Double answer ```javascript theme={null} // WRONG — answering an already-active call call.answer(); // First answer — starts PeerConnection call.answer(); // Second answer — creates ANOTHER PeerConnection! // Result: Two PeerConnections, the second one never connects properly // SDK bug: CallReportCollector may track the wrong PC → reports show zero audio ``` **Fix:** Guard against double answer in your UI: ```javascript theme={null} let answered = false; function answerCall(call) { if (answered || call.state !== 'ringing') return; answered = true; call.answer(); } ``` ### Not handling `destroyed` ```javascript theme={null} // WRONG — only checking for 'active' if (call.state === 'active') { startTimer(); } // What if the call goes to 'destroyed'? Timer keeps running forever. // CORRECT — handle both if (call.state === 'active') { startTimer(); } else if (call.state === 'destroyed') { stopTimer(); cleanupCall(call); } ``` ### Missing `reconnecting` ```javascript theme={null} // If you don't handle reconnecting, the user thinks the call dropped // and tries to call again — creating a second call // Show a banner so the user knows to wait if (call.state === 'reconnecting') { showReconnectingBanner(); } ``` *** ## See Also * [Call Class](/development/webrtc/js-sdk/reference/call) — Methods for each state * [INotification](/development/webrtc/js-sdk/reference/inotification) — All notification types * [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) — Reconnection flow * [Handle Multiple Calls](/development/webrtc/js-sdk/explanation/call-state-lifecycle) — Hold/resume patterns * [How WebRTC Signaling Works](/development/webrtc/js-sdk/explanation/webrtc-signaling) — SIP message flow # How ICE & TURN Work Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/ice-and-turn/index How ICE connectivity checks, STUN, and TURN relay work in the Telnyx WebRTC JS SDK — and why they matter for call quality. # How ICE & TURN Work If you've ever wondered why some calls sound great and others don't, the answer is often in ICE — the protocol that finds the best path for media between two endpoints. Understanding ICE helps you diagnose one-way audio, connection failures, and latency issues. *** ## The Problem ICE Solves Two devices want to send audio to each other. But between them: * **NAT (Network Address Translation)** — Private IPs (192.168.x.x) aren't reachable from the internet * **Firewalls** — Block incoming connections * **Symmetric NAT** — Even STUN can't discover the public mapping ICE (Interactive Connectivity Establishment) systematically tries every possible path and picks the best one. *** ## The Three Candidate Types ICE discovers three types of candidates, in order of preference: ### 1. Host Candidates (Local) Your device's local network interfaces (e.g., `192.168.1.105` on WiFi). * **Works when:** Both devices are on the same LAN (rare for WebRTC calls) * **Quality:** Best — zero extra latency * **Reality:** Almost never used for WebRTC calls — both parties are rarely on the same network ### 2. Server-Reflexive Candidates (srflx) — via STUN Your public IP, discovered by asking a STUN server (e.g., `203.0.113.5`). **How STUN works:** 1. SDK sends a request to `stun.telnyx.com:3478` 2. STUN server sees the source IP (your public IP) 3. STUN server sends it back: "Your public IP is 203.0.113.5" 4. SDK creates a srflx candidate with that IP * **Works when:** Your NAT allows inbound traffic to the mapped port (most home/office routers) * **Quality:** Good — direct path, minimal extra latency * **Blockers:** Symmetric NAT, strict firewalls ### 3. Relay Candidates — via TURN An IP address allocated on a TURN server that relays your media (e.g., `64.16.248.1`). **How TURN works:** 1. SDK authenticates with `turn.telnyx.com:3478` (UDP) or `turn.telnyx.com:443` (TCP) 2. TURN server allocates a relay address (e.g., `64.16.248.1:50000`) 3. All media is sent TO the TURN server, which forwards it to the remote party 4. Remote party also sends TO the TURN server, which forwards to you * **Works when:** Always — TURN is the fallback that never fails * **Quality:** Adds latency (each packet goes through the TURN server) but guarantees connectivity * **Required when:** Symmetric NAT, strict corporate firewalls, mobile carriers that block P2P *** ## ICE Candidate Priority The SDK tries candidates in this priority order: | Priority | Type | Path | Latency Impact | | --------- | --------- | ------------------------ | ---------------------- | | 1 (best) | **Host** | Direct LAN | None | | 2 | **srflx** | Direct internet via STUN | Minimal | | 3 (worst) | **Relay** | Through TURN server | +20-80ms per direction | In practice, **most WebRTC calls use srflx (direct) or relay (TURN)**. Host candidates rarely work because both parties are on different networks. **A common misconception:** "If my call uses TURN relay, something is wrong." **False.** TURN relay is normal and expected in many network conditions — mobile networks, corporate networks, some ISPs. The question isn't "is TURN being used?" but "is the TURN server close to me?" *** ## ICE Gathering Process When a call starts, the SDK gathers candidates in this sequence: | Time | Event | Result | | ------- | -------------------------------------------- | ------------------------------------------------------------------------- | | t=0ms | SDK starts ICE gathering | Host candidates collected (e.g., `192.168.1.105` WiFi, `10.0.0.2` Docker) | | \~50ms | STUN request to `stun.telnyx.com:3478` | srflx candidate discovered (e.g., `203.0.113.5:54321`) | | \~100ms | TURN allocate to `turn.telnyx.com:3478` | relay candidate allocated (e.g., `64.16.248.1:50000`) | | \~200ms | SDP sent to remote party with all candidates | (or sent incrementally with Trickle ICE) | ### Trickle ICE By default, the SDK uses **Trickle ICE** — it sends candidates as they're discovered rather than waiting for all of them: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, trickleIce: true, // default in SDK 2.25.20+ }); ``` | Mode | Behavior | Call setup impact | | ----------------------- | --------------------------------------------------------------------------------------- | ----------------- | | **Without Trickle ICE** | SDK waits for ALL candidates (200-500ms) before sending INVITE | Slower setup | | **With Trickle ICE** | SDK sends INVITE immediately with host candidates, then sends srflx/relay as discovered | 200-500ms faster | *** ## ICE Connectivity Checks Once both sides have candidates, ICE performs connectivity checks in this order: | Step | Protocol | Purpose | | ---- | ------------------ | ---------------------------------------- | | 1 | **STUN Binding** | Can I reach you? Can you reach me? | | 2 | **Nomination** | This candidate pair works — let's use it | | 3 | **DTLS handshake** | Encrypt the media path | | 4 | **SRTP flows** | Encrypted audio starts | If the STUN check fails (e.g., firewall blocks it), ICE tries the next candidate pair until it finds one that works — falling back to TURN relay if necessary. *** ## DTLS — Encrypting Media After ICE finds a working path, DTLS (Datagram Transport Layer Security) encrypts the media: | Property | Value | | ------------ | ------------------------------------------ | | Protocol | DTLS-SRTP (RFC 5764) | | Cipher | AES\_CM\_128\_HMAC\_SHA1\_80 (most common) | | Key exchange | ECDHE (forward secrecy) | | Fingerprint | In SDP, verified during handshake | **DTLS states:** | State | Meaning | | ------------ | ------------------------------------------------- | | `new` | No handshake started | | `connecting` | Handshake in progress | | `connected` | Keys exchanged, media encrypted | | `failed` | Handshake failed (often a network/firewall issue) | If DTLS is stuck at `connecting`, media won't flow even if ICE connected. This is the #1 cause of one-way audio. *** ## TURN Server Selection Telnyx operates TURN servers in multiple regions: | Region | TURN Server | IP Range | | ------------ | ------------------------- | ----------- | | US East | `turn-us-east.telnyx.com` | 64.16.248.x | | US West | `turn-us-west.telnyx.com` | 64.16.229.x | | Europe | `turn-eu.telnyx.com` | 185.183.x.x | | Asia-Pacific | `turn-apac.telnyx.com` | (varies) | The SDK automatically selects the nearest TURN server. You can override: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, iceServers: [{ urls: 'turn:turn-eu.telnyx.com:443?transport=udp', username: '...', credential: '...', }], }); ``` ### UDP vs TCP TURN | Transport | Port | Latency | When to Use | | ----------------- | ---- | ------------------------ | -------------------------- | | **UDP** (default) | 3478 | Lower | Most cases | | **TCP** | 443 | Higher (\~20-40ms extra) | When UDP is blocked | | **TLS** | 443 | Highest | When TCP is blocked (rare) | The SDK tries UDP first, falls back to TCP automatically. *** ## Troubleshooting ICE Issues ### STUN fails (error 701) **Cause:** Firewall blocks `stun.telnyx.com:3478` (UDP) **Result:** No srflx candidates — must use relay **Fix:** Open UDP 3478 to STUN servers, or accept TURN relay ### All ICE fails **Cause:** Both STUN and TURN are blocked **Result:** Call cannot connect — no media path exists **Fix:** Open access to TURN servers (TCP 443 minimum) ### Relay when srflx should work **Cause:** Symmetric NAT — NAT mapping changes per destination **Result:** STUN-discovered port doesn't accept inbound from B2BUA-RTC **Fix:** This is normal; TURN relay is the correct solution ### High latency on relay **Cause:** TURN server is geographically distant **Result:** 100ms+ added round-trip **Fix:** Configure `iceServers` to use a closer TURN server *** ## See Also * [Configure Network & Firewall](/development/webrtc/js-sdk/how-to/configure-network-firewall) — Firewall rules and IP allowlists * [Debug Call Issues](/development/webrtc/js-sdk/how-to/debug-call-issues) — How to diagnose ICE/TURN problems * [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) — Check ICE stats in production * [Call State Lifecycle](/development/webrtc/js-sdk/explanation/call-state-lifecycle) * [How WebRTC Signaling Works](/development/webrtc/js-sdk/explanation/webrtc-signaling) # How WebRTC Signaling Works Source: https://developers.telnyx.com/development/webrtc/js-sdk/explanation/webrtc-signaling/index How the Telnyx WebRTC JS SDK communicates with Telnyx infrastructure — WebSocket connection, SIP signaling, and the full call flow from dial to hangup. # How WebRTC Signaling Works WebRTC itself has no signaling protocol — it only defines how to establish media. The signaling (how you say "call this number" or "I'm ringing") is up to the application. Here's how the Telnyx WebRTC SDK does it. *** ## The Signaling Path ```mermaid theme={null} flowchart LR A[Your App] --> B[TelnyxRTC SDK] B --> C[WebSocket] C --> D[VSP] D --> E[SIP Proxy] E --> F[Carrier] G[B2BUA-RTC] -.-> D G -.->|Media| Client style C fill:#e1f5fe style D fill:#f3e5f5 style G fill:#fff3e0 ``` **Key components:** | Component | Role | Protocol | | ----------------- | -------------------------------------------- | --------------- | | **Your App** | User interface | JavaScript | | **TelnyxRTC SDK** | SDK logic | Internal | | **VSP** | Voice SDK Proxy — translates WebSocket ↔ SIP | WebSocket + SIP | | **SIP Proxy** | Routes SIP messages to carriers | SIP/UDP | | **B2BUA-RTC** | Media gateway (WebRTC ↔ RTP) | DTLS/SRTP + RTP | **VSP handles signaling only.** B2BUA-RTC handles media only. They are separate systems. *** ## WebSocket Connection The SDK opens a single persistent WebSocket to `rtc.telnyx.com`: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt }); client.connect(); // WebSocket lifecycle: // 1. DNS resolves rtc.telnyx.com → nearest VSP instance // 2. TLS handshake (port 443) // 3. WebSocket upgrade // 4. Login message sent (JWT or credential) // 5. Server responds with session info // 6. telnyx.ready fires — you can make/receive calls ``` ### What the DNS resolution does `rtc.telnyx.com` resolves to the nearest VSP based on DNS-based geo-routing: | Region | VSP DC | | ------------- | --------- | | North America | NJ1 | | Europe | AMS3, FR5 | | Asia-Pacific | CN1 | If the DNS routes to a suboptimal VSP (e.g., an Indian client hitting FR5 instead of CN1), call latency increases. See [Configure Network & Firewall](/development/webrtc/js-sdk/how-to/configure-network-firewall) for troubleshooting. *** ## Outbound Call Flow When you call `client.newCall()`: ```mermaid theme={null} sequenceDiagram participant C as Client (SDK) participant V as VSP participant S as SIP Proxy participant R as Carrier C->>V: invite V->>S: SIP INVITE S->>R: INVITE R-->>S: 100 Trying S-->>V: 180 Ringing V-->>C: callUpdate (state: ringing) R-->>S: 200 OK S-->>V: 200 OK V-->>C: callUpdate (state: active) Note over C,R: Media flows (RTP/SRTP) ``` **What the SDK does at each step:** 1. **`newCall()`** — Creates a Call object, starts ICE gathering 2. **SIP INVITE** — SDK sends invite message over WebSocket, VSP translates to SIP 3. **SDP negotiation** — Codec selection (OPUS, PCMU, PCMA), ICE candidates exchanged 4. **Ringing** — Remote party's phone is ringing. `call.state === 'ringing'` 5. **Answer (200 OK)** — Remote party picked up. `call.state === 'active'` 6. **Media flows** — Audio transmitted via WebRTC (separate from signaling) *** ## Inbound Call Flow When someone calls your WebRTC client: ```mermaid theme={null} sequenceDiagram participant R as Carrier participant S as SIP Proxy participant V as VSP participant C as Client (SDK) R->>S: INVITE S->>V: SIP INVITE V->>C: invite C-->>V: (auto acknowledge) Note over C: callUpdate (state: ringing) C->>V: answer (call.answer()) V->>S: 200 OK S->>R: 200 OK Note over C,R: Media flows (RTP/SRTP) ``` **What the SDK does:** 1. **Incoming INVITE** — VSP receives SIP INVITE, pushes to SDK over WebSocket 2. **`callUpdate` notification** — `notification.call.state === 'ringing'` 3. **Your app decides** — Call `call.answer()` or `call.hangup()` 4. **Answer** — SDK sends 200 OK, establishes WebRTC media 5. **Media flows** — Two-way audio established *** ## Session Description Protocol (SDP) During call setup, both sides exchange SDP (Session Description Protocol) to agree on: | SDP Negotiates | Example | | -------------------- | ---------------------------------------------- | | **Audio codecs** | OPUS (preferred), PCMU (G.711u), PCMA (G.711a) | | **Codec parameters** | OPUS with FEC, stereo/mono, sample rate | | **ICE candidates** | How to reach each other for media | | **DTLS fingerprint** | For encrypting media (SRTP) | | **Media direction** | Sendrecv (two-way), sendonly, recvonly | | **Bandwidth** | Maximum bitrate | The SDK handles SDP negotiation automatically. You don't need to construct SDP manually. ### Codec Priority The SDK's default codec priority: 1. **OPUS** — Best quality, handles packet loss well, variable bitrate 2. **PCMU** — G.711μ-law, universal compatibility, 64kbps 3. **PCMA** — G.711A-law, European PSTN standard, 64kbps OPUS is strongly preferred — it handles jitter and packet loss better than G.711, and uses less bandwidth. *** ## WebSocket Reconnection If the WebSocket drops, the SDK automatically reconnects: ```mermaid theme={null} flowchart LR A[Connected] -->|connection lost| B[Reconnecting 1s] B --> C[Reconnecting 2s] C --> D[...] D -->|success| A D -->|~30s exhausted| E[Disconnected] ``` See [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) for the full reconnection behavior and how to handle it in your app. *** ## Custom Headers You can pass custom SIP headers in both directions: ### Outbound (your app → carrier) ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', customHeaders: [ { name: 'X-My-Header', value: 'value1' }, { name: 'X-Another', value: 'value2' }, ], }); ``` These appear as SIP headers in the INVITE. ### Inbound (carrier → your app) Inbound custom headers are available in the notification: ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate' && notification.call.state === 'ringing') { const customHeaders = notification.call.customHeaders; // e.g., { 'X-Caller-Name': 'John' } } }); ``` *** ## What Signals What | Action | SDK Method | SIP Message | Who Initiates | | ---------------- | ------------------- | ----------------------- | ------------- | | Make a call | `newCall()` | INVITE | Client | | Answer a call | `call.answer()` | 200 OK | Client | | Reject a call | `call.hangup()` | 487 Request Terminated | Client | | End a call | `call.hangup()` | BYE | Either side | | Put on hold | `call.hold()` | re-INVITE with sendonly | Client | | Resume from hold | `call.unhold()` | re-INVITE with sendrecv | Client | | Send DTMF | `call.sendDigits()` | INFO (RFC 2833) | Client | | Mute audio | `call.mute()` | (local only, no SIP) | Client | Mute is a **local operation** — it stops sending audio from your microphone but doesn't send any SIP signal. The remote party doesn't know you're muted (unless you tell them via your app). *** ## See Also * [Call State Lifecycle](/development/webrtc/js-sdk/explanation/call-state-lifecycle) * [How ICE & TURN Work](/development/webrtc/js-sdk/explanation/ice-and-turn) * [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) * [TelnyxRTC Class](/development/webrtc/js-sdk/reference/telnyxrtc) # Authentication Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/authenticating-your-app/index How to authenticate the Telnyx WebRTC JS SDK using JWT, credentials, or anonymous login. Includes token refresh and security best practices. # Authentication The Telnyx WebRTC SDK supports three authentication methods. **Use JWT for all production applications.** ## Overview | Method | IClientOptions | Use Case | Security | Identity | | -------------- | -------------------------- | ------------------------ | ----------------------- | -------------- | | **JWT** | `login_token` | Production | Token expires in 24h | Per-user | | **Credential** | `login` + `password` | Development only | Long-lived, no rotation | Per-credential | | **Anonymous** | `anonymous_login` (object) | AI assistant connections | No SIP identity | Per-assistant | **Use JWT (`login_token`) for all production applications.** Credentials (`login` + `password`) are long-lived with no automatic rotation. JWTs expire after 24 hours and can be refreshed via `TOKEN_EXPIRING_SOON`. *** ## Method 1: JWT (Recommended) JWT is the most secure authentication method. You generate a short-lived token on your backend and pass it to the SDK. ### How It Works ```mermaid theme={null} sequenceDiagram participant Browser participant YourBackend participant TelnyxAPI participant rtc.telnyx.com Browser->>YourBackend: Request JWT YourBackend->>TelnyxAPI: POST /telephony_credentials/{id}/token TelnyxAPI-->>YourBackend: JWT (expires in 24h) YourBackend-->>Browser: JWT Browser->>rtc.telnyx.com: new TelnyxRTC({ login_token: jwt }) rtc.telnyx.com-->>Browser: telnyx.ready ``` ### Step 1: Create a Credential Connection Create a SIP Credential Connection in the Telnyx Portal or via API: ```bash theme={null} curl -X POST https://api.telnyx.com/v2/credential_connections \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "connection_name": "My WebRTC Connection", "transport_protocol": "TLS", "sip_uri_calling_preference": "enabled", "sip_uri_calling_region": "any" }' ``` See [Credential Connections](/development/webrtc/js-sdk/how-to/authenticating-your-app) for full configuration options. ### Step 2: Create a Telephony Credential Each user needs their **own credential**. Never share one credential across multiple users. ```bash theme={null} curl -X POST https://api.telnyx.com/v2/telephony_credentials \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "connection_id": "YOUR_CONNECTION_ID", "name": "user-123" }' ``` See [Telephony Credentials](/development/webrtc/js-sdk/how-to/authenticating-your-app) for full CRUD operations. ### Step 3: Generate a JWT Generate the JWT on your **backend** — never on the client. This requires your API key. ```bash theme={null} curl -X POST https://api.telnyx.com/v2/telephony_credentials/{credential_id}/token \ -H "Authorization: Bearer YOUR_API_KEY" ``` **Response:** ``` eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ0ZWxueXhfdGVsZXBob255IiwiZXhwIjox... ``` This token expires in **24 hours**. You must handle refresh (see below). **Node.js example:** ```javascript theme={null} import Telnyx from 'telnyx'; const telnyx = new Telnyx(process.env.TELNYX_API_KEY); // Express endpoint: return JWT to authenticated user app.get('/api/telnyx-token', async (req, res) => { // Use the credential ID associated with this user const credentialId = getUserCredentialId(req.user.id); try { const token = await telnyx.telephonyCredentials.createToken(credentialId); res.send(token); } catch (err) { res.status(500).send({ error: 'Failed to generate token' }); } }); ``` ### Step 4: Use JWT in the SDK ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; // Fetch JWT from your backend const jwt = await fetch('/api/telnyx-token').then(r => r.text()); const client = new TelnyxRTC({ login_token: jwt, }); client.connect(); ``` ### Token Refresh JWTs expire after 24 hours. Handle the `TOKEN_EXPIRING_SOON` warning to refresh without dropping the connection: ```javascript theme={null} import { TELNYX_WARNING_CODES } from '@telnyx/webrtc'; client.on('telnyx.warning', async (warning) => { if (warning.code === 34001) { console.log('Token expiring soon — refreshing...'); try { const newToken = await fetch('/api/telnyx-token').then(r => r.text()); // Refresh token without reconnecting client.updateToken(newToken); console.log('Token refreshed '); } catch (err) { console.error('Failed to refresh token:', err); // Force reconnect if refresh fails client.disconnect(); client.connect(); } } }); ``` Start refreshing tokens at least **1 hour before expiry**. The `TOKEN_EXPIRING_SOON` warning fires \~1 hour before expiration. *** ## Method 2: Credential (Development Only) Use `login` + `password` for local development and testing only. ```javascript theme={null} const client = new TelnyxRTC({ login: 'gencred...', // SIP username from Telephony Credential password: 'your-password', // SIP password }); ``` **When to use:** * Local development and testing * Quick prototyping before setting up JWT infrastructure **When NOT to use:** * Production applications * Multi-user scenarios where each user needs their own identity * Any environment where you need automatic token rotation The `login` value is the `sip_username` from a Telephony Credential (e.g., `gencrednb4ADiBVjsvgvxem0OwkeNfryiIwhaUSJMJXjiwY3Y`). The `password` is set when creating the credential. *** ## Method 3: Anonymous (AI Assistants) Connect to an AI assistant without requiring a credential. The `anonymous_login` option accepts an object specifying the target: ```javascript theme={null} const client = new TelnyxRTC({ anonymous_login: { target_type: 'ai_assistant', target_id: 'YOUR_AI_ASSISTANT_ID', }, }); ``` **Use cases:** * Click-to-call widgets connecting users directly to an AI assistant * Embedding voice AI in web apps without managing credentials **Limitations:** * Cannot receive inbound calls * No SIP identity — calls are outbound to the specified AI assistant only * Limited call control features ### Continue a conversation Pass a `conversation_id` to resume an existing conversation with the AI assistant: ```javascript theme={null} const client = new TelnyxRTC({ anonymous_login: { target_type: 'ai_assistant', target_id: 'YOUR_AI_ASSISTANT_ID', target_params: { conversation_id: 'conv_xyz789', }, }, }); ``` *** ## Credential Hierarchy Understanding how Telnyx auth resources relate to each other: ```mermaid theme={null} graph TD A[Credential Connection] --> B1[Telephony Credential 1] A --> B2[Telephony Credential 2] A --> B3[Telephony Credential N] B1 --> C1[JWT 1 → User A] B2 --> C2[JWT 2 → User B] B3 --> C3[JWT 3 → User C] ``` * **Credential Connection** — SIP-level configuration (transport, codecs, webhook) * **Telephony Credential** — Individual identity (one per user) * **JWT** — Short-lived token generated from a credential **One credential per user.** Never share a credential across multiple users. Each user should have their own credential and their own JWT. Sharing credentials causes registration conflicts — only the most recently connected device receives inbound calls. *** ## Common Mistakes | Don't | Do | | -------------------------------------- | --------------------------------------- | | Use `login` + `password` in production | Use `login_token` (JWT) | | Share one credential across users | Create one credential per user | | Generate JWT on the client side | Generate JWT on your backend | | Ignore token expiry | Handle `TOKEN_EXPIRING_SOON` | | Hardcode JWTs in source code | Fetch JWTs from your backend at runtime | | Store API keys in client code | Keep API keys server-side only | *** ## Server-Side Token Generation Here's a complete Node.js/Express endpoint for generating JWTs: ```javascript theme={null} import express from 'express'; import Telnyx from 'telnyx'; const app = express(); const telnyx = new Telnyx(process.env.TELNYX_API_KEY); // Map your user IDs to Telnyx credential IDs // In production, store this in your database const userCredentialMap = { 'user-123': 'credential-abc', 'user-456': 'credential-def', }; app.get('/api/telnyx-token', async (req, res) => { // Authenticate user (your auth middleware) const userId = req.user?.id; if (!userId) { return res.status(401).send({ error: 'Not authenticated' }); } const credentialId = userCredentialMap[userId]; if (!credentialId) { return res.status(404).send({ error: 'No credential found for user' }); } try { const token = await telnyx.telephonyCredentials.createToken(credentialId); res.set('Cache-Control', 'no-store'); // Never cache JWTs res.send(token); } catch (err) { console.error('JWT generation failed:', err); res.status(500).send({ error: 'Token generation failed' }); } }); app.listen(3000); ``` *** ## See Also * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — Full client configuration * [Quickstart](/development/webrtc/js-sdk/quickstart) — Get started in 5 minutes * [Credential Connections API](/api-reference/credential-connections) — Create connections via API * [Telephony Credentials API](/api-reference/credentials) — Manage credentials via API * [Create Access Token API](/api-reference/access-tokens/create-an-access-token) — Generate JWTs via API * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices#security) — Security best practices # Network Connectivity Requirements Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/configure-network-firewall/index Required endpoints, ports, and firewall configuration for the Telnyx WebRTC JS SDK. # Network Connectivity Requirements For the Telnyx WebRTC JS SDK to function properly, the client must be able to reach Telnyx's signaling and media infrastructure. *** ## Overview The SDK requires connectivity to three types of endpoints: ```mermaid theme={null} graph LR A[Client Browser] -->|WebSocket WSS| B[rtc.telnyx.com:443] A -->|STUN UDP| C[stun.telnyx.com:3478] A -->|TURN UDP/TCP| D[turn.telnyx.com:443] B --> E[Telnyx SIP Platform] D --> E ``` *** ## Signaling The SDK uses a persistent WebSocket connection for call signaling (invite, answer, hangup, etc.). | Property | Value | | ------------- | ---------------------------- | | **Host** | `rtc.telnyx.com` | | **Port** | 443 | | **Protocol** | WSS (WebSocket Secure / TLS) | | **Direction** | Outbound | **Requirements:** * Outbound WebSocket connections must be allowed on port 443 * No HTTP long-polling fallback — WebSocket is required * Connection must remain open for the duration of the session **Custom endpoint:** You can override the signaling server using [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) `env` property, but this is not recommended for production. *** ## STUN STUN servers help the client discover its public IP address for ICE negotiation. | Property | Value | | ------------- | ------------------------- | | **Primary** | `stun.telnyx.com:3478` | | **Fallback** | `stun.l.google.com:19302` | | **Protocol** | UDP | | **Direction** | Outbound | The SDK automatically uses these STUN servers. No configuration required. *** ## TURN TURN servers relay media when direct peer-to-peer connectivity is not possible (e.g., symmetric NAT, restrictive firewalls). | Property | Value | | ------------------ | --------------------------------- | | **Host** | `turn.telnyx.com` | | **Port (UDP)** | 3478 | | **Port (TCP)** | 443 | | **Protocol** | UDP (preferred) / TCP (fallback) | | **Authentication** | Automatic (long-term credentials) | | **Direction** | Outbound | The SDK automatically provisions TURN credentials. No manual configuration required. **UDP vs TCP:** * **UDP** (preferred) — Lower latency, better for real-time audio * **TCP** (fallback) — Higher latency, used only when UDP is blocked TURN credentials are automatically provisioned by the SDK. You do not need to configure TURN usernames or passwords. *** ## Firewall Configuration ### Minimum required rules | Direction | Destination | Port | Protocol | Purpose | | --------- | ----------------- | ---- | -------- | ------------------ | | Outbound | `rtc.telnyx.com` | 443 | WSS | Signaling | | Outbound | `stun.telnyx.com` | 3478 | UDP | STUN | | Outbound | `turn.telnyx.com` | 3478 | UDP | TURN (media relay) | | Outbound | `turn.telnyx.com` | 443 | TCP | TURN (fallback) | ### Optional but recommended | Direction | Destination | Port | Protocol | Purpose | | --------- | ------------------- | ----- | -------- | ------------- | | Outbound | `stun.l.google.com` | 19302 | UDP | STUN fallback | ### Media ports RTP media uses dynamic ports allocated by the browser. These are ephemeral and cannot be whitelisted by port number. Instead: * **Ensure TURN is accessible** — TURN handles media relay when direct connectivity fails * **Allow UDP outbound** to Telnyx media servers (the `remote_media_ip` seen in SDP) * **Don't restrict outbound UDP to specific ports** — this will break WebRTC *** ## Restrictive Network Scenarios ### STUN fails (error 701) **Symptom:** Client cannot discover its public IP. No `srflx` or `prflx` ICE candidates. **Fix:** 1. Check firewall allows UDP to `stun.telnyx.com:3478` 2. If STUN is blocked, TURN may still work — the SDK falls back automatically 3. If both STUN and TURN are blocked, calls cannot connect ### TURN fails **Symptom:** Client is on a restrictive network (symmetric NAT), can't get `relay` candidates. **Fix:** 1. Check firewall allows TCP/443 to `turn.telnyx.com` 2. If UDP is blocked, TCP TURN will work but with higher latency 3. As a last resort, use `forceRelayCandidate: true` to skip direct connectivity attempts: ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', forceRelayCandidate: true, }); ``` ### Corporate VPN **Symptom:** Calls fail or have poor quality through VPN. **Fix:** 1. Whitelist `rtc.telnyx.com`, `stun.telnyx.com`, and `turn.telnyx.com` in VPN split-tunneling config 2. Ensure VPN doesn't block UDP traffic to TURN servers 3. Consider split-tunneling so WebRTC traffic bypasses the VPN ### Docker / Container environments **Symptom:** STUN errors, no ICE candidates, one-way audio. **Fix:** 1. Docker's default bridge network (`172.x` or `10.x`) can interfere with ICE candidate gathering 2. Use `--network host` mode for the container 3. Or configure the Docker network to use the host's network stack *** ## Testing Connectivity ### Quick test Open your browser's DevTools console and run: ```javascript theme={null} // Test WebSocket signaling const ws = new WebSocket('wss://rtc.telnyx.com:443'); ws.onopen = () => console.log(' WebSocket OK'); ws.onerror = () => console.error(' WebSocket FAILED'); // Test STUN const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.telnyx.com:3478' }], }); pc.createDataChannel('test'); pc.createOffer().then(offer => pc.setLocalDescription(offer)); pc.onicecandidate = (e) => { if (e.candidate) { const type = e.candidate.type; console.log(`ICE candidate type: ${type}`); if (type === 'srflx') console.log(' STUN works'); if (type === 'relay') console.log(' TURN works'); } }; ``` ### Debug tools * **SDK debug mode:** Set `debug: true` and `debugOutput: 'socket'` in [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) * **Debug visualizer:** Upload debug data to `https://webrtc-debug.telnyx.com/` * **Call reports:** Enable `enableCallReports: true` for programmatic access to ICE stats See [Debug Data & Call Quality Analysis](/development/webrtc/js-sdk/how-to/debug-call-issues) for interpreting debug output. *** ## Bandwidth Requirements | Codec | Bitrate | Notes | | ------------ | ---------- | ------------------------------------- | | Opus | 6-510 kbps | Default, adaptive. Typical: \~30 kbps | | PCMU (G.711) | 64 kbps | Fallback codec | | PCMA (G.711) | 64 kbps | Fallback codec | **Recommended minimum bandwidth per call:** * **Audio only:** 100 kbps (including overhead) * **With video:** 500-2000 kbps depending on resolution **RTT requirements:** | Quality | RTT | | ---------- | -------- | | Excellent | \< 100ms | | Good | \< 150ms | | Acceptable | \< 300ms | | Poor | > 300ms | *** ## See Also * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — ICE and network configuration * [Debug Data & Call Quality Analysis](/development/webrtc/js-sdk/how-to/debug-call-issues) — Interpreting ICE and quality data * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production deployment guide * [Error Handling](/development/webrtc/js-sdk/error-handling) — ICE and WebSocket error codes # Debug Data & Call Quality Analysis Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/debug-call-issues/index How to collect, interpret, and troubleshoot WebRTC call quality using debug reports, call reports, and the Telnyx debug visualizer. # Debug Data & Call Quality Analysis When calls have quality issues, the Telnyx WebRTC JS SDK provides multiple tools to diagnose the problem. This guide covers collecting debug data, interpreting results, and common troubleshooting patterns. *** ## Data Collection Methods | Method | When to Use | Data Available | | -------------------- | --------------------- | -------------------------------------------------- | | **Call Reports** | Production monitoring | RTT, jitter, packet loss, ICE state, audio levels | | **Debug Reports** | Deep troubleshooting | Full WebRTC stats, SDP, ICE candidates, timestamps | | **Console Debug** | Development | SDK internal logs, WebSocket messages | | **Debug Visualizer** | Visual analysis | Charts of call quality over time | *** ## Method 1: Call Reports (Production) Enable call reports for production quality monitoring: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, enableCallReports: true, callReportInterval: 5000, }); ``` See [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) for the full guide. *** ## Method 2: Debug Reports (Deep Troubleshooting) Enable debug output for detailed troubleshooting data. Use `debug: true` with `debugOutput` to control where the data goes: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, enableCallReports: true, // Collect call stats debug: true, // Enable debug mode debugOutput: 'file', // Write debug data to a file }); ``` Debug data includes: * Full ICE candidate list with timestamps * DTLS handshake state * SDP offer/answer with codec negotiation * Packet-level stats (bytes, packets, loss per direction) * Audio level measurements ### Accessing debug data Call report data is available via the Call Report Stats API after the call ends: ```bash theme={null} curl "http://voice-sdk-call-report-stats.query.prod.telnyx.io:4000/api/v1/calls/{user_id}/{call_id}" ``` ### Interpreting debug data **Key sections to check:** | Section | What to Look For | | ------------------------ | ------------------------------------------------- | | `ice_data.transport` | DTLS state, ICE state, SRTP cipher | | `ice_data.selected_pair` | Which candidate pair is in use (host/srflx/relay) | | `ice_data.candidates` | All gathered candidates with timestamps | | `segments` | Periodic RTT, jitter, packet loss measurements | *** ## Method 3: Console Debug (Development) Enable `debug: true` to get verbose SDK logging in the browser console: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, }); ``` This outputs SDK internal logs (WebSocket messages, ICE events, signaling) to the browser console. No additional configuration needed — `debug: true` enables console logging by default. *** ## Method 4: Debug Visualizer Send debug output to the Telnyx debug visualizer for graphical analysis: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, debugOutput: 'socket', // Send to visualizer }); ``` Open **[https://webrtc-debug.telnyx.com/](https://webrtc-debug.telnyx.com/)** in another tab to see the live visualization. The visualizer shows: * Call timeline with state transitions * ICE candidate gathering progress * DTLS handshake status * Audio quality graphs (RTT, jitter, packet loss) * Media flow direction *** ## Common Issues & Diagnosis ### One-Way Audio **Check:** 1. Is DTLS connected? → `ice_data.transport.dtls_state === "connected"` 2. Is audio being sent? → Check `bytesSent` in stats 3. Is audio being received? → Check `bytesReceived` in stats 4. Which candidate type? → `ice_data.selected_pair` shows host/srflx/relay **Common causes:** * Asymmetric TURN relay (two nominated candidate pairs, one sending and one receiving) * Firewall blocks media in one direction * VPN interferes with ICE candidates **Diagnosis from debug data:** ``` If dtls_state: "connecting" and ice_state: "connected" → DTLS handshake failing. Check for multiple NICs or asymmetric routing. If bytesSent > 0 but bytesReceived = 0 → Audio is being sent but not received. Check remote firewall. If bytesSent = 0 and bytesReceived > 0 → Audio is being received but not sent. Check local microphone permissions. ``` ### Call Doesn't Connect **Check:** 1. WebSocket state → `client.connection.connected` 2. ICE state → `ice_data.transport.ice_state` 3. STUN accessibility → Any `srflx` candidates? **Common causes:** * Firewall blocks `rtc.telnyx.com:443` (signaling) * Firewall blocks `stun.telnyx.com:3478` (STUN) * Firewall blocks `turn.telnyx.com:443` (TURN) * No `relay` candidates and symmetric NAT ### Choppy Audio **Check:** 1. Jitter → `stats.jitter > 50ms` is poor 2. Packet loss → `stats.packetLoss > 3%` is poor 3. RTT → `stats.rtt > 300ms` is poor **Common causes:** * WiFi congestion (high jitter) * Network congestion (high packet loss) * Long routing path (high RTT) * VPN adding latency ### Echo **Common causes:** * Built-in speakers + mic without echo cancellation * Two audio elements playing the same stream * Headset echo cancellation not working **Fix:** * Recommend headphones * Ensure only one audio element is active per call * Check browser echo cancellation settings *** ## Quick Diagnostic Script Run this in the browser console during a problematic call: ```javascript theme={null} (async () => { const client = window.__telnyxClient; // Your client instance const calls = client.calls; console.log('=== Telnyx Call Diagnostic ==='); console.log(`Active calls: ${calls.length}`); console.log(`Connected: ${client.connection.connected}`); for (const call of calls) { console.log(` Call ${call.id}: state=${call.state}, direction=${call.direction}`); console.log(` Remote: ${call.remotePartyNumber}`); const pc = call.peerConnection; if (pc) { const stats = await pc.getStats(); stats.forEach(report => { if (report.type === 'candidate-pair' && report.nominated) { console.log(` ICE: state=${report.state}, RTT=${report.currentRoundTripTime * 1000}ms`); } if (report.type === 'inbound-rtp' && report.kind === 'audio') { console.log(` Audio In: packets=${report.packetsReceived}, lost=${report.packetsLost}, jitter=${report.jitter}`); } if (report.type === 'outbound-rtp' && report.kind === 'audio') { console.log(` Audio Out: packets=${report.packetsSent}`); } }); } } })(); ``` *** ## See Also * [Call Report Stats](/development/webrtc/js-sdk/call-report-stats) — Full stats API reference * [Error Handling](/development/webrtc/js-sdk/error-handling) — Error and warning codes * [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall) — Firewall and connectivity * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — `debug`, `debugOutput` * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices#audio-quality) — Quality monitoring # Error Handling Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/error-handling/index How to handle errors, warnings, and connection failures with the Telnyx WebRTC JS SDK. # Error Handling The SDK exposes error-related behavior through three main channels: | Event | Purpose | Recommended use | | --------------------- | ------------------------------------------------------ | ---------------------------------------------- | | `telnyx.error` | Fatal or blocking SDK errors | Show actionable errors, retry, re-authenticate | | `telnyx.warning` | Non-fatal quality, connectivity, and token warnings | Show degraded-state UI, collect telemetry | | `telnyx.notification` | Call lifecycle updates and compatibility notifications | Drive call UI and hangup handling | Use `telnyx.ready` to know when the client is authenticated and the gateway is ready. Do not treat readiness as a notification case. *** ## Structured Errors (`telnyx.error`) `telnyx.error` is the primary error surface. Listen for it to handle authentication failures, media errors, and connection issues. ### Imports ```javascript theme={null} import { SwEvent, TelnyxError, TELNYX_ERROR_CODES, isMediaRecoveryErrorEvent, } from '@telnyx/webrtc'; ``` ### Basic example ```javascript theme={null} client.on(SwEvent.Error, (event) => { if (isMediaRecoveryErrorEvent(event)) { openPermissionsDialog({ deadline: event.retryDeadline, onRetry: () => event.resume(), onCancel: () => event.reject(), }); return; } if (!(event.error instanceof TelnyxError)) { showErrorMessage('An unknown SDK error occurred.'); return; } switch (event.error.code) { case TELNYX_ERROR_CODES.NETWORK_OFFLINE: showErrorMessage('You appear to be offline.'); break; case TELNYX_ERROR_CODES.AUTHENTICATION_REQUIRED: showErrorMessage('Session expired. Please authenticate again.'); break; default: showErrorMessage(event.error.message); } }); ``` ### Media permission recovery When `mediaPermissionsRecovery.enabled` is configured and `getUserMedia()` fails while answering a call, the error event includes `recoverable: true` with `resume()` and `reject()` callbacks: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, mediaPermissionsRecovery: { enabled: true, timeout: 10000, }, }); client.on(SwEvent.Error, (event) => { if (isMediaRecoveryErrorEvent(event)) { // Show a dialog asking the user to grant microphone permission // event.retryDeadline is the timestamp by which they must act showPermissionDialog({ onGrant: () => event.resume(), onDismiss: () => event.reject(), }); } }); ``` *** ## Error Code Reference ### SDP errors | Code | Name | Typical trigger | | ------- | ----------------------------------- | ----------------------------------------- | | `40001` | `SDP_CREATE_OFFER_FAILED` | `createOffer()` failed | | `40002` | `SDP_CREATE_ANSWER_FAILED` | `createAnswer()` failed | | `40003` | `SDP_SET_LOCAL_DESCRIPTION_FAILED` | `setLocalDescription()` failed | | `40004` | `SDP_SET_REMOTE_DESCRIPTION_FAILED` | `setRemoteDescription()` failed | | `40005` | `SDP_SEND_FAILED` | Invite/answer signaling could not be sent | ### Media errors | Code | Name | Typical trigger | | ------- | ------------------------------------ | ------------------------------------------------- | | `42001` | `MEDIA_MICROPHONE_PERMISSION_DENIED` | Browser or OS denied microphone permission | | `42002` | `MEDIA_DEVICE_NOT_FOUND` | Missing/disconnected device or invalid `deviceId` | | `42003` | `MEDIA_GET_USER_MEDIA_FAILED` | `getUserMedia()` failed for another reason | ### Call-control errors | Code | Name | Typical trigger | | ------- | ------------------------- | -------------------------------------------- | | `44001` | `HOLD_FAILED` | Hold request failed | | `44002` | `INVALID_CALL_PARAMETERS` | Required call params were missing or invalid | | `44003` | `BYE_SEND_FAILED` | BYE could not be sent | | `44004` | `SUBSCRIBE_FAILED` | Verto subscribe failed | ### WebSocket and transport errors | Code | Name | Typical trigger | | ------- | ----------------------------- | ---------------------------------------- | | `45001` | `WEBSOCKET_CONNECTION_FAILED` | WebSocket connection failed | | `45002` | `WEBSOCKET_ERROR` | Browser `ws.onerror` fired | | `45003` | `RECONNECTION_EXHAUSTED` | Reconnect attempts exhausted | | `45004` | `GATEWAY_FAILED` | Gateway reported `FAILED` or `FAIL_WAIT` | ### Authentication and session errors | Code | Name | Typical trigger | | ------- | ------------------------- | ----------------------------------------------- | | `46001` | `LOGIN_FAILED` | Login rejected or never reached ready state | | `46002` | `INVALID_CREDENTIALS` | Client-side login validation failed | | `46003` | `AUTHENTICATION_REQUIRED` | Request sent before auth or after auth was lost | | `48001` | `NETWORK_OFFLINE` | Browser `offline` event fired | | `49001` | `UNEXPECTED_ERROR` | Unclassified failure during peer/call setup | *** ## Structured Warnings (`telnyx.warning`) Warnings are not fatal. They describe degraded behavior, quality issues, or situations that may need user action before the session breaks. ### Basic example ```javascript theme={null} import { SwEvent, TELNYX_WARNING_CODES } from '@telnyx/webrtc'; client.on(SwEvent.Warning, ({ warning, callId }) => { if (warning.code === TELNYX_WARNING_CODES.TOKEN_EXPIRING_SOON) { refreshToken(); return; } if (warning.code === TELNYX_WARNING_CODES.PEER_CONNECTION_FAILED) { showWarningBanner('Call is reconnecting'); return; } console.warn(`[${warning.code}] ${warning.name}: ${warning.message}`); }); ``` ### Warning code reference #### Network quality warnings | Code | Name | Typical trigger | | ------- | ------------------ | ---------------------------------- | | `31001` | `HIGH_RTT` | RTT stayed above threshold | | `31002` | `HIGH_JITTER` | Jitter stayed above threshold | | `31003` | `HIGH_PACKET_LOSS` | Packet loss stayed above threshold | | `31004` | `LOW_MOS` | MOS stayed below threshold | #### Data-flow warnings | Code | Name | Typical trigger | | ------- | -------------------- | ------------------------------------- | | `32001` | `LOW_BYTES_RECEIVED` | Remote audio bytes stopped increasing | | `32002` | `LOW_BYTES_SENT` | Local audio bytes stopped increasing | #### Connectivity warnings | Code | Name | Typical trigger | | ------- | -------------------------- | ------------------------------------------ | | `33001` | `ICE_CONNECTIVITY_LOST` | ICE connection state became `disconnected` | | `33002` | `ICE_GATHERING_TIMEOUT` | ICE gathering safety timeout fired | | `33003` | `ICE_GATHERING_EMPTY` | No candidates were collected | | `33004` | `PEER_CONNECTION_FAILED` | Peer connection state became `failed` | | `33005` | `ONLY_HOST_ICE_CANDIDATES` | SDP contained only host ICE candidates | #### Authentication and session warnings | Code | Name | Typical trigger | | ------- | ------------------------ | -------------------------------- | | `34001` | `TOKEN_EXPIRING_SOON` | JWT expires within 120 seconds | | `35001` | `SESSION_NOT_REATTACHED` | Active call lost after reconnect | *** ## Call Termination Data When a call reaches `hangup`, inspect these fields on the `Call` object: | Field | Type | Meaning | | ----------- | -------- | ----------------------------------------------------- | | `cause` | `string` | High-level cause (`USER_BUSY`, `CALL_REJECTED`, etc.) | | `causeCode` | `number` | Numeric cause code | | `sipCode` | `number` | SIP response code when available | | `sipReason` | `string` | SIP reason phrase when available | Common causes: | Cause | Meaning | | -------------------- | ------------------------------------------ | | `NORMAL_CLEARING` | Expected call completion | | `USER_BUSY` | Remote party was busy | | `CALL_REJECTED` | Remote party rejected the call | | `NO_ANSWER` | Call timed out unanswered | | `UNALLOCATED_NUMBER` | Dialed number is invalid or does not exist | *** ## Socket Events ### `telnyx.socket.close` Delivers the browser `CloseEvent`. During a forced safety cleanup, the SDK emits a synthetic abnormal close with `code: 1006` and `wasClean: false`. Useful close codes: | Code | Meaning | | ------ | ---------------- | | `1000` | Normal closure | | `1001` | Going away | | `1006` | Abnormal closure | | `1011` | Internal error | ### `telnyx.socket.error` Delivers `{ error: ErrorEvent, sessionId: string }`. Browsers expose very little information for WebSocket errors. The SDK also emits `telnyx.error` with code `45002` (`WEBSOCKET_ERROR`) when `ws.onerror` fires. *** ## Connection State Helpers The browser session exposes WebSocket state helpers on `client.connection`: | Getter | Meaning | | ----------------------------- | ---------------------- | | `client.connection.connected` | WebSocket is in `OPEN` | | `client.connection.isAlive` | `CONNECTING` or `OPEN` | | `client.connection.isDead` | `CLOSING` or `CLOSED` | Example: ```javascript theme={null} const placeCall = (destinationNumber) => { if (!client.connection.connected) { showErrorMessage('Still connecting to Telnyx. Please try again shortly.'); return; } client.newCall({ destinationNumber }); }; ``` *** ## Reconnection Behavior On `telnyx.socket.close` or `telnyx.socket.error`, the SDK clears subscriptions and resets gateway readiness state. If `autoReconnect` is enabled, the browser session schedules `connect()` after `reconnectDelay` (1000ms). ### Gateway retry behavior * **UNREGED / NOREG:** Up to 5 registration retries, each delayed 2-6 seconds randomly. After that, `LOGIN_FAILED` (`46001`). * **FAILED / FAIL\_WAIT:** `GATEWAY_FAILED` (`45004`) emitted on first detection. Up to 5 retries with 2-6 second random delay before `RECONNECTION_EXHAUSTED` (`45003`). ### Keeping media alive If `keepConnectionAliveOnSocketClose` is `true`, the SDK preserves active peer connections while signaling reconnects. Recovery can create a new `Call` object with `recoveredCallId`. *** ## See Also * [Call Class](/development/webrtc/js-sdk/reference/call) — Call control methods * [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) — Reconnection guide * [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) — Quality monitoring * [Server Events](/development/webrtc/js-sdk/reference/sw-events) — Low-level signaling events # Reconnection & Call Recovery Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/handle-reconnection/index How the Telnyx WebRTC JS SDK handles reconnection, when calls survive network interruptions, and how to configure recovery behavior. # Reconnection & Call Recovery Network interruptions happen — Wi-Fi drops, VPNs reconnect, laptops sleep. The Telnyx WebRTC JS SDK automatically handles reconnection so your users experience minimal disruption. *** ## How Reconnection Works ```mermaid theme={null} stateDiagram-v2 [*] --> Connected: connect() Connected --> Reconnecting: WebSocket drops Reconnecting --> Connected: Reconnect succeeds Reconnecting --> Disconnected: Reconnect fails (exhausted) Connected --> Disconnected: disconnect() Disconnected --> [*] ``` When the WebSocket connection to `rtc.telnyx.com` drops: 1. **SDK detects the disconnect** via WebSocket `close` or `error` event 2. **SDK attempts reconnection** with exponential backoff (1s, 2s, 4s, 8s, 16s, 32s...) 3. **On successful reconnect**, the SDK re-authenticates and re-attaches to existing calls 4. **If reconnection fails** after exhausting retries, the `RECONNECTION_EXHAUSTED` error is emitted **No manual intervention required.** The SDK handles this automatically. *** ## When Calls Survive Reconnection Calls can survive a brief WebSocket disconnect if: | Condition | Required | | -------------------------------------------- | -------- | | Call was in `active` state | | | `keepConnectionAliveOnSocketClose` is `true` | | | PeerConnection is still alive | | | Reconnect happens within timeout | | **Configuration:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, keepConnectionAliveOnSocketClose: true, // Keep PeerConnection alive }); ``` When `keepConnectionAliveOnSocketClose` is enabled: * The PeerConnection (WebRTC media) stays alive even when the WebSocket (signaling) drops * Audio continues flowing during the reconnection attempt * On reconnect, the SDK re-attaches the existing call to the new WebSocket * The call ID may change — use `recoveredCallId` to correlate ### `recoveredCallId` After a successful reconnection, the call may have a new ID. The previous ID is available as `recoveredCallId`: ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; if (call.recoveredCallId) { console.log(`Call ${call.recoveredCallId} recovered as ${call.id}`); } } }); ``` *** ## When Calls Don't Survive | Scenario | Why | | ------------------------------------------------------- | ---------------------------------- | | Call was in `ringing` or `requesting` state | Not yet fully established | | `keepConnectionAliveOnSocketClose` is `false` (default) | PeerConnection closed immediately | | Reconnect took too long | PeerConnection timed out | | Network changed completely | DTLS fingerprint no longer matches | When a call doesn't survive reconnection, the SDK emits a `hangup` state for that call. *** ## Handling Reconnection in Your UI ### Show reconnection status ```javascript theme={null} let isReconnecting = false; client.on('telnyx.socket.close', () => { isReconnecting = true; showReconnectingBanner(); }); client.on('telnyx.ready', () => { if (isReconnecting) { isReconnecting = false; hideReconnectingBanner(); } }); client.on('telnyx.error', (error) => { if (error.code === TELNYX_ERROR_CODES.RECONNECTION_EXHAUSTED) { showDisconnectedMessage(); } }); ``` ### Handle recovered calls ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; if (call.recoveredCallId) { // Update your UI state to use the new call ID updateCallInUI(call.recoveredCallId, call.id); } } }); ``` *** ## Inbound Calls After Reconnection After a WebSocket reconnect, the browser may need to re-acquire microphone permissions to receive inbound calls. This is a browser security requirement, not an SDK limitation. ### `mediaPermissionsRecovery` Handle microphone permission failures for inbound calls with a recoverable error pattern. When enabled and `getUserMedia` fails while answering, the SDK emits a recoverable `telnyx.error` event with `resume()` and `reject()` callbacks so your app can prompt the user to fix permissions before the call fails: ```javascript theme={null} import { TelnyxRTC, isMediaRecoveryErrorEvent } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: jwt, mediaPermissionsRecovery: { enabled: true, timeout: 20000, // Wait up to 20s for user to fix permissions onSuccess: () => console.log('Media recovered'), onError: (err) => console.error('Recovery failed', err), }, }); client.on('telnyx.error', (event) => { if (isMediaRecoveryErrorEvent(event)) { showPermissionDialog({ onContinue: () => event.resume(), onCancel: () => event.reject?.(), }); } }); ``` **How it works:** 1. An inbound call arrives and the user tries to answer 2. `getUserMedia()` fails (permission denied, device busy, etc.) 3. Instead of immediately failing the call, SDK emits a recoverable error with `resume()` and `reject()` callbacks 4. Your app shows a UI prompting the user to grant permissions 5. If the user fixes permissions and you call `resume()`, the SDK retries `getUserMedia()` 6. If the user declines or `timeout` expires, the call is terminated `mediaPermissionsRecovery` only works for inbound calls. Recovery is attempted only when the initial `getUserMedia` call fails while answering. *** ## Explicit Disconnect When a user intentionally disconnects (e.g., signs out), you want to prevent automatic reconnection: ```javascript theme={null} // Bad — may auto-reconnect client.disconnect(); // Good — prevent auto-reconnect client.clearReconnectToken(); client.disconnect(); ``` `clearReconnectToken()` removes the session token that the SDK uses for automatic reconnection. After calling it, the SDK will not attempt to reconnect. *** ## Common Issues ### Rapid reconnection loops **Symptom:** WebSocket connects and immediately disconnects, repeating rapidly. **Cause:** Usually an authentication issue — the JWT has expired or the credential has been revoked. **Fix:** 1. Check that the JWT is still valid 2. Verify the credential still exists in the Telnyx Portal 3. Check for `telnyx.error` events with `AUTH_FAILED` code ### `RECONNECTION_EXHAUSTED` **Symptom:** SDK stops trying to reconnect after multiple failures. **Cause:** All reconnection attempts have been exhausted (exponential backoff capped). **Fix:** 1. Check network connectivity 2. Verify `rtc.telnyx.com` is reachable 3. Offer a manual "Reconnect" button in the UI: ```javascript theme={null} client.on('telnyx.error', (error) => { if (error.code === TELNYX_ERROR_CODES.RECONNECTION_EXHAUSTED) { showManualReconnectButton(); } }); // Manual reconnect reconnectButton.addEventListener('click', () => { client.connect(); }); ``` ### Calls die after network change (Wi-Fi → Cellular) **Symptom:** Call drops when switching networks, even with `keepConnectionAliveOnSocketClose`. **Cause:** The PeerConnection's ICE candidates are tied to the old network. The new network has different candidates that weren't part of the original negotiation. **Fix:** This is a WebRTC limitation. The SDK attempts ICE restart, but it may not always succeed. The user will need to place a new call. *** ## Configuration Summary | Option | Location | Default | Description | | ---------------------------------- | ---------------- | ------- | ---------------------------------------------------- | | `keepConnectionAliveOnSocketClose` | IClientOptions | `false` | Keep PeerConnection alive during WebSocket reconnect | | `mediaPermissionsRecovery` | IClientOptions | — | Auto-recover media permissions for inbound calls | | `clearReconnectToken()` | TelnyxRTC method | — | Prevent auto-reconnection on disconnect | *** ## See Also * [TelnyxRTC Class](/development/webrtc/js-sdk/classes/telnyxrtc) — Client configuration and methods * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — Full configuration reference * [Error Handling](/development/webrtc/js-sdk/error-handling) — Error codes including reconnection errors * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices#reconnection--recovery) — Production reconnection guidance # Framework Integration Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/integrate-with-frameworks/index How to integrate the Telnyx WebRTC JS SDK with React, Next.js, Vue, and other JavaScript frameworks. # Framework Integration The Telnyx WebRTC JS SDK works with any JavaScript framework. This guide covers integration patterns for popular frameworks. *** ## React ### Install ```bash theme={null} npm install @telnyx/webrtc @telnyx/react-client ``` ### Using the React wrapper The `@telnyx/react-client` package provides hooks and context providers: ```jsx theme={null} import { TelnyxClientProvider, useCall, useTelnyxClient } from '@telnyx/react-client'; function App() { return ( ); } function CallScreen() { const { client } = useTelnyxClient(); const { call, makeCall, hangup } = useCall(); return (
{call?.state === 'active' &&

Call in progress

} {call && }
); } ``` ### Using the SDK directly If you prefer to use the SDK without the React wrapper: ```jsx theme={null} import { useEffect, useRef, useState } from 'react'; import { TelnyxRTC } from '@telnyx/webrtc'; function useTelnyxRTC(token) { const clientRef = useRef(null); const [calls, setCalls] = useState([]); useEffect(() => { const client = new TelnyxRTC({ login_token: token }); client.on('telnyx.ready', () => { console.log('Connected'); }); client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { setCalls([...client.calls]); } }); client.connect(); clientRef.current = client; return () => { client.disconnect(); }; }, [token]); return { client: clientRef.current, calls }; } ``` Always disconnect the client on component unmount to prevent zombie WebSocket connections. *** ## Next.js Next.js requires special handling because the SDK uses browser APIs (`WebSocket`, `RTCPeerConnection`) that don't exist on the server. ### Dynamic import ```jsx theme={null} import dynamic from 'next/dynamic'; const CallScreen = dynamic(() => import('../components/CallScreen'), { ssr: false, // Required — SDK uses browser APIs }); export default function Page() { return ; } ``` ### Client component (App Router) ```jsx theme={null} 'use client'; import { useEffect, useState } from 'react'; export default function CallScreen() { const [client, setClient] = useState(null); useEffect(() => { // Dynamic import to avoid SSR import('@telnyx/webrtc').then(({ TelnyxRTC }) => { const rtc = new TelnyxRTC({ login_token: getToken() }); rtc.connect(); setClient(rtc); }); return () => { client?.disconnect(); }; }, []); return
Call UI here
; } ``` *** ## Vue ### Composable ```javascript theme={null} // composables/useTelnyx.js import { ref, onUnmounted } from 'vue'; import { TelnyxRTC } from '@telnyx/webrtc'; export function useTelnyx(token) { const client = ref(null); const calls = ref([]); const connected = ref(false); function connect() { const rtc = new TelnyxRTC({ login_token: token }); rtc.on('telnyx.ready', () => { connected.value = true; }); rtc.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { calls.value = [...rtc.calls]; } }); rtc.connect(); client.value = rtc; } function disconnect() { client.value?.disconnect(); connected.value = false; } onUnmounted(() => { disconnect(); }); return { client, calls, connected, connect, disconnect }; } ``` ### Component ```vue theme={null} ``` *** ## Angular ### Service ```typescript theme={null} import { Injectable, OnDestroy } from '@angular/core'; import { TelnyxRTC } from '@telnyx/webrtc'; @Injectable({ providedIn: 'root' }) export class TelnyxService implements OnDestroy { private client: TelnyxRTC | null = null; connect(token: string) { this.client = new TelnyxRTC({ login_token: token }); this.client.on('telnyx.ready', () => { console.log('Connected'); }); this.client.on('telnyx.notification', (notification) => { // Handle notifications }); this.client.connect(); } makeCall(destination: string) { return this.client?.newCall({ destinationNumber: destination, audio: true, }); } disconnect() { this.client?.disconnect(); this.client = null; } ngOnDestroy() { this.disconnect(); } } ``` *** ## General Patterns ### Token fetching All frameworks should fetch JWT tokens from a backend endpoint: ```javascript theme={null} // Don't hardcode tokens const token = await fetch('/api/telnyx-token').then(r => r.text()); ``` ### Audio element management The SDK auto-creates audio elements, but in some frameworks you may want to manage them yourself: ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, remoteElement: document.getElementById('remoteAudio'), localElement: document.getElementById('localAudio'), }); ``` Or after the call is active: ```javascript theme={null} // The SDK appends audio elements to document.body by default // You can move them: const audioEl = document.querySelector('audio[src^="blob:"]'); if (audioEl) { document.getElementById('audioContainer').appendChild(audioEl); } ``` ### Cleanup Always clean up on unmount/unload: ```javascript theme={null} // React useEffect(() => { return () => client?.disconnect(); }, []); // Vue onUnmounted(() => client?.disconnect()); // Angular ngOnDestroy() { this.client?.disconnect(); } // Vanilla window.addEventListener('beforeunload', () => client?.disconnect()); ``` *** ## See Also * [Quickstart](/development/webrtc/js-sdk/quickstart) — Get started in 5 minutes * [Authentication](/development/webrtc/js-sdk/how-to/authenticating-your-app) — JWT setup for production * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — Client configuration * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production deployment guide * [Demo App](https://github.com/team-telnyx/webrtc-demo-js) — Full React reference application # Call Report Stats Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/monitor-call-quality/index How to enable, access, and interpret WebRTC call reports from the Telnyx JS SDK — RTT, jitter, packet loss, ICE data, and audio quality metrics. # Call Report Stats The Telnyx WebRTC JS SDK can automatically collect WebRTC statistics during and after calls. Use call reports to monitor quality, diagnose issues, and build real-time quality indicators. *** ## Enabling Call Reports ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, enableCallReports: true, // Required (default: true) callReportInterval: 5000, // Stats every 5 seconds (default) }); ``` | Option | Type | Default | Description | | -------------------- | --------- | ------- | ------------------------------------- | | `enableCallReports` | `boolean` | `true` | Enable call report collection | | `callReportInterval` | `number` | `5000` | Interval in ms between periodic stats | *** ## Real-Time Stats (`telnyx.stats.frame`) Fires periodically during an active call (every `callReportInterval` ms): ```javascript theme={null} client.on('telnyx.stats.frame', (stats) => { console.log('RTT:', stats.rtt); console.log('Jitter:', stats.jitter); console.log('Packet loss:', stats.packetLoss); }); ``` ### StatsFrame Properties | Property | Type | Description | | ----------------- | -------- | --------------------------------- | | `rtt` | `number` | Round-trip time in milliseconds | | `jitter` | `number` | Jitter in milliseconds | | `packetLoss` | `number` | Packet loss percentage | | `bytesSent` | `number` | Total bytes sent | | `bytesReceived` | `number` | Total bytes received | | `packetsSent` | `number` | Total RTP packets sent | | `packetsReceived` | `number` | Total RTP packets received | | `packetsLost` | `number` | Total RTP packets lost | | `audioLevel` | `number` | Current audio level (0.0 - 1.0) | | `timestamp` | `number` | Unix timestamp of the measurement | ### Quality Thresholds | Metric | Good | Fair | Poor | | ----------- | -------- | --------- | ------- | | RTT | \< 150ms | 150-300ms | > 300ms | | Jitter | \< 20ms | 20-50ms | > 50ms | | Packet Loss | \< 1% | 1-3% | > 3% | ### Building a quality indicator ```javascript theme={null} client.on('telnyx.stats.frame', (stats) => { let quality = 'excellent'; if (stats.rtt > 300 || stats.packetLoss > 3) { quality = 'poor'; } else if (stats.rtt > 150 || stats.packetLoss > 1) { quality = 'fair'; } updateQualityIndicator(quality); }); ``` *** ## End-of-Call Report (`telnyx.stats.report`) Fires when a call ends with a summary of the entire call: ```javascript theme={null} client.on('telnyx.stats.report', (report) => { console.log('Call ended:', report.callId); console.log('Duration:', report.duration, 'seconds'); console.log('Average RTT:', report.avgRtt); }); ``` *** ## Call Report Stats API For SDK 2.25.20+, call reports are also available via HTTP API: ```bash theme={null} # Get full call report with ICE data curl "http://voice-sdk-call-report-stats.query.prod.telnyx.io:4000/api/v1/calls/{user_id}/{call_id}" # Get ICE candidate data curl "http://voice-sdk-call-report-stats.query.prod.telnyx.io:4000/api/v1/calls/{user_id}/{call_id}/ice" ``` ### API Response Structure ```json theme={null} { "data": { "call": { "call_id": "98041520-...", "duration": 45, "sdk_version": "2.26.3", "telnyx_session_id": "...", "telnyx_leg_id": "..." }, "segments": [ { "timestamp": 1712000000, "bytesSent": 12345, "bytesReceived": 23456, "rtt": 45, "jitter": 3, "audioLevel": 0.5 } ], "ice_data": { "transport": { "dtls_state": "connected", "ice_state": "connected", "srtp_cipher": "AES_CM_128_HMAC_SHA1_80" }, "selected_pair": { "local_candidate": { "type": "relay", "ip": "64.16.248.1", "port": 50000 }, "remote_candidate": { "type": "host", "ip": "10.239.207.80", "port": 50001 }, "nominated": true, "state": "succeeded" }, "candidates": [ { "type": "host", "ip": "192.168.1.5", "port": 50000, "timestamp": 1712000000 }, { "type": "srflx", "ip": "203.0.113.5", "port": 50000, "timestamp": 1712000001 }, { "type": "relay", "ip": "64.16.248.1", "port": 50000, "timestamp": 1712000002 } ] }, "logs": ["SDK console log entries if captured"] } } ``` ### Key Fields for Diagnostics | Field | Path | What It Tells You | | --------------- | -------------------------------- | ------------------------------------------------------------- | | DTLS state | `ice_data.transport.dtls_state` | `"connected"` = media encrypted , `"connecting"` = DTLS stuck | | ICE state | `ice_data.transport.ice_state` | `"connected"` = ICE worked | | SRTP cipher | `ice_data.transport.srtp_cipher` | Null = no encryption (DTLS failed) | | Selected pair | `ice_data.selected_pair` | Which candidate pair is actually in use | | Candidate types | `ice_data.candidates[].type` | `host` = direct, `srflx` = STUN, `relay` = TURN | *** ## Diagnosing Issues from Call Reports ### DTLS stuck ("connecting") ``` ice_data.transport.dtls_state: "connecting" ice_data.transport.ice_state: "connected" ice_data.transport.srtp_cipher: null ``` **Cause:** ICE succeeded but DTLS handshake failed. Usually a network issue where DTLS packets from one side aren't reaching the other (asymmetric routing, multiple NICs, firewall). **Action:** Check if client has multiple network interfaces. See [Best Practices → Network](/development/webrtc/js-sdk/how-to/production-best-practices#audio-quality). ### All relay candidates ``` ice_data.candidates: [ { type: "relay", ... }, { type: "relay", ... } ] ``` **Cause:** Client can't generate host or srflx candidates. Likely behind strict NAT or VPN. **Action:** Check firewall settings. If expected (e.g., for privacy), set `forceRelayCandidate: true`. ### No candidates at all ``` ice_data.candidates: [] ``` **Cause:** STUN/TURN servers unreachable, or browser denied media permissions before ICE gathering started. **Action:** Check network connectivity to `stun.telnyx.com` and `turn.telnyx.com`. See [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall). *** ## See Also * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — `enableCallReports`, `callReportInterval` * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices#audio-quality) — Quality monitoring guidance * [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall) — ICE/STUN/TURN configuration * [Debug Data & Call Quality Analysis](/development/webrtc/js-sdk/how-to/debug-call-issues) — Interpreting debug output # Production Best Practices Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/production-best-practices/index Production deployment guide for the Telnyx WebRTC JS SDK — security, reliability, performance, and monitoring. # Production Best Practices Going from "it works on my machine" to "it works for all users, reliably" requires addressing security, reliability, performance, and monitoring. This guide covers the key areas. *** ## Authentication ### Use JWT in production ```javascript theme={null} // Production const client = new TelnyxRTC({ login_token: jwt }); // Development only const client = new TelnyxRTC({ login: 'user', password: 'pass' }); ``` JWTs are time-limited, revocable, and don't expose passwords. See [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app). ### Generate JWTs on your backend ```javascript theme={null} // Backend generates token — API key never reaches the browser app.post('/api/telnyx-token', async (req, res) => { const token = await telnyx.telephonyCredentials.createToken(credentialId); res.json({ token }); }); // Never do this — API key in browser source const response = await fetch('https://api.telnyx.com/v2/telnyx_rtc/access_tokens', { headers: { Authorization: `Bearer ${API_KEY}` }, // API_KEY exposed! }); ``` ### Handle token refresh ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'userMediaError') return; // Check for token expiring soon if (notification.type === 'callUpdate' && notification.call?.state === 'destroyed') { // If disconnected due to auth, try refresh } }); // Or use the session event client.on('telnyx.ready', () => { console.log('Connected and authenticated'); }); ``` ### One credential per user Never share a Telephony Credential across multiple users. Each user must have their own JWT to ensure they receive their own incoming calls. *** ## Connection Management ### One client instance per tab ```javascript theme={null} // Create once let client = null; function getClient() { if (!client) { client = new TelnyxRTC({ login_token: getJwt() }); client.connect(); } return client; } // Creating multiple instances const client1 = new TelnyxRTC({ login_token: jwt }); // WebSocket 1 const client2 = new TelnyxRTC({ login_token: jwt }); // WebSocket 2 — wasteful ``` ### Clean up on page unload ```javascript theme={null} window.addEventListener('beforeunload', () => { if (client) { client.calls.forEach(call => call.hangup()); client.disconnect(); } }); ``` ### Handle reconnection gracefully ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; if (call.state === 'reconnecting') { showBanner('Connection lost. Reconnecting...'); } else if (call.state === 'active' && wasReconnecting) { hideBanner(); } } }); ``` See [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) for the full guide. *** ## Audio Quality ### Request microphone with constraints ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, // SDK handles getUserMedia internally }); ``` If you need to control the microphone before making a call: ```javascript theme={null} const stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true, }, }); ``` ### Monitor call quality Enable call reports in production: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, enableCallReports: true, callReportInterval: 5000, }); ``` Set up quality alerts: ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callQuality') { const { mos, rtt, jitter, packetLoss } = notification.callQuality; if (mos < 3.0 || rtt > 500 || jitter > 100 || packetLoss > 5) { logQualityIssue(notification); } } }); ``` ### Recommend headphones for agents Built-in speakers + microphone create echo. For call center agents, recommend USB headsets or enforce echo cancellation. *** ## Network Configuration ### Allowlist Telnyx domains Ensure your firewall allows: | Domain | Port | Protocol | Purpose | | ----------------- | ---- | --------------- | ------------- | | `rtc.telnyx.com` | 443 | WebSocket (TLS) | Signaling | | `stun.telnyx.com` | 3478 | UDP | STUN (ICE) | | `turn.telnyx.com` | 3478 | UDP | TURN relay | | `turn.telnyx.com` | 443 | TCP | TURN fallback | | `api.telnyx.com` | 443 | HTTPS | REST API | ### Don't force relay unless necessary ```javascript theme={null} // Only if you have a specific security requirement const client = new TelnyxRTC({ login_token: jwt, forceRelayCandidate: true, // Forces all media through TURN }); // Default — lets ICE find the best path const client = new TelnyxRTC({ login_token: jwt, }); ``` Forcing relay adds 20-80ms latency per direction. Use it only when corporate policy requires all media to go through a relay. See [Configure Network & Firewall](/development/webrtc/js-sdk/how-to/configure-network-firewall) for the full guide. *** ## Error Handling ### Always handle errors ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'userMediaError') { const { code, message } = notification.error; switch (code) { case 1: // Not allowed showError('Microphone access denied. Please allow access in browser settings.'); break; case 2: // Not found showError('No microphone detected. Please connect a microphone.'); break; case 3: // Not readable showError('Microphone in use by another application.'); break; } } }); ``` ### Handle connection failures ```javascript theme={null} client.on('telnyx.socket.close', () => { showError('Connection to Telnyx lost. Attempting to reconnect...'); }); client.on('telnyx.socket.error', (error) => { logError('WebSocket error', error); }); ``` ### Don't show raw errors to users ```javascript theme={null} // Technical error exposed to user showError(`Call failed: ${error.message}`); // User-friendly message showError('Unable to connect the call. Please try again.'); ``` *** ## Memory Management ### Clean up call references ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.call?.state === 'destroyed') { // Remove call from your state removeCallFromState(notification.call.id); } }); ``` ### Remove event listeners ```javascript theme={null} // When component unmounts (React example) useEffect(() => { const handler = (notification) => { /* ... */ }; client.on('telnyx.notification', handler); return () => { client.off('telnyx.notification', handler); }; }, []); ``` *** ## Monitoring & Observability ### Enable call reports ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, enableCallReports: true, // Auto-upload reports after each call callReportInterval: 5000, // Stats every 5 seconds }); ``` ### Track key metrics | Metric | Good | Warning | Critical | | ----------- | -------- | --------- | -------- | | MOS | > 4.0 | 3.0–4.0 | \< 3.0 | | RTT | \< 150ms | 150–300ms | > 300ms | | Jitter | \< 20ms | 20–50ms | > 50ms | | Packet Loss | \< 1% | 1–3% | > 3% | ### Log quality issues server-side ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callQuality') { sendToMonitoring({ callId: notification.call.id, mos: notification.callQuality.mos, timestamp: Date.now(), }); } }); ``` *** ## Deployment Checklist | Requirement | Details | | ------------------------------------------------- | ------------------------------------------------------------------- | | Authentication uses JWT | `login_token` in production, not `login`+`password` | | JWT generated on backend | API key never in browser | | Token refresh handles `TOKEN_EXPIRING_SOON` | Call `client.updateToken()` on warning code 34001 | | `beforeunload` disconnects client | Hang up calls and call `client.disconnect()` | | `enableCallReports: true` | Automatic call reports for production monitoring | | Error handling covers key events | `userMediaError`, `socket.close`, `socket.error` | | Firewall allows Telnyx domains | `rtc.telnyx.com:443`, `stun.telnyx.com:3478`, `turn.telnyx.com:443` | | Reconnection UI shown during `reconnecting` state | Users should see connection status | | Call references cleaned up on `destroyed` state | Prevent memory leaks | | No `forceRelayCandidate: true` unless required | Forced relay adds 20-80ms latency | | Quality metrics logged to monitoring | Track MOS, RTT, jitter, packet loss | | User-friendly error messages | No raw errors shown to users | *** ## See Also * [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app) * [Configure Network & Firewall](/development/webrtc/js-sdk/how-to/configure-network-firewall) * [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) * [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) * [Debug Call Issues](/development/webrtc/js-sdk/how-to/debug-call-issues) * [Error Handling](/development/webrtc/js-sdk/how-to/error-handling) # Device Management Source: https://developers.telnyx.com/development/webrtc/js-sdk/how-to/switch-audio-devices/index How to select, switch, and manage audio input/output devices (microphones, speakers) with the Telnyx WebRTC JS SDK. # Device Management The Telnyx WebRTC JS SDK uses the browser's `MediaDevices` API for audio device management. This guide covers selecting devices, switching mid-call, and handling permission changes. *** ## Enumerate Devices List available audio input and output devices: ```javascript theme={null} const devices = await navigator.mediaDevices.enumerateDevices(); const microphones = devices.filter(d => d.kind === 'audioinput'); const speakers = devices.filter(d => d.kind === 'audiooutput'); microphones.forEach((mic, i) => { console.log(`Mic ${i}: ${mic.label} (${mic.deviceId})`); }); speakers.forEach((speaker, i) => { console.log(`Speaker ${i}: ${speaker.label} (${speaker.deviceId})`); }); ``` Device labels are only available after the user grants microphone permission. Before permission, `label` is an empty string and `deviceId` is a placeholder. *** ## Request Permissions Before you can select a specific device, the user must grant microphone access: ```javascript theme={null} try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); // Permission granted — device labels now available stream.getTracks().forEach(track => track.stop()); // Release immediately } catch (err) { if (err.name === 'NotAllowedError') { console.error('User denied microphone permission'); } else if (err.name === 'NotFoundError') { console.error('No microphone found'); } } ``` *** ## Select a Specific Device ### When placing a call ```javascript theme={null} // Get the device ID first const devices = await navigator.mediaDevices.getUserMedia({ audio: true }); const micDeviceId = devices.getAudioTracks()[0].getSettings().deviceId; devices.getTracks().forEach(t => t.stop()); // Use it when placing the call const call = client.newCall({ destinationNumber: '+12345678900', audio: true, localStream: await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: micDeviceId }, }, }), }); ``` ### Via ICallOptions constraints ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, // The SDK will request this specific device }); ``` *** ## Switch Devices Mid-Call Replace the audio track on an active PeerConnection: ```javascript theme={null} async function switchMicrophone(newDeviceId) { if (!call?.peerConnection) return; // Get new stream with the selected device const newStream = await navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: newDeviceId }, }, }); const newTrack = newStream.getAudioTracks()[0]; const sender = call.peerConnection .getSenders() .find(s => s.track?.kind === 'audio'); if (sender) { await sender.replaceTrack(newTrack); console.log('Switched to microphone:', newTrack.label); } } ``` `replaceTrack()` doesn't require renegotiation — the switch is seamless. The remote party won't hear a gap. *** ## Speaker Output Set the audio output device (sink) on the audio element: ```javascript theme={null} const audioElement = document.getElementById('remoteAudio'); // Check if the browser supports sink selection if (typeof audioElement.sinkId !== 'undefined') { const devices = await navigator.mediaDevices.enumerateDevices(); const speakers = devices.filter(d => d.kind === 'audiooutput'); // Switch to a specific speaker await audioElement.setSinkId(speakers[1].deviceId); } ``` `setSinkId()` is not supported in all browsers. Safari does not support it as of 2026. Check `typeof audioElement.sinkId !== 'undefined'` before using. *** ## Device Change Detection Listen for device changes (headphones plugged in, Bluetooth connected, etc.): ```javascript theme={null} navigator.mediaDevices.addEventListener('devicechange', async () => { console.log('Audio devices changed'); const devices = await navigator.mediaDevices.enumerateDevices(); const mics = devices.filter(d => d.kind === 'audioinput'); // Update device picker UI updateMicrophoneList(mics); }); ``` **Common scenarios:** * Headphones plugged in → switch output to headphones * Bluetooth headset disconnected → fall back to built-in speaker * USB microphone connected → update device list *** ## Mute vs Device Off Don't confuse muting with device management: | Action | What it does | Remote party hears | | ---------------------------- | -------------------------- | ------------------ | | `call.muteAudio()` | Stops sending audio | Silence | | `track.enabled = false` | Same as mute (lower level) | Silence | | Switching to a different mic | Changes input device | New mic audio | | Revoking mic permission | Browser blocks access | Nothing | *** ## Common Issues ### "Device not found" after permission grant **Cause:** The device list was cached before permission was granted. Labels and real device IDs are only available after `getUserMedia()`. **Fix:** Re-enumerate devices after permission is granted: ```javascript theme={null} const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); stream.getTracks().forEach(t => t.stop()); // Now enumerate — labels and real IDs are available const devices = await navigator.mediaDevices.enumerateDevices(); ``` ### Echo or feedback **Cause:** Speaker output is being picked up by the microphone (especially with built-in speakers + mic on laptops). **Fix:** 1. Use echo cancellation (enabled by default in most browsers) 2. Recommend headphones for long calls 3. Use `call.muteAudio()` when not speaking ### Device disappears mid-call **Cause:** Bluetooth disconnected, USB device unplugged. **Fix:** 1. Listen for `devicechange` events 2. Fall back to the default device: ```javascript theme={null} navigator.mediaDevices.addEventListener('devicechange', async () => { const devices = await navigator.mediaDevices.enumerateDevices(); const defaultMic = devices.find(d => d.kind === 'audioinput'); if (defaultMic) { await switchMicrophone(defaultMic.deviceId); } }); ``` *** ## See Also * [Call Class](/development/webrtc/js-sdk/classes/call) — `muteAudio()`, `unmuteAudio()` * [ICallOptions](/development/webrtc/js-sdk/interfaces/icalloptions) — `localStream` for custom device selection * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production deployment guide # Call Class Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/call/index The Call object represents an active voice call — make, answer, hang up, mute, and hold. # Call Class The `Call` object represents a voice call. It's created by `client.newCall()` (outbound) or received via `telnyx.notification` (inbound). *** ## Getting a Call Object ### Outbound call ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); ``` ### Inbound call ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate' && notification.call.state === 'ringing') { const call = notification.call; call.answer(); } }); ``` *** ## Properties | Property | Type | Description | | ------------------- | ------------------------- | -------------------------------------------------------------- | | `id` | `string` | Unique call identifier | | `state` | `CallState` | Current call state (see [Call States](#call-states)) | | `direction` | `'inbound' \| 'outbound'` | Call direction | | `remotePartyNumber` | `string` | Remote party's phone number | | `remotePartyName` | `string` | Remote party's display name (if available) | | `localPartyNumber` | `string` | Local party's phone number | | `active` | `boolean` | Whether the call is currently active | | `recoveredCallId` | `string` | Previous call ID if this call was recovered after reconnection | | `peerConnection` | `RTCPeerConnection` | Underlying WebRTC PeerConnection (for advanced use) | *** ## Call States ```mermaid theme={null} stateDiagram-v2 [*] --> new: newCall() new --> requesting: INVITE sent new --> ringing: INVITE received requesting --> ringing: 180 Ringing ringing --> answering: answer() answering --> active: Media connected ringing --> active: Media connected active --> held: hold() held --> active: unhold() active --> hangup: hangup() or remote BYE ringing --> hangup: reject / cancel requesting --> hangup: cancel / failure active --> recovering: Reconnection recovering --> active: Recovery OK hangup --> destroy: Cleanup destroy --> [*] ``` | State | Description | | ------------ | -------------------------------------------------- | | `new` | Call object created, not yet dialed | | `requesting` | Outbound INVITE sent to server | | `ringing` | Inbound: INVITE received. Outbound: remote ringing | | `answering` | Inbound call being answered (media negotiation) | | `active` | Call connected — media flowing | | `held` | Call on hold | | `hangup` | Call ended (local or remote hangup) | | `destroy` | Call object cleaned up | | `recovering` | Call being recovered after reconnection | *** ## Methods ### `answer()` Answer an incoming call. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate' && notification.call.state === 'ringing') { notification.call.answer(); } }); ``` Only call `answer()` when the call state is `ringing`. Calling `answer()` on an already-active call creates a duplicate PeerConnection, which causes one-way audio issues. ### `hangup()` End the call. ```javascript theme={null} // SDK 2.25.x — synchronous call.hangup(); // SDK 2.26.x — async (returns Promise) await call.hangup(); ``` See [Migration Guide](/development/webrtc/js-sdk/migration-guide) for upgrading from 2.25.x. ### `muteAudio()` / `unmuteAudio()` Toggle the microphone. ```javascript theme={null} call.muteAudio(); // Mute call.unmuteAudio(); // Unmute ``` ### `hold()` / `unhold()` Put the call on hold or resume it. ```javascript theme={null} call.hold(); // Put on hold (remote hears hold music) call.unhold(); // Resume ``` ### `dtmf(digit)` Send a DTMF tone (0-9, \*, #). ```javascript theme={null} call.dtmf('1'); call.dtmf('*'); call.dtmf('#'); ``` ### `sendDigits(digits)` Send a sequence of DTMF digits. ```javascript theme={null} call.sendDigits('1'); ``` *** ## Events Register event listeners using `call.on(eventName, handler)`: ### Call State Events | Event | Payload | Description | | --------------------- | ------------------------------------------------------------------- | -------------------------------- | | `telnyx.notification` | [INotification](/development/webrtc/js-sdk/reference/inotification) | Call state updates, media events | ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); call.on('telnyx.notification', (notification) => { switch (notification.call.state) { case 'active': console.log('Call connected'); break; case 'hangup': console.log('Call ended'); break; } }); ``` *** ## Advanced ### Access the PeerConnection For custom WebRTC monitoring or manipulation: ```javascript theme={null} const pc = call.peerConnection; // Get current ICE connection state console.log('ICE state:', pc.iceConnectionState); // Get current DTLS state console.log('DTLS state:', pc.connectionState); // Get stats const stats = await pc.getStats(); stats.forEach((report) => { if (report.type === 'candidate-pair' && report.nominated) { console.log('Nominated pair:', report); } }); ``` Direct PeerConnection access is for advanced use cases only. The SDK manages the PeerConnection lifecycle — calling methods like `close()` or `setRemoteDescription()` directly may break the call. ### Custom headers Add SIP headers to the INVITE for server-side correlation: ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, customHeaders: [ { name: 'X-Call-Session', value: sessionUuid }, { name: 'X-Agent-ID', value: agentId }, ], }); ``` *** ## Common Patterns ### Simple outbound call with state handling ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); call.on('telnyx.notification', (notification) => { switch (notification.call.state) { case 'requesting': showDialingUI(); break; case 'ringing': showRingingUI(); break; case 'active': showActiveCallUI(); break; case 'hangup': cleanupCallUI(); break; } }); // Cancel the call if not yet connected cancelButton.addEventListener('click', () => { call.hangup(); }); ``` ### Inbound call with accept/reject UI ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate' && notification.call.state === 'ringing') { const call = notification.call; showIncomingCallUI({ from: call.remotePartyNumber, onAccept: () => call.answer(), onReject: () => call.hangup(), }); } }); ``` ### Hold and resume ```javascript theme={null} // Put call on hold holdButton.addEventListener('click', () => { call.hold(); }); // Resume the call resumeButton.addEventListener('click', () => { call.unhold(); }); ``` *** ## See Also * [ICallOptions](/development/webrtc/js-sdk/reference/icalloptions) — Call configuration options * [INotification](/development/webrtc/js-sdk/reference/inotification) — Notification types and payloads * [TelnyxRTC Class](/development/webrtc/js-sdk/reference/telnyxrtc) — Client methods and events * [SDK Commonalities](/development/webrtc/js-sdk/explanation/call-state-lifecycle) — Call states across all SDK platforms * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production call management guide # ICallOptions Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/icalloptions/index Configuration options for placing a call with the Telnyx WebRTC JS SDK. # ICallOptions Options passed to `client.newCall(options)` to configure call behavior. *** ## Quick Reference ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', // Required audio: true, // Required callerName: 'John Doe', // Optional caller ID trickleIce: true, // Faster call setup }); ``` *** ## Required Properties | Property | Type | Description | | ------------------- | --------- | --------------------------------------------------------------------------------------------------------------- | | `destinationNumber` | `string` | Phone number or SIP URI to call. Use E.164 format for PSTN (e.g., `+12345678900`) or `sip:user@domain` for SIP. | | `audio` | `boolean` | Enable audio for this call. Always `true` for voice calls. | *** ## Call Identity Customize how the call appears to the remote party. | Property | Type | Default | Description | | --------------- | ------------- | ------- | ------------------------------------------------------------------------------------------- | | `callerName` | `string` | — | Display name shown to the remote party (Caller ID name) | | `callerNumber` | `string` | — | Phone number shown to the remote party (Caller ID number) | | `customHeaders` | `SipHeader[]` | — | Custom SIP headers to include in the INVITE. Each header has `name` and `value` properties. | **Example — Custom caller ID:** ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, callerName: 'Acme Corp', callerNumber: '+18005551234', customHeaders: [ { name: 'X-Customer-ID', value: '12345' }, { name: 'X-Agent-Name', value: 'john.doe' }, ], }); ``` *** ## ICE & Network Control how the call establishes media connectivity. | Property | Type | Default | Description | | ----------------------- | ---------------- | ------- | --------------------------------------------------------------------------------------------------------------- | | `trickleIce` | `boolean` | `true` | Send ICE candidates incrementally instead of waiting for all to gather. **Keep enabled for faster call setup.** | | `prefetchIceCandidates` | `boolean` | `true` | Pre-gather ICE candidates before the call is placed. Reduces call setup time. | | `forceRelayCandidate` | `boolean` | `false` | Force all media through TURN relay servers. Hides the client's public IP. Adds latency. | | `iceServers` | `RTCIceServer[]` | Auto | Custom ICE servers. Overrides the SDK's default STUN/TURN configuration. | **Example — Force TURN for privacy:** ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, forceRelayCandidate: true, // All media through TURN }); ``` **Example — Custom ICE servers:** ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, iceServers: [ { urls: 'stun:stun.custom.com:3478' }, { urls: 'turn:turn.custom.com:443', username: 'myuser', credential: 'mypass', }, ], }); ``` The SDK automatically provisions STUN/TURN servers. Only override `iceServers` if you have custom infrastructure. See [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall). *** ## Media Configuration Control audio devices and streams. | Property | Type | Default | Description | | -------------------- | ------------------------- | ------------ | ---------------------------------------------------------------- | | `localElement` | `HTMLAudioElement` | Auto-created | HTML element for playing local audio (hearing yourself) | | `remoteElement` | `HTMLAudioElement` | Auto-created | HTML element for playing remote audio (hearing the other party) | | `localStream` | `MediaStream` | — | Custom local media stream. Use to provide a pre-obtained stream. | | `remoteStream` | `MediaStream` | — | Custom remote media stream. | | `preferred_codecs` | `RTCRtpCodecCapability[]` | — | Preferred audio codecs. Defaults to Opus. | | `sdpASBandwidthKbps` | `number` | — | Bandwidth limit in kbps (set in SDP AS attribute) | **Example — Custom audio elements:** ```javascript theme={null} const remoteAudio = document.getElementById('remoteAudio'); const localAudio = document.getElementById('localAudio'); const call = client.newCall({ destinationNumber: '+12345678900', audio: true, remoteElement: remoteAudio, localElement: localAudio, }); ``` **Example — Pre-obtained media stream:** ```javascript theme={null} // Get microphone access before placing the call const stream = await navigator.mediaDevices.getUserMedia({ audio: true }); const call = client.newCall({ destinationNumber: '+12345678900', audio: true, localStream: stream, }); ``` *** ## Advanced | Property | Type | Default | Description | | ----------------- | --------- | ------- | -------------------------------------------------- | | `sessionId` | `string` | — | Custom session ID for call correlation | | `retryBucketId` | `string` | — | ID for call retry bucket | | `timeoutSecs` | `number` | — | Call setup timeout in seconds | | `telnyxSessionId` | `string` | — | Telnyx session ID (for re-attach scenarios) | | `telnyxCallId` | `string` | — | Telnyx call ID (for re-attach scenarios) | | `isRecovered` | `boolean` | — | Whether this call was recovered after reconnection | *** ## Common Patterns ### Basic voice call ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); ``` ### Call with SIP URI ```javascript theme={null} const call = client.newCall({ destinationNumber: 'sip:agent@customer.sip.telnyx.com', audio: true, }); ``` ### Call with custom headers (for Call Control correlation) ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, customHeaders: [ { name: 'X-Call-Session', value: sessionUuid }, ], }); ``` ### Privacy-focused call (force TURN) ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, forceRelayCandidate: true, }); ``` *** ## See Also * [Call Class](/development/webrtc/js-sdk/classes/call) — Call control methods (answer, hangup, mute, hold) * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — Client-level configuration * [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall) — ICE/STUN/TURN configuration * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices#call-management) — Call management best practices # IClientOptions Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/iclientoptions/index Configuration options for the TelnyxRTC client — authentication, connection, ICE, call reports, and debugging. # IClientOptions Options passed to the `TelnyxRTC` constructor to configure the client. *** ## Quick Reference ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: 'YOUR_JWT_TOKEN', // Authentication (required) enableCallReports: true, // Call quality monitoring (default: true) debug: false, // Debug output }); ``` *** ## Authentication Choose one authentication method. See [Authentication](/development/webrtc/js-sdk/how-to/authenticating-your-app) for the full guide. | Property | Type | Required | Description | | ----------------- | -------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `login_token` | `string` | (if using JWT) | JWT token for authentication. **Recommended for production.** Generate from your backend via `POST /v2/telephony_credentials/{id}/token`. Valid for 24 hours. | | `login` | `string` | (if using credentials) | SIP username (from Telephony Credential). **Development only.** | | `password` | `string` | (if using credentials) | SIP password. **Development only.** | | `anonymous_login` | `object` | (if anonymous) | Connect to an AI assistant without credentials. See [Anonymous Login](#anonymous-login). | **Use `login_token` (JWT) for production applications.** Credentials (`login` + `password`) are long-lived with no automatic rotation. JWTs expire after 24 hours and support refresh. See [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app). **JWT (production):** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, }); ``` **Credential (development only):** ```javascript theme={null} const client = new TelnyxRTC({ login: 'gencred...', password: 'your-password', }); ``` ### Anonymous Login Connect to an AI assistant without requiring a credential. The `anonymous_login` option accepts an object with the target configuration: ```javascript theme={null} const client = new TelnyxRTC({ anonymous_login: { target_type: 'ai_assistant', // Currently the only supported type target_id: 'YOUR_AI_ASSISTANT_ID', // The AI assistant to connect to }, }); ``` | Property | Type | Required | Description | | ------------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `target_type` | `string` | | The target type. Currently only `'ai_assistant'` is supported. | | `target_id` | `string` | | The ID of the AI assistant to connect to. | | `target_version_id` | `string` | — | A specific version of the AI assistant. | | `target_params` | `object` | — | Optional parameters forwarded to the assistant. Known key: `conversation_id` (string) to join an existing conversation. Additional keys are passed through as-is. | **Example — Continue a conversation:** ```javascript theme={null} const client = new TelnyxRTC({ anonymous_login: { target_type: 'ai_assistant', target_id: 'asst_abc123', target_params: { conversation_id: 'conv_xyz789', // Resume existing conversation }, }, }); ``` *** ## Connection Control WebSocket, reconnection, and region behavior. | Property | Type | Default | Description | | ---------------------------------- | --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `env` | `string` | — | Custom signaling server URL. Override `rtc.telnyx.com`. Only use for testing. | | `region` | `string` | — | Region to use for the connection. | | `keepConnectionAliveOnSocketClose` | `boolean` | `false` | Keep PeerConnection alive during WebSocket reconnection. Call media continues flowing while signaling reconnects. | | `skipLastVoiceSdkId` | `boolean` | `false` | When reconnecting with a stored `voice_sdk_id`, route to a different B2BUA-RTC instance instead of sticky-reconnecting to the same one. Useful when retrying after errors caused by stale state on a specific node. | | `rtcIp` | `string` | — | Custom RTC connection IP address. Useful when using a custom signaling server. | | `rtcPort` | `number` | — | Custom RTC connection port. Useful when using a custom signaling server. | | `useCanaryRtcServer` | `boolean` | `false` | Use Telnyx's canary RTC server. | The SDK automatically reconnects when the WebSocket drops. There is no `reconnect` option — reconnection is always automatic. **Enable call recovery:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, keepConnectionAliveOnSocketClose: true, }); ``` *** ## ICE & Network Configure STUN/TURN and ICE behavior. | Property | Type | Default | Description | | ----------------------- | ---------------- | ---------------- | ------------------------------------------------------------------------------------------------------------ | | `iceServers` | `RTCIceServer[]` | Auto-provisioned | Custom ICE servers. Overrides SDK defaults. Only use if you have custom TURN infrastructure. | | `prefetchIceCandidates` | `boolean` | `true` | Pre-gather ICE candidates before the call is placed. Reduces call setup time. | | `forceRelayCandidate` | `boolean` | `false` | Force all media through TURN relay servers. Hides the client's public IP but adds latency. | | `trickleIce` | `boolean` | — | Enable Trickle ICE. Sends candidates incrementally instead of waiting for full gathering. Faster call setup. | | `mutedMicOnStart` | `boolean` | — | Start with microphone muted by default. | The SDK automatically provisions STUN/TURN servers. You don't need to configure `iceServers` in most cases. See [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall). **Force TURN for privacy:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, forceRelayCandidate: true, // All media through TURN }); ``` **Custom ICE servers:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, iceServers: [ { urls: 'stun:stun.custom.com:3478' }, { urls: 'turn:turn.custom.com:443?transport=udp', username: 'myuser', credential: 'mypass', }, ], }); ``` *** ## Audio | Property | Type | Default | Description | | -------------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `ringtoneFile` | `string` | — | URL of a wav/mp3 file to play as the incoming call ringtone. | | `ringbackFile` | `string` | — | URL of a wav/mp3 file to play as ringback tone. Use when you've disabled "Generate Ringback Tone" in your SIP Connection configuration. | **Custom ringtone and ringback:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, ringtoneFile: './sounds/incoming_call.mp3', ringbackFile: './sounds/ringback_tone.mp3', }); ``` *** ## Call Reports Enable post-call quality monitoring and real-time stats. | Property | Type | Default | Description | | -------------------- | --------- | ------- | --------------------------------------------------------------------------- | | `enableCallReports` | `boolean` | `true` | Enable call reports with WebRTC stats (RTT, jitter, packet loss, ICE data). | | `callReportInterval` | `number` | `5000` | Interval in milliseconds between `telnyx.stats.frame` events during calls. | **Call reports are enabled by default.** You can customize the interval: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, callReportInterval: 3000, // Stats every 3 seconds }); ``` **Listen for stats:** ```javascript theme={null} client.on('telnyx.stats.frame', (stats) => { console.log('RTT:', stats.rtt, 'Jitter:', stats.jitter); }); client.on('telnyx.stats.report', (report) => { console.log('Call ended. Final report:', report); }); ``` See [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) for the full data schema. *** ## Debugging Configure debug output for troubleshooting. | Property | Type | Default | Description | | ------------- | -------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `debug` | `boolean` | `false` | Enable debug logging. Outputs SDK internal logs to the browser console. | | `debugOutput` | `'socket' \| 'file'` | — | Where to send debug output. `'socket'` sends to the debug visualizer at `https://webrtc-debug.telnyx.com/`. `'file'` writes debug data to a file. | **Enable console debug logging:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, }); ``` **Send to debug visualizer:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, debugOutput: 'socket', // View at https://webrtc-debug.telnyx.com/ }); ``` **Write debug data to a file:** ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, debugOutput: 'file', }); ``` See [Debug Call Issues](/development/webrtc/js-sdk/how-to/debug-call-issues) for interpreting debug output. *** ## Media Permissions Recovery Handle microphone permission failures for inbound calls with a recoverable error pattern. | Property | Type | Default | Description | | ------------------------------------ | ------------------------ | ------- | ------------------------------------------------------------------------------------------------ | | `mediaPermissionsRecovery.enabled` | `boolean` | `false` | Enable the recovery flow. | | `mediaPermissionsRecovery.timeout` | `number` | — | Maximum time in ms to wait for the app to call `resume()` or `reject()`. Recommended max: 25000. | | `mediaPermissionsRecovery.onSuccess` | `() => void` | — | Called when retry `getUserMedia` succeeds after `resume()`. | | `mediaPermissionsRecovery.onError` | `(error: Error) => void` | — | Called when retry fails, timeout expires, or app calls `reject()`. | When enabled and `getUserMedia` fails while answering an inbound call, the SDK emits a recoverable `telnyx.error` event with `resume()` and `reject()` callbacks. Your app can prompt the user to fix permissions before the call fails: ```javascript theme={null} import { TelnyxRTC, isMediaRecoveryErrorEvent } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: jwt, mediaPermissionsRecovery: { enabled: true, timeout: 20000, onSuccess: () => console.log('Media recovered'), onError: (err) => console.error('Recovery failed', err), }, }); client.on('telnyx.error', (event) => { if (isMediaRecoveryErrorEvent(event)) { showPermissionDialog({ onContinue: () => event.resume(), onCancel: () => event.reject?.(), }); } }); ``` *** ## Full Example ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; const client = new TelnyxRTC({ // Authentication login_token: 'YOUR_JWT_TOKEN', // Connection recovery keepConnectionAliveOnSocketClose: true, // Media recovery for inbound calls mediaPermissionsRecovery: { enabled: true, timeout: 20000, }, // Call reports (enabled by default) callReportInterval: 5000, // ICE optimization prefetchIceCandidates: true, trickleIce: true, }); client.on('telnyx.ready', () => { console.log('Connected'); }); client.on('telnyx.error', (error) => { console.error('Error:', error.code, error.message); }); client.connect(); ``` *** ## See Also * [TelnyxRTC Class](/development/webrtc/js-sdk/reference/telnyxrtc) — Client methods and events * [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app) — JWT, credentials, and token refresh * [ICallOptions](/development/webrtc/js-sdk/reference/icalloptions) — Per-call configuration * [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) — Connection recovery * [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall) — STUN/TURN/firewall * [Production Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production configuration guide # INotification Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/inotification/index Notification object emitted by the Telnyx WebRTC JS SDK for call updates, media events, and SDK notifications. # INotification The `INotification` object is emitted via the `telnyx.notification` event. It contains information about call state changes, media events, and SDK notifications. *** ## Properties | Property | Type | Description | | ----------- | ----------------------------------------------- | ------------------------------------------------------------ | | `type` | `string` | Notification type (see below) | | `call` | [Call](/development/webrtc/js-sdk/classes/call) | The call object this notification relates to (if applicable) | | `timestamp` | `number` | Unix timestamp of the notification | *** ## Notification Types | Type | Description | When It Fires | | --------------------------- | ------------------------------- | -------------------------------------------- | | `callUpdate` | Call state changed | Call rings, connects, hangs up, etc. | | `userMediaError` | Media access failed | Browser denied microphone/camera permissions | | `peerConnectionFailedError` | ICE/DTLS connection failed | Media could not be established | | `signalingStateClosed` | PeerConnection signaling closed | SIP signaling terminated unexpectedly | | `vertoClientReady` | Client is ready | Initial connection established | *** ## Type: `callUpdate` The most common notification type. Fired whenever a call's state changes. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; switch (call.state) { case 'new': // Call object created (before dialing) break; case 'requesting': // Outbound call: INVITE sent to server break; case 'ringing': // Inbound call: received INVITE // Outbound call: remote party is ringing break; case 'answering': // Inbound call: answering in progress break; case 'active': // Call connected — media flowing break; case 'held': // Call on hold break; case 'hangup': // Call ended break; case 'destroy': // Call object cleaned up break; case 'recovering': // Call being recovered after reconnection break; } } }); ``` ### Call State Diagram ```mermaid theme={null} stateDiagram-v2 [*] --> new: newCall() new --> requesting: INVITE sent (outbound) new --> ringing: INVITE received (inbound) requesting --> ringing: 180 Ringing ringing --> answering: answer() answering --> active: Media connected ringing --> active: Media connected active --> held: hold() held --> active: unhold() active --> hangup: hangup() or remote hangup ringing --> hangup: reject or hangup requesting --> hangup: cancel or failure active --> recovering: Reconnection recovering --> active: Recovery successful hangup --> destroy: Cleanup ``` *** ## Type: `userMediaError` Fired when the browser denies or fails to access media devices (microphone/camera). ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'userMediaError') { console.error('Media error:', notification.call.state); // Common causes: // - User denied microphone permission // - No microphone available // - Another app is using the microphone showPermissionErrorUI(); } }); ``` **Common causes:** * User clicked "Block" on the permission prompt * No microphone/camera detected * Another application is using the device * System-level permission denied (OS settings) **Recommended response:** Show a clear message asking the user to grant microphone access, with a link to browser settings. *** ## Type: `peerConnectionFailedError` Fired when the WebRTC PeerConnection fails to establish media. This usually means ICE negotiation or DTLS handshake failed. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'peerConnectionFailedError') { console.error('Peer connection failed'); // Common causes: // - Firewall blocking TURN servers // - Symmetric NAT without TURN // - DTLS fingerprint mismatch showConnectionErrorUI(); } }); ``` **Common causes:** * Firewall blocks UDP to TURN servers * Symmetric NAT prevents direct connectivity * VPN interfering with ICE * Docker/container network issues **Recommended response:** Suggest the user check their network connection. See [Network Requirements](/development/webrtc/js-sdk/how-to/configure-network-firewall). *** ## Type: `signalingStateClosed` Fired when the PeerConnection's signaling state becomes `closed`, indicating the SIP signaling channel has terminated. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'signalingStateClosed') { console.warn('Signaling state closed for call:', notification.call.id); // The call will transition to hangup state shortly } }); ``` This is usually followed by a `callUpdate` with state `hangup`. *** ## Type: `vertoClientReady` Fired when the client has successfully connected and authenticated with the Telnyx signaling server. This is equivalent to the `telnyx.ready` event but delivered as a notification. ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'vertoClientReady') { console.log('Client ready for calls'); } }); ``` *** ## Listening to Notifications ### On the Client ```javascript theme={null} client.on('telnyx.notification', (notification) => { switch (notification.type) { case 'callUpdate': handleCallUpdate(notification.call); break; case 'userMediaError': handleMediaError(notification.call); break; case 'peerConnectionFailedError': handleConnectionError(notification.call); break; } }); ``` ### On a Call You can also listen on individual call objects: ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); call.on('telnyx.notification', (notification) => { // Only notifications for this specific call if (notification.call.state === 'active') { console.log('Call connected!'); } }); ``` Listening on the client gives you notifications for ALL calls. Listening on a specific call gives you notifications for that call only. Choose based on your app's architecture. *** ## See Also * [Call Class](/development/webrtc/js-sdk/classes/call) — Call state and control methods * [TelnyxRTC Class](/development/webrtc/js-sdk/classes/telnyxrtc) — Client-level events * [Error Handling](/development/webrtc/js-sdk/error-handling) — Error and warning codes * [SDK Commonalities](/development/webrtc/js-sdk/explanation/call-state-lifecycle) — Call states across all SDK platforms # Switch/Server Events Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/sw-events/index Events emitted by the Telnyx signaling server during the WebRTC call lifecycle — login, invite, answer, bye, and more. # Switch/Server Events The Telnyx signaling server sends events over the WebSocket connection during the call lifecycle. These are the raw server-side events — most applications should use the higher-level `telnyx.notification` event instead. See [INotification](/development/webrtc/js-sdk/interfaces/inotification) for the recommended approach. **Most developers don't need to handle these events directly.** The SDK translates them into [INotification](/development/webrtc/js-sdk/interfaces/inotification) objects. Use `telnyx.notification` unless you need low-level signaling details. *** ## Event Reference ### Client Lifecycle | Event | Direction | Description | | ---------------------- | --------------- | ---------------------------------------------------------- | | `telnyx.login` | Client → Server | Authentication request (login + password or login\_token) | | `telnyx.login.success` | Server → Client | Authentication successful | | `telnyx.login.error` | Server → Client | Authentication failed (invalid credentials, expired token) | | `telnyx.logout` | Client → Server | Client disconnecting | ### Call Lifecycle | Event | Direction | Description | | ------------------------ | --------------- | --------------------------------------------------- | | `telnyx.invite` | Server → Client | Incoming call (INVITE) | | `telnyx.invite.response` | Client → Server | Response to incoming call (trying, ringing, answer) | | `telnyx.answer` | Client → Server | Accept incoming call | | `telnyx.ringing` | Server → Client | Remote party is ringing (outbound call) | | `telnyx.bridge` | Server → Client | Call bridged (both parties connected) | | `telnyx.bye` | Server → Client | Remote party hung up | | `telnyx.hangup` | Client → Server | Local hangup | ### Media | Event | Direction | Description | | ------------------------ | --------------- | --------------------------- | | `telnyx.media` | Client → Server | SDP offer/answer exchange | | `telnyx.media.candidate` | Client → Server | ICE candidate (trickle ICE) | ### Call Control | Event | Direction | Description | | ----------------- | --------------- | ------------------- | | `telnyx.hold` | Client → Server | Put call on hold | | `telnyx.unhold` | Client → Server | Take call off hold | | `telnyx.dtmf` | Client → Server | Send DTMF tone | | `telnyx.transfer` | Client → Server | Transfer call | | `telnyx.fax` | Server → Client | Fax detection event | ### Presence & Registration | Event | Direction | Description | | ---------------------- | --------------- | ---------------------------------- | | `telnyx.register` | Client → Server | SIP REGISTER (credential-based) | | `telnyx.unregister` | Client → Server | SIP UNREGISTER | | `telnyx.gateway.state` | Server → Client | Gateway connection state (up/down) | *** ## Event Flow: Outbound Call ```mermaid theme={null} sequenceDiagram participant Client participant Server participant Remote Client->>Server: telnyx.media (SDP offer) Client->>Server: telnyx.media.candidate (ICE candidates) Server->>Remote: INVITE Server->>Client: telnyx.ringing Remote->>Server: 200 OK Server->>Client: telnyx.bridge Note over Client,Remote: Media flowing (active call) Remote->>Server: BYE Server->>Client: telnyx.bye ``` *** ## Event Flow: Inbound Call ```mermaid theme={null} sequenceDiagram participant Remote participant Server participant Client Remote->>Server: INVITE Server->>Client: telnyx.invite Client->>Server: telnyx.invite.response (trying) Client->>Server: telnyx.answer Client->>Server: telnyx.media (SDP answer) Client->>Server: telnyx.media.candidate (ICE candidates) Server->>Client: telnyx.bridge Note over Client,Remote: Media flowing (active call) Client->>Server: telnyx.hangup Server->>Remote: BYE ``` *** ## Listening to Server Events For advanced use cases, you can listen to raw server events by enabling debug mode and parsing the WebSocket messages: ```javascript theme={null} const client = new TelnyxRTC({ login_token: jwt, debug: true, debugOutput: 'socket', }); ``` Or intercept WebSocket messages directly: ```javascript theme={null} // Low-level: intercept raw WebSocket messages const originalSend = client.connection.socket.send.bind(client.connection.socket); client.connection.socket.send = function(data) { const parsed = JSON.parse(data); console.log('→ Server:', parsed.method); return originalSend(data); }; ``` Listening to raw WebSocket messages is **not a supported API**. The message format may change between SDK versions. Use `telnyx.notification` for stable event handling. *** ## Server Events vs INotification | Aspect | Server Events | INotification | | -------------- | ----------------------------------- | -------------------------- | | **Level** | Low-level signaling | High-level SDK abstraction | | **Stability** | May change between versions | Stable across versions | | **Payload** | Raw SIP/Verto format | Structured call object | | **Use case** | Debugging, low-level control | Application development | | **Event name** | `telnyx.invite`, `telnyx.bye`, etc. | `telnyx.notification` | **Use `telnyx.notification` (INotification) for application code:** ```javascript theme={null} // Recommended — high-level, stable client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; // Handle call state changes } }); // Not recommended — low-level, may change // (No public API for this — would require intercepting WebSocket) ``` *** ## Gateway State Events The `telnyx.gateway.state` event indicates when the WebSocket connection to the gateway goes up or down: ```javascript theme={null} // Listen via notification client.on('telnyx.notification', (notification) => { if (notification.type === 'gatewayStateUpdate') { console.log('Gateway state:', notification.state); // 'up' = connected, 'down' = disconnected } }); ``` **Gateway DOWN** can indicate: * Network interruption * Server-side maintenance * Credential revoked * WebSocket timeout The SDK automatically attempts reconnection. See [Reconnection & Recovery](/development/webrtc/js-sdk/how-to/handle-reconnection). *** ## See Also * [INotification](/development/webrtc/js-sdk/interfaces/inotification) — High-level notification types (recommended) * [Call Class](/development/webrtc/js-sdk/classes/call) — Call state and control methods * [TelnyxRTC Class](/development/webrtc/js-sdk/classes/telnyxrtc) — Client events * [Error Handling](/development/webrtc/js-sdk/error-handling) — Error and warning codes * [Architecture](/development/webrtc/js-sdk/explanation/sdk-architecture) — How signaling and media flows work # TelnyxRTC Class Source: https://developers.telnyx.com/development/webrtc/js-sdk/reference/telnyxrtc/index Main entry point for the Telnyx WebRTC JS SDK. Connect, disconnect, and manage calls. # TelnyxRTC The `TelnyxRTC` class is the main entry point for the Telnyx WebRTC JS SDK. It manages the WebSocket connection to Telnyx's signaling server and provides methods to create calls, handle events, and control the client lifecycle. ## Constructor ```typescript theme={null} new TelnyxRTC(options: IClientOptions) ``` Creates a new client instance. Does **not** connect automatically — call `connect()` to establish the WebSocket connection. **Parameters:** | Parameter | Type | Required | Description | | --------- | ---------------------------------------------------------------------- | -------- | -------------------- | | `options` | [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) | Yes | Client configuration | **Example:** ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: 'YOUR_JWT_TOKEN', // Optional: see IClientOptions for all options debug: false, enableCallReports: true, }); ``` *** ## Methods ### `connect()` Opens a WebSocket connection to `rtc.telnyx.com` and authenticates using the configured credentials. ```javascript theme={null} client.connect(); ``` Fires `telnyx.ready` on success or `telnyx.error` on failure. ### `disconnect()` Closes the WebSocket connection and cleans up all active calls. ```javascript theme={null} client.disconnect(); ``` Always call `disconnect()` when the user leaves your app to avoid zombie WebSocket connections. See [Best Practices → Connection Lifecycle](/development/webrtc/js-sdk/how-to/production-best-practices#connection-lifecycle). ### `newCall(options)` Creates and places a new outbound call. ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, }); ``` **Parameters:** | Parameter | Type | Required | Description | | --------- | ------------------------------------------------------------------ | -------- | ------------------ | | `options` | [ICallOptions](/development/webrtc/js-sdk/interfaces/icalloptions) | Yes | Call configuration | **Returns:** [Call](/development/webrtc/js-sdk/classes/call) See [ICallOptions](/development/webrtc/js-sdk/interfaces/icalloptions) for all available options including custom headers, ICE configuration, and media settings. ### `off(event, handler)` Removes an event listener. ```javascript theme={null} const onReady = () => { /* ... */ }; client.on('telnyx.ready', onReady); // Later: client.off('telnyx.ready', onReady); ``` ### `removeAllListeners()` Removes all event listeners from the client. ```javascript theme={null} client.removeAllListeners(); ``` *** ## Properties ### `connection` Provides helpers to check the current connection state. ```javascript theme={null} client.connection.connecting // true during WebSocket handshake client.connection.connected // true when WebSocket is open and authenticated client.connection.closed // true when WebSocket is closed client.connection.isAlive // true if connection is active ``` | Property | Type | Description | | ------------ | --------- | --------------------------------- | | `connecting` | `boolean` | True during WebSocket handshake | | `connected` | `boolean` | True when authenticated and ready | | `closed` | `boolean` | True when disconnected | | `isAlive` | `boolean` | True if connection is active | ### `calls` An array of all active [Call](/development/webrtc/js-sdk/classes/call) objects. ```javascript theme={null} // Check if any calls are active if (client.calls.length > 0) { console.log(`Active calls: ${client.calls.length}`); } // Hang up all calls client.calls.forEach(call => call.hangup()); ``` *** ## Events Register event listeners using `client.on(eventName, handler)`: ```javascript theme={null} client.on('telnyx.ready', () => { /* ... */ }); client.on('telnyx.error', (error) => { /* ... */ }); ``` ### Connection Events | Event | Payload | Description | | --------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | | `telnyx.ready` | — | Client connected and authenticated. **Wait for this before making calls.** | | `telnyx.error` | `ClientErrorEvent` | Connection or authentication error. See [Error Handling](/development/webrtc/js-sdk/error-handling). | | `telnyx.warning` | `ClientWarningEvent` | Non-fatal warning (e.g., token expiring, quality degradation). See [Warning Codes](/development/webrtc/js-sdk/error-handling#warning-codes). | | `telnyx.socket.close` | `CloseEvent` | WebSocket closed. SDK will attempt reconnection automatically. | | `telnyx.socket.error` | `Event` | WebSocket error. | ### Call Events | Event | Payload | Description | | --------------------- | -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | | `telnyx.notification` | [INotification](/development/webrtc/js-sdk/interfaces/inotification) | Call state updates, media events, and SDK notifications. This is the **primary event** for handling call lifecycle. | ### Stats Events | Event | Payload | Description | | --------------------- | ------------- | ---------------------------------------------------------------------------------------- | | `telnyx.stats.frame` | `StatsFrame` | Periodic WebRTC stats (RTT, jitter, packet loss). Emitted every `callReportInterval` ms. | | `telnyx.stats.report` | `StatsReport` | End-of-call summary report. Emitted when a call ends. | *** ## Typical Usage ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; // 1. Create client with JWT const client = new TelnyxRTC({ login_token: 'YOUR_JWT_TOKEN', enableCallReports: true, }); // 2. Register event handlers BEFORE connecting client.on('telnyx.ready', () => { console.log('Connected! Ready to make calls.'); }); client.on('telnyx.error', (error) => { console.error('Error:', error.code, error.message); }); client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; switch (call.state) { case 'ringing': // Incoming call — show UI break; case 'active': // Call connected break; case 'hangup': // Call ended break; } } }); client.on('telnyx.warning', (warning) => { console.warn('Warning:', warning.code, warning.message); }); // 3. Connect client.connect(); // 4. Make a call (after ready) function makeCall(destination) { if (!client.connection.connected) { console.error('Not connected yet!'); return; } const call = client.newCall({ destinationNumber: destination, audio: true, }); } // 5. Disconnect on cleanup window.addEventListener('beforeunload', () => { client.disconnect(); }); ``` *** ## Reconnection The SDK automatically reconnects when the WebSocket drops. You don't need to handle this manually in most cases. ```mermaid theme={null} stateDiagram-v2 [*] --> Connecting: connect() Connecting --> Connected: telnyx.ready Connected --> Disconnected: socket.close Disconnected --> Connecting: Auto-reconnect Connected --> Disconnected: disconnect() Disconnected --> [*] ``` For advanced reconnection handling, see [Reconnection & Recovery](/development/webrtc/js-sdk/how-to/handle-reconnection). **Key configuration:** | Option | Default | Description | | ---------------------------------- | ------- | ------------------------------------------------ | | `keepConnectionAliveOnSocketClose` | `false` | Keep PeerConnection alive during reconnect | | `mediaPermissionsRecovery` | — | Auto-recover media permissions for inbound calls | *** ## See Also * [IClientOptions](/development/webrtc/js-sdk/interfaces/iclientoptions) — Full configuration reference * [Call Class](/development/webrtc/js-sdk/classes/call) — Call control methods * [Error Handling](/development/webrtc/js-sdk/error-handling) — Error and warning codes * [Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Production deployment guide * [Authentication](/development/webrtc/js-sdk/how-to/authenticating-your-app) — JWT generation and token refresh # Build a Call Center Agent Source: https://developers.telnyx.com/development/webrtc/js-sdk/tutorials/build-call-center-agent/index Step-by-step tutorial for building a call center agent with the Telnyx WebRTC JS SDK — answering calls, muting, and holding. # Build a Call Center Agent This tutorial walks you through building a fully functional call center agent interface. You'll learn how to answer incoming calls, mute/unmute, and place calls on hold — the basics a real agent needs. **Prerequisites:** * Completed [Make Your First Call](/development/webrtc/js-sdk/tutorials/make-your-first-call) * A Telnyx account with a Credential Connection and JWT set up * A phone number routed to your Credential Connection **What you'll build:** A browser-based agent dashboard that: * Receives incoming calls * Shows caller ID * Supports mute and hold * Tracks call duration * Handles multiple calls with hold/resume **This SDK is client-side only.** The WebRTC JS SDK handles real-time audio in the browser — it connects agents to calls, manages call state, and streams media. To route calls, create dial plans, or implement IVR logic, you need a backend application using: * **[Programmable Voice (Call Control)](/docs/v2/call-control)** — Build server-side call flows with the Telnyx API. Create calls, transfer, bridge, and play audio programmatically. * **[TeXML](/docs/voice/texml)** — Telnyx's markup language for voice applications. Define call flows in XML with verbs for dial, gather, play, say, and more. This tutorial assumes you already have a backend routing calls to your agents via one of these methods. *** ## Step 1: Set Up the HTML Create `agent.html`: ```html theme={null} Call Center Agent

Call Center Agent

Disconnected

Unknown Caller

``` *** ## Step 2: Connect and Authenticate Add a ` ``` *** ## Step 3: Handle Incoming Calls ```javascript theme={null} function handleNotification(notification) { switch (notification.type) { case 'callUpdate': handleCallUpdate(notification.call); break; case 'userMediaError': alert('Microphone access denied. Please allow microphone access and try again.'); break; } } function handleCallUpdate(call) { switch (call.state) { case 'ringing': if (call.direction === 'inbound') { incomingCall = call; document.getElementById('incoming-from').textContent = `Incoming call from: ${call.remotePartyNumber || 'Unknown'}`; document.getElementById('incoming').style.display = 'block'; } break; case 'active': // Call is connected — add to active calls activeCalls.set(call.id, { call, startTime: Date.now() }); startCallTimer(call.id); renderActiveCalls(); break; case 'held': renderActiveCalls(); break; case 'destroyed': stopCallTimer(call.id); activeCalls.delete(call.id); renderActiveCalls(); break; } } ``` *** ## Step 4: Answer and Reject ```javascript theme={null} function answerIncoming() { if (incomingCall) { incomingCall.answer(); document.getElementById('incoming').style.display = 'none'; incomingCall = null; } } function rejectIncoming() { if (incomingCall) { incomingCall.hangup(); document.getElementById('incoming').style.display = 'none'; incomingCall = null; } } ``` *** ## Step 5: Call Controls ```javascript theme={null} function muteCall(callId) { const entry = activeCalls.get(callId); if (entry) { entry.call.mute(); renderActiveCalls(); } } function unmuteCall(callId) { const entry = activeCalls.get(callId); if (entry) { entry.call.unmute(); renderActiveCalls(); } } function holdCall(callId) { const entry = activeCalls.get(callId); if (entry) { entry.call.hold(); } } function unholdCall(callId) { const entry = activeCalls.get(callId); if (entry) { entry.call.unhold(); } } function hangupCall(callId) { const entry = activeCalls.get(callId); if (entry) { entry.call.hangup(); } } ``` *** ## Step 6: Render the Active Calls UI ```javascript theme={null} function renderActiveCalls() { const container = document.getElementById('active-calls'); container.innerHTML = ''; if (activeCalls.size === 0) { container.innerHTML = '

No active calls

'; return; } activeCalls.forEach((entry, callId) => { const call = entry.call; const isMuted = call.isMuted; // Check mute state const isHeld = call.state === 'held'; const card = document.createElement('div'); card.className = `call-card ${call.state}`; card.innerHTML = `
${call.remotePartyNumber || 'Unknown'} ${call.state} ${isMuted ? ' Muted' : ''}
00:00
${isMuted ? '' : '' } ${isHeld ? '' : '' }
`; container.appendChild(card); }); } ``` *** ## Step 7: Call Timer ```javascript theme={null} function startCallTimer(callId) { const entry = activeCalls.get(callId); if (!entry) return; const startTime = entry.startTime; const timerElement = () => document.getElementById(`timer-${callId}`); callTimers.set(callId, setInterval(() => { const elapsed = Math.floor((Date.now() - startTime) / 1000); const minutes = String(Math.floor(elapsed / 60)).padStart(2, '0'); const seconds = String(elapsed % 60).padStart(2, '0'); const el = timerElement(); if (el) el.textContent = `${minutes}:${seconds}`; }, 1000)); } function stopCallTimer(callId) { const timer = callTimers.get(callId); if (timer) { clearInterval(timer); callTimers.delete(callId); } } ``` *** ## Step 8: Cleanup ```javascript theme={null} // Clean up when page closes window.addEventListener('beforeunload', () => { if (client) { client.calls.forEach(call => call.hangup()); client.disconnect(); } }); ``` *** ## What's Next? You now have a working call center agent interface. Here are ways to extend it: **Client-side (this SDK):** | Feature | Guide | | --------------------------- | ------------------------------------------------------------------------------------------ | | Auto-answer incoming calls | [ICallOptions](/development/webrtc/js-sdk/reference/icalloptions) — set `autoAnswer: true` | | DTMF (press 1 for sales...) | `call.dtmf('1')` — See [Call Class](/development/webrtc/js-sdk/reference/call) | | Custom SIP headers | [ICallOptions](/development/webrtc/js-sdk/reference/icalloptions) — `customHeaders` | | Call quality monitoring | [Monitor Call Quality](/development/webrtc/js-sdk/how-to/monitor-call-quality) | | Reconnection handling | [Handle Reconnection](/development/webrtc/js-sdk/how-to/handle-reconnection) | | React integration | [Integrate with Frameworks](/development/webrtc/js-sdk/how-to/integrate-with-frameworks) | | Debug call issues | [Debug Call Issues](/development/webrtc/js-sdk/how-to/debug-call-issues) | **Server-side (backend):** | Feature | Guide | | -------------------------- | -------------------------------------------------------------- | | Route calls to agents | [Programmable Voice](/docs/v2/call-control) — Call Control API | | Build IVR menus | [TeXML](/docs/voice/texml) — ``, ``, `` | | Transfer and bridge calls | [Call Control Transfer](/docs/v2/calls/call-actions#transfer) | | Queue and distribute calls | [Call Control Queues](/docs/v2/call-control/queues) | *** ## See Also * [Make Your First Call](/development/webrtc/js-sdk/tutorials/make-your-first-call) — Basic tutorial * [Programmable Voice](/docs/v2/call-control) — Server-side call management * [TeXML](/docs/voice/texml) — XML-based voice applications * [Production Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices) — Deployment guide # Quickstart Source: https://developers.telnyx.com/development/webrtc/js-sdk/tutorials/make-your-first-call/index Get started with the Telnyx WebRTC JS SDK in 5 minutes. Make and receive calls from your browser. # Quickstart Get the Telnyx WebRTC JS SDK running in your app — make your first call in under 5 minutes. ## Before You Begin You'll need: * A [Telnyx account](https://telnyx.com/sign-up) * Node.js 16+ or a modern browser ### Portal Setup Set up everything you need in the Telnyx Portal — no API calls required. **1. Buy a number** Go to **Numbers → Buy Numbers** in the Portal. Purchase a number in your desired country and area code. **2. Create a Credential Connection** Go to **Call Connections → Create → SIP Credential Connection**. This defines how your WebRTC client authenticates with the SIP network. Give it a name and keep the defaults. **3. Create a Telephony Credential** Go to **Call Connections → \[Your Connection] → Credentials → Create**. Each user (or device) needs its own credential. Note the **username** and **password** — you'll use these to generate a JWT. **4. Assign your number to the connection** Go to **Numbers → Your Numbers**, select your number, and assign it to the Credential Connection you created. **5. Generate a JWT** Still in the Credentials section, click **Generate Token** for the credential you created. Copy the JWT — this is what you'll pass to the SDK as `login_token`. For production, generate JWTs from your backend using the API. See [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app) for the full flow. ## Install ```bash theme={null} npm install @telnyx/webrtc ``` ## Create a Client The SDK connects to Telnyx via WebSocket and establishes WebRTC media sessions. Here's the minimal setup: ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; const client = new TelnyxRTC({ login_token: 'YOUR_JWT_TOKEN', // Generate from your backend }); client.on('telnyx.ready', () => { console.log(' Connected to Telnyx'); }); client.on('telnyx.error', (error) => { console.error(' Connection error:', error.code, error.message); }); client.on('telnyx.notification', (notification) => { // Handle call updates (incoming calls, state changes) console.log('Notification:', notification.type); }); client.connect(); ``` **Always wait for `telnyx.ready` before making calls.** The client needs to establish a WebSocket connection and authenticate before it can place calls. ## Authentication The SDK supports three authentication methods: | Method | Property | Use Case | Security | | --------------------- | -------------------- | ------------------------------ | ----------------------------- | | **JWT** (recommended) | `login_token` | Production apps | Token expires in 24h | | **Credential** | `login` + `password` | Call Control apps, development | Long-lived, no rotation | | **Anonymous** | `anonymous_login` | AI assistant connections | No identity, limited features | **JWT (Production):** ```javascript theme={null} const client = new TelnyxRTC({ login_token: 'eyJhbGciOi...', // From your backend }); ``` **Credential (Call Control):** If you're using Telnyx Call Control, you can generate a SIP credential and use it directly: ```javascript theme={null} const client = new TelnyxRTC({ login: 'gencred...', // SIP username from Portal password: 'your-password', // SIP password }); ``` Each user should get their own credential to avoid registration conflicts. JWT is still preferred for production — credentials don't expire and can't be rotated without updating the client. **Anonymous (AI Assistants):** ```javascript theme={null} const client = new TelnyxRTC({ anonymous_login: { target_type: 'ai_assistant', target_id: 'YOUR_AI_ASSISTANT_ID', }, }); ``` Anonymous login connects to an AI assistant without requiring a credential. Use this for click-to-call widgets that connect users directly to an AI agent. For the full authentication guide including JWT generation, token refresh, and security best practices, see [Authenticating Your App](/development/webrtc/js-sdk/how-to/authenticating-your-app). ## Make an Outbound Call ```javascript theme={null} client.on('telnyx.ready', () => { const call = client.newCall({ destinationNumber: '+12345678900', // E.164 format audio: true, }); // Listen for call state changes call.on('telnyx.notification', (notification) => { switch (notification.call.state) { case 'ringing': console.log(' Ringing...'); break; case 'active': console.log(' Call connected!'); break; case 'hangup': console.log(' Call ended'); break; } }); }); ``` ## Receive an Inbound Call ```javascript theme={null} client.on('telnyx.notification', (notification) => { if (notification.type === 'callUpdate') { const call = notification.call; if (call.state === 'ringing') { // Incoming call — answer it console.log(' Incoming call from', call.remotePartyNumber); call.answer(); } } }); ``` For more control, show an "Accept/Reject" UI instead of auto-answering. ## Play Audio The SDK handles audio elements automatically, but you can provide your own: ```javascript theme={null} const call = client.newCall({ destinationNumber: '+12345678900', audio: true, // Optional: provide audio elements for playback remoteElement: document.getElementById('remoteAudio'), localElement: document.getElementById('localAudio'), }); ``` Or let the SDK create them: ```html theme={null} ``` ## Handle Errors ```javascript theme={null} import { TELNYX_ERROR_CODES } from '@telnyx/webrtc'; client.on('telnyx.error', (error) => { switch (error.code) { case TELNYX_ERROR_CODES.WEBSOCKET_CONNECTION_FAILED: console.error('WebSocket failed — check network'); break; case TELNYX_ERROR_CODES.ICE_CONNECTION_FAILED: console.error('ICE failed — check firewall/TURN config'); break; default: console.error('Error:', error.code, error.message); } }); ``` See the full [Error Handling Guide](/development/webrtc/js-sdk/reference/sw-events) for all error codes and recommended responses. ## Disconnect Always disconnect when the user leaves or the app unloads: ```javascript theme={null} // User clicks "logout" document.getElementById('logout').addEventListener('click', () => { client.disconnect(); }); // Page unload (tab close, navigation) window.addEventListener('beforeunload', () => { client.disconnect(); }); ``` ## Next Steps * **[Authentication](/development/webrtc/js-sdk/how-to/authenticating-your-app)** — JWT generation, token refresh, security best practices * **[Call State Machine](/development/webrtc/js-sdk/explanation/call-state-lifecycle)** — Understanding call lifecycle and state transitions * **[Call Options](/development/webrtc/js-sdk/reference/icalloptions)** — Custom headers, ICE config, media control * **[Error Handling](/development/webrtc/js-sdk/reference/sw-events)** — Structured error codes and recovery * **[Best Practices](/development/webrtc/js-sdk/how-to/production-best-practices)** — Production checklist, performance, security * **[Demo App](/development/webrtc/js-sdk/tutorials/make-your-first-call)** — Full working reference application *** ## Quick Reference ```javascript theme={null} import { TelnyxRTC } from '@telnyx/webrtc'; // 1. Create client const client = new TelnyxRTC({ login_token: 'YOUR_JWT' }); // 2. Listen for events client.on('telnyx.ready', () => { /* Connected */ }); client.on('telnyx.error', (err) => { /* Handle errors */ }); client.on('telnyx.notification', (notif) => { if (notif.type === 'callUpdate' && notif.call.state === 'ringing') { notif.call.answer(); } }); // 3. Connect client.connect(); // 4. Make a call const call = client.newCall({ destinationNumber: '+12345678900' }); // 5. Call control call.hangup(); // End call (async in 2.26+) call.muteAudio(); // Mute microphone call.unmuteAudio(); // Unmute // 6. Disconnect client.disconnect(); ``` # Changelog Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/changelog/index Release notes and version history for the React Native SDK. # CHANGELOG.md ## [0.1.8-beta.0](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.8-beta.0) (2026-02-27) ### Bug Fixing • Fixed push data race condition in Expo apps — `clearPendingVoipPush()` is now deferred until the CallKit coordinator fulfills the answer, end, or reject action, preventing push data from being consumed and cleared before the user answers • Fixed duplicate push notification processing by also checking for `CONNECTING` state (not just `CONNECTED`) in `checkForInitialPushNotification` • Fixed premature protection-flag resets — `hasProcessingCalls()` now returns `true` while `isCallFromPush` is set, preventing the `calls$` subscription from clearing `isHandlingForegroundCall` and `backgroundDetectorIgnore` before the WebRTC call arrives ## [0.1.7](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.7) (2026-02-20) ### Enhancement • Added `TelnyxVoipClient.isLaunchedFromPushNotification()` static method to check if the app was cold-started from a push notification, allowing consumers to skip auto-login and avoid double-login races • `createTelnyxVoipClient()` now returns a singleton — safe to call inside React component bodies without creating a new instance on every render • Added `destroyTelnyxVoipClient()` to tear down the singleton when a fresh instance is needed • `TelnyxVoiceApp` now automatically wires the `voipClient` on the CallKit coordinator on mount — consumers no longer need to manually call `setVoipClient()` at the correct component level ### Bug Fixing • Fixed cold-start push notification failures caused by double-login race between user auto-login and SDK internal push login • Fixed CallKit coordinator having no `voipClient` reference when user answered a call via CallKit before navigating to the correct screen • Fixed `call_id` extraction in `checkForInitialPushNotification` — the double-nested path `pushData.metadata?.metadata?.call_id` never resolved, so the CallKit coordinator was bypassed on iOS • Refactored `checkForInitialPushNotification` into `getAndroidPushData` and `getIOSPushData` helpers to reduce nesting and improve readability ### Deprecation • `setVoipClient()` on `CallKitCoordinator` and `useCallKitCoordinator()` hook is now deprecated — `TelnyxVoiceApp` handles this automatically ## [0.1.7-beta.0](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.7-beta.0) (2026-02-18) ### Bug Fixing • Fixed `call_id` extraction in `checkForInitialPushNotification` — the double-nested path `pushData.metadata?.metadata?.call_id` never resolved, so the CallKit coordinator was bypassed and all iOS push calls fell through to direct handling • Refactored `checkForInitialPushNotification` into `getAndroidPushData` and `getIOSPushData` helpers to reduce nesting and improve readability ## [0.1.6](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.6) (2025-12-09) ### Enhancement • Added Android native components to npm package for proper distribution • Complete Android native integration support for Firebase messaging and call management ### Bug Fixing • Fixed missing Android directory in npm package files array • Resolved native component availability issues for Android integrations ## [0.1.5](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.5) (2025-12-08) ### Enhancement • Updated to use @telnyx/react-native-voice-sdk\@0.3.0 with advanced media events support ## [0.1.4](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.4) (2025-11-25) ### Enhancement • Enhanced 4G/WiFi reconnection mechanism for better network handling • iOS version integration improvements ## [0.1.3](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.3) (2025-11-20) ### Enhancement • Fixed background answer functionality for iOS • Added connecting state to Telnyx client • Improved reconnection logic for Android using foreground service implementation ## [0.1.2](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.2) (2025-11-04) ### Enhancement • Comprehensive package README with integration examples • Documentation for credential-based and token-based authentication • Native integration guides for Android (MainActivity) and iOS (AppDelegate) • Examples for push notification setup • Troubleshooting section ### Bug Fixing • Package metadata and npm publishing configuration ## [0.1.1](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.1) (2025-11-02) ### Enhancement • Initial npm package release • Core VoIP client (`TelnyxVoipClient`) • TelnyxVoiceApp component for React Native lifecycle management • CallKit integration for iOS native call UI • Android ConnectionService support • Push notification handling (FCM for Android, APNs for iOS) • Reactive state streams with RxJS • Call management APIs (make, answer, hold, mute, transfer, hangup) • Connection state management • Call state machine • Automatic reconnection logic • Session management • TypeScript type definitions ## [0.1.0](https://github.com/team-telnyx/react-native-voice-commons/releases/tag/0.1.0) (2025-11-01) ### Enhancement • Initial development version • Basic VoIP functionality • Call management • State management interfaces # Call Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/classes/call/index Represents a call with reactive state streams. Wraps the underlying Telnyx Call object and provides reactive streams for all call state changes. # Class: Call Defined in: [models/call.ts:14](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L14) Represents a call with reactive state streams. This class wraps the underlying Telnyx Call object and provides reactive streams for all call state changes, making it easy to integrate with any state management solution. ## Constructors ### Constructor > **new Call**(`_telnyxCall`, `_callId`, `_destination`, `_isIncoming`, `isReattached`, `_originalCallerName?`, `_originalCallerNumber?`): `Call` Defined in: [models/call.ts:23](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L23) ### Parameters ### \_telnyxCall [`TelnyxCall`](../interfaces/TelnyxCall.md) ### \_callId `string` ### \_destination `string` ### \_isIncoming `boolean` ### isReattached `boolean` = `false` ### \_originalCallerName? `string` ### \_originalCallerNumber? `string` ### Returns `Call` ## Accessors ### callId ### Get Signature > **get** **callId**(): `string` Defined in: [models/call.ts:44](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L44) Unique identifier for this call ### Returns `string` *** ### destination ### Get Signature > **get** **destination**(): `string` Defined in: [models/call.ts:51](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L51) The destination number or SIP URI ### Returns `string` *** ### isIncoming ### Get Signature > **get** **isIncoming**(): `boolean` Defined in: [models/call.ts:58](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L58) Whether this is an incoming call ### Returns `boolean` *** ### isOutgoing ### Get Signature > **get** **isOutgoing**(): `boolean` Defined in: [models/call.ts:65](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L65) Whether this is an outgoing call ### Returns `boolean` *** ### currentState ### Get Signature > **get** **currentState**(): [`TelnyxCallState`](../enumerations/TelnyxCallState.md) Defined in: [models/call.ts:72](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L72) Current call state (synchronous access) ### Returns [`TelnyxCallState`](../enumerations/TelnyxCallState.md) *** ### currentIsMuted ### Get Signature > **get** **currentIsMuted**(): `boolean` Defined in: [models/call.ts:79](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L79) Current mute state (synchronous access) ### Returns `boolean` *** ### currentIsHeld ### Get Signature > **get** **currentIsHeld**(): `boolean` Defined in: [models/call.ts:86](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L86) Current hold state (synchronous access) ### Returns `boolean` *** ### currentDuration ### Get Signature > **get** **currentDuration**(): `number` Defined in: [models/call.ts:93](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L93) Current call duration in seconds (synchronous access) ### Returns `number` *** ### inviteCustomHeaders ### Get Signature > **get** **inviteCustomHeaders**(): `object`\[] Defined in: [models/call.ts:102](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L102) Custom headers received from the WebRTC INVITE message. These headers are passed during call initiation and can contain application-specific information. Format should be `[{"name": "X-Header-Name", "value": "Value"}]` where header names must start with "X-". ### Returns `object`\[] *** ### answerCustomHeaders ### Get Signature > **get** **answerCustomHeaders**(): `object`\[] Defined in: [models/call.ts:111](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L111) Custom headers received from the WebRTC ANSWER message. These headers are passed during call acceptance and can contain application-specific information. Format should be `[{"name": "X-Header-Name", "value": "Value"}]` where header names must start with "X-". ### Returns `object`\[] *** ### telnyxCall ### Get Signature > **get** **telnyxCall**(): [`TelnyxCall`](../interfaces/TelnyxCall.md) Defined in: [models/call.ts:119](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L119) **`Internal`** Get the underlying Telnyx Call object (for internal use) ### Returns [`TelnyxCall`](../interfaces/TelnyxCall.md) *** ### callState\$ ### Get Signature > **get** **callState\$**(): `Observable`\<[`TelnyxCallState`](../enumerations/TelnyxCallState.md)> Defined in: [models/call.ts:126](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L126) Observable stream of call state changes ### Returns `Observable`\<[`TelnyxCallState`](../enumerations/TelnyxCallState.md)> *** ### isMuted\$ ### Get Signature > **get** **isMuted\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:133](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L133) Observable stream of mute state changes ### Returns `Observable`\<`boolean`> *** ### isHeld\$ ### Get Signature > **get** **isHeld\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:140](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L140) Observable stream of hold state changes ### Returns `Observable`\<`boolean`> *** ### duration\$ ### Get Signature > **get** **duration\$**(): `Observable`\<`number`> Defined in: [models/call.ts:147](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L147) Observable stream of call duration changes (in seconds) ### Returns `Observable`\<`number`> *** ### canAnswer\$ ### Get Signature > **get** **canAnswer\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:154](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L154) Observable that emits true when the call can be answered ### Returns `Observable`\<`boolean`> *** ### canHangup\$ ### Get Signature > **get** **canHangup\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:164](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L164) Observable that emits true when the call can be hung up ### Returns `Observable`\<`boolean`> *** ### canHold\$ ### Get Signature > **get** **canHold\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:174](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L174) Observable that emits true when the call can be put on hold ### Returns `Observable`\<`boolean`> *** ### canResume\$ ### Get Signature > **get** **canResume\$**(): `Observable`\<`boolean`> Defined in: [models/call.ts:184](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L184) Observable that emits true when the call can be resumed from hold ### Returns `Observable`\<`boolean`> ## Methods ### answer() > **answer**(`customHeaders?`): `Promise`\<`void`> Defined in: [models/call.ts:195](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L195) Answer the incoming call ### Parameters ### customHeaders? `object`\[] Optional custom headers to include with the answer ### Returns `Promise`\<`void`> *** ### hangup() > **hangup**(`customHeaders?`): `Promise`\<`void`> Defined in: [models/call.ts:227](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L227) Hang up the call ### Parameters ### customHeaders? `object`\[] Optional custom headers to include with the hangup request ### Returns `Promise`\<`void`> *** ### hold() > **hold**(): `Promise`\<`void`> Defined in: [models/call.ts:266](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L266) Put the call on hold ### Returns `Promise`\<`void`> *** ### resume() > **resume**(): `Promise`\<`void`> Defined in: [models/call.ts:282](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L282) Resume the call from hold ### Returns `Promise`\<`void`> *** ### mute() > **mute**(): `Promise`\<`void`> Defined in: [models/call.ts:298](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L298) Mute the call ### Returns `Promise`\<`void`> *** ### unmute() > **unmute**(): `Promise`\<`void`> Defined in: [models/call.ts:315](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L315) Unmute the call ### Returns `Promise`\<`void`> *** ### toggleMute() > **toggleMute**(): `Promise`\<`void`> Defined in: [models/call.ts:332](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L332) Toggle mute state ### Returns `Promise`\<`void`> *** ### setConnecting() > **setConnecting**(): `void` Defined in: [models/call.ts:344](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L344) **`Internal`** Set the call to connecting state (used for push notification calls when answered via CallKit) ### Returns `void` *** ### dispose() > **dispose**(): `void` Defined in: [models/call.ts:352](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/call.ts#L352) Clean up resources when the call is disposed ### Returns `void` # TelnyxVoipClient Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/classes/telnyxvoipclient/index Main VoIP client class for React Native applications. Provides methods for call management, user registration, and WebRTC functionality. # Class: TelnyxVoipClient Defined in: [telnyx-voip-client.ts:30](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L30) The main public interface for the react-voice-commons module. This class serves as the Façade for the entire module, providing a simplified API that completely hides the underlying complexity. It is the sole entry point for developers using the react-voice-commons package. The TelnyxVoipClient is designed to be state-management agnostic, exposing all observable state via RxJS streams. This allows developers to integrate it into their chosen state management solution naturally. ## Constructors ### Constructor > **new TelnyxVoipClient**(`options`): `TelnyxVoipClient` Defined in: [telnyx-voip-client.ts:41](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L41) Creates a new TelnyxVoipClient instance. ### Parameters ### options [`TelnyxVoipClientOptions`](../interfaces/TelnyxVoipClientOptions.md) = `{}` Configuration options for the client ### Returns `TelnyxVoipClient` ## Accessors ### connectionState\$ ### Get Signature > **get** **connectionState\$**(): `Observable`\<[`TelnyxConnectionState`](../enumerations/TelnyxConnectionState.md)> Defined in: [telnyx-voip-client.ts:74](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L74) Stream of connection state changes. Emits the current status of the connection to the Telnyx backend. Values include connecting, connected, disconnected, and error states. Listen to this to show connection indicators in your UI. ### Returns `Observable`\<[`TelnyxConnectionState`](../enumerations/TelnyxConnectionState.md)> *** ### calls\$ ### Get Signature > **get** **calls\$**(): `Observable`\<[`Call`](Call.md)> Defined in: [telnyx-voip-client.ts:85](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L85) Stream of all current calls. Emits a list of all current Call objects. Use this for applications that need to support multiple simultaneous calls (e.g., call waiting, conference calls). ### Returns `Observable`\<[`Call`](Call.md)> *** ### activeCall\$ ### Get Signature > **get** **activeCall\$**(): `Observable`\<[`Call`](Call.md)> Defined in: [telnyx-voip-client.ts:96](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L96) Stream of the currently active call. A convenience stream that emits the currently active Call object. It emits null when no call is in progress. Ideal for applications that only handle a single call at a time. ### Returns `Observable`\<[`Call`](Call.md)> *** ### currentConnectionState ### Get Signature > **get** **currentConnectionState**(): [`TelnyxConnectionState`](../enumerations/TelnyxConnectionState.md) Defined in: [telnyx-voip-client.ts:105](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L105) Current connection state (synchronous access). ### Returns [`TelnyxConnectionState`](../enumerations/TelnyxConnectionState.md) *** ### currentCalls ### Get Signature > **get** **currentCalls**(): [`Call`](Call.md) Defined in: [telnyx-voip-client.ts:112](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L112) Current list of calls (synchronous access). ### Returns [`Call`](Call.md) *** ### currentActiveCall ### Get Signature > **get** **currentActiveCall**(): [`Call`](Call.md) Defined in: [telnyx-voip-client.ts:119](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L119) Current active call (synchronous access). ### Returns [`Call`](Call.md) *** ### sessionId ### Get Signature > **get** **sessionId**(): `string` Defined in: [telnyx-voip-client.ts:126](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L126) Current session ID (UUID) for this connection. ### Returns `string` *** ### options ### Get Signature > **get** **options**(): `Required`\<[`TelnyxVoipClientOptions`](../interfaces/TelnyxVoipClientOptions.md)> Defined in: [telnyx-voip-client.ts:133](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L133) Configuration options for this client instance. ### Returns `Required`\<[`TelnyxVoipClientOptions`](../interfaces/TelnyxVoipClientOptions.md)> ## Methods ### login() > **login**(`config`): `Promise`\<`void`> Defined in: [telnyx-voip-client.ts:148](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L148) Connects to the Telnyx platform using credential authentication. ### Parameters ### config [`CredentialConfig`](../interfaces/CredentialConfig.md) The credential configuration containing SIP username and password ### Returns `Promise`\<`void`> A Promise that completes when the connection attempt is initiated Listen to connectionState\$ to monitor the actual connection status. Credentials are automatically stored for future reconnection. *** ### loginWithToken() > **loginWithToken**(`config`): `Promise`\<`void`> Defined in: [telnyx-voip-client.ts:175](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L175) Connects to the Telnyx platform using token authentication. ### Parameters ### config [`TokenConfig`](../interfaces/TokenConfig.md) The token configuration containing the authentication token ### Returns `Promise`\<`void`> A Promise that completes when the connection attempt is initiated Listen to connectionState\$ to monitor the actual connection status. Token is automatically stored for future reconnection. *** ### logout() > **logout**(): `Promise`\<`void`> Defined in: [telnyx-voip-client.ts:199](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L199) Disconnects from the Telnyx platform. This method terminates the connection, ends any active calls, and cleans up all related resources. ### Returns `Promise`\<`void`> *** ### loginFromStoredConfig() > **loginFromStoredConfig**(): `Promise`\<`boolean`> Defined in: [telnyx-voip-client.ts:219](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L219) Attempts to reconnect using previously stored configuration. This method is used for auto-reconnection scenarios where the app comes back to the foreground and needs to restore the connection. ### Returns `Promise`\<`boolean`> `Promise` - true if reconnection was successful, false otherwise *** ### newCall() > **newCall**(`destination`, `callerName?`, `callerNumber?`, `customHeaders?`): `Promise`\<[`Call`](Call.md)> Defined in: [telnyx-voip-client.ts:296](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L296) Initiates a new outgoing call. ### Parameters ### destination `string` The destination number or SIP URI to call ### callerName? `string` Optional caller name to display ### callerNumber? `string` Optional caller ID number ### customHeaders? `Record`\<`string`, `string`> Optional custom headers to include with the call ### Returns `Promise`\<[`Call`](Call.md)> A Promise that completes with the Call object once the invitation has been sent The call's state can be monitored through the returned Call object's streams. *** ### handlePushNotification() > **handlePushNotification**(`payload`): `Promise`\<`void`> Defined in: [telnyx-voip-client.ts:335](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L335) Handle push notification payload. This is the unified entry point for all push notifications. It intelligently determines whether to show a new incoming call UI or to process an already actioned (accepted/declined) call upon app launch. ### Parameters ### payload `Record`\<`string`, `any`> The push notification payload ### Returns `Promise`\<`void`> *** ### disablePushNotifications() > **disablePushNotifications**(): `void` Defined in: [telnyx-voip-client.ts:371](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L371) Disables push notifications for the current session. This method sends a request to the Telnyx backend to disable push notifications for the current registered device/session. ### Returns `void` *** ### setCallConnecting() > **setCallConnecting**(`callId`): `void` Defined in: [telnyx-voip-client.ts:388](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L388) **`Internal`** Set a call to connecting state (used for push notification calls when answered via CallKit) ### Parameters ### callId `string` The ID of the call to set to connecting state ### Returns `void` *** ### findCallByTelnyxCall() > **findCallByTelnyxCall**(`telnyxCall`): [`Call`](Call.md) Defined in: [telnyx-voip-client.ts:397](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L397) **`Internal`** Find a call by its underlying Telnyx call object ### Parameters ### telnyxCall `any` The Telnyx call object to find ### Returns [`Call`](Call.md) *** ### queueAnswerFromCallKit() > **queueAnswerFromCallKit**(`customHeaders`): `void` Defined in: [telnyx-voip-client.ts:406](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L406) Queue an answer action for when the call invite arrives (for CallKit integration) This should be called when the user answers from CallKit before the socket connection is established ### Parameters ### customHeaders `Record`\<`string`, `string`> = `{}` Optional custom headers to include with the answer ### Returns `void` *** ### queueEndFromCallKit() > **queueEndFromCallKit**(): `void` Defined in: [telnyx-voip-client.ts:427](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L427) Queue an end action for when the call invite arrives (for CallKit integration) This should be called when the user ends from CallKit before the socket connection is established ### Returns `void` *** ### dispose() > **dispose**(): `void` Defined in: [telnyx-voip-client.ts:453](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L453) Dispose of the client and clean up all resources. After calling this method, the client instance should not be used anymore. This is particularly important for background clients that should be disposed after handling push notifications. ### Returns `void` # Error Handling Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/error-handling/index Common errors, debugging techniques, and troubleshooting for the React Native SDK. # Error Handling Common errors, debugging techniques, and troubleshooting guide for the Telnyx React Native SDK. ## Authentication Errors ### Invalid Credentials **Error**: `AUTH_FAILED` or `INVALID_CREDENTIALS` **Symptoms**: Login fails with credential-based authentication. **Solutions**: ```tsx theme={null} import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; const handleAuthError = async (voipClient, username, password) => { try { const config = createCredentialConfig(username, password, { debug: true, // Enable debug logging }); await voipClient.login(config); } catch (error) { if (error.code === 'AUTH_FAILED') { console.error('Invalid credentials provided'); // Show user-friendly error message Alert.alert('Login Failed', 'Please check your username and password'); } else if (error.code === 'NETWORK_ERROR') { console.error('Network connection failed'); // Retry logic or offline handling } } }; ``` ### Token Validation Errors **Error**: `INVALID_TOKEN` or `TOKEN_EXPIRED` **Symptoms**: JWT token authentication fails. **Solutions**: ```tsx theme={null} import { createTokenConfig } from '@telnyx/react-voice-commons-sdk'; const handleTokenAuth = async (voipClient, token) => { try { const config = createTokenConfig(token, { debug: true, }); await voipClient.loginWithToken(config); } catch (error) { switch (error.code) { case 'INVALID_TOKEN': console.error('Token format is invalid'); // Request new token from your server break; case 'TOKEN_EXPIRED': console.error('Token has expired'); // Refresh token and retry break; case 'TOKEN_NOT_FOUND': console.error('Token not provided'); // Redirect to login break; } } }; ``` ### Connection Errors **Error**: `CONNECTION_FAILED` or `NETWORK_ERROR` **Symptoms**: Cannot establish WebRTC connection. **Solutions**: ```tsx theme={null} import NetInfo from '@react-native-community/netinfo'; const handleConnectionError = async (voipClient) => { // Check network connectivity const netInfo = await NetInfo.fetch(); if (!netInfo.isConnected) { console.error('No network connection'); Alert.alert('Network Error', 'Please check your internet connection'); return; } // Implement retry logic const retryConnection = async (attempts = 3) => { for (let i = 0; i < attempts; i++) { try { await voipClient.loginFromStoredConfig(); console.log('Reconnection successful'); return; } catch (error) { console.warn(`Retry attempt ${i + 1} failed:`, error.message); if (i === attempts - 1) { console.error('All retry attempts failed'); // Handle final failure } else { // Wait before retry await new Promise(resolve => setTimeout(resolve, 2000 * (i + 1))); } } } }; await retryConnection(); }; ``` ## Call Errors ### Call Creation Failures **Error**: `CALL_FAILED` or `INVALID_DESTINATION` **Symptoms**: Cannot initiate outgoing calls. **Solutions**: ```tsx theme={null} const makeCallWithErrorHandling = async (voipClient, destination) => { try { // Validate destination format if (!destination || destination.trim().length === 0) { throw new Error('INVALID_DESTINATION'); } // Check connection state if (voipClient.currentConnectionState !== 'CONNECTED') { throw new Error('NOT_CONNECTED'); } const call = await voipClient.newCall(destination); console.log('Call initiated successfully:', call.callId); return call; } catch (error) { switch (error.message) { case 'INVALID_DESTINATION': Alert.alert('Invalid Number', 'Please enter a valid phone number'); break; case 'NOT_CONNECTED': Alert.alert('Connection Error', 'Please check your connection and try again'); break; case 'CALL_LIMIT_EXCEEDED': Alert.alert('Call Limit', 'Maximum number of concurrent calls reached'); break; default: console.error('Call failed:', error); Alert.alert('Call Failed', 'Unable to place call. Please try again.'); } } }; ``` ### Call Control Errors **Error**: `CALL_NOT_FOUND` or `INVALID_STATE` **Symptoms**: Call control operations fail. **Solutions**: ```tsx theme={null} const safeCallOperation = async (call, operation, operationName) => { try { if (!call) { throw new Error('CALL_NOT_FOUND'); } // Check call state before operation const validStates = { answer: ['ringing'], hold: ['active'], unhold: ['held'], hangup: ['ringing', 'active', 'held'], }; if (validStates[operation] && !validStates[operation].includes(call.state)) { throw new Error('INVALID_STATE'); } await call[operation](); console.log(`${operationName} successful`); } catch (error) { switch (error.message) { case 'CALL_NOT_FOUND': console.error('Call no longer exists'); break; case 'INVALID_STATE': console.error(`Cannot ${operationName} call in state: ${call.state}`); break; default: console.error(`${operationName} failed:`, error); } } }; // Usage examples await safeCallOperation(call, 'answer', 'Answer call'); await safeCallOperation(call, 'hold', 'Hold call'); await safeCallOperation(call, 'hangup', 'End call'); ``` ## Audio and Media Errors ### Audio Permission Errors **Error**: `MICROPHONE_PERMISSION_DENIED` **Symptoms**: No audio in calls, microphone access denied. **Solutions**: ```tsx theme={null} import { PermissionsAndroid, Platform } from 'react-native'; const requestAudioPermissions = async () => { try { if (Platform.OS === 'android') { const granted = await PermissionsAndroid.request( PermissionsAndroid.PERMISSIONS.RECORD_AUDIO, { title: 'Microphone Permission', message: 'This app needs microphone access for voice calls', buttonNeutral: 'Ask Me Later', buttonNegative: 'Cancel', buttonPositive: 'OK', } ); if (granted !== PermissionsAndroid.RESULTS.GRANTED) { throw new Error('MICROPHONE_PERMISSION_DENIED'); } } return true; } catch (error) { console.error('Audio permission error:', error); Alert.alert( 'Microphone Permission Required', 'Please grant microphone permission in device settings to make calls', [ { text: 'Cancel', style: 'cancel' }, { text: 'Settings', onPress: () => Linking.openSettings() }, ] ); return false; } }; ``` ### Audio Routing Issues **Error**: `AUDIO_ROUTING_FAILED` **Symptoms**: Audio plays through wrong device (speaker/earpiece). **Solutions**: ```tsx theme={null} // Audio routing is handled automatically by the SDK // For custom audio routing, you can listen to call state changes const handleAudioRouting = (call) => { call.callState$.subscribe((state) => { switch (state) { case 'active': console.log('Call active - audio should route to earpiece by default'); break; case 'held': console.log('Call on hold - audio routing paused'); break; } }); }; ``` ## Push Notification Errors ### Token Registration Errors **Error**: `PUSH_TOKEN_INVALID` or `PUSH_REGISTRATION_FAILED` **Symptoms**: Push notifications not working. **Solutions**: ```tsx theme={null} import messaging from '@react-native-firebase/messaging'; const handlePushTokenError = async () => { try { // Clear and regenerate FCM token await messaging().deleteToken(); const newToken = await messaging().getToken(); if (!newToken) { throw new Error('PUSH_TOKEN_GENERATION_FAILED'); } console.log('New push token:', newToken); return newToken; } catch (error) { console.error('Push token error:', error); // Fallback: Continue without push notifications Alert.alert( 'Push Notifications', 'Unable to setup push notifications. You may miss calls when the app is closed.', [{ text: 'OK' }] ); } }; ``` ### Background Processing Errors **Error**: `BACKGROUND_PROCESSING_FAILED` **Symptoms**: Incoming calls not handled when app is backgrounded. **Solutions**: ```tsx theme={null} // Ensure proper background handler setup messaging().setBackgroundMessageHandler(async (remoteMessage) => { try { console.log('Background message received:', remoteMessage); await TelnyxVoiceApp.handleBackgroundPush(remoteMessage.data); } catch (error) { console.error('Background processing failed:', error); // Log error for debugging crashlytics().recordError(error); } }); ``` ## Network and Connectivity Errors ### WebRTC Connection Issues **Error**: `WEBRTC_CONNECTION_FAILED` or `ICE_CONNECTION_FAILED` **Symptoms**: Calls connect but no audio, or connection drops frequently. **Solutions**: ```tsx theme={null} const diagnoseNetworkIssues = async () => { const netInfo = await NetInfo.fetch(); console.log('Network diagnostics:', { isConnected: netInfo.isConnected, type: netInfo.type, isInternetReachable: netInfo.isInternetReachable, details: netInfo.details, }); // Check for specific network issues if (netInfo.type === 'cellular' && netInfo.details?.cellularGeneration === '2g') { Alert.alert( 'Network Warning', 'Your connection may be too slow for voice calls. Try connecting to Wi-Fi.' ); } if (!netInfo.isInternetReachable) { Alert.alert( 'Connection Issue', 'Unable to reach the internet. Please check your connection.' ); } }; ``` ### Firewall and NAT Issues **Error**: `NAT_TRAVERSAL_FAILED` or `FIREWALL_BLOCKED` **Symptoms**: Cannot connect to WebRTC servers, especially on corporate networks. **Solutions**: ```tsx theme={null} const checkNetworkRestrictions = () => { console.log('If experiencing connection issues on corporate networks:'); console.log('- Ensure UDP traffic is allowed'); console.log('- Check if STUN/TURN servers are accessible'); console.log('- Verify WebSocket connections are permitted'); Alert.alert( 'Network Configuration', 'If you\'re on a corporate network, please contact your IT administrator to ensure VoIP traffic is allowed.', [{ text: 'OK' }] ); }; ``` ## Memory and Performance Errors ### Memory Leaks **Error**: `MEMORY_WARNING` or app crashes **Symptoms**: App becomes slow or crashes after extended use. **Solutions**: ```tsx theme={null} // Proper cleanup of subscriptions const useCallSubscription = (call) => { useEffect(() => { if (!call) return; const subscription = call.callState$.subscribe((state) => { console.log('Call state:', state); }); // Critical: Always unsubscribe return () => { subscription.unsubscribe(); }; }, [call]); }; // Cleanup client resources const cleanupVoipClient = (voipClient) => { useEffect(() => { return () => { // Cleanup when component unmounts voipClient.logout().catch(console.error); }; }, [voipClient]); }; ``` ### Performance Issues **Error**: Slow UI, delayed call operations **Solutions**: ```tsx theme={null} // Optimize state updates const useOptimizedCallState = (voipClient) => { const [calls, setCalls] = useState([]); useEffect(() => { // Throttle rapid state updates const subscription = voipClient.calls$ .pipe( throttleTime(100), // Limit updates to once per 100ms distinctUntilChanged() // Only update when actually changed ) .subscribe(setCalls); return () => subscription.unsubscribe(); }, [voipClient]); return calls; }; ``` ## Debugging Tools ### Enable Debug Logging ```tsx theme={null} import { createTelnyxVoipClient } from '@telnyx/react-voice-commons-sdk'; // Enable comprehensive debug logging const voipClient = createTelnyxVoipClient({ debug: true, // Enable detailed logging }); // Custom error logging const logError = (context, error) => { console.error(`[${context}] Error:`, { message: error.message, code: error.code, stack: error.stack, timestamp: new Date().toISOString(), }); }; ``` ### Network Request Monitoring ```tsx theme={null} // Monitor all network requests const originalFetch = global.fetch; global.fetch = (...args) => { console.log('Network request:', args[0]); return originalFetch(...args) .then(response => { console.log('Network response:', response.status, response.statusText); return response; }) .catch(error => { console.error('Network error:', error); throw error; }); }; ``` ### Call State Debugging ```tsx theme={null} const debugCallState = (call) => { call.callState$.subscribe((state) => { console.log('Call State Debug:', { callId: call.callId, state: state, destination: call.destination, isIncoming: call.isIncoming, duration: call.duration, timestamp: new Date().toISOString(), }); }); }; ``` ## Error Recovery Strategies ### Automatic Recovery ```tsx theme={null} const createResilientVoipClient = () => { const voipClient = createTelnyxVoipClient({ debug: __DEV__, }); // Auto-recovery for connection issues voipClient.connectionState$.subscribe((state) => { if (state === 'DISCONNECTED') { console.log('Connection lost, attempting recovery...'); setTimeout(async () => { try { await voipClient.loginFromStoredConfig(); console.log('Auto-recovery successful'); } catch (error) { console.error('Auto-recovery failed:', error); } }, 5000); // Wait 5 seconds before retry } }); return voipClient; }; ``` ### Graceful Degradation ```tsx theme={null} const handleGracefulDegradation = (error) => { switch (error.code) { case 'PUSH_NOTIFICATIONS_UNAVAILABLE': // Continue without push notifications console.warn('Push notifications disabled, app must stay foreground'); break; case 'MICROPHONE_PERMISSION_DENIED': // Disable calling features console.warn('Microphone access denied, calling disabled'); break; case 'NETWORK_UNREACHABLE': // Show offline mode console.warn('Network unreachable, entering offline mode'); break; default: // General error handling console.error('Unhandled error, continuing with limited functionality'); } }; ``` ## Best Practices ### Error Handling Patterns 1. **Always wrap async operations in try-catch** 2. **Provide user-friendly error messages** 3. **Log detailed error information for debugging** 4. **Implement retry logic for transient failures** 5. **Gracefully degrade functionality when possible** ### Monitoring and Analytics ```tsx theme={null} // Error tracking with analytics const trackError = (error, context) => { // Send to your analytics service analytics().logEvent('voip_error', { error_code: error.code, error_message: error.message, context: context, platform: Platform.OS, app_version: DeviceInfo.getVersion(), }); }; ``` ### Testing Error Scenarios ```tsx theme={null} // Test error handling in development const testErrorScenarios = async (voipClient) => { if (__DEV__) { // Test invalid credentials try { await voipClient.login(createCredentialConfig('invalid', 'invalid')); } catch (error) { console.log('✓ Invalid credentials handled correctly'); } // Test network disconnection // (manually disconnect network to test) // Test invalid phone numbers try { await voipClient.newCall('invalid_number'); } catch (error) { console.log('✓ Invalid destination handled correctly'); } } }; ``` ## Getting Help When encountering persistent issues: 1. **Enable debug logging** and collect detailed logs 2. **Document reproduction steps** clearly 3. **Include device and OS information** 4. **Check the error handling guides** for your specific issue 5. **Contact Telnyx Support** with comprehensive information ## See Also * **[Push Notification Setup](pathname:///development/webrtc/react-native-sdk/push-notification/portal-setup)**: Push notification configuration * **[Quickstart Guide](pathname:///development/webrtc/react-native-sdk/quickstart)**: Setup and configuration * **[API Reference](pathname:///development/webrtc/react-native-sdk/classes)**: Detailed method documentation # React Native SDK Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/index Official Telnyx React Native SDK for building cross-platform real-time communication applications with WebRTC. # Telnyx React Native Voice SDK Demo A comprehensive demo application showcasing the **@telnyx/react-voice-commons-sdk** library - a high-level, state-agnostic, drop-in module for the Telnyx React Native SDK that simplifies WebRTC voice calling integration. ## Overview This demo app demonstrates how to integrate the `@telnyx/react-voice-commons-sdk` library to create a fully functional VoIP calling application with native call UI support, push notifications, and background handling. ### Key Features Demonstrated * **TelnyxVoiceApp Integration**: Automatic lifecycle management and push notification handling * **Native Call UI**: CallKit (iOS) and ConnectionService (Android) integration * **Background Handling**: Seamless app state transitions and background call processing * **Push Notifications**: Firebase (Android) and APNs (iOS) integration * **Reactive State Management**: RxJS-based state streams for real-time UI updates * **Modern UI Components**: Built with NativeWind v4 and react-native-reusables * **Dark/Light Mode**: Persistent theme support with system navigation bar matching ## About @telnyx/react-voice-commons-sdk The `@telnyx/react-voice-commons-sdk` library provides: * **Headless Operation**: Core library that can establish and manage call state programmatically * **Reactive Streams**: All state exposed via RxJS observables for easy integration * **Simplified API**: Single facade class (`TelnyxVoipClient`) that hides underlying complexity * **Automatic Lifecycle Management**: Background/foreground handling with `TelnyxVoiceApp` component * **Call State Management**: Central state machine for managing multiple calls * **Session Management**: Automatic connection lifecycle with reconnection logic * **Push Notification Support**: Built-in handling for background push notifications * **TypeScript Support**: Full TypeScript definitions for better developer experience ## Integration Guide ### Basic Setup The demo shows how to integrate the library using the `TelnyxVoiceApp` component for automatic lifecycle management: ```tsx theme={null} import { TelnyxVoiceApp, createTelnyxVoipClient } from '@telnyx/react-voice-commons-sdk'; // Create the VoIP client instance const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Optional: Enable automatic app state management (default: true) debug: true, // Optional: Enable debug logging }); export default function App() { return ( ); } ``` ## Core Components Used in Demo ### 1. VoIP Client Configuration ```tsx theme={null} const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Optional: Enable automatic app state management (default: true) debug: true, // Optional: Enable debug logging }); ``` **Configuration Options Explained:** * **`enableAppStateManagement: true`** - **Optional (default: true)**: Enables automatic background/foreground app state management. When enabled, the library automatically disconnects when the app goes to background (unless there's an active call) and handles reconnection logic. Set to `false` if you want to handle app lifecycle manually. * **`debug: true`** - **Optional**: Enables detailed logging for connection states, call transitions, and push notification processing. Useful for development and troubleshooting. ### 2. TelnyxVoiceApp Wrapper The `TelnyxVoiceApp` component handles: * Automatic background/foreground lifecycle management * Push notification processing from terminated state * Login state management with automatic reconnection * Background client management for push notifications ### 3. Reactive State Management ```tsx theme={null} // Listen to connection state voipClient.connectionState$.subscribe((state) => { console.log('Connection state:', state); }); // Listen to active calls voipClient.calls$.subscribe((calls) => { console.log('Active calls:', calls); }); // Handle individual call state call.callState$.subscribe((state) => { console.log('Call state:', state); }); ``` ### 4. Call Management ```tsx theme={null} // Make a call const call = await voipClient.newCall('1234567890'); // Answer incoming call await call.answer(); // Control call await call.mute(); await call.hold(); await call.hangup(); ``` ### Authentication & Persistent Storage The library supports both credential-based and token-based authentication with automatic persistence for seamless reconnection. ### Authentication Methods ### 1. Credential-Based Authentication ```tsx theme={null} import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; const config = createCredentialConfig('your_sip_username', 'your_sip_password', { debug: true, pushNotificationDeviceToken: 'your_device_token', }); await voipClient.login(config); ``` ### 2. Token-Based Authentication ```tsx theme={null} import { createTokenConfig } from '@telnyx/react-voice-commons-sdk'; const config = createTokenConfig('your_jwt_token', { debug: true, pushNotificationDeviceToken: 'your_device_token', }); await voipClient.loginWithToken(config); ``` ### Automatic Storage & Reconnection The library automatically stores authentication data securely for seamless reconnection. **You don't need to manually manage these storage keys** - the library handles everything internally. ### Internal Storage (Managed Automatically) The library uses these AsyncStorage keys internally: * `@telnyx_username` - SIP username (credential auth) * `@telnyx_password` - SIP password (credential auth) * `@credential_token` - JWT authentication token (token auth) * `@push_token` - Push notification device token **Note**: These are managed automatically by the library. You only need to call `login()` once, and the library will handle storage and future reconnections. ### Auto-Reconnection ```tsx theme={null} // Automatically reconnects using internally stored credentials or token const success = await voipClient.loginFromStoredConfig(); if (!success) { // No stored authentication data found, show login UI console.log('Please log in again'); } ``` **When Auto-Reconnection Happens:** * App launches from background/terminated state * Push notification received while disconnected * Network reconnection after connectivity loss * App state changes (foreground/background transitions) **Demo App Note**: The demo app's `TelnyxLoginForm` component does additional storage for UI convenience (pre-filling the login form). This is separate from the library's internal authentication storage and is not required for production apps. ### Manual Storage Management (Advanced Use Only) If you need to clear stored authentication data manually: ```tsx theme={null} import AsyncStorage from '@react-native-async-storage/async-storage'; // Clear all Telnyx authentication data await AsyncStorage.multiRemove([ '@telnyx_username', '@telnyx_password', '@credential_token', '@push_token', ]); ``` **Important**: This is typically not needed. The library manages authentication storage automatically. Only use this for advanced scenarios like implementing a "logout" feature that clears all stored data. ### Native Integration The demo app shows complete native integration for both platforms. These integrations are required for production apps using the library. ### Android Integration ### 1. MainActivity Setup Your app's MainActivity should extend `TelnyxMainActivity` for automatic push notification handling: ```kotlin theme={null} // In your app's MainActivity.kt import com.telnyx.react_voice_commons.TelnyxMainActivity class MainActivity : TelnyxMainActivity() { // Your app-specific code override fun onHandleIntent(intent: Intent) { super.onHandleIntent(intent) // Handle any additional intent processing } } ``` The `TelnyxMainActivity` provides: * Automatic push notification intent handling * Call action processing (Answer/Decline from notifications) * Proper lifecycle management for VoIP functionality * Integration with `VoicePnManager` for push notification state ### 2. Push Notification Setup 1. Place `google-services.json` in the project root 2. Register background message handler: ```tsx theme={null} import messaging from '@react-native-firebase/messaging'; import { TelnyxVoiceApp } from '@telnyx/react-voice-commons-sdk'; messaging().setBackgroundMessageHandler(async (remoteMessage) => { await TelnyxVoiceApp.handleBackgroundPush(remoteMessage.data); }); ``` ### iOS Integration ### 1. AppDelegate Setup Your AppDelegate only needs to implement `PKPushRegistryDelegate` for VoIP push notifications. CallKit integration is automatically handled by CallBridge: ```swift theme={null} import PushKit import TelnyxVoiceCommons @UIApplicationMain public class AppDelegate: ExpoAppDelegate, PKPushRegistryDelegate { public override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { // Your existing setup... // Initialize VoIP push registry via react-voice-commons TelnyxVoipPushHandler.initializeVoipRegistration() return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // MARK: - VoIP Push Notifications public func pushRegistry(_ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType) { TelnyxVoipPushHandler.shared.handleVoipTokenUpdate(pushCredentials, type: type) } public func pushRegistry(_ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void) { TelnyxVoipPushHandler.shared.handleVoipPush(payload, type: type, completion: completion) } } ``` **Note**: CallKit integration (CXProvider, CXProviderDelegate, audio session management) is automatically handled by the internal CallBridge component. You don't need to implement any CallKit delegate methods manually. ### 2. VoIP Push Certificate Setup * Configure VoIP push certificates in your Apple Developer account * The `TelnyxVoipPushHandler` automatically handles token registration and push processing * CallKit integration is automatically managed by CallBridge - no manual setup required ### Key Native Features Integrated 1. **Push Notification Handling**: Both platforms handle background push notifications properly 2. **Native Call UI**: CallKit (iOS, managed by CallBridge) and ConnectionService (Android) integration 3. **Audio Session Management**: Automatic audio session handling for VoIP calls via CallBridge 4. **Background Processing**: Seamless app state transitions and background call handling 5. **Intent Processing**: Android intent handling for notification actions (Answer/Decline) 6. **Token Management**: Automatic push token registration and updates ## Running the Demo Application ### Prerequisites * Node.js and npm * Expo CLI * iOS development: Xcode * Android development: Android Studio ### Installation and Setup 1. **Remove global Expo CLI** (if previously installed): ```bash theme={null} npm uninstall -g expo ``` 2. **Install dependencies** (including local Expo): ```bash theme={null} npm install ``` 3. **Run Expo install** to ensure all dependencies are properly configured: ```bash theme={null} npx expo install ``` 4. **Configure Firebase for Android**: * Download the `google-services.json` file from your Firebase project * Place it in the root directory of the project 5. **Prebuild the project**: ```bash theme={null} npx expo prebuild ``` 6. **Install iOS dependencies** (required for iOS): ```bash theme={null} cd ios && pod install && cd .. ``` ### Running the Application 1. **Start Metro bundler** (in a separate terminal): ```bash theme={null} npx expo start --clear --reset-cache ``` 2. **Run on iOS**: ```bash theme={null} npx expo run:ios ``` 3. **Run on Android**: ```bash theme={null} npx expo run:android ``` > **Note**: Make sure you have the necessary development environment set up for iOS (Xcode) or Android (Android Studio) before running the respective commands. ### Demo App Features Once running, the demo app provides: * **Login Form**: Enter your Telnyx SIP credentials or token * **Dialer Interface**: Make outgoing calls with a native dialer UI * **Call Management**: Answer, decline, hold, mute, and transfer calls * **Native Call UI**: Integrated CallKit (iOS) and ConnectionService (Android) * **Push Notifications**: Receive calls when app is in background or terminated * **Multiple Call Support**: Handle multiple simultaneous calls * **Background Handling**: Seamless app state transitions ### Configuration The demo app includes debug logging enabled by default: ```tsx theme={null} // Enable debug logging for the Telnyx SDK if (__DEV__) { log.setLevel('debug'); (global as any).__TELNYX_DEBUG__ = true; } ``` This provides detailed logging for: * Connection state changes * Call state transitions * Push notification processing * Background lifecycle events ## Troubleshooting ### iOS Connection Issues (First Run) If you encounter network connection errors on iOS: ```bash theme={null} # Try clearing cache and resetting npx expo start --clear --reset-cache # Or use tunnel mode npx expo start --tunnel # Or specify host explicitly npx expo start --host lan ``` ### iOS VoIP Push Notification Issues If you see VoIP-related crashes on iOS, ensure your AppDelegate.swift includes the VoIP push notification delegate methods. The project includes these by default, but if you encounter issues, rebuild the iOS project: ```bash theme={null} npx expo prebuild --platform ios --clean npx expo run:ios ``` ### Common Integration Issues ### Double Login Ensure you're not calling login methods manually when using `TelnyxVoiceApp` with auto-reconnection enabled. ### Background Disconnection Check if `enableAutoReconnect` is set appropriately for your use case in the `TelnyxVoiceApp` configuration. ### Push Notifications Not Working * **Android**: * Verify `google-services.json` is in the correct location and Firebase is properly configured * Ensure your MainActivity extends `TelnyxMainActivity` * Check that `VoicePnManager` is properly handling push actions * **iOS**: * Ensure VoIP push certificates are configured in your Apple Developer account * Verify AppDelegate implements `PKPushRegistryDelegate` and delegates to `TelnyxVoipPushHandler` * Check that `TelnyxVoipPushHandler.initializeVoipRegistration()` is called in `didFinishLaunchingWithOptions` * **Both**: Check that background message handlers are properly registered ### Native Integration Issues * **Android**: Ensure MainActivity extends `TelnyxMainActivity` for proper intent handling * **iOS**: Verify AppDelegate implements `PKPushRegistryDelegate` and delegates to `TelnyxVoipPushHandler` * **CallKit**: On iOS, CallKit integration is automatically handled by CallBridge - no manual setup required ### Audio Issues * **iOS**: Audio session management is automatically handled by CallBridge * **Android**: Verify ConnectionService is properly configured for audio routing * **Both**: Ensure proper audio permissions are granted ### Memory Leaks Ensure you're unsubscribing from RxJS observables in your React components: ```tsx theme={null} useEffect(() => { const subscription = voipClient.connectionState$.subscribe(handleStateChange); return () => subscription.unsubscribe(); }, []); ``` ## Documentation For complete API documentation and advanced usage patterns, see: * **[API Reference](https://developers.telnyx.com/development/webrtc/react-native-sdk)** - Auto-generated TypeDoc documentation * **[TelnyxVoiceApp Documentation](https://developers.telnyx.com/development/webrtc/react-native-sdk)** - Detailed component guide ## License MIT License - see LICENSE file for details. # CredentialConfig Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/credentialconfig/index Configuration for credential-based authentication with SIP username and password. # Interface: CredentialConfig Defined in: [models/config.ts:4](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L4) Configuration for credential-based authentication ## Properties ### type > **type**: `"credential"` Defined in: [models/config.ts:5](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L5) *** ### sipUser > **sipUser**: `string` Defined in: [models/config.ts:6](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L6) *** ### sipPassword > **sipPassword**: `string` Defined in: [models/config.ts:7](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L7) *** ### debug? > `optional` **debug**: `boolean` Defined in: [models/config.ts:8](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L8) Enable WebSocket-based debug stats collection. When enabled, the SDK sends real-time WebRTC statistics to the Telnyx debug service over the WebSocket connection. Default: `false` *** ### pushNotificationDeviceToken? > `optional` **pushNotificationDeviceToken**: `string` Defined in: [models/config.ts:9](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L9) *** ### enableCallReports? > `optional` **enableCallReports**: `boolean` Defined in: [models/config.ts:11](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L11) Enable automatic call quality reporting. When enabled, the SDK collects WebRTC stats and structured logs during calls and POSTs them to the `/call_report` endpoint when calls end. Default: `true` *** ### callReportInterval? > `optional` **callReportInterval**: `number` Defined in: [models/config.ts:13](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L13) Stats collection interval in seconds. Default: `5` *** ### callReportLogLevel? > `optional` **callReportLogLevel**: `string` Defined in: [models/config.ts:15](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L15) Minimum log level to capture for call reports: `'debug'` | `'info'` | `'warn'` | `'error'`. Default: `'debug'` *** ### callReportMaxLogEntries? > `optional` **callReportMaxLogEntries**: `number` Defined in: [models/config.ts:17](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L17) Maximum number of log entries to buffer per call. Default: `1000` # TelnyxVoiceAppOptions Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/telnyxvoiceappoptions/index Configuration options for the TelnyxVoiceApp component including VoIP client management and push notification handling. # Interface: TelnyxVoiceAppOptions Defined in: [telnyx-voice-app.tsx:11](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L11) Configuration options for TelnyxVoiceApp ## Extended by * [`TelnyxVoiceAppProps`](TelnyxVoiceAppProps.md) ## Properties ### voipClient > **voipClient**: [`TelnyxVoipClient`](../classes/TelnyxVoipClient.md) Defined in: [telnyx-voice-app.tsx:13](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L13) The TelnyxVoipClient instance to manage *** ### onPushNotificationProcessingStarted()? > `optional` **onPushNotificationProcessingStarted**: () => `void` Defined in: [telnyx-voice-app.tsx:16](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L16) Optional callback when push notification processing starts ### Returns `void` *** ### onPushNotificationProcessingCompleted()? > `optional` **onPushNotificationProcessingCompleted**: () => `void` Defined in: [telnyx-voice-app.tsx:19](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L19) Optional callback when push notification processing completes ### Returns `void` *** ### onAppStateChanged()? > `optional` **onAppStateChanged**: (`state`) => `void` Defined in: [telnyx-voice-app.tsx:22](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L22) Optional callback for additional background/foreground handling ### Parameters ### state `AppStateStatus` ### Returns `void` *** ### enableAutoReconnect? > `optional` **enableAutoReconnect**: `boolean` Defined in: [telnyx-voice-app.tsx:25](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L25) Whether to enable automatic login/reconnection (default: true) *** ### skipWebBackgroundDetection? > `optional` **skipWebBackgroundDetection**: `boolean` Defined in: [telnyx-voice-app.tsx:28](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L28) Whether to skip web platform for background detection (default: true) *** ### debug? > `optional` **debug**: `boolean` Defined in: [telnyx-voice-app.tsx:31](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voice-app.tsx#L31) Enable debug logging. Default: `false` # TelnyxVoipClientOptions Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/telnyxvoipclientoptions/index Configuration options for TelnyxVoipClient including app state management and debug settings. # Interface: TelnyxVoipClientOptions Defined in: [telnyx-voip-client.ts:11](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L11) Configuration options for TelnyxVoipClient ## Properties ### enableAppStateManagement? > `optional` **enableAppStateManagement**: `boolean` Defined in: [telnyx-voip-client.ts:13](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L13) Enable automatic app state management (background/foreground behavior) - default: true *** ### debug? > `optional` **debug**: `boolean` Defined in: [telnyx-voip-client.ts:16](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/telnyx-voip-client.ts#L16) Enable debug logging. Default: `false` # TokenConfig Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/interfaces/tokenconfig/index Configuration for token-based authentication with JWT tokens. # Interface: TokenConfig Defined in: [models/config.ts:15](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L15) Configuration for token-based authentication ## Properties ### type > **type**: `"token"` Defined in: [models/config.ts:16](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L16) *** ### token > **token**: `string` Defined in: [models/config.ts:17](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L17) *** ### debug? > `optional` **debug**: `boolean` Defined in: [models/config.ts:18](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L18) Enable WebSocket-based debug stats collection. When enabled, the SDK sends real-time WebRTC statistics to the Telnyx debug service over the WebSocket connection. Default: `false` *** ### pushNotificationDeviceToken? > `optional` **pushNotificationDeviceToken**: `string` Defined in: [models/config.ts:19](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L19) *** ### enableCallReports? > `optional` **enableCallReports**: `boolean` Defined in: [models/config.ts:29](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L29) Enable automatic call quality reporting. When enabled, the SDK collects WebRTC stats and structured logs during calls and POSTs them to the `/call_report` endpoint when calls end. Default: `true` *** ### callReportInterval? > `optional` **callReportInterval**: `number` Defined in: [models/config.ts:31](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L31) Stats collection interval in seconds. Default: `5` *** ### callReportLogLevel? > `optional` **callReportLogLevel**: `string` Defined in: [models/config.ts:33](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L33) Minimum log level to capture for call reports: `'debug'` | `'info'` | `'warn'` | `'error'`. Default: `'debug'` *** ### callReportMaxLogEntries? > `optional` **callReportMaxLogEntries**: `number` Defined in: [models/config.ts:35](https://github.com/team-telnyx/react-native-voice-commons/blob/5f0c1df513588a68afc08a15104d57f9daa9c0a1/react-voice-commons-sdk/src/models/config.ts#L35) Maximum number of log entries to buffer per call. Default: `1000` # App Setup Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/app-setup/index Configure your React Native application for push notifications on both iOS and Android platforms. # Push Notification App Setup This guide covers the complete setup required in your React Native application to enable push notifications for incoming calls using the `@telnyx/react-voice-commons-sdk`. ## Overview The Telnyx React Voice Commons SDK provides comprehensive push notification support for both iOS and Android platforms: * **iOS**: Uses Apple Push Notification Service (APNs) with VoIP certificates for instant call delivery * **Android**: Uses Firebase Cloud Messaging (FCM) for background call notifications * **Background Handling**: Automatic call processing when app is in background or terminated * **Native Call UI**: Integration with CallKit (iOS) and ConnectionService (Android) * **Multidevice Support**: Up to 5 devices can receive push notifications for the same user ## Multidevice Push Notifications Telnyx WebRTC supports multidevice push notifications. A single user can have up to 5 device tokens (either iOS - APNs or Android - FCM). When a user logs into the socket and provides a push token, our services will register this token to that user - allowing it to receive push notifications for incoming calls. If a 6th registration is made, the least recently used token will be removed. This effectively means that you can have up to 5 devices that can receive push notifications for the same incoming call. ## Prerequisites Before implementing push notifications, ensure you have: 1. **Telnyx Portal Configuration**: Push certificates and FCM keys configured in your Telnyx portal 2. **Development Environment**: React Native development environment set up for both platforms 3. **Firebase Project** (Android): Firebase project created with FCM enabled 4. **Apple Developer Account** (iOS): VoIP push certificates configured > **Note**: For portal configuration instructions, see [Portal Setup](./portal-setup.md). ## Application Setup ### 1. Install Dependencies The SDK requires specific dependencies for push notification handling: ```bash theme={null} # iOS VoIP push notifications npm install react-native-voip-push-notification # Expo notifications for Android FCM token (if using Expo) npx expo install expo-notifications # Note: Firebase messaging is handled natively on Android # No @react-native-firebase/messaging dependency required ``` ### 2. Firebase Configuration (Android) ### Step 1: Download Configuration File 1. Download the `google-services.json` file from your Firebase project console 2. Place it in your project root directory (same level as `package.json`) ```txt theme={null} your-project/ ├── google-services.json ← Place here ├── package.json ├── android/ └── ios/ ``` ### Step 2: Configure Firebase in Android Manifest Ensure your `android/app/src/main/AndroidManifest.xml` includes Firebase services: ```xml theme={null} ``` ### 3. Native Implementation ### Android Implementation ### Step 1: Extend TelnyxMainActivity Your app's `MainActivity` should extend `TelnyxMainActivity` for automatic push notification handling: ```kotlin theme={null} // android/app/src/main/java/com/yourpackage/MainActivity.kt package com.yourpackage import com.telnyx.react_voice_commons.TelnyxMainActivity import android.content.Intent import android.os.Bundle class MainActivity : TelnyxMainActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Your app-specific initialization } override fun onHandleIntent(intent: Intent) { super.onHandleIntent(intent) // Handle any additional intent processing if needed } } ``` **Key Features Provided by TelnyxMainActivity:** * Automatic push notification intent handling * Call action processing (Answer/Decline from notifications) * Proper lifecycle management for VoIP functionality * Integration with `VoicePnManager` for push notification state ### Step 2: Create Firebase Messaging Service Create a Firebase messaging service that extends `TelnyxFirebaseMessagingService`: ```kotlin theme={null} // android/app/src/main/java/com/yourpackage/AppFirebaseMessagingService.kt package com.yourpackage import com.telnyx.react_voice_commons.TelnyxFirebaseMessagingService /** * App-specific FCM service that extends the Telnyx base service */ class AppFirebaseMessagingService : TelnyxFirebaseMessagingService() { // All Telnyx voice push notification handling is inherited from the base class // Add any app-specific FCM handling here if needed } ``` ### Step 3: Create Notification Action Receiver Create a notification action receiver for handling notification actions: ```kotlin theme={null} // android/app/src/main/java/com/yourpackage/AppNotificationActionReceiver.kt package com.yourpackage import com.telnyx.react_voice_commons.TelnyxNotificationActionReceiver /** * App-specific notification action receiver */ class AppNotificationActionReceiver : TelnyxNotificationActionReceiver() { // All notification action handling is inherited from the base class // Add any app-specific notification handling here if needed } ``` ### iOS Implementation ### Step 1: Configure AppDelegate Your `AppDelegate` should implement `PKPushRegistryDelegate` and delegate to `TelnyxVoipPushHandler`: ```swift theme={null} // ios/YourApp/AppDelegate.swift import UIKit import PushKit import TelnyxVoiceCommons @UIApplicationMain public class AppDelegate: ExpoAppDelegate, PKPushRegistryDelegate { public override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { // Your existing setup... // Initialize VoIP push registry via react-voice-commons TelnyxVoipPushHandler.initializeVoipRegistration() return super.application(application, didFinishLaunchingWithOptions: launchOptions) } // MARK: - VoIP Push Notifications public func pushRegistry( _ registry: PKPushRegistry, didUpdate pushCredentials: PKPushCredentials, for type: PKPushType ) { TelnyxVoipPushHandler.shared.handleVoipTokenUpdate(pushCredentials, type: type) } public func pushRegistry( _ registry: PKPushRegistry, didReceiveIncomingPushWith payload: PKPushPayload, for type: PKPushType, completion: @escaping () -> Void ) { TelnyxVoipPushHandler.shared.handleVoipPush(payload, type: type, completion: completion) } } ``` **Important Notes:** * CallKit integration is automatically handled by the internal `CallBridge` component * You don't need to implement any CallKit delegate methods manually * Audio session management is automatically handled * The `TelnyxVoipPushHandler` manages all VoIP push notification processing ### Step 2: Configure Info.plist Add the required background modes to your `ios/YourApp/Info.plist`: ```xml theme={null} UIBackgroundModes voip background-processing ``` ### 4. JavaScript/TypeScript Integration ### Step 1: Configure TelnyxVoiceApp Wrap your app with `TelnyxVoiceApp` for automatic lifecycle management: ```tsx theme={null} // App.tsx import React from 'react'; import { TelnyxVoiceApp, createTelnyxVoipClient } from '@telnyx/react-voice-commons-sdk'; import YourAppContent from './YourAppContent'; // Create the VoIP client instance const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Enable automatic app state management debug: true, // Enable debug logging }); export default function App() { return ( ); } ``` ### Step 2: No Background Handler Required **Android push notifications are handled automatically by the SDK's native components.** You don't need to register any background message handlers in your JavaScript code. The SDK handles everything natively through: * `TelnyxMainActivity` (extends your MainActivity) * `TelnyxFirebaseMessagingService` (extends your FCM service) Simply extend these classes as shown in the native implementation steps above, and push notifications will work automatically. ### Step 3: Token Registration (Optional) Push tokens are handled automatically by the SDK during authentication. For most apps, you don't need to do anything additional. If you want to handle push tokens manually (for logging or custom logic), you can use the `VoipTokenFetcher` component: ```tsx theme={null} import { VoipTokenFetcher } from './VoipTokenFetcher'; export function YourLoginComponent() { const handleTokenReceived = (token: string) => { console.log('Push token received:', token); // Store or use the token as needed }; return ( {/* Your login form here */} ); } ``` The `VoipTokenFetcher` component automatically: * Requests notification permissions * Retrieves FCM tokens (Android) and VoIP tokens (iOS) * Handles platform-specific token registration ### Step 4: Authentication Include push tokens in your login configuration: ```tsx theme={null} // Login with automatic push token handling import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; const handleLogin = async (username: string, password: string) => { const config = createCredentialConfig(username, password, { debug: true, // Push tokens are automatically retrieved and registered by the SDK }); await voipClient.login(config); }; ``` ## Configuration Options ### TelnyxVoiceApp Configuration ```tsx theme={null} { console.log('Push notification processing started'); }} onPushNotificationProcessingCompleted={() => { console.log('Push notification processing completed'); }} onAppStateChanged={(state) => { console.log('App state changed:', state); }} > {children} ``` ### VoIP Client Configuration ```tsx theme={null} const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Enable automatic app state management debug: true, // Enable debug logging }); ``` **Configuration Options Explained:** * **`enableAppStateManagement: true`**: Enables automatic background/foreground app state management. When enabled, the library automatically disconnects when the app goes to background (unless there's an active call) and handles reconnection logic. * **`debug: true`**: Enables detailed logging for connection states, call transitions, and push notification processing. ### Authentication with Push Tokens Push tokens are automatically handled by the SDK. You only need to include the SDK and authenticate normally: ### Credential-Based Authentication ```tsx theme={null} import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; const config = createCredentialConfig('your_sip_username', 'your_sip_password', { debug: true, // Push tokens are automatically managed by the SDK }); await voipClient.login(config); ``` ### Token-Based Authentication ```tsx theme={null} import { createTokenConfig } from '@telnyx/react-voice-commons-sdk'; const config = createTokenConfig('your_jwt_token', { debug: true, // Push tokens are automatically managed by the SDK }); await voipClient.loginWithToken(config); ``` ## What Happens Automatically The SDK handles push notifications automatically once you: 1. **Android**: Extend `TelnyxMainActivity` and `TelnyxFirebaseMessagingService` 2. **iOS**: Implement `PKPushRegistryDelegate` and delegate to `TelnyxVoipPushHandler` 3. **Both**: Wrap your app with `TelnyxVoiceApp` and authenticate with the SDK ### Android Automatic Features * FCM token registration with Telnyx servers * Background push notification processing * Incoming call notifications with Answer/Decline buttons * App launching from terminated state * Call connection and audio setup ### iOS Automatic Features * VoIP token registration with Telnyx servers * CallKit integration for native call UI * Background call processing * App launching from terminated state * Audio session management ## Advanced Configuration ### Custom FCM Message Handling (Android) If you need to handle additional FCM messages beyond Telnyx voice calls, extend the service: ```kotlin theme={null} // android/app/src/main/java/com/yourpackage/AppFirebaseMessagingService.kt class AppFirebaseMessagingService : TelnyxFirebaseMessagingService() { override fun onMessageReceived(remoteMessage: RemoteMessage) { // Let Telnyx handle voice notifications first super.onMessageReceived(remoteMessage) // Handle your app's other notifications if (remoteMessage.data.containsKey("your_app_notification_type")) { // Handle your custom notifications } } } ``` ### Push Notification Debugging Enable comprehensive debugging for push notification issues: ```tsx theme={null} // Enable global debug logging if (__DEV__) { (global as any).__TELNYX_DEBUG__ = true; } const voipClient = createTelnyxVoipClient({ debug: true, // Enable SDK debug logging }); ``` ## Troubleshooting ### Common Issues ### Push Notifications Not Received **Android:** * Verify `google-services.json` is in the correct location * Check Firebase project configuration and FCM keys in Telnyx portal * Ensure `AppFirebaseMessagingService` is properly registered in AndroidManifest.xml * Verify app is not in battery optimization/doze mode **iOS:** * Ensure VoIP push certificates are configured in Apple Developer account * Verify certificates are uploaded to Telnyx portal * Check that `TelnyxVoipPushHandler.initializeVoipRegistration()` is called * Ensure app has proper VoIP background modes configured ### App Not Launching from Push **Android:** * Verify `MainActivity` extends `TelnyxMainActivity` * Check intent filters in AndroidManifest.xml * Ensure `onHandleIntent` is properly implemented **iOS:** * Verify AppDelegate implements `PKPushRegistryDelegate` * Ensure proper delegation to `TelnyxVoipPushHandler` * Check VoIP background modes in Info.plist ### Call Connection Issues * Verify authentication is successful before push notification * Check network connectivity and Telnyx service availability * Ensure proper error handling in push notification flow * Verify call state management in `TelnyxVoiceApp` ### Debug Logging Enable detailed logging to troubleshoot issues: ```tsx theme={null} // In your main component useEffect(() => { // Listen to connection states const connectionSub = voipClient.connectionState$.subscribe((state) => { console.log('Connection state:', state); }); // Listen to call states const callsSub = voipClient.calls$.subscribe((calls) => { console.log('Active calls:', calls.length); calls.forEach((call, index) => { console.log(`Call ${index}:`, call.currentState); }); }); return () => { connectionSub.unsubscribe(); callsSub.unsubscribe(); }; }, []); ``` ## Security Considerations 1. **Token Storage**: Push tokens are automatically stored securely by the SDK 2. **Certificate Management**: Keep VoIP certificates and FCM keys secure 3. **Authentication**: Ensure proper authentication before accepting calls 4. **Network Security**: Use secure connections for all Telnyx communications ## Next Steps After completing the app setup: 1. **Test Push Notifications**: Test with both foreground and background scenarios 2. **Call Flow Testing**: Verify complete call flow from push to termination 3. **Production Deployment**: Configure production certificates and keys 4. **Monitoring**: Implement logging and monitoring for production use For additional configuration and troubleshooting, see: * [Portal Setup Guide](./portal-setup.md) * [API Documentation](../README.md) * [Telnyx Developer Portal](https://developers.telnyx.com) # Portal Setup Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/portal-setup/index Configure push notifications for React Native applications in the Telnyx Portal. ## Android The Telnyx React Native Client WebRTC SDK uses Firebase Cloud Messaging (FCM) to deliver push notifications for Android devices. To enable notifications for incoming calls on your Android mobile device, you need to set up Firebase Cloud Messaging in your application. Follow these steps to configure Firebase Cloud Messaging for your Android application through the Telnyx portal: 1. Visit the [Portal Setup Android](https://developers.telnyx.com/docs/voice/webrtc/android-sdk/push-notification/portal-setup) to complete the setup process. ## ios The Telnyx React Native Client WebRTC SDK uses Apple Push Notification Service (APNs) to deliver push notifications for iOS devices. To enable notifications for incoming calls on your iOS device, you need to set up APNs in your application. Follow these steps to configure Apple Push Notification Service (APNs) for your iOS application through the Telnyx portal: 1. Visit the [Portal Setup iOS](https://developers.telnyx.com/docs/voice/webrtc/ios-sdk/push-notification/portal-setup) to complete the setup process. # React Native SDK Quickstart Source: https://developers.telnyx.com/development/webrtc/react-native-sdk/quickstart/index Get started with the Telnyx React Native SDK in minutes. Complete setup guide from installation to making your first call. # Quick Start Guide Get up and running with the `@telnyx/react-voice-commons-sdk` in just a few minutes! ## Installation ```bash theme={null} npm install @telnyx/react-voice-commons-sdk ``` ## Basic Setup ### 1. Wrap Your App ```tsx theme={null} // App.tsx import React from 'react'; import { TelnyxVoiceApp, createTelnyxVoipClient } from '@telnyx/react-voice-commons-sdk'; import YourAppContent from './YourAppContent'; // Create the VoIP client instance const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Enable automatic app state management debug: true, // Enable debug logging }); export default function App() { return ( ); } ``` ### 2. Create a Login Component ```tsx theme={null} // LoginScreen.tsx import React, { useState } from 'react'; import { View, TextInput, TouchableOpacity, Text } from 'react-native'; import { useTelnyxVoice, createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; export function LoginScreen() { const { voipClient } = useTelnyxVoice(); const [username, setUsername] = useState(''); const [password, setPassword] = useState(''); const handleLogin = async () => { const config = createCredentialConfig(username, password, { debug: true, }); await voipClient.login(config); }; return ( Connect ); } ``` ### 3. Make Your First Call ```tsx theme={null} // DialerScreen.tsx import React, { useState } from 'react'; import { View, TextInput, TouchableOpacity, Text } from 'react-native'; import { useTelnyxVoice } from '@telnyx/react-voice-commons-sdk'; export function DialerScreen() { const { voipClient } = useTelnyxVoice(); const [phoneNumber, setPhoneNumber] = useState(''); const makeCall = async () => { const call = await voipClient.newCall(phoneNumber); console.log('Call initiated:', call); }; return ( Call ); } ``` ### 4. Listen to Connection State ```tsx theme={null} // useConnectionState.ts import { useEffect, useState } from 'react'; import { useTelnyxVoice, TelnyxConnectionState } from '@telnyx/react-voice-commons-sdk'; export function useConnectionState() { const { voipClient } = useTelnyxVoice(); const [connectionState, setConnectionState] = useState(voipClient.currentConnectionState); useEffect(() => { const subscription = voipClient.connectionState$.subscribe(setConnectionState); return () => subscription.unsubscribe(); }, [voipClient]); return connectionState; } ``` ## That's It You now have a basic VoIP calling app! The SDK automatically handles: * **Connection management** - Automatic reconnection and lifecycle * **Call state management** - Complete call state machine * **Background handling** - App state transitions * **Authentication storage** - Secure credential persistence ## Next Steps ### Add Push Notifications For incoming calls when your app is in the background: * **[Push Notification Setup](https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/portal-setup)** - Complete push notification guide ### Native Integration For production apps, you'll need native integration: * **[Android Setup](https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/app-setup#android-implementation)** - MainActivity and Firebase setup * **[iOS Setup](https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notification/app-setup#ios-implementation)** - AppDelegate and VoIP push setup ### Advanced Features The SDK provides extensive capabilities for building production VoIP apps: * **Call Management** - Hold, mute, transfer, and conference calls (see [Call API](https://team-telnyx.github.io/react-native-voice-commons/classes/Call.html)) * **Error Handling** - Robust error handling patterns (see [Error Handling Guide](https://developers.telnyx.com/development/webrtc/react-native-sdk/error-handling)) * **State Management** - RxJS observables and reactive patterns (see [TelnyxVoipClient API](https://team-telnyx.github.io/react-native-voice-commons/classes/TelnyxVoipClient.html)) ## Configuration Options ### VoIP Client Options ```tsx theme={null} const voipClient = createTelnyxVoipClient({ enableAppStateManagement: true, // Auto-handle background/foreground debug: true, // Enable debug logging }); ``` ### TelnyxVoiceApp Options ```tsx theme={null} { console.log('Push notification processing started'); }} onPushNotificationProcessingCompleted={() => { console.log('Push notification processing completed'); }} onAppStateChanged={(state) => { console.log('App state changed:', state); }} > {children} ``` ## Authentication Options ### Credential-Based Authentication ```tsx theme={null} import { createCredentialConfig } from '@telnyx/react-voice-commons-sdk'; const config = createCredentialConfig('your_sip_username', 'your_sip_password', { debug: true, }); await voipClient.login(config); ``` ### Token-Based Authentication ```tsx theme={null} import { createTokenConfig } from '@telnyx/react-voice-commons-sdk'; const config = createTokenConfig('your_jwt_token', { debug: true, }); await voipClient.loginWithToken(config); ``` ### Auto-Reconnection ```tsx theme={null} // Automatically reconnect using stored credentials const success = await voipClient.loginFromStoredConfig(); if (!success) { // Show login form console.log('Please log in again'); } ``` ## Need Help? * **[API Documentation](https://developers.telnyx.com/development/webrtc/react-native-sdk/classes)** - Complete API reference * **[Push Notifications](https://developers.telnyx.com/development/webrtc/react-native-sdk/push-notifications)** - Push notification setup * **[Troubleshooting](https://developers.telnyx.com/development/webrtc/react-native-sdk/error-handling)** - Common issues and solutions * **[Demo App](https://github.com/team-telnyx/react-native-voice-commons/)** - Full demo application source code ## You're Ready Start building your VoIP application with the Telnyx React Voice Commons SDK. The SDK handles the complexity so you can focus on building great user experiences! # React quickstart Source: https://developers.telnyx.com/development/webrtc/react-sdk/index Get started with the Telnyx React SDK for building WebRTC voice applications in React. The React SDK can be added to your application by installing the npm packages: ```bash theme={null} npm install --save @telnyx/react-client @telnyx/webrtc ``` ## Client initialization In the `TelnyxRTCProvider` component, you can pass credentials and options objects with custom ringtones: ```jsx theme={null} // App.jsx import { TelnyxRTCProvider } from '@telnyx/react-client'; function App() { const credential = { login_token: 'mytoken', }; const options = { ringtoneFile: "./ringtone.mp3", ringbackFile: "./ringback.mp3", }; return ( ); } ``` ## Phone component In the `Phone` component, you would subscribe to the notifications from the WebRTC client, specify callbacks for Telnyx client event handlers, and define an Audio element. First import the React client: ```jsx theme={null} import { useNotification, Audio, useCallbacks } from "@telnyx/react-client"; ``` Define a `Phone` function component where you will manage event handlers using callbacks and control audio stream in the `