TryVox

Bring Your Own Carrier (BYOC)

Register your own SIP carrier with TryVox so calls egress through it instead of TryVox's default carriers.

Bring Your Own Carrier (BYOC)

By default, TryVox routes outbound calls through its own carrier mix. BYOC lets you register an external SIP carrier (your existing carrier contract, an upstream wholesaler, a regional operator) so calls placed by your account egress through it. You configure SIP credentials, dialing prefixes, codec preferences, and concurrency caps; TryVox's routing engine picks one of your carriers per call based on prefix match and priority.

You retain the carrier relationship and the per-minute commercials. TryVox handles SIP signalling, NAT traversal, and call control.

When to use BYOC

  • You already have a carrier contract you want to keep using.
  • You need to reach destinations TryVox's default carriers don't cover well.
  • Compliance requires calls to traverse a specific operator (regulated markets, PSAP routing, government numbers).
  • You want to A/B carrier quality without leaving the TryVox call control surface.

Concepts

TermDescription
CarrierTop-level record. Holds SIP host, credentials, capacity, codec list, status.
Carrier RouteA dialing rule attached to a carrier: prefix + priority + optional rate. The same destination prefix can exist on multiple carriers — routing picks by priority then weight.
Health StatusHealth-checker pings the carrier's SIP host and updates health_status (healthy, degraded, unhealthy). Calls don't get routed to unhealthy carriers.
LCRLeast-Cost Routing. Internal lookup that picks a carrier for a destination by walking matching routes in priority order.

Endpoints

All carrier management endpoints are scoped to your account. Both the account-scoped and ID-only forms are accepted; prefer the account-scoped form so resources stay attached to the right Auth ID.

MethodPathPurpose
POST/v1/account/{auth_id}/carriersCreate a carrier
GET/v1/account/{auth_id}/carriersList carriers
GET/v1/account/{auth_id}/carriers/{id}Get a carrier
PUT/v1/account/{auth_id}/carriers/{id}Update a carrier
DELETE/v1/account/{auth_id}/carriers/{id}Delete a carrier
GET/v1/account/{auth_id}/carriers/{id}/routesList carrier routes
POST/v1/account/{auth_id}/carriers/{id}/routesAdd a route
DELETE/v1/account/{auth_id}/carriers/{carrier_id}/routes/{route_id}Delete a route
GET/v1/account/{auth_id}/carriers/{id}/healthGet health log

Create a carrier

POST /v1/account/{auth_id}/carriers

Request body

FieldTypeRequiredDescription
namestringyesDisplay name.
codestringnoShort identifier you can use in routing rules (e.g. CC-IN). Defaults to a slug of name.
carrier_typestringnoinbound, outbound, or bidirectional. Default: outbound.
sip_hoststringconditionalSIP host or FQDN. Required for outbound carriers.
sip_portintegernoDefault: 5060.
transportstringnoudp, tcp, or tls. Default: udp.
auth_usernamestringnoSIP digest username if the carrier requires auth.
auth_passwordstringnoSIP digest password. Stored encrypted.
max_channelsintegernoConcurrent call cap. Calls beyond this fall through to the next carrier.
priorityintegernoHigher wins. Default: 100.
weightintegernoRound-robin weight among carriers with the same priority. Default: 1.
health_check_urlstringnoURL to GET for health checks (instead of SIP OPTIONS ping).
configstringnoFree-form JSON for carrier-specific overrides.

Example

curl -X POST https://api.tryvox.io/v1/account/$TRYVOX_AUTH_ID/carriers \
  -u $TRYVOX_AUTH_ID:$TRYVOX_AUTH_TOKEN \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Telecom — IN",
    "code": "ACME-IN",
    "carrier_type": "outbound",
    "sip_host": "sip.acmetel.example",
    "sip_port": 5060,
    "transport": "udp",
    "auth_username": "tryvox-trunk-42",
    "auth_password": "<sip-secret>",
    "max_channels": 200,
    "priority": 100
  }'

Response

201 Created — the full carrier record:

{
  "id": "8f7a4b2e-91c2-4f3d-9a1e-2c4b6d8f0a1c",
  "name": "Acme Telecom — IN",
  "code": "ACME-IN",
  "carrier_type": "outbound",
  "sip_host": "sip.acmetel.example",
  "sip_port": 5060,
  "transport": "udp",
  "auth_username": "tryvox-trunk-42",
  "max_channels": 200,
  "active_channels": 0,
  "priority": 100,
  "weight": 1,
  "status": "active",
  "health_status": "unknown",
  "codec_preferences": ["PCMU", "PCMA"],
  "country_code": "IN",
  "created_at": "2026-04-09T10:30:00Z"
}

