Skip to main content
Get up and running with KV by creating a namespace, binding it to your function, and reading/writing data.

1. Create a Namespace

telnyx-edge storage kv create --name my-cache
Namespace creation is asynchronous. Poll the namespace endpoint until status changes from pending to provision_ok.

2. Add to Your Function

Configure the binding in func.toml:
[edge_compute]
func_name = "my-function"

[storage.kv.MY_CACHE]
id = "kv-abc123"  # Storage resource ID from provisioning API

3. Access KV in Your Code

KV can be accessed via HTTP endpoints or SDK (coming soon). Currently, use HTTP requests to the storage API:
const KV_NAMESPACE_ID = process.env.KV_MY_CACHE_ID;
const API_KEY = process.env.TELNYX_API_KEY;

// UTF-8 safe base64 encoding/decoding (handles large payloads)
function toBase64(str) {
    const bytes = new TextEncoder().encode(str);
    let binary = '';
    for (let i = 0; i < bytes.length; i++) {
        binary += String.fromCharCode(bytes[i]);
    }
    return btoa(binary);
}
function fromBase64(b64) {
    const binary = atob(b64);
    const bytes = new Uint8Array(binary.length);
    for (let i = 0; i < binary.length; i++) {
        bytes[i] = binary.charCodeAt(i);
    }
    return new TextDecoder().decode(bytes);
}

async function kvGet(key) {
    const response = await fetch(
        `https://api.telnyx.com/v2/storage/kvs/${KV_NAMESPACE_ID}/keys/${encodeURIComponent(key)}`,
        { headers: { "Authorization": `Bearer ${API_KEY}` } }
    );
    if (response.status === 404) return null; // Key not found
    if (!response.ok) throw new Error(`KV error: ${response.status}`);
    const data = await response.json();
    return fromBase64(data.data.value);
}

async function kvPut(key, value) {
    const response = await fetch(
        `https://api.telnyx.com/v2/storage/kvs/${KV_NAMESPACE_ID}/keys/${encodeURIComponent(key)}`,
        {
            method: "PUT",
            headers: {
                "Authorization": `Bearer ${API_KEY}`,
                "Content-Type": "application/json"
            },
            body: JSON.stringify({ value: toBase64(value) })
        }
    );
    if (!response.ok) throw new Error(`KV write error: ${response.status}`);
}

export async function handler(request) {
    // Write a value (Unicode safe)
    await kvPut("user:123", JSON.stringify({ name: "Alice 👋" }));
    
    // Read a value
    const user = await kvGet("user:123");
    
    return new Response(user);
}
Native SDK support is coming soon. The SDK will follow the Telnyx client pattern:
import Telnyx from 'telnyx';
const client = new Telnyx({ apiKey: process.env.TELNYX_API_KEY });

// Get a value
const value = await client.storage.kvs.keys.get("kv-abc123", "user:123");

// Put a value with TTL
await client.storage.kvs.keys.put("kv-abc123", "user:123", {
  value: "data",
  expirationTtl: 3600,
  metadata: { type: "session" }
});
Currently, access KV via HTTP endpoints as shown above.

Best Practices

Key Naming

Use structured key names with prefixes:
user:123              # User data
session:abc           # Session data
cache:api:/users      # Cached API response
flag:new-feature      # Feature flag

Value Serialization

Always serialize complex values as JSON before base64 encoding:
// Write
const value = JSON.stringify({ name: "Alice", age: 30 });
await kvPut("user:123", value);

// Read
const user = JSON.parse(await kvGet("user:123"));

Error Handling

Handle missing keys gracefully:
const value = await kvGet("possibly-missing-key");
if (value === null) {
    // Key doesn't exist
    return new Response("Not found", { status: 404 });
}