Documentation Index
Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
Use this file to discover all available pages before exploring further.
Bindings allow your edge functions to interact with Telnyx platform services. They provide secure, auto-authenticated access without managing API keys in your code.
Available Bindings
| Binding | Description | Status |
|---|
| Voice | Make and receive calls | ✅ Available |
| Messaging | Send SMS/MMS | ✅ Available |
| Phone Numbers | Manage numbers | ✅ Available |
| Fax | Send faxes | ✅ Available |
| Verify | 2FA/verification | ✅ Available |
| Cloud Storage | S3-compatible storage | ✅ Available |
| KV | Key-value store | 🔜 Coming soon |
| SQL DB | Serverless database | 🔜 Coming soon |
What is a Binding?
When you configure a binding for your function, you grant it the capability to access Telnyx services. The binding handles authentication automatically — your API key is never exposed in your code or logs.
Your Function → Binding Proxy → Telnyx API
↓ ↓ ↓
Placeholder Resolves Actual API
API Key Credentials Call Made
When you deploy a function with an active binding:
- Your function receives a JWT credential as the
TELNYX_API_KEY environment variable
- Your function receives the binding proxy URL as
TELNYX_BASE_URL
- API calls made to
${TELNYX_BASE_URL}/v2/<api-path> are routed through the binding proxy, which authenticates with your real API key
- The API call proceeds with proper authentication
Important: You must construct API URLs using TELNYX_BASE_URL — do not call https://api.telnyx.com directly. Direct calls will return 401 because the binding-injected JWT is not a standard Telnyx API key.
// ✅ Correct — use TELNYX_BASE_URL from binding
const baseUrl = process.env.TELNYX_BASE_URL;
const response = await fetch(`${baseUrl}/v2/messages`, {
headers: { 'Authorization': `Bearer ${process.env.TELNYX_API_KEY}` }
});
// ❌ Wrong — direct calls to api.telnyx.com return 401 with binding JWT
const response = await fetch('https://api.telnyx.com/v2/messages', {
headers: { 'Authorization': `Bearer ${process.env.TELNYX_API_KEY}` }
});
Notice the /v2/ in the URL path: ${TELNYX_BASE_URL}/v2/messages. Even though TELNYX_BASE_URL already contains a /v2/ segment in its path (e.g. .../v2/compute/internal/binding-proxy), you must still include /v2/ between the proxy URL and the API endpoint path.
Benefits:
- API key never appears in function code
- API key never appears in logs
- Credentials can be rotated without code changes
Creating a Binding
One-time setup per organization:
# Create a binding for your organization
telnyx-edge bindings create
# Verify the binding works
telnyx-edge bindings validate
Managing Bindings
# View your current binding
telnyx-edge bindings get
# Validate the binding is working
telnyx-edge bindings validate
# Rotate binding credentials (recommended monthly)
telnyx-edge bindings update
# Remove the binding
telnyx-edge bindings delete
Using Bindings: Telnyx API
With a binding configured, use TELNYX_BASE_URL and TELNYX_API_KEY to make API calls through the binding proxy. The proxy handles authentication with your real API key.
JavaScript
Go
Python
Java
const http = require('http');
const BASE_URL = process.env.TELNYX_BASE_URL;
const API_KEY = process.env.TELNYX_API_KEY;
http.createServer(async (req, res) => {
if (req.url === '/health/liveness' || req.url === '/health/readiness') {
res.writeHead(200, { 'Content-Type': 'text/plain' });
return res.end('ok');
}
// Send a message via binding proxy
const response = await fetch(`${BASE_URL}/v2/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
from: '+12345678901',
to: '+12345678902',
text: 'Hello from Edge Compute!'
})
});
const data = await response.json();
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify(data));
}).listen(8080);
package main
import (
"fmt"
"github.com/telnyx/telnyx-go"
)
func main() {
// SDK automatically uses TELNYX_API_KEY and TELNYX_BASE_URL
client := telnyx.NewClient()
// Get account balance
balance, err := client.Balance.Get()
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
fmt.Printf("Balance: %s %s\n", balance.Balance, balance.Currency)
}
func sendMessage(to, from, text string) error {
client := telnyx.NewClient()
message, err := client.Messages.Create(&telnyx.MessageParams{
From: from,
To: to,
Text: text,
})
if err != nil {
return err
}
fmt.Printf("Message sent: %s\n", message.ID)
return nil
}
import telnyx
# SDK automatically uses TELNYX_API_KEY and TELNYX_BASE_URL
# No manual configuration needed!
def get_balance():
"""Retrieve account balance."""
balance = telnyx.Balance.retrieve()
return {
"balance": balance.balance,
"currency": balance.currency
}
def send_message(to_number, from_number, text):
"""Send an SMS using Telnyx SDK."""
message = telnyx.Message.create(
from_=from_number,
to=to_number,
text=text
)
return {"message_id": message.id, "status": message.status}
def make_call(to_number, from_number, webhook_url):
"""Initiate an outbound call."""
call = telnyx.Call.create(
to=to_number,
from_=from_number,
connection_id="your-connection-id",
webhook_url=webhook_url
)
return {"call_id": call.id}
import com.telnyx.sdk.ApiClient;
import com.telnyx.sdk.api.MessagesApi;
import com.telnyx.sdk.model.CreateMessageRequest;
@ApplicationScoped
public class MessageResource {
// SDK automatically uses TELNYX_API_KEY and TELNYX_BASE_URL
@Inject
ApiClient telnyxClient;
@POST
@Path("/send")
@Produces(MediaType.APPLICATION_JSON)
public Response sendMessage(MessageRequest req) {
MessagesApi api = new MessagesApi(telnyxClient);
CreateMessageRequest request = new CreateMessageRequest()
.from(req.getFrom())
.to(req.getTo())
.text(req.getText());
var message = api.createMessage(request);
return Response.ok(message).build();
}
}
Using Bindings: Cloud Storage
The binding-injected TELNYX_API_KEY (a JWT) does not work for S3-compatible Cloud Storage operations. The Cloud Storage endpoint (*.telnyxcloudstorage.com) requires AWS SigV4 authentication with a valid AWS access key — the binding JWT is not a valid AWS credential and will be rejected.For Cloud Storage operations (ListObjectsV2, GetObject, PutObject, etc.), store a regular Telnyx API key as a secret and use it as the S3 access key:telnyx-edge secrets add TELNYX_STORAGE_KEY YOUR_API_KEY
The binding proxy handles api.telnyx.com routes only. S3-compatible calls go directly to the storage endpoint.
Using Cloud Storage with a Secret
package main
import (
"os"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3"
)
func getStorageClient() *s3.S3 {
// Use a real API key stored as a secret, NOT the binding TELNYX_API_KEY
apiKey := os.Getenv("TELNYX_STORAGE_KEY") // set via: telnyx-edge secrets add
if apiKey == "" {
apiKey = os.Getenv("TELNYX_API_KEY") // fallback: only works with real API key, not binding JWT
}
sess := session.Must(session.NewSession(&aws.Config{
Endpoint: aws.String("https://us-east-1.telnyxcloudstorage.com"),
Region: aws.String("us-east-1"),
Credentials: credentials.NewStaticCredentials(
apiKey,
"", // Not required for Telnyx
"",
),
}))
return s3.New(sess)
}
func listObjects(bucket string) ([]string, error) {
client := getStorageClient()
result, err := client.ListObjectsV2(&s3.ListObjectsV2Input{
Bucket: aws.String(bucket),
})
if err != nil {
return nil, err
}
var keys []string
for _, obj := range result.Contents {
keys = append(keys, *obj.Key)
}
return keys, nil
}
import os
import boto3
def get_storage_client():
"""Create a Cloud Storage client using a stored API key secret."""
# Use a real API key stored as a secret, NOT the binding TELNYX_API_KEY
api_key = os.environ.get('TELNYX_STORAGE_KEY') # set via: telnyx-edge secrets add
if not api_key:
api_key = os.environ.get('TELNYX_API_KEY') # fallback: only works with real API key, not binding JWT
return boto3.client(
's3',
aws_access_key_id=api_key,
aws_secret_access_key='', # Not required for Telnyx
endpoint_url='https://us-east-1.telnyxcloudstorage.com'
)
def upload_file(bucket, key, data):
"""Upload a file to Cloud Storage."""
client = get_storage_client()
client.put_object(Bucket=bucket, Key=key, Body=data)
return {"uploaded": key}
def download_file(bucket, key):
"""Download a file from Cloud Storage."""
client = get_storage_client()
response = client.get_object(Bucket=bucket, Key=key)
return response['Body'].read()
def list_objects(bucket, prefix=''):
"""List objects in a bucket."""
client = get_storage_client()
response = client.list_objects_v2(Bucket=bucket, Prefix=prefix)
return [obj['Key'] for obj in response.get('Contents', [])]
The binding proxy handles api.telnyx.com routes (Voice, Messaging, etc.) only. For S3-compatible operations against the Cloud Storage endpoint, use a regular Telnyx API key stored via telnyx-edge secrets add.
Using Bindings: KV
🔜 Coming soon — KV bindings will allow key-value storage directly from edge functions.
Using Bindings: SQL DB
🔜 Coming soon — SQL DB bindings will provide serverless database access from edge functions.
Bindings vs Secrets
| Feature | Bindings | Secrets |
|---|
| Purpose | Telnyx service access | General sensitive data |
| Scope | One per organization | Unlimited per organization |
| Credentials | Auto-managed (JWT via proxy) | User-provided |
| Injection | TELNYX_API_KEY (JWT), TELNYX_BASE_URL (proxy URL) | Custom environment variables |
| Rotation | bindings update | Manual re-add |
| Use case | Telnyx SDK/API integration | Database passwords, external API keys |
Use bindings for Telnyx service access — credentials are managed automatically.
Use secrets for third-party services or when you need multiple different credentials.
Error Handling
import telnyx
from telnyx.error import TelnyxError, AuthenticationError, APIError
def safe_api_call():
try:
balance = telnyx.Balance.retrieve()
return {"balance": balance.balance}
except AuthenticationError as e:
# Binding issue - credentials invalid or expired
return {
"error": "Authentication failed",
"hint": "Try: telnyx-edge bindings update"
}
except APIError as e:
# API-level error
return {
"error": f"API error: {e.message}",
"code": e.code
}
except TelnyxError as e:
# General Telnyx error
return {"error": str(e)}
Troubleshooting
Binding not found
$ telnyx-edge bindings get
❌ No binding found
# Solution: Create a binding
$ telnyx-edge bindings create
Validation failed
$ telnyx-edge bindings validate
❌ Binding validation failed
# Solutions:
# 1. Update the binding
telnyx-edge bindings update
# 2. Check your Telnyx account status
# 3. Verify authentication
telnyx-edge auth status
Function can’t access Telnyx API
# Check binding exists
telnyx-edge bindings get
# Validate binding works
telnyx-edge bindings validate
# Redeploy function to get latest credentials
telnyx-edge ship