auth_password is never returned. To rotate, PUT a new value.

List carriers

GET /v1/account/{auth_id}/carriers
curl -u $TRYVOX_AUTH_ID:$TRYVOX_AUTH_TOKEN \
  https://api.tryvox.io/v1/account/$TRYVOX_AUTH_ID/carriers

Returns 200 OK with an array of carrier records.

Get a carrier

GET /v1/account/{auth_id}/carriers/{id}

Returns 200 OK with the same shape as Create. Returns 404 NOT_FOUND if the carrier doesn't exist or belongs to another account.

Update a carrier

PUT /v1/account/{auth_id}/carriers/{id}

Pass any subset of the create fields; only the keys present are applied. Use this to rotate credentials, change priority, or flip status between active and disabled.

curl -X PUT https://api.tryvox.io/v1/account/$TRYVOX_AUTH_ID/carriers/$CARRIER_ID \
  -u $TRYVOX_AUTH_ID:$TRYVOX_AUTH_TOKEN \
  -H "Content-Type: application/json" \
  -d '{"priority": 50, "max_channels": 400}'

Returns 200 OK with the updated carrier.

Delete a carrier

DELETE /v1/account/{auth_id}/carriers/{id}

Returns 204 No Content. Routes attached to the carrier are removed at the same time. In-flight calls already routed through the carrier complete normally; no new calls match.

Carrier Routes

Routes attach to a single carrier and define which destinations the carrier handles.

List routes

GET /v1/account/{auth_id}/carriers/{id}/routes
[
  {
    "id": "1b2c3d4e-5f60-7180-9a2b-3c4d5e6f7a8b",
    "carrier_id": "8f7a4b2e-91c2-4f3d-9a1e-2c4b6d8f0a1c",
    "prefix": "+91",
    "priority": 100,
    "rate": 0.0085,
    "rate_currency": "USD",
    "status": "active",
    "created_at": "2026-04-09T10:31:00Z"
  }
]

Add a route

POST /v1/account/{auth_id}/carriers/{id}/routes
FieldTypeRequiredDescription
prefixstringyesE.164 prefix to match (e.g. +91, +9198, +1415). Longer prefixes win over shorter ones.
priorityintegernoWithin prefix matches across carriers, higher priority wins. Default: 100.
ratenumbernoPer-minute rate. Used by LCR when picking among equal-priority carriers.
rate_currencystringnoISO 4217 currency code. Default: USD.
curl -X POST https://api.tryvox.io/v1/account/$TRYVOX_AUTH_ID/carriers/$CARRIER_ID/routes \
  -u $TRYVOX_AUTH_ID:$TRYVOX_AUTH_TOKEN \
  -H "Content-Type: application/json" \
  -d '{"prefix": "+91", "priority": 100, "rate": 0.0085}'

201 Created with the new route.

Delete a route

DELETE /v1/account/{auth_id}/carriers/{carrier_id}/routes/{route_id}

Returns 204 No Content.

Health log

GET /v1/account/{auth_id}/carriers/{id}/health

Returns the most recent health probes (latest first):

[
  {
    "id": "...",
    "carrier_id": "...",
    "status": "healthy",
    "response_time_ms": 42,
    "created_at": "2026-04-09T10:34:00Z"
  },
  {
    "id": "...",
    "carrier_id": "...",
    "status": "unhealthy",
    "error_message": "SIP OPTIONS timeout",
    "created_at": "2026-04-09T10:30:00Z"
  }
]

Health checks run every 30 seconds by default and update carriers.health_status automatically. Two consecutive failures flip the carrier to unhealthy and remove it from routing; one success flips it back.

Routing decision

When you place an outbound call:

  1. The destination to number is normalised to E.164.
  2. The router walks routes whose prefix matches the destination, longest-prefix first.
  3. Among matches, carriers are ranked by priority (descending), then by weight (round-robin), then by rate (ascending) for LCR.
  4. Carriers with status != active, health_status = unhealthy, or active_channels >= max_channels are skipped.
  5. The first surviving carrier wins. If none survive, the call fails with 502 NO_CARRIER_AVAILABLE.

You can preview the decision with the internal LCR endpoint surfaced for support — contact us if you need API access for capacity planning.

Notes

  • Credentials are write-only. auth_password is never returned by GET. Rotate via PUT.
  • Carriers are tenant-scoped. Other accounts on the platform can't see or use yours.
  • Soft-disable instead of delete when iterating: set status: "disabled" to remove from routing without losing the configuration.
  • Default carriers still exist — BYOC carriers are added to the routing pool, not as a replacement, unless you explicitly disable the defaults.

On this page