Skip to content

Telephony

Connect your Plivo, Twilio, Vonage, or Telnyx account to use for outbound and inbound PSTN legs. Rymi encrypts provider credentials before storage.

Self-serve BYOC carrier costs are not bundled into Rymi's platform minute price. Your carrier bills PSTN minutes, number rental, taxes, and add-ons directly. Rymi bills at the agent's per-minute rate: its managed SKU price, or for a custom agent the stack's component cost plus the flat $0.02/min platform fee. Enterprise plans can bundle telecom under a custom agreement.

List Available Providers

GET/v1/telephony/providers

Returns the full carrier catalog with the credential field shapes the dashboard uses to render dynamic connect forms. No auth required, since field metadata is not sensitive.

Response 200

json
{
  "providers": [
    {
      "id": "twilio",
      "displayName": "Twilio",
      "credentialFields": [
        { "key": "auth_id", "label": "Account SID", "type": "text", "required": true },
        { "key": "auth_token", "label": "Auth Token", "type": "secret", "required": true }
      ]
    }
  ]
}

Validate Without Saving

POST/v1/telephony/validate

Pings the carrier's API and returns whether the credentials authenticate, without storing them. Rate-limited to 3 attempts per 5 minutes per tenant.

Request Body

Same shape as Connect Provider.

Response 200

json
{ "valid": true, "accountName": "Acme Twilio" }
json
{ "valid": false, "error": "Invalid credentials — could not authenticate with the provider" }

Errors

StatusMeaning
400Unsupported provider
401Missing Rymi auth context
429Too many validation attempts; wait and retry

Connect Provider

POST/v1/telephony/connect

Only one active telephony carrier is used per tenant at a time. Connecting a new provider deactivates the previous active carrier.

Request Body

FieldTypeRequiredDefaultDescription
providerstringYesplivo, twilio, vonage, or telnyx
auth_idstringYes (Plivo/Twilio/Telnyx)Plivo Auth ID, Twilio Account SID, or Telnyx API Key
auth_tokenstringYes (Plivo/Twilio)Provider auth token. For Telnyx this is the Connection ID and is optional — Rymi auto-creates a TeXML app when omitted
api_keystringYes (Vonage)Vonage API key
api_secretstringYes (Vonage)Vonage API secret
application_idstringYes (Vonage)Vonage Voice Application ID
private_keystringYes (Vonage)Vonage Voice private key (PEM)
auth_secretstringNoOptional webhook signing secret (Telnyx Ed25519 verification)
signature_secretstringNoOptional Vonage signature secret for webhook verification (required to receive inbound calls)

Example: Twilio

bash
curl -X POST https://api.rymi.live/v1/telephony/connect \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "twilio",
    "auth_id": "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "auth_token": "your_twilio_auth_token"
  }'
ts
const result = await rymi.telephony.connect({
  provider: "twilio",
  auth_id: "ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  auth_token: "your_twilio_auth_token",
});
python
result = rymi.telephony.connect(
    provider="twilio",
    auth_id="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    auth_token="your_twilio_auth_token",
)

Example: Plivo

bash
curl -X POST https://api.rymi.live/v1/telephony/connect \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "plivo",
    "auth_id": "your_plivo_auth_id",
    "auth_token": "your_plivo_auth_token"
  }'
ts
const result = await rymi.telephony.connect({
  provider: "plivo",
  auth_id: "your_plivo_auth_id",
  auth_token: "your_plivo_auth_token",
});
python
result = rymi.telephony.connect(
    provider="plivo",
    auth_id="your_plivo_auth_id",
    auth_token="your_plivo_auth_token",
)

Example: Vonage

bash
curl -X POST https://api.rymi.live/v1/telephony/connect \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "vonage",
    "api_key": "your_vonage_api_key",
    "api_secret": "your_vonage_api_secret",
    "application_id": "your_vonage_voice_application_id",
    "private_key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
    "signature_secret": "your_vonage_signature_secret"
  }'
ts
const result = await rymi.telephony.connect({
  provider: "vonage",
  api_key: "your_vonage_api_key",
  api_secret: "your_vonage_api_secret",
  application_id: "your_vonage_voice_application_id",
  private_key: "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
  signature_secret: "your_vonage_signature_secret",
});
python
result = rymi.telephony.connect(
    provider="vonage",
    api_key="your_vonage_api_key",
    api_secret="your_vonage_api_secret",
    application_id="your_vonage_voice_application_id",
    private_key="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
    signature_secret="your_vonage_signature_secret",
)

Example: Telnyx

