# Telnyx Edge: Overview — Full Documentation > Complete page content for Overview (Edge section) of the Telnyx developer docs (https://developers.telnyx.com). > Root index: https://developers.telnyx.com/llms.txt · Lightweight index for this subsection: https://telnyx-openapi-ng.s3.us-east-1.amazonaws.com/llms/edge/overview.txt ## Overview ### Platform > Source: https://developers.telnyx.com/docs/edge-compute/platform-overview.md ## A Purpose-Built Infrastructure Your code runs on the same infrastructure that powers Telnyx voice, messaging, and AI services. We understand infrastructure because we built it — bare metal up. ### Low latency Real-time voice demands single-digit millisecond latency. That forced us to push infrastructure into carrier facilities as close to end users as possible. Your edge workloads inherit that same proximity — not generic cloud availability zones, but sites inside the networks your traffic already traverses. ### High redundancy Every region is backed by multiple independent sites hosted across different providers, with public cloud spillover for burst capacity. If a site goes down, traffic shifts automatically. No single facility, no single provider, no single point of failure. ### Full control We own the bare metal. We control the networking. No abstraction layers we can't see through, no shared tenancy we can't isolate, no vendor bottlenecks we can't route around. When something breaks at 3 AM, we're not filing a support ticket — we're on the hardware. --- ### Products > Source: https://developers.telnyx.com/docs/edge-compute/products.md --- ## Tutorials ### Tutorials > Source: https://developers.telnyx.com/docs/edge-compute/demos.md Learn by building real applications on Telnyx Edge. Each tutorial walks you through a complete project from start to deployment. ## Getting Started Create a JSON API with routing, validation, and error handling. **Time:** 15 min · **Level:** Beginner Process incoming SMS messages and send automated replies. **Time:** 20 min · **Level:** Beginner Route calls based on time of day and caller location. **Time:** 25 min · **Level:** Intermediate Resize and optimize images on-the-fly at the edge. **Time:** 20 min · **Level:** Intermediate --- ## More Tutorials Add JWT validation to protect your APIs. *Coming soon* Implement rate limiting with sliding windows. *Coming soon* Route traffic between variants for experiments. *Coming soon* Verify signatures from third-party services. *Coming soon* ## Related Resources - [Quickstart](/docs/edge-compute/quickstart) — Deploy your first function - [Examples](/docs/edge-compute/examples) — Code snippets and patterns - [CLI Reference](/docs/edge-compute/reference/cli) — Full command documentation --- ### Build a REST API > Source: https://developers.telnyx.com/docs/edge-compute/demos/build-a-rest-api.md Build a complete REST API with CRUD operations, input validation, and error handling. **What you'll learn:** - Routing requests to different handlers - Parsing JSON request bodies - Returning proper HTTP status codes - Error handling patterns ## Prerequisites - Telnyx account with Edge Compute enabled - `telnyx-edge` CLI installed ## Step 1: Create the Function ```bash telnyx-edge new-func -l=python -n=my-api cd my-api ``` ## Step 2: Implement the API Replace `src/main.py`: ```python import json from urllib.parse import urlparse, parse_qs # In-memory storage (use KV for persistence) items = {} next_id = 1 class Function: async def handler(self, request): path = urlparse(request.url).path method = request.method # Route requests if path == "/items" and method == "GET": return self.list_items() elif path == "/items" and method == "POST": return await self.create_item(request) elif path.startswith("/items/") and method == "GET": return self.get_item(path.split("/")[-1]) elif path.startswith("/items/") and method == "DELETE": return self.delete_item(path.split("/")[-1]) else: return self.json_response({"error": "Not found"}, 404) def list_items(self): return self.json_response(list(items.values())) async def create_item(self, request): global next_id try: body = json.loads(await request.text()) except json.JSONDecodeError: return self.json_response({"error": "Invalid JSON"}, 400) if "name" not in body: return self.json_response({"error": "name is required"}, 400) item = {"id": str(next_id), "name": body["name"]} items[str(next_id)] = item next_id += 1 return self.json_response(item, 201) def get_item(self, item_id): if item_id in items: return self.json_response(items[item_id]) return self.json_response({"error": "Not found"}, 404) def delete_item(self, item_id): if item_id in items: del items[item_id] return self.json_response({"deleted": True}) return self.json_response({"error": "Not found"}, 404) def json_response(self, data, status=200): return { "status": status, "headers": {"Content-Type": "application/json"}, "body": json.dumps(data) } ``` ## Step 3: Test Locally ```bash telnyx-edge dev ``` In another terminal: ```bash # Create an item curl -X POST http://localhost:8787/items \ -H "Content-Type: application/json" \ -d '{"name": "Test Item"}' # List items curl http://localhost:8787/items # Get single item curl http://localhost:8787/items/1 # Delete item curl -X DELETE http://localhost:8787/items/1 ``` ## Step 4: Deploy ```bash telnyx-edge ship ``` Your API is now live at `https://my-api-{orgId}.telnyxcompute.com`. --- ### SMS Webhook Handler > Source: https://developers.telnyx.com/docs/edge-compute/demos/sms-webhook-handler.md Process incoming SMS messages and respond automatically based on keywords. **What you'll learn:** - Handling Telnyx webhooks - Parsing SMS payloads - Sending SMS responses via Telnyx API ## Prerequisites - Telnyx account with a phone number - Phone number configured for SMS ## Step 1: Create the Function ```bash telnyx-edge new-func -l=javascript -n=sms-handler cd sms-handler ``` ## Step 2: Implement the Handler Replace `src/index.js`: ```javascript export async function handler(request) { // Verify this is a POST from Telnyx if (request.method !== "POST") { return new Response("Method not allowed", { status: 405 }); } const webhook = await request.json(); const event = webhook.data; // Handle incoming SMS if (event.event_type === "message.received") { const from = event.payload.from.phone_number; const text = event.payload.text.toLowerCase().trim(); // Keyword-based responses let reply; if (text === "help") { reply = "Commands: HOURS, LOCATION, STATUS"; } else if (text === "hours") { reply = "We're open Mon-Fri 9am-5pm EST"; } else if (text === "location") { reply = "123 Main St, New York, NY 10001"; } else if (text === "status") { reply = "All systems operational ✓"; } else { reply = `Thanks for your message! Reply HELP for options.`; } // Send reply via Telnyx API await sendSMS(from, reply); } return new Response(JSON.stringify({ received: true }), { headers: { "Content-Type": "application/json" } }); } async function sendSMS(to, text) { const response = await fetch("https://api.telnyx.com/v2/messages", { method: "POST", headers: { "Authorization": `Bearer ${process.env.TELNYX_API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ from: process.env.TELNYX_PHONE_NUMBER, to: to, text: text }) }); if (!response.ok) { console.error("Failed to send SMS:", await response.text()); } } ``` ## Step 3: Configure Secrets ```bash telnyx-edge secrets add TELNYX_API_KEY "your-api-key-from-portal" telnyx-edge secrets add TELNYX_PHONE_NUMBER "+15551234567" ``` Get your API key from the [Telnyx Portal](https://portal.telnyx.com) under **API Keys**. Use your Telnyx phone number in E.164 format. ## Step 4: Deploy and Configure Webhook ```bash telnyx-edge ship ``` In the Telnyx Portal: 1. Go to **Messaging → Phone Numbers** 2. Select your number 3. Set webhook URL to `https://sms-handler-{orgId}.telnyxcompute.com` ## Step 5: Test Send an SMS with "HELP" to your Telnyx number. You should receive the help menu. --- ### Voice Call Router > Source: https://developers.telnyx.com/docs/edge-compute/demos/voice-call-router.md Route incoming calls based on time of day, caller location, or custom logic. **What you'll learn:** - TeXML for call control - Time-based routing logic - Geographic routing ## Step 1: Create the Function ```bash telnyx-edge new-func -l=python -n=call-router cd call-router ``` ## Step 2: Add Dependencies Create `requirements.txt`: ```txt pytz>=2024.1 ``` ## Step 3: Implement Call Routing ```python from datetime import datetime import pytz class Function: async def handler(self, request): webhook = await request.json() caller = webhook.get("from", "") # Determine routing destination = self.get_destination(caller) # Generate TeXML response texml = f""" Please hold while we connect your call. {destination} We're sorry, no one is available. Please try again later. """ return { "status": 200, "headers": {"Content-Type": "application/xml"}, "body": texml } def get_destination(self, caller): # Time-based routing est = pytz.timezone("America/New_York") now = datetime.now(est) hour = now.hour # Business hours: 9am-5pm EST if 9 <= hour < 17: # Route to main office return "+15551234567" else: # Route to after-hours support return "+15559876543" # Geographic routing example: # if caller.startswith("+44"): # return "+441onal support" # return "+1 US support" ``` ## Step 4: Deploy ```bash telnyx-edge ship ``` Configure your Telnyx number to use this function as the TeXML webhook. --- ### Image Resizer > Source: https://developers.telnyx.com/docs/edge-compute/demos/image-resizer.md Resize and optimize images on-the-fly based on URL parameters. **What you'll learn:** - Processing binary data - Query parameter handling - Caching strategies ## Step 1: Create the Function ```bash telnyx-edge new-func -l=python -n=image-resizer cd image-resizer ``` ## Step 2: Add Dependencies Create or update `requirements.txt`: ```txt pillow>=10.0.0 httpx>=0.27.0 ``` ## Step 3: Implement the Resizer ```python from PIL import Image from io import BytesIO from urllib.parse import urlparse, parse_qs import base64 import httpx class Function: def __init__(self): self.client = httpx.AsyncClient() async def handler(self, request): params = parse_qs(urlparse(request.url).query) # Get parameters image_url = params.get("url", [None])[0] width = int(params.get("w", [0])[0]) or None height = int(params.get("h", [0])[0]) or None quality = int(params.get("q", [85])[0]) if not image_url: return {"status": 400, "body": "Missing url parameter"} # Fetch original image response = await self.client.get(image_url) if response.status_code != 200: return {"status": 404, "body": "Image not found"} # Process image img = Image.open(BytesIO(response.content)) # Resize if dimensions provided if width or height: if width and height: img = img.resize((width, height), Image.LANCZOS) elif width: ratio = width / img.width img = img.resize((width, int(img.height * ratio)), Image.LANCZOS) else: ratio = height / img.height img = img.resize((int(img.width * ratio), height), Image.LANCZOS) # Convert to bytes output = BytesIO() img.save(output, format="JPEG", quality=quality, optimize=True) return { "status": 200, "headers": { "Content-Type": "image/jpeg", "Cache-Control": "public, max-age=86400" }, "body": base64.b64encode(output.getvalue()).decode() } ``` ## Step 4: Deploy and Test ```bash telnyx-edge ship ``` Test with: ``` https://image-resizer-{orgId}.telnyxcompute.com/?url=https://example.com/photo.jpg&w=400&q=80 ``` --- ## Reference Architectures ### Reference Architectures > Source: https://developers.telnyx.com/docs/edge-compute/frameworks.md Reference architectures demonstrate how Edge Compute products work together to solve real-world problems. Each architecture includes a diagram, component breakdown, and sample implementation. ## Architectures Route API traffic globally with caching, auth, and rate limiting. Process voice, SMS, and messaging events in real-time. Transform and route media streams at the edge. Collect and process IoT sensor data globally. --- ## Related Resources - [Examples](/docs/edge-compute/examples) — Code snippets for common patterns - [Tutorials](/docs/edge-compute/demos) — Step-by-step guides - [Runtime](/docs/edge-compute/runtime) — Execution environment details --- ### Global API Gateway > Source: https://developers.telnyx.com/docs/edge-compute/frameworks/global-api-gateway.md A globally distributed API gateway that provides authentication, rate limiting, and caching for backend services. ## Architecture Diagram ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Client Requests │ └─────────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────────┐ │ Telnyx Edge (Global PoPs) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │ │ Auth │→ │Rate Limiter │→ │ Cache │→ │ Router │ │ │ │ Middleware │ │ │ │ Layer │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ │ └─────────────────────────────────────────────────────────────────────┘ │ ┌─────────────┼─────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Service │ │ Service │ │ Service │ │ A │ │ B │ │ C │ └──────────┘ └──────────┘ └──────────┘ ``` ## Components | Component | Product | Purpose | |-----------|---------|---------| | Edge Function | Edge Compute | Request processing, routing | | Rate Limiting | Edge KV | Distributed counters | | Caching | Edge KV | Response cache | | Auth | Secrets | JWT verification keys | ## Implementation ```python import os import jwt import json import hashlib from datetime import datetime from urllib.parse import urlparse, urlencode, parse_qs class APIGateway: def __init__(self): self.jwt_secret = os.getenv("JWT_SECRET") self.rate_limit = 100 # requests per minute async def handler(self, request): # 1. Authentication auth_result = self.authenticate(request) if auth_result["error"]: return self.json_response(auth_result, 401) user_id = auth_result["user_id"] # 2. Rate limiting if await self.is_rate_limited(user_id): return self.json_response( {"error": "Rate limit exceeded"}, 429, {"Retry-After": "60"} ) # 3. Cache check cache_key = self.cache_key(request) cached = await self.kv.get(cache_key) if cached: return self.json_response(json.loads(cached)) # 4. Route to backend response = await self.route_request(request) # 5. Cache response if response["status"] == 200: await self.kv.put(cache_key, json.dumps(response), ttl=300) return response def authenticate(self, request): auth_header = request.headers.get("Authorization", "") if not auth_header.startswith("Bearer "): return {"error": "Missing token", "user_id": None} token = auth_header[7:] try: payload = jwt.decode(token, self.jwt_secret, algorithms=["HS256"]) return {"error": None, "user_id": payload["sub"]} except jwt.InvalidTokenError: return {"error": "Invalid token", "user_id": None} async def is_rate_limited(self, user_id): key = f"rate:{user_id}:{datetime.utcnow().strftime('%Y%m%d%H%M')}" count = int(await self.kv.get(key) or 0) if count >= self.rate_limit: return True await self.kv.put(key, str(count + 1), ttl=60) return False def cache_key(self, request): # Generate cache key from method + path + query string return f"cache:{request.method}:{request.path}:{hashlib.md5(request.url.encode()).hexdigest()}" async def route_request(self, request): parsed = urlparse(request.url) path = parsed.path query = parsed.query # Preserve query string # Route based on path prefix if path.startswith("/api/users"): backend = "https://users-service.internal" elif path.startswith("/api/orders"): backend = "https://orders-service.internal" else: return self.json_response({"error": "Not found"}, 404) # Forward request with query string preserved upstream_url = f"{backend}{path}" if query: upstream_url = f"{upstream_url}?{query}" response = await fetch(upstream_url, { "method": request.method, "headers": request.headers, "body": await request.text() if request.method != "GET" else None }) return { "status": response.status, "headers": dict(response.headers), "body": await response.text() } ``` ## Use Cases - **Microservices gateway** — Unified entry point for distributed services - **Third-party API proxy** — Add auth and rate limiting to external APIs - **Multi-region deployment** — Route to nearest backend region --- ### Telecom Event Processor > Source: https://developers.telnyx.com/docs/edge-compute/frameworks/telecom-event-processor.md Process voice calls, SMS messages, and fax events in real-time with low latency. ## Architecture Diagram ``` ┌──────────────────────────────────────────────────────────────┐ │ Telnyx Network │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ Voice │ │ SMS │ │ Fax │ │ Number │ │ │ │ Calls │ │ Messages │ │ Events │ │ Lookup │ │ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ └────┬─────┘ │ └───────┼─────────────┼─────────────┼─────────────┼────────────┘ │ │ │ │ └─────────────┴──────┬──────┴─────────────┘ ▼ ┌──────────────────────────────┐ │ Edge Compute Function │ │ ┌─────────┐ ┌───────────┐ │ │ │ Webhook │→ │ Business │ │ │ │ Handler │ │ Logic │ │ │ └─────────┘ └───────────┘ │ └──────────────────────────────┘ │ ┌──────────────┼──────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ CRM │ │ Analytics│ │ Alerts │ │ System │ │ Platform │ │ Service │ └──────────┘ └──────────┘ └──────────┘ ``` ## Implementation ```javascript // Unified telecom event handler export async function handler(request) { const webhook = await request.json(); const eventType = webhook.data.event_type; // Route by event type switch (eventType) { case "call.initiated": case "call.answered": case "call.hangup": return handleVoiceEvent(webhook); case "message.received": case "message.sent": return handleSMSEvent(webhook); case "fax.received": return handleFaxEvent(webhook); case "fax.sent": return handleFaxEvent(webhook); default: console.log(`Unhandled event: ${eventType}`); return new Response("OK"); } } async function handleVoiceEvent(webhook) { const event = webhook.data; const callId = event.payload.call_control_id; // Log to analytics await fetch(process.env.ANALYTICS_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ type: "voice", event: event.event_type, call_id: callId, from: event.payload.from, to: event.payload.to, timestamp: event.occurred_at }) }); // Business logic if (event.event_type === "call.initiated") { // Check CRM for caller info const caller = await lookupCaller(event.payload.from); if (caller.vip) { // Route VIP to priority queue return generateTeXML(` Welcome back, ${caller.name}. Connecting you now. `); } } return new Response("OK"); } async function handleSMSEvent(webhook) { const event = webhook.data; if (event.event_type === "message.received") { const text = event.payload.text.toLowerCase(); const from = event.payload.from.phone_number; // Keyword detection (TCPA-compliant opt-out keywords) if (text.includes("stop") || text.includes("unsubscribe") || text.includes("cancel") || text.includes("quit")) { await updateOptOut(from, true); await sendSMS(from, "You have been unsubscribed. Reply START to resubscribe."); } else if (text.includes("help")) { await sendSMS(from, "Reply STOP to unsubscribe, START to resubscribe."); } else if (text.includes("start")) { await updateOptOut(from, false); await sendSMS(from, "You have been resubscribed."); } } return new Response("OK"); } async function handleFaxEvent(webhook) { const event = webhook.data; // Log fax event await fetch(process.env.ANALYTICS_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ type: "fax", event: event.event_type, fax_id: event.payload.fax_id, from: event.payload.from, to: event.payload.to, pages: event.payload.page_count, timestamp: event.occurred_at }) }); // Download and store fax if received if (event.event_type === "fax.received" && event.payload.media_url) { await storeFax(event.payload.fax_id, event.payload.media_url); } return new Response("OK"); } ``` ## Use Cases - **Contact center** — Route calls based on caller history - **SMS marketing** — Process opt-ins/outs in real-time - **Two-factor auth** — Generate and verify SMS codes --- ### Real-Time Media Pipeline > Source: https://developers.telnyx.com/docs/edge-compute/frameworks/real-time-media-pipeline.md Transform and route media streams for video, audio, and real-time communication. ## Architecture Diagram ``` ┌─────────────┐ ┌─────────────────────────────────────────┐ │ Media │ │ Telnyx Edge │ │ Source │─────▶│ ┌──────────┐ ┌──────────┐ ┌────────┐ │ │ (Camera) │ │ │ Ingest │→ │Transform │→ │ Route │ │ └─────────────┘ │ └──────────┘ └──────────┘ └────────┘ │ └─────────────────────────────────────────┘ │ ┌──────────────────┼──────────────────┐ ▼ ▼ ▼ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ Storage │ │ CDN │ │ LiveKit │ │ (S3) │ │ Delivery │ │ Stream │ └──────────┘ └──────────┘ └──────────┘ ``` ## Implementation ```python import asyncio from datetime import datetime class MediaPipeline: async def handler(self, request): content_type = request.headers.get("Content-Type", "") if "video" in content_type or "audio" in content_type: return await self.process_media(request) elif "application/json" in content_type: return await self.handle_control(request) else: return {"status": 400, "body": "Unsupported content type"} async def process_media(self, request): media_data = await request.bytes() stream_id = request.headers.get("X-Stream-ID") # Transform (e.g., transcode, watermark) processed = await self.transform(media_data) # Route to destinations await asyncio.gather( self.store_archive(stream_id, processed), self.push_to_cdn(stream_id, processed), self.forward_to_livekit(stream_id, processed) ) return {"status": 200, "body": "OK"} async def transform(self, media_data): # Apply transformations # - Resize/transcode # - Add watermark # - Extract thumbnails return media_data async def store_archive(self, stream_id, data): await self.s3.put_object( Bucket="media-archive", Key=f"{stream_id}/{datetime.utcnow().isoformat()}.webm", Body=data ) async def push_to_cdn(self, stream_id, data): await fetch(f"{self.cdn_ingest_url}/{stream_id}", { "method": "POST", "body": data }) async def forward_to_livekit(self, stream_id, data): # Forward to LiveKit SFU for real-time distribution await fetch(f"{self.livekit_url}/ingest/{stream_id}", { "method": "POST", "headers": {"Authorization": f"Bearer {self.livekit_token}"}, "body": data }) async def handle_control(self, request): # Handle control messages (start/stop stream, change settings) body = await request.json() action = body.get("action") stream_id = body.get("stream_id") if action == "start": # Initialize stream resources return {"status": 200, "body": {"stream_id": stream_id, "status": "started"}} elif action == "stop": # Clean up stream resources return {"status": 200, "body": {"stream_id": stream_id, "status": "stopped"}} else: return {"status": 400, "body": {"error": "Unknown action"}} ``` ## Use Cases - **Live streaming** — Ingest and distribute live video - **Video conferencing** — Real-time media processing - **Surveillance** — Edge processing for camera feeds --- ### IoT Data Ingestion > Source: https://developers.telnyx.com/docs/edge-compute/frameworks/iot-data-ingestion.md Collect sensor data from IoT devices globally with edge processing and aggregation. ## Architecture Diagram ``` ┌──────────────────────────────────────────────────────────────────┐ │ IoT Devices (Global) │ │ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ ┌───────┐ │ │ │Sensor │ │Sensor │ │Sensor │ │Sensor │ │Sensor │ │ │ │ A │ │ B │ │ C │ │ D │ │ E │ │ │ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ └───┬───┘ │ └──────┼──────────┼──────────┼──────────┼──────────┼───────────────┘ │ │ │ │ │ └──────────┴────┬─────┴──────────┴──────────┘ ▼ ┌──────────────────────────────┐ │ Telnyx Edge (Per-PoP) │ │ ┌─────────┐ ┌───────────┐ │ │ │Validate │→ │ Aggregate │ │ │ │ + Parse │ │ + Buffer │ │ │ └─────────┘ └───────────┘ │ └──────────────────────────────┘ │ ▼ ┌──────────────────────────────┐ │ Central Data Lake │ └──────────────────────────────┘ ``` ## Implementation ```javascript // IoT data ingestion with edge processing // Note: For production, use a persistent queue (e.g., Kafka, Redis) // to avoid data loss. This example shows the processing pattern. export async function handler(request) { // Parse sensor data const data = await request.json(); // Validate if (!isValidSensorData(data)) { return new Response(JSON.stringify({ error: "Invalid data" }), { status: 400 }); } // Enrich with edge metadata const enriched = { ...data, edge_pop: process.env.TELNYX_POP, received_at: Date.now(), device_id: request.headers.get("X-Device-ID") }; // Send directly to data lake (no in-memory buffering to avoid data loss) const response = await fetch(process.env.DATA_LAKE_URL, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ reading: enriched, edge_pop: process.env.TELNYX_POP }) }); if (!response.ok) { // Return error so client can retry return new Response(JSON.stringify({ error: "Failed to store" }), { status: 502 }); } return new Response(JSON.stringify({ received: true })); } function isValidSensorData(data) { return data.sensor_type && typeof data.value === "number" && data.timestamp; } ``` For high-volume ingestion with batching, use an external queue (Kafka, Redis Streams) to buffer data reliably. In-memory buffers in serverless functions risk data loss on cold starts or process recycling. ## Use Cases - **Fleet management** — Vehicle telemetry processing - **Smart buildings** — Sensor data aggregation - **Industrial IoT** — Edge preprocessing for manufacturing ---