> ## 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.

# Session Storage

> Store user sessions at the edge with Telnyx KV and expire them using an application-level TTL.

Store user sessions at the edge and expire them after a day. This uses the [KV binding](/docs/edge-compute/kv/quick-start#path-a-the-function-binding) (bound as `MY_KV`). The binding's `expirationTtl` option is a no-op today, so this example enforces expiry in code with the `putWithExpiry`/`getWithExpiry` helpers from [Key Expiration](/docs/edge-compute/kv/ttl-and-metadata). (Server-side TTL is also available over REST via `ttl_secs`.)

```ts theme={null}
import { env } from "@telnyx/edge-runtime";

const SESSION_TTL = 86_400; // 24 hours

// Application-level expiry (see Key Expiration).
async function putWithExpiry(key: string, value: string, ttlSeconds: number) {
    await env.MY_KV.put(key, JSON.stringify({ value, expires_at: Date.now() + ttlSeconds * 1000 }));
}
async function getWithExpiry(key: string): Promise<string | null> {
    const w = await env.MY_KV.get<{ value: string; expires_at: number }>(key, { type: "json" });
    if (w === null) return null;
    if (Date.now() > w.expires_at) { await env.MY_KV.delete(key); return null; }
    return w.value;
}

export async function handler(request: Request): Promise<Response> {
    const sessionId = request.headers.get("X-Session-ID");
    if (!sessionId) {
        return new Response("Missing X-Session-ID", { status: 400 });
    }
    const key = `session/${sessionId}`;

    // Read session (null if missing or expired)
    const existing = await getWithExpiry(key);
    const data = existing
        ? { ...JSON.parse(existing), views: JSON.parse(existing).views + 1 }
        : { created: Date.now(), views: 0 };

    // Store with a 24h expiry
    await putWithExpiry(key, JSON.stringify(data), SESSION_TTL);

    return new Response(JSON.stringify(data), {
        headers: { "Content-Type": "application/json" },
    });
}
```

<Note>
  Non-TypeScript functions build the same expiry envelope on top of the raw `kvGet`/`kvPut` [REST helpers](/docs/edge-compute/kv/quick-start#path-b-the-rest-api) — or use the native `ttl_secs` REST parameter. See [Key Expiration](/docs/edge-compute/kv/ttl-and-metadata).
</Note>