bash
curl -X POST https://api.rymi.live/v1/telephony/connect \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "provider": "telnyx",
    "auth_id": "your_telnyx_api_key",
    "auth_token": "your_telnyx_connection_id",
    "auth_secret": "your_telnyx_webhook_signing_secret"
  }'

Response 200

json
{
  "status": "connected",
  "provider": "twilio",
  "account_name": "Acme Twilio",
  "message": "twilio account connected successfully"
}

Errors

StatusMeaning
400Missing or unsupported provider, missing provider-specific credentials, or invalid carrier credentials (validation failed)
401Missing Rymi auth context
429Too many credential connection attempts in a short window
500Credential storage failed

Status

GET/v1/telephony/status

Returns the current telephony connection state for the authenticated tenant. No query parameters.

Example Request

bash
curl https://api.rymi.live/v1/telephony/status \
  -H "Authorization: Bearer YOUR_API_KEY"
ts
const status = await rymi.telephony.status();
python
status = rymi.telephony.status()

Response 200

json
{
  "connected": true,
  "provider": "twilio",
  "account_name": "Acme Twilio",
  "test_pool": { "enabled": true, "countries": ["US", "IN"] }
}

test_pool is always present, on both the connected and disconnected branches, and reports the shared test-number pool for the tenant.

FieldTypeDescription
connectedbooleanWhether a telephony provider is currently connected
providerstring or nullActive provider: plivo, twilio, vonage, or telnyx
account_namestring or nullDisplay name from the provider account
test_poolobjectShared test-number pool status: { enabled: boolean, countries: string[] }

Errors

StatusMeaning
401Missing or invalid API key
500Provider status lookup failed

Provider Numbers

GET/v1/telephony/numbers

Returns carrier-owned numbers synced into Rymi for the connected provider. Read-only: it does not search, buy, release, assign, or unassign carrier numbers.

Example Request

bash
curl https://api.rymi.live/v1/telephony/numbers \
  -H "Authorization: Bearer YOUR_API_KEY"
ts
const { numbers } = await rymi.telephony.numbers();
python
result = rymi.telephony.numbers()

Response 200

json
{
  "numbers": [
    {
      "id": "num_123",
      "provider": "twilio",
      "phone_number": "+15551234567",
      "number_type": "local",
      "number_status": "active",
      "assigned_app_id": null,
      "backend_agent_id": "550e8400-e29b-41d4-a716-446655440000",
      "synced_at": "2026-04-01T10:00:00Z",
      "agents": { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "Support Bot" }
    }
  ]
}
FieldTypeDescription
idstringInternal number record ID
providerstringCarrier provider name
phone_numberstringPhone number in E.164 format
number_typestring or nullCarrier-reported number type (e.g. local, tollfree)
number_statusstringactive or inactive
assigned_app_idstring or nullCarrier application/connection the number is bound to, if any
backend_agent_iduuid or nullAgent attached to this number, if any
synced_atstring or nullTimestamp of the last carrier sync for this number
agentsobject or nullAttached agent { id, name }, joined from backend_agent_id

Errors

StatusMeaning
401Missing or invalid API key
500Provider number lookup failed

Disconnect

POST/v1/telephony/disconnect

Deactivates the current telephony provider. No request body required.

Example Request

bash
curl -X POST https://api.rymi.live/v1/telephony/disconnect \
  -H "Authorization: Bearer YOUR_API_KEY"
ts
const result = await rymi.telephony.disconnect();
python
result = rymi.telephony.disconnect()

Response 200

json
{
  "status": "disconnected",
  "message": "Telephony disconnected."
}

Errors

StatusMeaning
401Missing or invalid API key
500Disconnect operation failed

Sync Numbers from Carrier

POST/v1/telephony/sync-numbers

Pulls phone-number inventory from the connected carrier and upserts it into provider_numbers. Numbers no longer present in the carrier inventory are removed locally. Rate-limited to one sync per 2 minutes per tenant.

Example Request

bash
curl -X POST https://api.rymi.live/v1/telephony/sync-numbers \
  -H "Authorization: Bearer YOUR_API_KEY"

Response 200

json
{
  "numbers": [
    {
      "phone_number": "+15551234567",
      "number_type": "local",
      "provider": "twilio"
    }
  ],
  "synced_at": "2026-04-01T10:00:00Z"
}

Errors

StatusMeaning
400No active telephony provider connected, or provider doesn't support sync
429Sync rate-limited; wait 2 minutes between syncs
500Carrier API call failed

Number Management

Rymi does not search or purchase carrier numbers. Provision numbers in your carrier account, sync them via POST /v1/telephony/sync-numbers, then use the Numbers API to attach them to agents.