# Telnyx Edge: Storage — Full Documentation > Complete page content for Storage (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.com/llms/edge/storage.txt ## Key-Value (KV) ### KV Quick Start > Source: https://developers.telnyx.com/docs/edge-compute/kv/quick-start.md Get up and running with KV by creating a namespace, binding it to your function, and reading/writing data. ## 1. Create a Namespace ```bash telnyx-edge storage kv create --name my-cache ``` ```bash curl -X POST https://api.telnyx.com/v2/storage/kvs \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"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`: ```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: ```javascript 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); } ``` ```go package main import ( "encoding/base64" "encoding/json" "fmt" "net/http" "net/url" "os" "strings" ) var ( kvNamespaceID = os.Getenv("KV_MY_CACHE_ID") apiKey = os.Getenv("TELNYX_API_KEY") ) func kvGet(key string) (string, error) { encodedKey := url.PathEscape(key) req, _ := http.NewRequest("GET", fmt.Sprintf("https://api.telnyx.com/v2/storage/kvs/%s/keys/%s", kvNamespaceID, encodedKey), nil) req.Header.Set("Authorization", "Bearer "+apiKey) resp, err := http.DefaultClient.Do(req) if err != nil { return "", err } defer resp.Body.Close() if resp.StatusCode == 404 { return "", nil // Key not found } if resp.StatusCode >= 400 { return "", fmt.Errorf("KV read error: %d", resp.StatusCode) } var result struct { Data struct { Value string `json:"value"` } `json:"data"` } json.NewDecoder(resp.Body).Decode(&result) decoded, _ := base64.StdEncoding.DecodeString(result.Data.Value) return string(decoded), nil } func kvPut(key, value string) error { encodedKey := url.PathEscape(key) encoded := base64.StdEncoding.EncodeToString([]byte(value)) body := fmt.Sprintf(`{"value":"%s"}`, encoded) req, _ := http.NewRequest("PUT", fmt.Sprintf("https://api.telnyx.com/v2/storage/kvs/%s/keys/%s", kvNamespaceID, encodedKey), strings.NewReader(body)) req.Header.Set("Authorization", "Bearer "+apiKey) req.Header.Set("Content-Type", "application/json") resp, err := http.DefaultClient.Do(req) if err != nil { return err } defer resp.Body.Close() if resp.StatusCode >= 400 { return fmt.Errorf("KV write error: %d", resp.StatusCode) } return nil } func handler(w http.ResponseWriter, r *http.Request) { kvPut("user:123", `{"name": "Alice 👋"}`) user, _ := kvGet("user:123") w.Header().Set("Content-Type", "application/json") fmt.Fprint(w, user) } ``` ```python import os import base64 from urllib.parse import quote import httpx KV_NAMESPACE_ID = os.getenv("KV_MY_CACHE_ID") API_KEY = os.getenv("TELNYX_API_KEY") BASE_URL = f"https://api.telnyx.com/v2/storage/kvs/{KV_NAMESPACE_ID}/keys" async def kv_get(key: str) -> str | None: async with httpx.AsyncClient() as client: response = await client.get( f"{BASE_URL}/{quote(key, safe='')}", headers={"Authorization": f"Bearer {API_KEY}"} ) if response.status_code == 404: return None # Key not found response.raise_for_status() # Raise on 401, 429, 5xx, etc. data = response.json() return base64.b64decode(data["data"]["value"]).decode() async def kv_put(key: str, value: str) -> None: async with httpx.AsyncClient() as client: response = await client.put( f"{BASE_URL}/{quote(key, safe='')}", headers={ "Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json" }, json={"value": base64.b64encode(value.encode()).decode()} ) response.raise_for_status() # Raise on non-2xx class Function: async def handler(self, request): await kv_put("user:123", '{"name": "Alice 👋"}') user = await kv_get("user:123") return {"body": user} ``` ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.regex.Matcher; import java.util.regex.Pattern; public class KVClient { private final String namespaceId = System.getenv("KV_MY_CACHE_ID"); private final String apiKey = System.getenv("TELNYX_API_KEY"); private final HttpClient client = HttpClient.newHttpClient(); /** * Encode key for use in URL path segment (RFC 3986). * Unlike URLEncoder, this encodes spaces as %20 not +. */ private static String encodePathSegment(String segment) { StringBuilder result = new StringBuilder(); for (byte b : segment.getBytes(StandardCharsets.UTF_8)) { char c = (char) (b & 0xFF); if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-' || c == '_' || c == '.' || c == '~') { result.append(c); } else { result.append(String.format("%%%02X", b)); } } return result.toString(); } /** * Get a value from KV. Returns null if key not found. */ public String get(String key) throws Exception { String encodedKey = encodePathSegment(key); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telnyx.com/v2/storage/kvs/" + namespaceId + "/keys/" + encodedKey)) .header("Authorization", "Bearer " + apiKey) .GET() .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 404) { return null; // Key not found } if (response.statusCode() != 200) { throw new RuntimeException("KV error: " + response.statusCode()); } String base64Value = parseValue(response.body()); return new String(Base64.getDecoder().decode(base64Value), StandardCharsets.UTF_8); } /** * Put a value to KV. Supports Unicode via UTF-8. */ public void put(String key, String value) throws Exception { String encodedKey = encodePathSegment(key); String encoded = Base64.getEncoder().encodeToString(value.getBytes(StandardCharsets.UTF_8)); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.telnyx.com/v2/storage/kvs/" + namespaceId + "/keys/" + encodedKey)) .header("Authorization", "Bearer " + apiKey) .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString("{\"value\":\"" + encoded + "\"}")) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() < 200 || response.statusCode() >= 300) { throw new RuntimeException("KV write error: " + response.statusCode()); } } // Extract "value" field from JSON response: {"data":{"value":"..."}} private String parseValue(String json) { Pattern pattern = Pattern.compile("\"value\"\\s*:\\s*\"([^\"]*)\""); Matcher matcher = pattern.matcher(json); if (matcher.find()) { return matcher.group(1); } throw new RuntimeException("Could not parse value from response: " + json); } } ``` Native SDK support is coming soon. The SDK will follow the Telnyx client pattern: ```javascript 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: ```javascript // 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: ```javascript const value = await kvGet("possibly-missing-key"); if (value === null) { // Key doesn't exist return new Response("Not found", { status: 404 }); } ``` --- ### KV API Reference > Source: https://developers.telnyx.com/docs/edge-compute/kv/api-reference.md Complete reference for the KV REST API. Base URL: `https://api.telnyx.com/v2/storage/kvs` ## Namespace Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/v2/storage/kvs` | Create a new namespace | | GET | `/v2/storage/kvs` | List all namespaces | | GET | `/v2/storage/kvs/{id}` | Get namespace details | | DELETE | `/v2/storage/kvs/{id}` | Delete a namespace | ## Key-Value Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | PUT | `/v2/storage/kvs/{id}/keys/{key}` | Write a value | | GET | `/v2/storage/kvs/{id}/keys/{key}` | Read a value | | DELETE | `/v2/storage/kvs/{id}/keys/{key}` | Delete a key | | GET | `/v2/storage/kvs/{id}/keys` | List keys | --- ## Namespace Operations ### Create Namespace ```bash curl -X POST https://api.telnyx.com/v2/storage/kvs \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name": "my-cache"}' ``` Response: ```json { "data": { "record_type": "storage_kv", "id": "550e8400-e29b-41d4-a716-446655440000", "name": "my-cache", "status": "pending", "created_at": "2024-01-15T10:30:00.000Z", "updated_at": "2024-01-15T10:30:00.000Z" } } ``` ### Namespace Status Poll the namespace until status is `provision_ok`: | Status | Description | |--------|-------------| | `pending` | Provisioning in progress | | `provision_ok` | Ready to use | | `provision_failed` | Provisioning failed | | `deleting` | Deletion in progress | | `delete_failed` | Deletion failed | | `deleted` | Fully removed (returns 404) | --- ## Key-Value Operations ### Write a Value Values must be base64-encoded: ```bash # Encode value VALUE=$(echo -n "Hello World" | base64) curl -X PUT "https://api.telnyx.com/v2/storage/kvs/{id}/keys/my-key" \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d "{\"value\": \"$VALUE\"}" ``` #### Write Options | Field | Type | Description | |-------|------|-------------| | `value` | string | Base64-encoded value (required) | | `expiration_ttl` | integer | Seconds until key expires (minimum: 60) | | `expiration` | integer | Unix timestamp when key expires | | `metadata` | object | JSON metadata to attach to key (max 1KB) | #### Write with TTL ```bash # Key expires in 1 hour (3600 seconds) curl -X PUT "https://api.telnyx.com/v2/storage/kvs/{id}/keys/session:abc" \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "eyJ1c2VyIjoiYWxpY2UifQ==", "expiration_ttl": 3600 }' ``` #### Write with Metadata ```bash curl -X PUT "https://api.telnyx.com/v2/storage/kvs/{id}/keys/user:123" \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "eyJuYW1lIjoiQWxpY2UifQ==", "metadata": { "type": "user", "created_by": "signup-flow", "version": 1 } }' ``` ### Read a Value ```bash curl "https://api.telnyx.com/v2/storage/kvs/{id}/keys/my-key" \ -H "Authorization: Bearer $TELNYX_API_KEY" ``` Response (value is base64-encoded): ```json { "data": { "key": "my-key", "value": "SGVsbG8gV29ybGQ=", "metadata": { "type": "user", "created_by": "signup-flow" }, "expiration": 1704067200 } } ``` `expiration` and `metadata` are only returned if they were set on the key. ### List Keys ```bash curl -g "https://api.telnyx.com/v2/storage/kvs/{id}/keys?prefix=user:&page[size]=100" \ -H "Authorization: Bearer $TELNYX_API_KEY" ``` The `-g` flag disables curl's glob parsing so square brackets in `page[size]` work correctly. Query parameters: - `prefix` — Filter keys by prefix - `page[number]` — Page number (default: 1) - `page[size]` — Results per page (default: 20, max: 250) --- ## Bindings Configuration Connect your function to a KV namespace using bindings in `func.toml`: ```toml [edge_compute] func_name = "my-function" [storage.kv.MY_CACHE] id = "550e8400-e29b-41d4-a716-446655440000" [storage.kv.SESSION_STORE] id = "660f9500-f39c-51e5-b817-557766551111" ``` The binding name (e.g., `MY_CACHE`) is injected as environment variables: - `KV_MY_CACHE_ID` — The namespace ID --- ### KV CLI > Source: https://developers.telnyx.com/docs/edge-compute/kv/cli.md Manage KV namespaces and keys using the `telnyx-edge` CLI. ## Namespace Management ```bash # List all namespaces telnyx-edge storage kv list # Create a namespace telnyx-edge storage kv create --name my-cache # Delete a namespace telnyx-edge storage kv delete ``` ## Key Operations ```bash # List keys in a namespace telnyx-edge storage kv key list # Get a value telnyx-edge storage kv key get # Put a value telnyx-edge storage kv key put "value" # Put a value with TTL (expires in 3600 seconds) telnyx-edge storage kv key put "value" --ttl 3600 # Put a value with metadata telnyx-edge storage kv key put "value" --metadata '{"type":"session"}' # Delete a key telnyx-edge storage kv key delete ``` --- ### KV TTL & Metadata > Source: https://developers.telnyx.com/docs/edge-compute/kv/ttl-and-metadata.md KV supports automatic key expiration (TTL) and metadata attachment for filtering and context. ## Key Expiration (TTL) KV supports automatic key expiration. Expired keys are automatically deleted and will return 404 on read. ### Setting Expiration Two ways to expire keys: | Option | Description | Example | |--------|-------------|---------| | `expiration_ttl` | Seconds from now until expiration (min: 60) | `3600` = 1 hour | | `expiration` | Unix timestamp when key expires | `1704067200` | ### CLI Example ```bash # Expire in 1 hour telnyx-edge storage kv key put session:abc "data" --ttl 3600 # Expire at specific time telnyx-edge storage kv key put promo:sale "data" --expiration 1704067200 ``` ### API Example ```bash curl -X PUT "https://api.telnyx.com/v2/storage/kvs/{id}/keys/session:abc" \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "c2Vzc2lvbiBkYXRh", "expiration_ttl": 3600 }' ``` ### Use Cases for TTL - **Sessions** — Expire after 24 hours of inactivity - **Cache** — Expire after 5 minutes to ensure freshness - **Rate limiting** — Expire counters after the rate limit window - **Temporary tokens** — Auto-cleanup verification codes Minimum TTL is 60 seconds. Keys with TTL less than 60 seconds will be rejected. --- ## Metadata Attach JSON metadata to keys for filtering, tagging, and context. Metadata is returned with the key on read. ### Setting Metadata ```bash curl -X PUT "https://api.telnyx.com/v2/storage/kvs/{id}/keys/user:123" \ -H "Authorization: Bearer $TELNYX_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": "eyJuYW1lIjoiQWxpY2UifQ==", "metadata": { "type": "user", "source": "signup", "version": 2 } }' ``` ### Reading Metadata Metadata is returned with the value: ```json { "data": { "key": "user:123", "value": "eyJuYW1lIjoiQWxpY2UifQ==", "metadata": { "type": "user", "source": "signup", "version": 2 } } } ``` ### Use Cases for Metadata - **Versioning** — Track schema versions for migrations - **Tagging** — Categorize keys by type, source, or owner - **Debugging** — Store creation context (who, when, why) - **Filtering** — Future: filter list operations by metadata Metadata must be valid JSON and cannot exceed 1KB when serialized. --- ### KV Use Cases > Source: https://developers.telnyx.com/docs/edge-compute/kv/use-cases.md Patterns for using KV in your edge functions. ## Session Storage with TTL Store user sessions at the edge with automatic expiration: ```javascript const SESSION_TTL = 86400; // 24 hours async function handler(request) { const sessionId = request.headers.get("X-Session-ID"); // Get session let session = await kvGet(`session:${sessionId}`); if (!session) { session = JSON.stringify({ created: Date.now(), views: 0 }); } else { const data = JSON.parse(session); data.views++; session = JSON.stringify(data); } // Update session with TTL (auto-expires in 24h) await kvPutWithTTL(`session:${sessionId}`, session, SESSION_TTL); return new Response(session); } // Helper: PUT with TTL async function kvPutWithTTL(key, value, ttl) { 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), expiration_ttl: ttl }) } ); if (!response.ok) { throw new Error(`KV write error: ${response.status}`); } } ``` ```python import os, base64, json, time, httpx from urllib.parse import quote SESSION_TTL = 86400 # 24 hours async def kv_put_with_ttl(key: str, value: str, ttl: int): async with httpx.AsyncClient() as client: await client.put( f"https://api.telnyx.com/v2/storage/kvs/{os.getenv('KV_NAMESPACE_ID')}/keys/{quote(key, safe='')}", headers={"Authorization": f"Bearer {os.getenv('TELNYX_API_KEY')}", "Content-Type": "application/json"}, json={"value": base64.b64encode(value.encode()).decode(), "expiration_ttl": ttl} ) async def handler(request): session_id = request.headers.get("X-Session-ID") session = await kv_get(f"session:{session_id}") if not session: session = json.dumps({"created": int(time.time()), "views": 0}) else: data = json.loads(session) data["views"] += 1 session = json.dumps(data) await kv_put_with_ttl(f"session:{session_id}", session, SESSION_TTL) return {"body": session} ``` ```go const sessionTTL = 86400 // 24 hours func handler(w http.ResponseWriter, r *http.Request) { sessionID := r.Header.Get("X-Session-ID") session, _ := kvGet(fmt.Sprintf("session:%s", sessionID)) var data map[string]interface{} if session == "" { data = map[string]interface{}{"created": time.Now().Unix(), "views": 0} } else { json.Unmarshal([]byte(session), &data) data["views"] = data["views"].(float64) + 1 } updated, _ := json.Marshal(data) kvPutWithTTL(fmt.Sprintf("session:%s", sessionID), string(updated), sessionTTL) w.Header().Set("Content-Type", "application/json") w.Write(updated) } ``` ## API Response Caching with TTL Cache expensive API responses with automatic expiration: ```javascript const CACHE_TTL = 300; // 5 minutes async function handler(request) { const cacheKey = `api:${new URL(request.url).pathname}`; // Check cache const cached = await kvGet(cacheKey); if (cached) { return new Response(cached, { headers: { "X-Cache": "HIT" } }); } // Fetch from origin const response = await fetch("https://api.example.com/data"); const data = await response.text(); // Cache with 5-minute TTL await kvPutWithTTL(cacheKey, data, CACHE_TTL); return new Response(data, { headers: { "X-Cache": "MISS" } }); } ``` ```python CACHE_TTL = 300 # 5 minutes async def handler(request): from urllib.parse import urlparse cache_key = f"api:{urlparse(request.url).path}" cached = await kv_get(cache_key) if cached: return {"body": cached, "headers": {"X-Cache": "HIT"}} async with httpx.AsyncClient() as client: resp = await client.get("https://api.example.com/data") data = resp.text await kv_put_with_ttl(cache_key, data, CACHE_TTL) return {"body": data, "headers": {"X-Cache": "MISS"}} ``` ```go const cacheTTL = 300 // 5 minutes func handler(w http.ResponseWriter, r *http.Request) { cacheKey := fmt.Sprintf("api:%s", r.URL.Path) cached, _ := kvGet(cacheKey) if cached != "" { w.Header().Set("X-Cache", "HIT") w.Write([]byte(cached)) return } resp, _ := http.Get("https://api.example.com/data") defer resp.Body.Close() data, _ := io.ReadAll(resp.Body) kvPutWithTTL(cacheKey, string(data), cacheTTL) w.Header().Set("X-Cache", "MISS") w.Write(data) } ``` ## Feature Flags Store and retrieve feature flags: ```javascript async function handler(request) { const newUIEnabled = await kvGet("feature:new-ui"); if (newUIEnabled === "true") { return serveNewUI(request); } return serveOldUI(request); } ``` ```python async def handler(request): enabled = await kv_get("feature:new-ui") if enabled == "true": return serve_new_ui(request) return serve_old_ui(request) ``` ```go func handler(w http.ResponseWriter, r *http.Request) { enabled, _ := kvGet("feature:new-ui") if enabled == "true" { serveNewUI(w, r) return } serveOldUI(w, r) } ``` --- ### KV Pricing > Source: https://developers.telnyx.com/docs/edge-compute/kv/pricing.md KV pricing is based on operations and storage. Egress is free. ## Pricing | Resource | Free Tier | Paid | |----------|-----------|------| | Reads | 10M/month | $0.35/million | | Writes | 1M/month | $3.50/million | | Deletes | 1M/month | $3.50/million | | Lists | 1M/month | $3.50/million | | Storage | 1 GB/month | $0.35/GB-month | Egress is free. No charges for data transferred out of KV. --- ## SQL Database ### SQL DB > Source: https://developers.telnyx.com/docs/edge-compute/sqldb.md **Coming Soon** — SQL DB is in development and will be available in a future release. SQL DB will be a serverless SQL database built for edge functions, providing SQLite-compatible queries with automatic replication. ## Related Resources - [KV](/docs/edge-compute/kv) — Key-value storage for caching - [Bindings](/docs/edge-compute/runtime/bindings) — Connect to storage services --- ## S3-Compatible Buckets ### Quick Start Guide > Source: https://developers.telnyx.com/docs/cloud-storage/quick-start.md There are four ways to get started on Telnyx cloud storage: - [Telnyx Mission Control Portal](https://portal.telnyx.com/#/storage/buckets) - AWS CLI - AWS SDK - S3 compatible [third party tools](https://support.telnyx.com/en/collections/3840515-telnyx-storage) ## Available Regions | Region | Endpoint | |--------|----------| | us-central-1 | us-central-1.telnyxcloudstorage.com | | us-east-1 | us-east-1.telnyxcloudstorage.com | | us-west-1 | us-west-1.telnyxcloudstorage.com | | eu-central-1 | eu-central-1.telnyxcloudstorage.com | Specify the region via the `--endpoint-url` flag in the AWS CLI or the equivalent SDK configuration. See [API Endpoints & Organization](/docs/cloud-storage/api-endpoints) for details on regional behavior. Some features are currently US-only, including presigned URLs, public buckets, and SSL certificates. See the [compatibility matrix](/docs/cloud-storage/supported) for full details. ## Option 1: Using Telnyx Mission Control Portal Follow [this support article](https://support.telnyx.com/en/articles/8344129-get-started-with-telnyx-storage-inference-guide). The Mission Control Portal is not the right tool to: Use the `aws s3 cp` CLI command or [multipart upload API](/docs/cloud-storage/multipart-upload) for more concurrency, better reliability, and bigger throughput. Use one of the S3 compatible [third party tools](https://support.telnyx.com/en/collections/3840515-telnyx-storage) when moving large object counts. ## Option 2: Using AWS CLI Follow the procedure [here](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html). Due to the latest AWS update, Telnyx Cloud Storage API is currently not compatible with CLI versions later than 2.22.35. - Inject your Telnyx [API key](https://portal.telnyx.com/#/api-keys) twice, once as access key and once as secret key. - Leave the region as blank; regionality is specified via `--endpoint-url` as shown subsequently. ```json user@localhost ~ % aws configure --profile mytelnyxprofile AWS Access Key ID [None]: XXX AWS Secret Access Key [None]: XXX Default region name [None]: Default output format [None]: json ``` Validate the profile has been created successfully. ```json user@localhost ~ % aws configure list-profiles mytelnyxprofile ``` Perform the following validation procedure to ensure everything is working as expected. **Create 2 buckets** Bucket names must be universally unique. Hence, `BucketAlreadyExists` error is expected on first attempt. ```json user@localhost ~ % aws s3api create-bucket --bucket demo-bucket --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com An error occurred (BucketAlreadyExists) when calling the CreateBucket operation: Unknown user@localhost ~ % aws s3api create-bucket --bucket demo-bucket-n1 --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com user@localhost ~ % aws s3api create-bucket --bucket demo-bucket-n2 --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com ``` **List buckets** Verify the buckets were created successfully. ```json user@localhost ~ % aws s3api list-buckets --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com { "Buckets": [ { "Name": "demo-bucket-n1", "CreationDate": "2024-07-26T17:31:14.888000+00:00" }, { "Name": "demo-bucket-n2", "CreationDate": "2024-07-26T17:31:25.225000+00:00" } ], "Owner": { "DisplayName": "XXX", "ID": "XXX" } } ``` **Add objects to a bucket** Upload some random objects. ```json user@localhost ~ % aws s3api put-object --key demo-obj-101 --body ~/Downloads/IMG_1752.mov --bucket demo-bucket-n1 --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com { "ETag": "\"bc864c2bc4549d72abadb0a5d44ee788\"" } user@localhost ~ % aws s3api put-object --key demo-obj-202 --body ~/Downloads/IMG_1753.mov --bucket demo-bucket-n1 --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com { "ETag": "\"bc864c2bc4549d72babdb0a5d44ee988\"" } ``` **List objects** Verify the objects were uploaded successfully. ```json user@localhost ~ % aws s3api list-objects-v2 --bucket demo-bucket-n1 --profile mytelnyxprofile --endpoint-url https://us-east-1.telnyxcloudstorage.com { "Contents": [ { "Key": "demo-obj-101", "LastModified": "2024-07-26T17:34:52.428000+00:00", "ETag": "\"bc864c2bc4549d72abadb0a5d44ee788\"", "Size": 136994934, "StorageClass": "STANDARD" }, { "Key": "demo-obj-202", "LastModified": "2024-07-26T17:36:31.799000+00:00", "ETag": "\"bc864c2bc4549d72babdb0a5d44ee988\"", "Size": 136994934, "StorageClass": "STANDARD" } ], "RequestCharged": null } ``` ## Option 3: AWS SDK Refer to this [collection of examples](/docs/cloud-storage/sdk/golang) ## Option 4: S3 compatible third party tools Many excellent tools exist to upload data at scale without any code. You can find the configuration guides [here](https://support.telnyx.com/en/collections/3840515-telnyx-storage). ## Read these documentations Some key differences exist between Telnyx cloud storage and AWS S3. It's advisable that they are reviewed and comprehended prior to Telnyx cloud storage is put into production. - Understand [API endpoints & organizations](/docs/cloud-storage/api-endpoints) - Review [supported API methods](/docs/cloud-storage/supported) - Heed the [warning on presigned URL](/docs/cloud-storage/presigned-urls) - Pay attention to [billing](/docs/cloud-storage/billing) - Know the [restrictions on policy and ACL](/docs/cloud-storage/public-buckets) ## Additional Resources - All available [AWS S3 CLI Commands](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/index.html) --- ### API Endpoints & Organization > Source: https://developers.telnyx.com/docs/cloud-storage/api-endpoints.md There exists two suites of Storage APIs: - S3 compatible, and - JSON companion ## S3 Compatible APIs This suite of APIs is compatible with AWS S3; as a result, minimal changes to existing integration are needed for migration to Telnyx. Endpoint URL Region us-central-1.telnyxcloudstorage.com us-central-1 us-east-1.telnyxcloudstorage.com us-east-1 us-west-1.telnyxcloudstorage.com us-west-1 eu-central-1.telnyxcloudstorage.com eu-central-1 Any US endpoint can be used for `ListBuckets` and `GetBucketLocation` across all US buckets, while the European endpoint (`eu-central-1`) will return only buckets located in Europe. However, all other API methods need to be directed at the regional endpoint that the bucket is homed. Otherwise an error will be returned. Hence, it is advisable to query the location of the bucket first before forming the correct regional endpoint for all subsequent API operations. Supported S3 APIs are documented in [this table](/docs/cloud-storage/supported). ## JSON Companion API This suite of APIs is an extension to the S3 API, accommodating the following functionalities: - [Querying usage](/docs/cloud-storage/billing) - [Create presigned URL](/docs/cloud-storage/presigned-urls) - [Manage SSL](/docs/cloud-storage/ssl-certificates) - [Migrating data from AWS S3](/docs/cloud-storage/migrating-from-aws) API endpoint to be used is `api.telnyx.com`. --- ### Authentication > Source: https://developers.telnyx.com/docs/cloud-storage/authentication.md API requests are authenticated with [API Keys](https://portal.telnyx.com/#/api-keys). Telnyx Storage requires passing an AWS Signature Version 4 authorization header in the API request. Telnyx Storage also requires that the Telnyx API key is substituted into the authorization header as the `access-key-id`. When an API request is made, Telnyx will parse the API key from the header, validate it, and then authorize the request. The remaining components of the authorization header (`date`, `aws-region`, `aws-service`, `secret-key`) are irrelevant to us. These values, as well as the generated signature from the secret key are all ignored. They only remain in the authorization header to maintain S3 compatibility. As long as you are passing an AWS Signature Version 4 authorization header, and the Telnyx API key is substituted into the header as the `access-key-id`, the request can be authenticated. An example is shown below, where `{{your_telnyx_api_key_here}}` is where you will substitute in your Telnyx API Key: ```bash Authorization: AWS4-HMAC-SHA256 Credential={{your_telnyx_api_key_here}}/20221129/us-east-1/s3/aws4_request, SignedHeaders=host;range;x-amz-date, Signature=d82d11938fe5edf39a778ec710ac79899bae1d9a46ae36607be30fb55f655a3c ``` After pasting the above content, remove any new line added. ## AWS CLI and S3 third party applications A general rule of thumb when trying to use Telnyx Storage with a third party application is: * `Access Key` → substitute in the Telnyx API token * `Secret Access Key` → either leave blank, or type something random in as a placeholder, or duplicate Telnyx API tokens --- ### Bucket Addressing > Source: https://developers.telnyx.com/docs/cloud-storage/bucket-addressing.md ## Path-style requests `https://[region].telnyxcloudstorage.com/[bucketname]/[objectname]` ## Virtual-hosted-style requests `https://[bucketname].[region].telnyxcloudstorage.com/[objectname]` --- ## Compatibility & Migration ### AWS S3 Compatibility > Source: https://developers.telnyx.com/docs/cloud-storage/aws-s3-compatibility.md [This table](/docs/cloud-storage/supported) documents all the supported S3 APIs. When an unsupported API method is invoked, an S3-compatible, XML-formated `NotImplemented` error response is returned. For the **_supported_** API methods documented, not all of the AWS S3 parameters, headers, and body XML elements are supported. ## AWS S3 PutObject For example, AWS S3 PutObject supports many headers. However, we only support what's documented under the [PutObject](https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/put-object/index#put-object) section. _They are unsupported by default unless otherwise explicitly specified._ ```json PUT /Key+ HTTP/1.1 Host: Bucket.s3.amazonaws.com x-amz-acl: ACL Cache-Control: CacheControl Content-Disposition: ContentDisposition Content-Encoding: ContentEncoding Content-Language: ContentLanguage Content-Length: ContentLength Content-MD5: ContentMD5 Content-Type: ContentType x-amz-sdk-checksum-algorithm: ChecksumAlgorithm x-amz-checksum-crc32: ChecksumCRC32 x-amz-checksum-crc32c: ChecksumCRC32C x-amz-checksum-sha1: ChecksumSHA1 x-amz-checksum-sha256: ChecksumSHA256 Expires: Expires x-amz-grant-full-control: GrantFullControl x-amz-grant-read: GrantRead x-amz-grant-read-acp: GrantReadACP x-amz-grant-write-acp: GrantWriteACP x-amz-server-side-encryption: ServerSideEncryption x-amz-storage-class: StorageClass x-amz-website-redirect-location: WebsiteRedirectLocation x-amz-server-side-encryption-customer-algorithm: SSECustomerAlgorithm x-amz-server-side-encryption-customer-key: SSECustomerKey x-amz-server-side-encryption-customer-key-MD5: SSECustomerKeyMD5 x-amz-server-side-encryption-aws-kms-key-id: SSEKMSKeyId x-amz-server-side-encryption-context: SSEKMSEncryptionContext x-amz-server-side-encryption-bucket-key-enabled: BucketKeyEnabled x-amz-request-payer: RequestPayer x-amz-tagging: Tagging x-amz-object-lock-mode: ObjectLockMode x-amz-object-lock-retain-until-date: ObjectLockRetainUntilDate x-amz-object-lock-legal-hold: ObjectLockLegalHoldStatus x-amz-expected-bucket-owner: ExpectedBucketOwner Body ``` --- ### Compatibility Matrix > Source: https://developers.telnyx.com/docs/cloud-storage/supported.md | API Data Type | API | Supported in US | Supported in EU | | --- | --- | --- | --- | | Bucket | CreateBucket | Yes | Yes | | Bucket | DeleteBucket | Yes | Yes | | Bucket | HeadBucket | Yes | Yes | | Bucket | ListBuckets | Yes | Yes | | BucketAccelerateConfiguration | GetBucketAccelerateConfiguration | No | No | | BucketAccelerateConfiguration | PutBucketAccelerateConfiguration | No | No | | BucketAcl | GetBucketAcl | Yes | No | | BucketAcl | PutBucketAcl | Yes | No | | BucketAnalyticsConfiguration | DeleteBucketAnalyticsConfiguration | No | No | | BucketAnalyticsConfiguration | GetBucketAnalyticsConfiguration | No | No | | BucketAnalyticsConfiguration | PutBucketAnalyticsConfiguration | No | No | | BucketAnalyticsConfigurations | ListBucketAnalyticsConfigurations | No | No | | BucketCors | DeleteBucketCors | Yes | No | | BucketCors | GetBucketCors | Yes | No | | BucketCors | PutBucketCors | Yes | No | | BucketEncryption | DeleteBucketEncryption | No | No | | BucketEncryption | GetBucketEncryption | No | No | | BucketEncryption | PutBucketEncryption | No | No | | BucketIntelligentTieringConfiguration | DeleteBucketIntelligentTieringConfiguration | No | No | | BucketIntelligentTieringConfiguration | GetBucketIntelligentTieringConfiguration | No | No | | BucketIntelligentTieringConfiguration | PutBucketIntelligentTieringConfiguration | No | No | | BucketIntelligentTieringConfigurations | ListBucketIntelligentTieringConfigurations | No | No | | BucketInventoryConfiguration | DeleteBucketInventoryConfiguration | No | No | | BucketInventoryConfiguration | GetBucketInventoryConfiguration | No | No | | BucketInventoryConfiguration | PutBucketInventoryConfiguration | No | No | | BucketInventoryConfigurations | ListBucketInventoryConfigurations | No | No | | BucketLifecycle | DeleteBucketLifecycle | Yes | No | | BucketLifecycle | GetBucketLifecycle | No | No | | BucketLifecycle | PutBucketLifecycle | No | No | | BucketLifecycleConfiguration | GetBucketLifecycleConfiguration | Yes | No | | BucketLifecycleConfiguration | PutBucketLifecycleConfiguration | Yes | No | | BucketLocation | GetBucketLocation | Yes | Yes | | BucketLogging | GetBucketLogging | No | No | | BucketLogging | PutBucketLogging | No | No | | BucketMetricsConfiguration | DeleteBucketMetricsConfiguration | No | No | | BucketMetricsConfiguration | GetBucketMetricsConfiguration | No | No | | BucketMetricsConfiguration | PutBucketMetricsConfiguration | No | No | | BucketMetricsConfigurations | ListBucketMetricsConfigurations | No | No | | BucketNotification | GetBucketNotification | No | No | | BucketNotification | PutBucketNotification | No | No | | BucketNotificationConfiguration | GetBucketNotificationConfiguration | No | No | | BucketNotificationConfiguration | PutBucketNotificationConfiguration | No | No | | BucketOwnershipControls | DeleteBucketOwnershipControls | No | No | | BucketOwnershipControls | GetBucketOwnershipControls | No | No | | BucketOwnershipControls | PutBucketOwnershipControls | No | No | | BucketPolicy | DeleteBucketPolicy | Yes | No | | BucketPolicy | GetBucketPolicy | Yes | No | | BucketPolicy | PutBucketPolicy | Yes | No | | BucketPolicyStatus | GetBucketPolicyStatus | Yes | No | | BucketReplication | DeleteBucketReplication | No | No | | BucketReplication | GetBucketReplication | No | No | | BucketReplication | PutBucketReplication | No | No | | BucketRequestPayment | GetBucketRequestPayment | No | No | | BucketRequestPayment | PutBucketRequestPayment | No | No | | BucketTagging | DeleteBucketTagging | Yes | No | | BucketTagging | GetBucketTagging | Yes | No | | BucketTagging | PutBucketTagging | Yes | No | | BucketVersioning | GetBucketVersioning | Yes | No | | BucketVersioning | PutBucketVersioning | Yes | No | | BucketWebsite | DeleteBucketWebsite | No | No | | BucketWebsite | GetBucketWebsite | No | No | | BucketWebsite | PutBucketWebsite | No | No | | Multipart | AbortMultipartUpload | Yes | No | | Multipart | CompleteMultipartUpload | Yes | No | | Multipart | CreateMultipartUpload | Yes | No | | Multipart | ListMultipartUploads | Yes | No | | Multipart | ListParts | Yes | No | | Multipart | UploadPart | Yes | No | | Multipart | UploadPartCopy | No | No | | Object | CopyObject | No | No | | Object | DeleteObject | Yes | Yes | | Object | DeleteObjects | Yes | Yes | | Object | GetObject | Yes | Yes | | Object | HeadObject | Yes | Yes | | Object | ListObjects | Yes | Yes | | Object | ListObjectsV2 | Yes | Yes | | Object | ListObjectVersions | Yes | No | | Object | PutObject | Yes | Yes | | Object | RestoreObject | No | No | | Object | WriteGetObjectResponse | No | No | | ObjectAcl | GetObjectAcl | Yes | No | | ObjectAcl | PutObjectAcl | Yes | No | | ObjectAttributes | GetObjectAttributes | No | No | | ObjectContent | SelectObjectContent | No | No | | ObjectLegalHold | GetObjectLegalHold | No | No | | ObjectLegalHold | PutObjectLegalHold | No | No | | ObjectLockConfiguration | GetObjectLockConfiguration | No | No | | ObjectLockConfiguration | PutObjectLockConfiguration | No | No | | ObjectRetention | GetObjectRetention | No | No | | ObjectRetention | PutObjectRetention | No | No | | ObjectTagging | DeleteObjectTagging | Yes | No | | ObjectTagging | GetObjectTagging | Yes | No | | ObjectTagging | PutObjectTagging | Yes | No | | ObjectTorrent | GetObjectTorrent | No | No | | PublicAccessBlock | DeletePublicAccessBlock | No | No | | PublicAccessBlock | GetPublicAccessBlock | No | No | | PublicAccessBlock | PutPublicAccessBlock | No | No | --- ### Migration from AWS S3 > Source: https://developers.telnyx.com/docs/cloud-storage/migrating-from-aws.md The [migration API](/api-reference/data-migration/create-a-migration) moves all data from a source AWS S3 bucket to a destination Telnyx Storage bucket without the user incurring a data egress charge by AWS. This is currently supported only for buckets located in the US. ## Feature The owner of the AWS account does not get charged by AWS on data transfer to Telnyx when this API is employed. ## Achieving minimal costs There are 3 components to this data pipeline: User’s AWS S3 bucket in AWS Region X. Telnyx’s migration engine in the same AWS Region X. Telnyx’s direct connects with AWS used to transfer the data. Cost minimization is achieved via the following billing practices by AWS. Intra-region data transfer between S3 and EC2, within the same account, or across different accounts, is free of charge. ![Intra-region-Data-Transfer-1](/img/cloudstorage-migration-api-1.png "Cloudstorage Migration API 1") Source: [AWS S3 Pricing](https://aws.amazon.com/s3/pricing/?nc=sn&loc=4) ![Intra-region-Data-Transfer-2](/img/cloudstorage-migration-api-2.png "Cloudstorage Migration API 2") Source: [AWS S3 FAQ](https://aws.amazon.com/s3/faqs/?nc=sn&loc=7) Hence, depending on the region of the source AWS S3 bucket, the API will select the co-located migration engines to best take advantage of this billing practice. Data Transfer Out (DTO) over AWS Direct Connect within the same geopolitical region is heavily discounted in comparison to DTO over the internet. ![Intra-region-Data-Transfer-3](/img/cloudstorage-migration-api-3.png "Cloudstorage Migration API 3") Source: [AWS Direct Connect](https://aws.amazon.com/directconnect/pricing/?nc=sn&loc=3) Telnyx’s infrastructure is multi-cloud and multi-region with PoPs in multiple geopolitical regions. AWS Direct Connect is one of the components of that architecture. As a result, the migration API takes advantage of the discounted rate of DTO within the same geopolitical region to move data off AWS into Telnyx. ## AWS S3 vs Telnyx Storage Costs Revisited Assume a user has the following pattern in us-east-2 Ohio. ![Intra-region-Data-Transfer-4](/img/cloudstorage-migration-api-4.png "Cloudstorage Migration API 4") Ignoring API operations since those costs are marginal, this is their costs breakdown. In the Appendix, you can see these costs are corroborated by AWS Cost Calculator. ![Intra-region-Data-Transfer-5](/img/cloudstorage-migration-api-5.png "Cloudstorage Migration API 5") With the migration API, data can be moved to Telnyx without egress charge from AWS. The post migration costs are as follows. ![Intra-region-Data-Transfer-6](/img/cloudstorage-migration-api-6.png "Cloudstorage Migration API 6") We are offering this API free of charge to users in its beta stage. In the future, we will require minimum storage duration to offset the costs we incur with AWS for DTO over Direct Connect. ## API Concepts and Procedure ### Coverage This API shows you the supported AWS S3 regions. Prior to using the API for migration, ensure the AWS S3 bucket you want to migrate is among the supported regions. ```bash curl --location 'https://api.telnyx.com/v2/storage/migration_source_coverage' \ --header 'Authorization: Bearer XXX' { "data": [ { "provider": "aws", "source_region": "us-west-1" }, { "provider": "aws", "source_region": "us-east-1" }, { "provider": "aws", "source_region": "us-east-2" } ] } ``` ### Migration Sources Only standard class is supported. Restore data in glacier before attempting migration. This API allows you to define the source bucket in AWS. In order to use this API, you need to provide it with a pair of AWS access key and secret access key. We advise you to create an IAM role with a Read Only user for this purpose. ```bash curl --location ‘https://api.telnyx.com/v2/storage/migration_sources’ \ --header ‘Content-Type: application/json’ \ --header ‘Authorization: Bearer XXX’ \ --data ‘{ “provider”: “aws”, “provider_auth”: { “access_key”: “XXX”, “secret_access_key”: “XXX” }, “bucket_name”: “source-west-bucket-demo” }’ { “data”: { “id”: “48f215e7-8f16-4e65-aa31-9340d4a18745”, “provider”: “aws”, “provider_auth”: { “access_key”: “XXX”, “secret_access_key”: “XXXXXX” }, “bucket_name”: “source-west-bucket-demo”, “source_region”: “us-west-1" } } ``` The following errors might be possible — ```json { "errors": [ { "code": "15005", "title": "Bucket does not exist", "detail": "Bucket does not exist." } ] } ``` ```json { "errors": [ { "code": "15025", "title": "Access denied", "detail": "Access denied reading migration source bucket." } ] } ``` ```json { "errors": [ { "code": "15003", "title": "Bucket region invalid", "detail": "You have provided an invalid bucket region." } ] } ``` ### Migrations Lastly, you can create a migration. If the target bucket doesn’t exist, the API will attempt to create it for you. If the desired bucket name is not available or invalid, you will receive an error right away. In addition, you do not have to match source bucket region to target bucket region; in other words, you can migrate data from an AWS source bucket in us-west-1 to Telnyx target bucket in us-east-1. You will not be charged for DTO by AWS as the API will use a migration engine in us-west-1. When the refresh parameter is set to false, a one time migration will be created. Otherwise, the API will periodically synchronize the source and destination bucket. ```bash curl --location 'https://api.telnyx.com/v2/storage/migrations' \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer XXX' \ --data '{ "source_id": "1c73c8d9-d65a-4f61-ab41-afa095324c5d", "target_bucket_name": "target-bucket-test-account", "target_region": "us-west-1", "refresh": false }' { "data": { "id": "04532400-7d40-4862-8437-17937d48b405", "source_id": "1c73c8d9-d65a-4f61-ab41-afa095324c5d", "target_bucket_name": "target-bucket-test-account", "target_region": "us-west-1", "refresh": false, "last_copy": "0001-01-01T00:00:00Z", "status": "pending", "bytes_to_migrate": 0, "bytes_migrated": 0, "speed": 0, "eta": "2024-05-10T20:47:33.821604511Z", "created_at": "2024-05-10T20:47:33.756241Z" } } ``` ### Checking Migration Progress You can periodically poll the API to see its status. ```bash curl --location 'https://api.telnyx.com/v2/storage/migrations/04532400-7d40-4862-8437-17937d48b405' \ --header 'Authorization: Bearer XXX' { "data": { "id": "04532400-7d40-4862-8437-17937d48b405", "source_id": "1c73c8d9-d65a-4f61-ab41-afa095324c5d", "target_bucket_name": "target-bucket-test-account", "target_region": "us-west-1", "refresh": false, "last_copy": "2024-05-10T21:07:27.43006Z", "status": "complete", "bytes_to_migrate": 10485760000, "bytes_migrated": 10485760000, "speed": 7226700, "eta": "0001-01-01T00:00:00Z", "created_at": "2024-05-10T20:47:33.756241Z" } } ``` Alternatively, check in on the metric of the target bucket. When it’s reached the expected size or all the objects appear in there, the migration is complete. ![Intra-region-Data-Transfer-7](/img/cloudstorage-migration-api-7.png "Cloudstorage Migration API 7") --- ### Third Party Applications > Source: https://developers.telnyx.com/docs/cloud-storage/third-party.md All S3 third-party tools, applications, clients, and libraries can be used to interact with Telnyx Cloud Storage. This includes popular applications like Cyberduck, S3 Browser, Wal-G, and many others. Visit our support page to find configuration guides for many of these commonly used third-party tools. If you don't see a guide for a particular application, please don't hesitate to reach out to us through our contact page. We would be happy to create a configuration guide for you. --- ## SDK Examples ### Node.js > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/node.md **For AWS SDK v3, make sure you set all checksum calculation and validation options to `WHEN_REQUIRED`.** The following example shows how the AWS Node.js SDK can be used to interact with Telnyx Cloud Storage. ```javascript const { S3Client, CreateBucketCommand, PutObjectCommand, ListObjectsCommand, GetObjectCommand } = require("@aws-sdk/client-s3"); const axios = require("axios"); const { v4: uuidv4 } = require("uuid"); const telnyxApiKey = process.env.TELNYX_API_KEY; if (!telnyxApiKey) { console.error("TELNYX_API_KEY environment variable not set"); process.exit(1); } const endpointUrl = "https://us-central-1.telnyxcloudstorage.com"; // 1. Initialize the AWS S3 client with specific options const s3Client = new S3Client({ endpoint: endpointUrl, region: "us-central-1", credentials: { accessKeyId: telnyxApiKey, secretAccessKey: telnyxApiKey }, forcePathStyle: true, requestChecksumCalculation: 'WHEN_REQUIRED', requestChecksumValidation: 'WHEN_REQUIRED', responseChecksumCalculation: 'WHEN_REQUIRED', responseChecksumValidation: 'WHEN_REQUIRED' }); (async () => { // 2. Create a bucket const bucketName = `my-test-bucket-${uuidv4()}`; await s3Client.send(new CreateBucketCommand({ Bucket: bucketName })); // 3. Upload two objects with random data for (let i = 0; i < 2; i++) { const name = `my-test-object-${i}`; const body = `Telnyx Cloud Storage ${i}`; await s3Client.send(new PutObjectCommand({ Bucket: bucketName, Key: name, Body: body })); } // 4. List objects in the bucket const listResult = await s3Client.send(new ListObjectsCommand({ Bucket: bucketName })); (listResult.Contents || []).forEach(obj => { console.log(obj.Key); }); // 5. Download the first object const getResult = await s3Client.send(new GetObjectCommand({ Bucket: bucketName, Key: "my-test-object-0" })); const streamToString = (stream) => new Promise((resolve, reject) => { const chunks = []; stream.on("data", (chunk) => chunks.push(chunk)); stream.on("error", reject); stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8"))); }); console.log(await streamToString(getResult.Body)); // 6. Create a presigned URL for the first file const presignResponse = await axios.post( `https://api.telnyx.com/v2/storage/buckets/${bucketName}/my-test-object-0/presigned_url`, { TTL: 30 }, { headers: { Authorization: `Bearer ${telnyxApiKey}` } } ); console.log(presignResponse.data); // 7. Download the file using the presigned URL const fileResponse = await axios.get(presignResponse.data.data.presigned_url); console.log(fileResponse.data); })(); ``` --- ### Python > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/python.md **For versions 1.36+, make sure you disable checksum calculation and verification.** The following example shows how AWS Python SDK can be used to interact with Telnyx Cloud Storage. ```python import requests import uuid import os from botocore.config import Config import boto3 # Only perform CRC checks `when_required` config = Config( request_checksum_calculation="when_required", response_checksum_validation="when_required", ) telnyx_api_key = os.getenv("TELNYX_API_KEY") if not telnyx_api_key: print("TELNYX_API_KEY environment variable not set") exit(1) # 1. Initialize the AWS client with specific options client = boto3.client( "s3", endpoint_url="https://us-central-1.telnyxcloudstorage.com", aws_access_key_id=telnyx_api_key, aws_secret_access_key=telnyx_api_key, config=config ) # 2. Create a bucket bucket_name = f"my-test-bucket-{uuid.uuid4()}" client.create_bucket(Bucket=bucket_name) # 3. Upload two objects with random data for i in range(2): name = f"my-test-object-{i}" body = f"Telnyx Cloud Storage {i}" client.put_object(Bucket=bucket_name, Key=name, Body=body) # 4. List objects in the bucket for obj in client.list_objects(Bucket=bucket_name)["Contents"]: print(obj["Key"]) # 5. Download the first object result = client.get_object(Bucket=bucket_name, Key="my-test-object-0") print(result["Body"].read()) # 6. Create a presigned URL for the first file response = requests.post( f"https://api.telnyx.com/v2/storage/buckets/{bucket_name}/my-test-object-0/presigned_url", json={"TTL": 30}, headers={"Authorization": f"Bearer {telnyx_api_key}"}, ) body = response.json() print(body) # 7. Download the file using the presigned URL response = requests.get(body["data"]["presigned_url"]) print(response.text) ``` --- ### Java > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/java.md **For versions 2.30+, make sure you disable checksum calculation and verification.** The following example shows how AWS Java SDK can be used to interact with Telnyx Cloud Storage. ## Add Dependency ``` software.amazon.awssdk s3 2.20.0 ``` ## Create S3 Bucket ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.CreateBucketRequest; public class CreateBucket { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "-- api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) // Only perform CRC checks `when_required` .requestChecksumCalculation(RequestChecksumCalculation.WHEN_REQUIRED) .responseChecksumValidation(ResponseChecksumValidation.WHEN_REQUIRED) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // create bucket CreateBucketRequest createBucketRequest = CreateBucketRequest.builder() .bucket(bucketName) .build(); s3.createBucket(createBucketRequest); System.out.println("Bucket created successfully: " + bucketName); // Close the S3 client s3.close(); } } ``` ## Upload an Object ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import java.net.URI; import java.nio.file.Paths; public class UploadObjectToS3 { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; String keyName = "your-object-key"; String filePath = "--path to file for upload--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // upload object PutObjectRequest putObjectRequest = PutObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); // Upload the file to S3 s3.putObject(putObjectRequest, RequestBody.fromFile(Paths.get(filePath))); // Close the S3 client s3.close(); } } ``` ## List Objects ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.ListObjectsV2Request; import software.amazon.awssdk.services.s3.model.ListObjectsV2Response; import software.amazon.awssdk.services.s3.model.S3Object; import java.net.URI; public class ListObjects { public static void main(String[] args) { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; // Create an S3 client S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // Create a ListObjectsV2Request ListObjectsV2Request listObjectsRequest = ListObjectsV2Request.builder() .bucket(bucketName) .build(); // Get the list of objects in the bucket ListObjectsV2Response listObjectsResponse = s3.listObjectsV2(listObjectsRequest); for (S3Object s3Object : listObjectsResponse.contents()) { System.out.println( s3Object.key()); } // Close the S3 client s3.close(); } } ``` ## Download Object ``` import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; public class DownloadObject { public static void main(String[] args) throws IOException { String bucketName = "--your-bucket-name--"; Region region = Region.US_EAST_1; String telnyxUrl = "https://us-central-1.telnyxcloudstorage.com"; String telnyxApiKey = "--your api key --"; String keyName = "your-object-key"; S3Client s3 = S3Client.builder() .region(region) .endpointOverride(URI.create(telnyxUrl)) .credentialsProvider( StaticCredentialsProvider.create(AwsBasicCredentials.create(telnyxApiKey, "does not matter"))) .build(); // Create a GetObjectRequest GetObjectRequest getObjectRequest = GetObjectRequest.builder() .bucket(bucketName) .key(keyName) .build(); // Download the object and transform the response to a byte array ResponseBytes objectBytes = s3.getObject(getObjectRequest, ResponseTransformer.toBytes()); // Write the file to the specified path File downloadedFile = new File("-- path to where to save the file --"); try (FileOutputStream fos = new FileOutputStream(downloadedFile)) { fos.write(objectBytes.asByteArray()); System.out.println("File downloaded successfully to -- path to where to save the file --"); } // Close the S3 client s3.close(); } } ``` ## Generate Presigned URLs for Upload and Download In order for this part to work, we will need to add json decoding library and http client. Any libraries will do, but for this example we picked: gson and okhttp3. ``` com.squareup.okhttp3 okhttp 4.9.2 com.google.code.gson gson 2.8.7 ``` ``` import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import okhttp3.*; import java.io.IOException; import java.util.Map; public class GeneratePresignedURLAndDownloadObject { public static void main(String[] args) throws IOException { OkHttpClient httpClient = new OkHttpClient(); Gson gson = new Gson(); String presignedUrlRequestJson = gson.toJson(Map.of("TTL", 30)); RequestBody presignedUrlRequestBody = RequestBody.create(MediaType.parse("application/json"), presignedUrlRequestJson); Request presignedUrlRequest = new Request.Builder() .url("https://api.telnyx.com/v2/storage/buckets/-- name of the bucket --/--name of the object--/presigned_url") .header("Authorization", "Bearer --your api key---") .post(presignedUrlRequestBody) .build(); try (Response response = httpClient.newCall(presignedUrlRequest).execute()) { if (!response.isSuccessful()) { throw new IOException("Failed to create presigned URL: " + response); } String responseBody = response.body().string(); Map responseBodyMap = gson.fromJson(responseBody, new TypeToken>() {}.getType()); String presignedUrl = ((Map) responseBodyMap.get("data")).get("presigned_url"); System.out.println("Presigned URL: " + presignedUrl); // 6. Download the file using the presigned URL Request downloadRequest = new Request.Builder() .url(presignedUrl) .build(); try (Response downloadResponse = httpClient.newCall(downloadRequest).execute()) { if (!downloadResponse.isSuccessful()) { throw new IOException("Failed to download file using presigned URL: " + downloadResponse); } System.out.println("Downloaded via presigned URL: " + downloadResponse.body().string()); } } } } ``` --- ### Go > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/golang.md The following example shows how AWS Golang SDK can be used to interact with Telnyx Cloud Storage. ``` package main import ( "bytes" "context" crand "crypto/rand" "encoding/json" "fmt" "io" "log" "math/rand" "net/http" "os" "time" "github.com/aws/aws-sdk-go-v2/aws" "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/s3" ) func main() { ctx := context.Background() randSeq := rand.Intn(1_000_000) telnyxAPIKey := os.Getenv("TELNYX_API_KEY") if telnyxAPIKey == "" { log.Fatal("TELNYX_API_KEY environment variable not set") } region := "us-central-1" endpoint := fmt.Sprintf("https://%s.telnyxcloudstorage.com", region) // 1. Initializing the AWS client with specific options cfg, err := config.LoadDefaultConfig(ctx, config.WithRegion(region), config.WithCredentialsProvider(aws.CredentialsProviderFunc( func(context.Context) (aws.Credentials, error) { return aws.Credentials{ AccessKeyID: telnyxAPIKey, // Use your Telnyx API key SecretAccessKey: telnyxAPIKey, // Optional, can be left blank }, nil })), config.WithS3UseARNRegion(true), config.WithS3DisableExpressAuth(true), config.WithS3DisableMultiRegionAccessPoints(true), ) if err != nil { log.Fatalf("s3 configuration error: %v", err) } cfg.BaseEndpoint = aws.String(endpoint) s3Client := s3.NewFromConfig(cfg) log.Printf("Created S3 client for region (%v) and endpoint (%v)", cfg.Region, *cfg.BaseEndpoint) // test-bucket-us-central-1.23-34.randomNumber ts := time.Now() bucketName := fmt.Sprintf("%v-%s.%v-%v.%v", "test-bucket", region, ts.Hour(), ts.Minute(), randSeq) log.Printf("Generated bucket name: %q", bucketName) // Create two objects in memory objs := make(map[string]*bytes.Reader) noFiles := 2 for i := 0; i < noFiles; i++ { ct := make([]byte, 1024*32) // fill with random data if _, err := crand.Read(ct); err != nil { log.Fatalf("failed to read random data: %v", err) } objName := fmt.Sprintf("%v.txt", i) objs[objName] = bytes.NewReader(ct) } // 2. Create a bucket _, err = s3Client.CreateBucket(ctx, &s3.CreateBucketInput{ Bucket: aws.String(bucketName), }) if err != nil { log.Fatalf("unable to create bucket: %v", err) } log.Printf("Created bucket: %v", bucketName) // 3. Upload the two objects into the newly created bucket for objName, body := range objs { if _, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: aws.String(bucketName), Key: aws.String(objName), Body: body, }); err != nil { log.Fatalf("unable to upload file (%v): %v", objName, err) } log.Printf("Uploaded file (%v) to bucket: %v", objName, bucketName) } // 4. List objects in the bucket listObj, err := s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{ Bucket: aws.String(bucketName), }) if err != nil { log.Fatalf("unable to list objects: %v", err) } for _, item := range listObj.Contents { log.Printf("Listed object: %v", *item.Key) } // 5. Download the object first out, err := s3Client.GetObject(ctx, &s3.GetObjectInput{ Bucket: aws.String(bucketName), Key: aws.String("1.txt"), }) if err != nil { log.Fatalf("unable to download object: %v", err) } defer out.Body.Close() dl, err := io.ReadAll(out.Body) if err != nil { log.Fatalf("unable to read object data: %v", err) } log.Printf("downloaded file size: %d", len(dl)) // 6. Create a presigned URL for the first file url := fmt.Sprintf("https://api.telnyx.com/v2/storage/buckets/%v/%v/presigned_url", bucketName, "1.txt") req, err := http.NewRequest(http.MethodPost, url, bytes.NewReader([]byte(`{"TTL": 30}`))) if err != nil { log.Fatalf("unable to create presigned request: %v", err) } req.Header.Set("Authorization", "Bearer "+telnyxAPIKey) resp, err := http.DefaultClient.Do(req) if err != nil { log.Fatalf("unable to send presigned request: %v", err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) log.Fatalf("unexpected status code: %v | response: %s", resp.StatusCode, b) } type presignedURL struct { Data struct { Token string `json:"token"` ExpiresAt time.Time `json:"expires_at"` PresignedURL string `json:"presigned_url"` } `json:"data"` } var purl presignedURL if err := json.NewDecoder(resp.Body).Decode(&purl); err != nil { log.Fatalf("unable to decode presigned URL: %v", err) } log.Printf("Generated presigned URL: %v", purl.Data.PresignedURL) // 7. Download the file again using the presigned URL res, err := http.Get(purl.Data.PresignedURL) if err != nil { log.Fatalf("unable to download presigned URL: %v", err) } defer res.Body.Close() log.Printf("Downloaded presigned URL status code: %v", res.StatusCode) } ``` Run the program. ```bash TELNYX_API_KEY=_YOUR_API_KEY go run main.go 2024/08/15 13:14:29 Created S3 client for region (us-central-1) and endpoint (https://us-central-1.telnyxcloudstorage.com) 2024/08/15 13:14:29 Generated bucket name: "test-bucket-us-central-1.13-14.536341" 2024/08/15 13:14:30 Created bucket: test-bucket-us-central-1.13-14.536341 2024/08/15 13:14:31 Uploaded file (0.txt) to bucket: test-bucket-us-central-1.13-14.536341 2024/08/15 13:14:31 Uploaded file (1.txt) to bucket: test-bucket-us-central-1.13-14.536341 2024/08/15 13:14:31 Listed object: 0.txt 2024/08/15 13:14:31 Listed object: 1.txt 2024/08/15 13:14:32 downloaded file size: 32768 2024/08/15 13:14:32 Generated presigned URL: https://us-central-1.telnyxcloudstorage.com/test-bucket-us-central-1.13-14.536341/1.txt?X-AMZ-Security-Token=sometoken 2024/08/15 13:14:33 Downloaded presigned URL status code: 200 ``` --- ### Ruby > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/ruby.md The following example shows how AWS Ruby SDK can be used to interact with Telnyx Cloud Storage. ``` require "aws-sdk-s3" require "net/http" # Create a new S3 resource telnyx_api_key = ENV["TELNYX_API_KEY"] resource = Aws::S3::Resource.new( region: "us-central-1", endpoint: "https://us-central-1.telnyxcloudstorage.com", access_key_id: telnyx_api_key, secret_access_key: "doesn't matter" ) bucket_name = "example-#{SecureRandom.hex(24)}" # Creating a bucket bucket = resource.create_bucket(bucket: bucket_name) puts "*" * 50 puts("Created bucket named #{bucket.name}.") puts "*" * 50 # Listing buckets puts "Listing buckets" puts "*" * 50 resource.buckets.each do |b| puts " - #{b.name}" end puts "*" * 50 # Upload a file File.open("document.txt", "w+") { |f| f.write("This is a text document.\n") } bucket = resource.bucket(bucket_name) the_object = bucket.object("document.txt") the_object.upload_file("document.txt") puts("Uploaded file document.txt into bucket #{bucket.name} with key #{the_object.key}.") puts "*" * 50 # Download an object from the bucket puts "Downloading object from bucket #{bucket.name}" file_name = "a-local-file.txt" the_object.download_file(file_name) puts("Object #{the_object.key} successfully downloaded to #{file_name}.") puts("Contents of #{file_name}: #{File.read(file_name).inspect}") puts "*" * 50 # Creating a presigned URL to upload a file object_key = "important-document.txt" uri = URI("https://api.telnyx.com/v2/storage/buckets/#{bucket_name}/#{object_key}/presigned_url") response = Net::HTTP.post( uri, { ttl: 30 }.to_json, "Authorization" => "Bearer #{telnyx_api_key}" ) raise "Bad response creating presigned URL" unless response.code == "200" parsed_response = JSON.parse(response.body) presigned_url = parsed_response["data"]["presigned_url"] puts "Created presigned upload URL:" puts "*" * 50 puts presigned_url puts "*" * 50 # Upload a file using the Telnyx presigned URL uri = URI(presigned_url) request = Net::HTTP.new(uri.host) response = request.put(uri, "This is an important text document.\n") raise "Couldn't upload file using presigned URL: #{response.inspect}" unless response.code == "200" puts "Uploaded file using presigned URL: #{response.inspect}" # Listing objects in the bucket puts "Listing objects in bucket #{bucket.name}" puts "*" * 50 bucket.objects.each do |o| puts " * #{o.key}" end puts "*" * 50 # Creating a presigned URL to download the file uri = URI("https://api.telnyx.com/v2/storage/buckets/#{bucket_name}/#{object_key}/presigned_url") response = Net::HTTP.post( uri, { ttl: 30 }.to_json, "Authorization" => "Bearer #{telnyx_api_key}" ) raise "Bad response creating presigned URL" unless response.code == "200" parsed_response = JSON.parse(response.body) presigned_url = parsed_response["data"]["presigned_url"] puts "Created presigned download URL:" puts "*" * 50 puts presigned_url puts "*" * 50 # Download the object using the presigned URL uri = URI(presigned_url) response = Net::HTTP.get(uri) puts("Downloaded object contents from presigned URL: #{response.inspect}") puts "*" * 50 # Cleaning up File.delete("document.txt") File.delete("a-local-file.txt") # Deleting the objects the_object.delete puts("Deleted object #{the_object.key}.") important_object = bucket.object(object_key) important_object.delete puts("Deleted object #{important_object.key}.") # Deleting the bucket bucket.delete puts("Deleted bucket #{bucket.name}.") puts("Done.") ``` --- ### PHP > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/php.md The following example shows how AWS PHP SDK can be used to interact with Telnyx Cloud Storage. ```php $region, 'version' => 'latest', 'endpoint' => $endpoint, 'credentials' => [ 'key' => $telnyxAPIKey, 'secret' => $telnyxAPIKey, ], 'use_path_style_endpoint' => true ]); $bucketName = "test-bucket-" . $region . '-' . date('H-i') . '-' . rand(0, 1000000); echo "Generated bucket name: " . $bucketName . PHP_EOL; // 2. Create a bucket try { $s3Client->createBucket([ 'Bucket' => $bucketName ]); echo "Created bucket: {$bucketName}" . PHP_EOL; } catch (AwsException $e) { die("Unable to create bucket: " . $e->getMessage()); } // 3. Upload two objects with random data for ($i = 0; $i < 2; $i++) { $content = random_bytes(1024 * 32); // 32KB of random data $objName = "{$i}.txt"; try { $s3Client->putObject([ 'Bucket' => $bucketName, 'Key' => $objName, 'Body' => $content ]); echo "Uploaded file ({$objName}) to bucket: {$bucketName}" . PHP_EOL; } catch (AwsException $e) { die("Unable to upload file ({$objName}): " . $e->getMessage()); } } // 4. List objects in the bucket try { $result = $s3Client->listObjects([ 'Bucket' => $bucketName ]); foreach ($result['Contents'] as $item) { echo "Listed object: " . $item['Key'] . PHP_EOL; } } catch (AwsException $e) { die("Unable to list objects: " . $e->getMessage()); } // 5. Download the first object try { $result = $s3Client->getObject([ 'Bucket' => $bucketName, 'Key' => '1.txt' ]); $data = $result['Body']->getContents(); echo "Downloaded file size: " . strlen($data) . PHP_EOL; } catch (AwsException $e) { die("Unable to download object: " . $e->getMessage()); } // 6. Create a presigned URL for the first file $url = "https://api.telnyx.com/v2/storage/buckets/{$bucketName}/1.txt/presigned_url"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(['TTL' => 30])); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $telnyxAPIKey, 'Content-Type: application/json' ]); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $response = curl_exec($ch); $httpcode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpcode != 200) { die("Unexpected status code: {$httpcode} | response: {$response}"); } $presignedData = json_decode($response, true); $presignedURL = $presignedData['data']['presigned_url']; echo "Generated presigned URL: {$presignedURL}" . PHP_EOL; // 7. Download the file using the presigned URL $ch = curl_init($presignedURL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $result = curl_exec($ch); curl_close($ch); echo "Downloaded presigned URL data size: " . strlen($result) . PHP_EOL; ?> ``` --- ### .NET > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/dotnet.md Chunk encoding is not supported by the Cloud Storage API. Please set `putObjectRequest.UseChunkEncoding = false`. The following example shows how AWS .Net SDK can be used to interact with Telnyx Cloud Storage. ```csharp using System.Text; using System.Text.Json; using Amazon.Runtime; using Amazon.S3; using Amazon.S3.Model; // 1. Configure and create Telnyx API Client var apiKeyTelnyx = "API-KEY-HERE"; var bucketName = "BUCKET-NAME-HERE"; var objectName = "OBJECT-NAME-HERE"; var region = "us-central-1"; var s3Config = new AmazonS3Config { ServiceURL = $"https://{region}.telnyxcloudstorage.com", ForcePathStyle = true, LogResponse = true, DisableLogging = false, SignatureVersion = "4", }; var telnyxClient = new AmazonS3Client( new BasicAWSCredentials(apiKeyTelnyx, apiKeyTelnyx), s3Config ); // 2. Create Bucket var createBucketRequest = new PutBucketRequest { BucketName = bucketName }; var createBucketResponse = await telnyxClient.PutBucketAsync(createBucketRequest); // 3. Upload object var putObjectRequest = new PutObjectRequest { BucketName = bucketName, Key = "objectName", FilePath = "/Users/yiuming/test.txt" }; // IMPORTANT: chunk encoding is not supported by the Cloud Storage API. putObjectRequest.UseChunkEncoding = false; var putObjectResponse = await telnyxClient.PutObjectAsync(putObjectRequest); // 4. List Objects var listObjectRequest = new ListObjectsRequest { BucketName = bucketName }; var listObjectResponse = await telnyxClient.ListObjectsAsync(listObjectRequest); // 5. List Buckets var listBucketsRequest = new ListBucketsRequest { }; var listBucketsResponse = await telnyxClient.ListBucketsAsync(listBucketsRequest); // 6. Download Object var getObjectRequest = new GetObjectRequest { BucketName = bucketName, Key = objectName }; var getObjectResponse = await telnyxClient.GetObjectAsync(getObjectRequest); // 7. Presigned URL Get using (HttpClient client = new HttpClient()) { client.BaseAddress = new Uri("https://api.telnyx.com"); var presignedUrlRequest = new Dictionary { { "ttl", 200 } }; var presignedUrlRequestJson = JsonSerializer.Serialize(presignedUrlRequest); var presignedUrlRequestContent = new StringContent( presignedUrlRequestJson, Encoding.UTF8, "application/json"); client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", apiKeyTelnyx); var presignedUrlResponse = await client.PostAsync($"/v2/storage/buckets/{bucketName}/{objectName}/presigned_url", presignedUrlRequestContent); var content = await presignedUrlResponse.Content.ReadAsStringAsync(); Console.WriteLine(content); } ``` --- ### Elixir > Source: https://developers.telnyx.com/docs/cloud-storage/sdk/elixir.md The following example shows how AWS Elixir SDK can be used to interact with Telnyx Cloud Storage. This example requires the following dependencies be added to your mix.exs file ```elixir {:aws, "~> 1.0.0"}, {:hackney, "~> 1.18"} ``` ```elixir telnyx_storage_client = AWS.Client.create( System.fetch_env!("TELNYX_V2_API_KEY"), # secret access key can be left blank for Telnyx Storage "", System.get_env("TELNYX_STORAGE_REGION", "us-east-1") ) |> AWS.Client.put_endpoint(fn options -> "#{options.region}.telnyxcloudstorage.com" end) # create a bucket bucket_name = System.get_env("TELNYX_STORAGE_BUCKET_NAME", "my-test-bucket-#{Enum.random(1..1_000_000)}") {:ok, _, _} = AWS.S3.create_bucket(telnyx_storage_client, bucket_name, %{}) # write a couple of objects to the bucket for i <- 1..2 do object_key = "object-#{i}.bin" # create a blob of random bytes upload_request = %{ "Body" => :rand.bytes(42), "ContentType" => "application/octet-stream" } {:ok, _, _} = AWS.S3.put_object(telnyx_storage_client, bucket_name, object_key, upload_request) end # list contents of a bucket {:ok, %{"ListBucketResult" => bucket_details}, _} = AWS.S3.list_objects(telnyx_storage_client, bucket_name) # print the object keys Enum.each(bucket_details["Contents"], fn content -> IO.puts("Object key: #{content["Key"]}") end) # download the first object object_key = List.first(bucket_details["Contents"])["Key"] {:ok, %{"Body" => object_data}, _} = AWS.S3.get_object(telnyx_storage_client, bucket_name, object_key) IO.puts("Downloaded object data: #{inspect(object_data)}") ``` For generating presigned URLs, the below example requires the following additional libraries added to your mix.exs file ```elixir {:req, "~> 0.5"}, {:jason, "~> 1.4"} ``` ```elixir url = "https://api.telnyx.com/v2/storage/buckets/#{bucket_name}/#{object_key}/presigned_url" api_key = System.fetch_env!("TELNYX_V2_API_KEY") headers = %{ "authorization" => "Bearer #{api_key}", "content_type" => "application/json", "accept" => "application/json" } body = %{ "ttl" => 30 } {:ok, %{body: %{"data" => %{"presigned_url" => presigned_url}}}} = Req.post(url, headers: headers, json: body) # download the object using the presigned url {:ok, %{body: object_data}} = Req.get(presigned_url) IO.puts("Downloaded object data using presigned URL: #{inspect(object_data)}") ``` --- ## Advanced Features ### Multipart Upload > Source: https://developers.telnyx.com/docs/cloud-storage/multipart-upload.md Large objects should be uploaded to your bucket via multipart upload. ## Using AWS CLI Assuming you have [AWS CLI set up](/docs/cloud-storage/quick-start#using-aws-cli) already: ``` user@localhost ~ % aws s3 cp ~/Projects/s3-test/testdata/10Gfile s3://target-bucket/10Gfile --profile mytelnyxprofile --endpoint-url https://us-west-1.telnyxcloudstorage.com ``` where * `~/Projects/s3-test/testdata/10Gfile` is the path to the raw bytes stored locally * `s3://target-bucket/10Gfile` is the target bucket name and the object key (aka object name) Depending on your environment, you may achieve throughput between 20 MiB/s (locally on a home network) to upward of 100+ MiB/s (on a lab or production network in a data center.) ## Using AWS API/SDK The general procedure to use the API/SDK is as follows: Initiate the upload session with [CreateMultipartUpload](https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/create-multipart-upload/index#create-multipart-upload). Stream each chunk with [UploadPart](https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/upload-part/index#upload-part). Finalize the transfer by calling [CompleteMultipartUpload](https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/complete-multipart-upload/index#complete-multipart-upload). --- ### Presigned URLs > Source: https://developers.telnyx.com/docs/cloud-storage/presigned-urls.md This is currently supported only for buckets located in the US. We do NOT follow how AWS does authentication — hence, you *MUST NOT* use the existing AWS SDK or CLI to generate presigned URLs. Otherwise, you will expose your API key to the public. Please use the [JSON companion API](/api-reference/presigned-object-urls/create-presigned-object-url) to generate ephemeral presigned URLs to allow anonymous **downloads** and **uploads** of objects to your bucket(s). In addition, creating long-lived presigned URL is a privileged action. Non-verified accounts are limited to presigned URLs with TTL no greater than 5 minutes. To verify your account, [request and obtain Level 2 verification](https://portal.telnyx.com/#/account/my-account/verifications) status. ## Examples Considering `8f0nh1jk8qvf` as an example of a presigned URL token, you can perform the following actions: ### Downloading an object using a presigned URL ``` curl -o my-object.bin https://us-central-1.telnyxcloudstorage.com/my-bucket/my-object.bin\?X-AMZ-Security-Token\=8f0nh1jk8qvf ``` ### Uploading an object using a presigned URL ``` curl -X PUT -F "file=@a-new-object.bin" https://us-central-1.telnyxcloudstorage.com/my-bucket/a-new-object.bin\?X-AMZ-Security-Token\=8f0nh1jk8qvf ``` where `a-new-object.bin` is the file you want to upload in `my-bucket`. If the object already exists, it will be overwritten. --- ### Object Encryption > Source: https://developers.telnyx.com/docs/cloud-storage/object-encryption.md This is currently supported only for buckets located in the US. We support [SSE-C](https://docs.aws.amazon.com/AmazonS3/latest/userguide/ServerSideEncryptionCustomerKeys.html). Here is an example on how to `PutObject` with encryption. ## PutObject with SSE-C *Don't forget to update `--sse-customer-key` here.* ```bash user@host ~ % aws s3api put-object --body /path/to/file.png --bucket mybestbucket --key objenc --sse-customer-algorithm AES256 --sse-customer-key XXX { "ETag": "\"18830c2cf6204ca111864bf967c40959\"", "SSECustomerAlgorithm": "AES256", "SSECustomerKeyMD5": "YYY" } ``` --- ### Public Buckets > Source: https://developers.telnyx.com/docs/cloud-storage/public-buckets.md This is currently supported only for buckets located in the US. Making a bucket public (via [policy](https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-policy/index#put-bucket-policy) or [ACL](https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-acl/index#put-bucket-acl)) is a privileged action. Follow the following procedure: Request and obtain [Level 2 verification](https://portal.telnyx.com/#/account/my-account/verifications) status. Use the [CLI](https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-policy/index#put-bucket-policy), API, or SDK to apply the desired policy to your bucket. --- ### HTTPS with Custom Domain > Source: https://developers.telnyx.com/docs/cloud-storage/ssl-certificates.md This is currently supported only for buckets located in the US. ## 1. Validate availability of bucket You must ensure the subdomain is available as a bucket name. If so, you may create the bucket. In this example, we created asset.gardening-homes.com. ![SSL Certificate 1](/img/storage-ssl-1.png "SSL Certificate 1") ## 2. Make the bucket public Since the content of this bucket will be publicly accessible, you need to apply a public read policy to it. Follow the instructions here: [Put Bucket Policy](/docs/cloud-storage/api-reference/bucket-operations/put-bucket-policy) ![SSL Certificate 2](/img/storage-ssl-2.png "SSL Certificate 2") ## 3. Configure DNS Through your domain/DNS provider, you need to set up an alias to the bucket with virtual addressing style ([Bucket Addressing](/docs/cloud-storage/bucket-addressing)) ![SSL Certificate 3](/img/storage-ssl-3.png "SSL Certificate 3") ## 4. Upload Certificate and Matching Key Select the bucket you created, under SSL/TLS, upload the certificate and matching key. ![SSL Certificate 4](/img/storage-ssl-4.png "SSL Certificate 4") When uploading a certificate file, please ensure the following: - The bucket name must match one of the certificate SNIs (Server Name Indication) exactly. If you have a wildcard SNI *.example.com, help.example.com will work, but example.com will not work. - If you have intermediate certificates, you must include them in the certificate file with the leaf certificate being at the top. - You may omit the root certificate, as we will verify known root certificates automatically. However, if you’d like to guarantee that your certificate will be accepted, it is better to include it. ## 5. Test Assuming all of the above is successful and there is an object named demo-image.jpg in the bucket, you may put https://asset.gardening-homes.com/demo-image.jpg in your browser and expect the following - The image shows up in your browser, and - Your browser will show “Connection is secure” and “Certificate is valid” ![SSL Certificate 5](/img/storage-ssl-5.png "SSL Certificate 5") --- ### Data Protection & Retention > Source: https://developers.telnyx.com/docs/cloud-storage/lock-and-retention.md This is currently supported only for buckets located in the US. To enable this feature, object lock MUST be enabled at bucket creation time. ```bash aws s3api create-bucket --bucket test-lock-v4 --object-lock-enabled-for-bucket --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com ``` Confirm this is set properly. ```bash aws s3api get-object-lock-configuration --bucket test-lock-v4 --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com { "ObjectLockConfiguration": { "ObjectLockEnabled": "Enabled" } } ``` Versioning is automatically enabled as a result. ```bash s3-test % aws s3api get-bucket-versioning --bucket test-lock-v4 --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com { "Status": "Enabled", "MFADelete": "Disabled" } ``` Upload an object. ```bash aws s3api put-object --key my-object --body ~/Downloads/random-bytes --bucket test-lock-v4 --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com { "ETag": "\"21074fc6c4a7aaee18b61bb235a9d372\"", "VersionId": "Z.gwUKVtPQx9bqbfD4VTxv3SraZdUlF" } ``` Now set the object retention policy. ```bash aws s3api put-object-retention --bucket test-lock-v4 --key my-object --retention '{ "Mode": "GOVERNANCE", "RetainUntilDate": "2024-11-20T00:00:00" }' --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com ``` And confirm it's set properly. ```bash aws s3api get-object-retention --bucket test-lock-v4 --key my-object --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com { "Retention": { "Mode": "GOVERNANCE", "RetainUntilDate": "2024-11-20T00:00:00+00:00" } } ``` Deleting the object produces an expected error. ```bash aws s3api delete-object --bucket test-lock-v4 --key my-object --version-id "Z.gwUKVtPQx9bqbfD4VTxv3SraZdUlF" --profile "*.telnyxcloudstorage.com" --endpoint-url https://us-central-1.telnyxcloudstorage.com An error occurred (AccessDenied) when calling the DeleteObject operation: forbidden by object lock ``` For additional information, please consult S3's API reference. --- ## Management & Operations ### Emptying Buckets > Source: https://developers.telnyx.com/docs/cloud-storage/emptying-bucket.md When a bucket has more than 1000 objects, it's burdensome to empty it synchronously. The best solution is to take advantage of lifecycle rules which asynchronously operate on destination bucket. Here is a sample lifecycle rule --- ## Sample lifecycle rule ```json { "Rules": [ { "ID": "delete_all_versions_and_delete_markers", "Status": "Enabled", "Filter": { "Prefix": "" }, "NoncurrentVersionExpiration": { "NoncurrentDays": 1 }, "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 1 }, "Expiration": { "Days": 1 } } ] } ``` Name that file as `lifecycle.json` and you can apply that to the bucket you intend to empty --- ```json aws s3api put-bucket-lifecycle-configuration --bucket mybucketname --lifecycle-configuration file://lifecycle.json --profile mytelnyxprofile --endpoint-url https://us-west-1.telnyxcloudstorage.com ``` You can verify that it's applied correctly the following way. ```json aws s3api get-bucket-lifecycle-configuration --bucket mybucketname --profile mytelnyxprofile --endpoint-url https://us-west-1.telnyxcloudstorage.com ``` Check on your bucket after 24 hours to validate it's being cleared. --- ### Limits & Quotas > Source: https://developers.telnyx.com/docs/cloud-storage/limits.md ## General API limits | Limit | Value | |-------|-------| | Requests per second per account | 500 | | Requests per second per bucket | 200 | | Concurrent PUT or COPY requests per object | 10 | These limits are subject to change. If you require higher throughput, please [contact support](https://support.telnyx.com) to discuss your use case. ## Specific limits - Max count of buckets per account is 100 - Max size of single object upload via PUT request is 5 GB - Max size of single part upload of a multi-part upload is 5 GB - Min size of single part upload of a multi-part upload is 5 MiB, except for the final part - Max count of parts of a multi-part upload is 10,000 - Max size of a completed multi-part upload is 5 TiB - Max count of objects per bucket is 50 million --- ### Billing & Pricing > Source: https://developers.telnyx.com/docs/cloud-storage/billing.md You are billed on two things - The bytes stored - The count of API operations invoked ## Storage billing explained The minimum billable **object** size is 4 KiB. Here is an example — if you have two 11-byte objects in a bucket, they will be counted as 4 KiB each, i.e. 8 KiB in total.  Storage consumed by each bucket is billed in multiples of 4 KiB, rounded up; Metadata counts towards storage consumed. ### US Storage Every month, your **first 10 GiB is free of charge**. Any bytes beyond that are billed at: - **$0.006 per GiB per month** for regular storage - **$0.60 per GiB per month** for AI embedded storage ### EU Storage EU storage has **no free tier** and is billed at: - **$0.025 per GiB per month** for regular storage - **$0.60 per GiB per month** for AI embedded storage Bytes stored across all buckets are **recorded hourly**. Usage is subsequently calculated and debited from your balance.  Here is a hypothetical example: - You have a $10 balance in your account. - At time `t`, you uploaded 11 GiB of objects into various buckets in your account. - At the next whole clock hour after time `t` - a snapshot of your total storage is recorded as 11 GiB - your usage is calculated as (11 GiB - 10 GiB) x ($ 0.006 / 30 days / 24 hrs) - that usage is then debited from your $10 balance Lastly, free tier is not available to an account if its available credit is negative. Here is a hypothetical example: - You have a $10 balance in your account - Through usage of Voice and Messaging API, you've depleted your balance and resulted in a negative available credit of -0.1 USD. - You will not be able to create a bucket and upload objects until your available credit is restored. ## API operations billing explained API operations are classified and billed the following way — ### US Storage Categories Applicable API Ops Prices Class A PUT, COPY, POST, LIST requests Every month, the first 1 Million is free of charge, thereafter $0.50 per 1 Million Class B GET, SELECT, and all other request Every month, the first 10 Million is free of charge, thereafter $0.04 per 1  Million ### EU Storage Categories Applicable API Ops Prices State-change operations PUT, COPY, POST, LIST requests $5.00 per 1 Million Read operations GET, SELECT, and all other requests $0.40 per 1 Million ## Account suspension and loss of data When an account's available credit becomes negative: - You will be notified via email of insufficient balance. - Your data is ***still retained*** in the system but API requests will fail with error message `UserSuspended`. - Access will be restored when available credit is made positive via payment. If available credit remains negative for 30 days, your account will be abolished. As a consequence, all data will be irreversibly purged. ## Relevant companion APIs Two companion APIs exist to allow for querying of usage: * [Bucket Snapshot](https://developers.telnyx.com/api-reference/bucket-usage/get-bucket-usage#get-bucket-usage) is a snapshot of the bytes your bucket is taking up at the moment of query. * [API Usage](https://developers.telnyx.com/api-reference/bucket-usage/get-api-usage#get-api-usage) shows the stats of your API requests. ### Query bucket snapshot **Example Request** ```json GET /v2/storage/buckets/mybucket/usage/storage HTTP/1.1 Host: api.telnyx.com Authorization: Bearer XXX ``` **Example Response** ```json { "data": [ { "size": 1078984704, "size_kb": 1053696, "num_objects": 2, "timestamp": "2024-07-30T14:26:43Z" } ], "meta": { "page_number": 1, "page_size": 1, "total_pages": 1, "total_results": 1 } } ``` ### Query API usage **Example Request** ```json GET /v2/storage/buckets/mybucket/usage/api?filter[start_time]=2024-07-01T00:00:00.000Z&filter[end_time]=2024-07-31T00:00:00.000Z HTTP/1.1 Host: api.telnyx.com Authorization: Bearer XXX ``` **Example Response** ```json { "data": [ { "categories": [ { "bytes_sent": 1768, "bytes_received": 0, "ops": 13, "successful_ops": 13, "category": "get_bucket_location" }, { "bytes_sent": 141, "bytes_received": 0, "ops": 1, "successful_ops": 1, "category": "get_bucket_policy_status" }, { "bytes_sent": 137, "bytes_received": 0, "ops": 1, "successful_ops": 1, "category": "get_bucket_versioning" }, { "bytes_sent": 2022703104, "bytes_received": 0, "ops": 2, "successful_ops": 2, "category": "get_obj" }, { "bytes_sent": 1623, "bytes_received": 0, "ops": 3, "successful_ops": 3, "category": "list_bucket" } ], "total": { "bytes_sent": 2022706773, "bytes_received": 0, "ops": 20, "successful_ops": 20 }, "timestamp": "2024-07-02T17:00:00.000Z" } ] } ``` --- ### Performance Benchmarks > Source: https://developers.telnyx.com/docs/cloud-storage/performance-benchmarks.md ## Storage benchmark summary We achieved the following throughput results given the bench test setup described in the subsequent sections. - **PutObject Aggregate: 2.029 GiB/s** - **GetObject Aggregate: 2.714 GiB/s** A few disclaimers - We did not exhaustively search the client configuration that produces the highest achievable throughputs. - This result is only indicative of what can be achieved with the available testbed hardware specifications and arrangement. - The test clients are not subjected to the limits outlined in the previous section. - As we launch new sites, we will continuously update our test results and methodology.  ## Benchmark environment explained ### Client hardware  (8) of the following bare metal machines are used as clients initiating requests to one of the regional endpoints. They are located off network with 100 Gbps uplink to the public internet. Type Count of nodes CPU Mem Storage Network Type 1 4 64 2 TiB 4 x 6.4TiB NVMe 100 Gbps Type 2 4 32 2 TiB 1 x 960GiB NVMe 100 Gbps No special optimizations are made on the client OS.  ### Benchmark Software https://github.com/wasabi-tech/s3-benchmark ### Client Setup Each client bare metal reads and writes to their individual bucket. ### Results ![Put Object Aggregate Throughput](/img/storage-PutObjectThroughput.png "Put Throughput") ![Get Object Aggregate Throughput](/img/storage-GetObjectThroughput.png "Get Throughput") --- ## Storage (S3-Compatible) ### Create bucket > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/create-bucket.md # CreateBucket [CreateBucket - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html) ## Supported headers and XML elements **✅Supported Headers** `x-amz-acl` - `private` - `public-read` **✅Supported XML Element** - `LocationConstraint` **Example request** ```bash PUT /mybucket HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T152207Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=eb67629c5cd507c56c5c5447323cc0190c605ab87c2b2fd3046825ca09a28425 Content-Length: 197 us-east-1 ``` Bucket’s location is inherited from the regional endpoint to which you sent the CreateBucket request. If LocationConstraint is specified in the request body, its value must match that of the location in the regional endpoint. Otherwise, an error will be returned. ```xml InvalidLocationConstraint The specified location-constraint is not valid mybucket tx00000e9df2217c8f5a351-00651445e0-e3e7-fl1 e3e7-fl1-us-east-1 ``` In general, bucket names should follow domain name constraints. Bucket names - must be unique. - cannot be formatted as IP address. - can be between 3 and 63 characters long. - must not contain uppercase characters or underscores. - must start with a lowercase letter or number. - can contain a dash (-). - must be a series of one or more labels. Adjacent labels are separated by a single period (.). Bucket names can contain lowercase letters, numbers, and hyphens. Each label must start and end with a lowercase letter or a number. Otherwise the following error will be returned ```xml InvalidBucketName invalidBucket tx0000040523d3a2d1ba956-006514716b-e3a0-fl1 e3a0-fl1-us-east-1 ``` --- ### Delete bucket > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/delete-bucket.md # DeleteBucket [DeleteBucket - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html) ## Example DeleteBucket request ```bash curl --location --request DELETE 'https:// [region].telnyxcloudstorage.com/[bucket_name]' \ --header 'X-Amz-Date: 20230927T175031Z' \ --header 'Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=06c306e4a75de6aa98a875cfe76ee3977a1c99d60aee86b6db1f53a47539d464' ``` --- ### Delete bucket CORS > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/delete-bucket-cors.md # DeleteBucketCors ## Example DeleteBucketCors request ```bash user@host % aws s3api delete-bucket-cors --bucket chatgpt-bucket-1696358562 --profile us-east-1.telnyxcloudstorage.com --endpoint-url https://us-east-1.telnyxcloudstorage.com ``` --- ### Delete bucket lifecycle > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/delete-bucket-lifecycle.md # DeleteBucketLifecycle [DeleteBucketLifecycle - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html) ## Example DeleteBucketLifecycle request ```bash DELETE /versionedbucket?lifecycle=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml X-Amz-Date: 20230927T173847Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-date, Signature=63c7e3d367d62488f9eba08ec8fdbe5bf89ef4484772b5fee952a4ac2dcd3362 ``` --- ### Delete bucket policy > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/delete-bucket-policy.md # DeleteBucketPolicy [DeleteBucketPolicy - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketPolicy.html) ## Example DeleteBucketPolicy request ```bash user@host % aws s3api delete-bucket-policy --bucket pubreadbuc ``` --- ### Delete bucket tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/delete-bucket-tagging.md # DeleteBucketTagging [DeleteBucketTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html) ## Example DeleteBucketTagging request ````bash DELETE /versionedbucket?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private X-Amz-Date: 20230927T182455Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=8bad860d937751e40011d5953da3f2463f57e30b1f00d9f25707d393f68f582b``` ```` --- ### Get bucket ACL > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-acl.md # GetBucketAcl [GetBucketAcl - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketAcl.html) ## Example GetBucketAcl request ```bash GET /versionedbucket?acl=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: public-read X-Amz-Date: 20230927T174306Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=050c7795578015f9b3f51bc6d3785d90f7394e5ef7e611ebb6ede54802faa996 ``` ## Example GetBucketAcl Response ```xml 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 http://acs.amazonaws.com/groups/global/AllUsers READ 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 FULL_CONTROL ``` --- ### Get bucket CORS > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-cors.md # GetBucketCors ## Example GetBucketCors request ```bash user@host % aws s3api get-bucket-cors --bucket my_bucket { "CORSRules": [ { "AllowedHeaders": [ "*" ], "AllowedMethods": [ "PUT", "DELETE", "POST" ], "AllowedOrigins": [ "http://www.example.com" ] }, { "AllowedMethods": [ "GET" ], "AllowedOrigins": [ "*" ] } ] } ``` --- ### Get bucket lifecycle configuration > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-lifecycle-configuration.md # GetBucketLifecycleConfiguration [GetBucketLifecycleConfiguration - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycleConfiguration.html) ## Example GetBucketLifecycleConfiguration request ```bash GET /versionedbucket?lifecycle=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml X-Amz-Date: 20230927T172450Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-date, Signature=c8e6ec2d0c5c34ea061e4dd47d2e7103fde5a885c25d9dca3ac743d8b6ab3330 ``` ## Example GetBucketLifecycleConfiguration response ```xml DeleteAfterBecomingNonCurrent logs/ Enabled 100 ``` --- ### Get bucket location > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-location.md # GetBucketLocation [GetBucketLocation - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLocation.html) ## Example GetBucketLocation request ```bash GET /versionedbucket?location=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private X-Amz-Date: 20230927T170849Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=107fa2b75c0af7f1982923de787b767f407718c4f1eb19937ff3445f2c0be332 ``` ## Example GetBucketLocation response ```xml us-east-1 ``` --- ### Get bucket policy > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-policy.md # GetBucketPolicy [GetBucketPolicy - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicy.html) ## Example GetBucketPolicy request ```bash user@host % aws s3api get-bucket-policy --bucket pubreadbuc { "Policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"PublicReadGetObject\",\n \"Effect\": \"Allow\",\n \"Principal\": \"*\",\n \"Action\": \"s3:GetObject\",\n \"Resource\": \"arn:aws:s3:::pubreadbuc *\"\n }\n ]\n }\n \n" } ``` --- ### Get bucket policy status > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-policy-status.md # GetBucketPolicyStatus [GetBucketPolicyStatus - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicyStatus.html) ## Example GetBucketPolicyStatus request ```bash user@host % aws s3api get-bucket-policy-status --bucket pubreadbuc { "PolicyStatus": { "IsPublic": true } } ``` --- ### Get bucket tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-tagging.md # GetBucketTagging [GetBucketTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html) ## Example GetBucketTagging request ```bash GET /versionedbucket?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private X-Amz-Date: 20230927T182418Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=94c986f7bf15c5ce04a1cdd83c0ee058d78eabfb8d0bab35caac92b965490b96 ``` ## Example GetBucketTagging response ```xml dimention_1 value_1 dimention_2 value_2 ``` --- ### Get bucket versioning > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/get-bucket-versioning.md # GetBucketVersioning [GetBucketVersioning - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html) ## Example GetBucketVersioning request ```bash GET /versionedbucket?versioning=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private X-Amz-Date: 20230927T165704Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=8d8723b48a60f1fef06b43a2f34ca9f4426efa5ae01f9dce8fcc49cba893b69e ``` ## Example GetBucketVersioning response ```xml Enabled Disabled ``` --- ### Head bucket > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/head-bucket.md # HeadBucket [HeadBucket - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadBucket.html) ## Example HeadBucket request ```bash HEAD /versionedbucket HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml X-Amz-Date: 20230927T174619Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-date, Signature=8cf0e5ebf1a74d2607aa36eb085659f696de84dd491a4b62adaf584572c8e90b ``` ## Example HeadBucket response ```bash HTTP/1.1 200 OK content-length: 0 date: Wed, 27 Sep 2023 17:48:02 GMT x-amz-request-id: tx000007a82340b0a467215-0065146ad2-e3bf-fl1 x-rgw-bytes-used: 608686 x-rgw-object-count: 4 x-rgw-quota-bucket-objects: -1 x-rgw-quota-bucket-size: -1 x-rgw-quota-max-buckets: 1000 x-rgw-quota-user-objects: -1 x-rgw-quota-user-size: -1 server: Telnyx API ``` --- ### List buckets > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/list-bucket.md # ListBuckets [ListBuckets - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html) ## Example ListBuckets request ```bash GET / HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T165213Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=5e8edce90f122eaf3810bb5934d8a4208530da8fe9bf634a1950f5eb49bf6197 ``` ## Example ListBuckets response ```xml 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 mybucket 2023-09-27T15:15:47.026Z publicbucket 2023-09-27T15:50:14.996Z testpostdeploybxx 2023-09-26T14:26:19.996Z versionedbucket 2023-09-27T16:51:50.678Z ``` --- ### Put bucket ACL > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-acl.md # PutBucketAcl **Warning:** Only verified users can update bucket policy. To request KYC on your account, go to [Portal Account Verifications](https://portal.telnyx.com/#/app/account/verifications) [PutBucketAcl - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketAcl.html) **✅ Supported Headers** `x-amz-acl` * `private` * `public-read` ## Example PutBucketAcl request ```bash PUT /versionedbucket?acl=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: public-read X-Amz-Date: 20230927T174201Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-acl;x-amz-date, Signature=3e206ed8dfb07bddf453f4735e4685527f2d7fb207ccaf00826353bb21db2164 ``` --- ### Put bucket CORS > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-cors.md # PutBucketCors ## Example PutBucketCors request ### Prepare a JSON file like this ```json { "CORSRules": [ { "AllowedOrigins": ["http://www.example.com"], "AllowedMethods": ["PUT", "POST", "DELETE"], "AllowedHeaders": ["*"] }, { "AllowedOrigins": ["*"], "AllowedMethods": ["GET"] } ] } ``` ### Then apply it to the target bucket ```bash user@host % aws s3api put-bucket-cors --bucket my_bucket --cors-configuration file://cors.json ``` --- ### Put bucket lifecycle configuration > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-life-cycle-configuration.md # PutBucketLifecycleConfiguration [PutBucketLifecycleConfiguration - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketLifecycleConfiguration.html) **✅ Supported XML Elements** - `ID` - `Status` - `Prefix` - `Expiration` - `AbortIncompleteMultipartUpload` ## Example PutBucketLifecycleConfiguration request — Non-versioned bucket ```bash PUT /mybucket?lifecycle=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T171857Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=bf5f1ef0813a985a4798dbbd63a722555f45a04de648f6bb7e975b4808974d80 Content-Length: 355 id2 logs/ Enabled 30 ``` ## Example PutBucketLifecycleConfiguration request - versioned bucket ```bash PUT /versionedbucket?lifecycle=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T172104Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-content-sha256;x-amz-date, Signature=a831851b8259ffb9e222ef5c755e5e44549972db7643d28f0570ac07b0600401 Content-Length: 436 DeleteAfterBecomingNonCurrent logs/ Enabled 100 ``` --- ### Put bucket policy > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-policy.md # PutBucketPolicy [PutBucketPolicy - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketPolicy.html) **Warning:** Only verified users can update bucket policy. To request KYC on your account, go to [Portal Account Verifications](https://portal.telnyx.com/#/app/account/verifications) ## Example PutBucketPolicy request Create a bucket where the objects stored in there can be read publicly without authentication Create a JSON file locally, e.g. `public_read_policy.json` ### Prepare a JSON file like this ```json { "Version": "2012-10-17", "Statement": [ { "Sid": "PublicReadGetObject", "Effect": "Allow", "Principal": "*", "Action": "s3:GetObject", "Resource": "arn:aws:s3:::/*" } ] } ``` ### Then apply that to an existing bucket ```bash user@host % aws s3api put-bucket-policy --bucket pubreadbuc --policy file://public_read_policy.json ``` --- ### Put bucket tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-tagging.md # PutBucketTagging [PutBucketTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html) ## Example PutBucketTagging request ```bash PUT /versionedbucket?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T182056Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=7eb598e87b95668e4502fef0694a515e960a98890c30185fc974bea5d8e72fe6 Content-Length: 310 dimention_1 value_1 dimention_2 value_2 ``` --- ### Put bucket versioning > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/bucket-operations/put-bucket-versioning.md # PutBucketVersioning [PutBucketVersioning - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html) **✅ Supported XML element** - `Status` ## Example PutBucketVersioning request ```bash PUT /versionedbucket?versioning=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: text/xml x-amz-acl: private Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T165559Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;content-length;content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=b9e0ced3fbf8e42c75b98f84c91758b74916b5bfe2d8a0208a67dffdbcb168e2 Content-Length: 167 Enabled ``` --- ### Delete object > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/delete-object.md # DeleteObject [DeleteObject - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html) ## Example DeleteObject Request ```bash DELETE /publicbucket/mymultiloader_1 HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T164329Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=539be1c5c92d8b89bcc4ea79eccb1f6e8ee3e1bd5c362dbf7b5f9bb2fa5515ca ``` --- ### Delete object tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/delete-object-tagging.md # DeleteObjectTagging [DeleteObjectTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html) ## Example DeleteObjectTagging request ```bash DELETE /mybucket/myobject?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: private X-Amz-Date: 20230927T180605Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date, Signature=361bbc366be4fa4e2f770dad0130b09948383d8e2bb58540fd469be3af24bbb0 ``` --- ### Delete objects > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/delete-objects.md # DeleteObjects [DeleteObjects - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) ## Example DeleteObjects request (using AWS S3 CLI) - Originally 3 objects exists in this bucket ```bash user@host ~ % aws s3api list-objects --bucket created-in-fl-1 { "Contents": [ { "Key": "xxx", "LastModified": "2023-10-02T19:11:54.788000+00:00", "ETag": "\"2da8bc8e8133ec2af9268515aae59e7a\"", "Size": 22905, "StorageClass": "STANDARD", "Owner": { "DisplayName": "xd", "ID": "xd" } }, { "Key": "yyy", "LastModified": "2023-10-02T19:11:38.436000+00:00", "ETag": "\"2da8bc8e8133ec2af9268515aae59e7a\"", "Size": 22905, "StorageClass": "STANDARD", "Owner": { "DisplayName": "xd", "ID": "xd" } }, { "Key": "zzz", "LastModified": "2023-10-02T19:11:25.551000+00:00", "ETag": "\"2da8bc8e8133ec2af9268515aae59e7a\"", "Size": 22905, "StorageClass": "STANDARD", "Owner": { "DisplayName": "xd", "ID": "xd" } } ], "RequestCharged": null } ``` - Delete 2 objects ```bash user@host ~ % aws s3api delete-objects --delete '{"Objects":[{"Key":"xxx"},{"Key":"yyy"}]}' --bucket created-in-fl-1 { "Deleted": [ { "Key": "xxx" }, { "Key": "yyy" } ] } ``` --- ### Get object > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/get-object.md # GetObject [GetObject - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) **✅ Supported Headers** - ` If-Match``If-Modified-Since ` - `If-None-Match` - `If-Unmodified-Since` - `Range` ## Example GetObject request ```bash GET /mybucket/myobject HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: application/octet-stream X-Amz-Date: 20230927T152801Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-date, Signature=41797df5b33f76003806aeb1eba3f25e108ecdb8582e6575e3bb1aaff4ddb839 ``` --- ### Get object ACL > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/get-object-acl.md # GetObjectAcl [GetObjectAcl - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html) ## Example GetObjectAcl request ```bash GET /mybucket/myobject?acl=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: private X-Amz-Date: 20230927T175743Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date, Signature=4edb4e62f2a28e4ff8e6b317fd867b4baf382b3c87b26e2404ea7a766779be4d ``` ## Example GetObjectAcl response ```xml 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 http://acs.amazonaws.com/groups/global/AllUsers READ 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 FULL_CONTROL ``` --- ### Get object tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/get-object-tagging.md # GetObjectTagging [GetObjectTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html) ## Example GetObjectTagging request ```bash GET /mybucket/myobject?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: private X-Amz-Date: 20230927T180458Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date, Signature=655002dff20fc340dcfb66b4e06595ddfe950b9e091992f4c82ac0777b42ff8e ``` ## Example GetObjectTagging response ```xml dimention_1 value_1 dimention_2 value_2 ``` --- ### Head object > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/head-object.md # HeadObject [HeadObject - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) **✅ Supported Headers** - `If-Match` - `If-Modified-Since` - `If-None-Match` - `If-Unmodified-Since` - `Range` ## Example HeadObject request ```bash HEAD /mybucket/myobject HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T164456Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=d198d5440102737bd0dc5753ce6e5a843a673779ece724acd84ae08aedfe8297 ``` ## Example HeadObject response ```bash HTTP/1.1 200 OK accept-ranges: bytes content-length: 22905 content-type: image/png date: Wed, 27 Sep 2023 16:47:00 GMT etag: "2da8bc8e8133ec2af9268515aae59e7a" last-modified: Wed, 27 Sep 2023 15:23:52 GMT x-amz-meta-author: john x-amz-request-id: tx00000b6702bae22c9729e-0065145c84-e3bf-fl1 x-amz-storage-class: STANDARD x-rgw-object-type: Normal server: Telnyx API ``` --- ### List object versions > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/list-object-versions.md # ListObjectVersions [ListObjectVersions - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectVersions.html) **✅ Supported Parameters** - `prefix` - `delimiter` - `marker ` - `max-keys` ## Example ListObjectVersions request ```bash GET /versionedbucket?versions=null HTTP/1.1 Host: [region].telnyxcloudstorage.com Accept: application/octet-stream X-Amz-Date: 20230927T170348Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=accept;host;x-amz-date, Signature=15c5f0d8404b4e43153138818ca4cd0895c6a0bd4b94173bb6080a71f41bc49f ``` ## Example ListObjectVersions response ```xml versionedbucket 1000 false versionedobject X04kXxTyoh1YjplIl647teiNbL0foEN true 2023-09-27T17:01:09.522Z "22472751e76c3a57583d89785e2330e4" 279010 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal versionedobject IWv2xkiXwOQvN1RClOuCeJZKKFIjjc7 false 2023-09-27T17:00:51.542Z "2da8bc8e8133ec2af9268515aae59e7a" 22905 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal versionedobject Hmvl0sI98e-m9fyFZW23gC2vz2hODKC false 2023-09-27T17:00:22.591Z "0e43168b1e60136a3d4292c54763d449" 27761 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal versionedobject_xxx TUKc1O3XHubZcxH9Wo.MPaddPsJY7Wi true 2023-09-27T17:03:44.249Z "22472751e76c3a57583d89785e2330e4" 279010 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal ``` --- ### List objects > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/list-objects.md # ListObjects [ListObjects - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html) **✅ Supported Parameters** - `prefix` - `delimiter` - `marker ` - `max-keys` ## Example ListObjects request ```bash GET /mybucket?prefix=myobject HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T154626Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=b77c8c94d8f0bd0913708ae7da0fbac552d14a6f2b8853b6e297a12127156e38 ``` ## Example ListObjects response ```xml mybucket myobject 1000 false myobject 2023-09-27T15:23:52.668Z "2da8bc8e8133ec2af9268515aae59e7a" 22905 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal myobject_2 2023-09-27T15:44:06.670Z "0e43168b1e60136a3d4292c54763d449" 27761 STANDARD 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 Normal ``` --- ### Put object > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/put-object.md # PutObject [PutObject - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) **✅ Supported Headers** `x-amz-acl` - `private` - `public-read` `x-amz-storage-class` - `STANDARD` `x-amz-meta-*` `x-amz-server-side-encryption-customer-algorithm` `x-amz-server-side-encryption-customer-key` `x-amz-server-side-encryption-customer-key-MD5` ```bash PUT /mybucket/myobject HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-storage-class: STANDARD x-amz-acl: private x-amz-meta-author: john Content-Type: image/png X-Amz-Date: 20230927T152352Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=f1a15846adc6247727c0dcfbb738d8ee4463527023e7818bf128866944981dea Content-Length: 22 "" ``` --- ### Put object ACL > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/put-object-acl.md # PutObjectACL **Warning:** Only verified users can update bucket policy. To request KYC on your account, go to [Portal Account Verifications](https://portal.telnyx.com/#/app/account/verifications) [PutObjectAcl - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html) **✅ Supported Headers** `x-amz-acl` * `private` * `public-read` `versionId` ## Example PutObjectACL request ```bash PUT /mybucket/myobject?acl=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: public-read X-Amz-Date: 20230927T175633Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date, Signature=71b70f25be863194c5d573fdf09ea02139af3cbcaa5e16dc53a0f30d41f7311a ``` --- ### Put object tagging > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/object-operations/put-object-tagging.md # PutObjectTagging [PutObjectTagging - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html) **✅ Supported Headers** - `versionId` ## Example PutObjectTagging request ```bash PUT /mybucket/myobject?tagging=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: private Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T180401Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-acl;x-amz-content-sha256;x-amz-date, Signature=cd6f3a0350f531a0bc89cfc145463f963fc967bcaeef2ae9d68490cee01ed8af Content-Length: 271 dimention_1 value_1 dimention_2 value_2 ``` --- ### Abort multipart upload > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/abort-multipart-upload.md # AbortMultipartUpload [AbortMultipartUpload - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html) **✅ Supported Parameters** - `uploadId` ## Example AbortMultipartUpload Request ```bash DELETE /publicbucket/mymultiloader?uploadId=2~vl8z2yj8-4JWQiQJZ1XiS-gUY9sIkcH HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T161834Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=9f9271ad23f0d4da20bb880962c217fe6c5b56731bacf96a895da12abeb7fca4 ``` --- ### Complete multipart upload > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/complete-multipart-upload.md # CompleteMultipartUpload [CompleteMultipartUpload - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html) **✅ Supported Parameters** - `uploadId` **✅ Supported XML element** - ` Etag``PartNUmber ` ## Example CompleteMultipartUpload request ```bash POST /publicbucket/mymultiloader_1?uploadId=2~3Y81uRI7FdyjpBLwnWlT_twccOWO5BB HTTP/1.1 Host: [region].telnyxcloudstorage.com Content-Type: application/xml X-Amz-Content-Sha256: beaead3198f7da1e70d03ab969765e0821b24fc913697e929e726aeaebf0eba3 X-Amz-Date: 20230927T162813Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-content-sha256;x-amz-date, Signature=b2cdd3c55ecfddc4f9f8773984b8ce2754672f8c3740fcc65feadae8d8905b94 Content-Length: 348 1 "df38b7a75236d2b16ce24c6f770b2615" 2 "df38b7a75236d2b16ce24c6f770b2615" ``` ## Example CompleteMultipartUpload response ```xml [region].telnyxcloudstorage.com/publicbucket/mymultiloader_1 publicbucket mymultiloader_1 ``` --- ### Create multipart upload > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/create-multipart-upload.md # CreateMultipartUpload [CreateMultipartUpload - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html) **✅ Supported Headers** `x-amz-acl` - `private` - `public-read` `x-amz-storage-class` - `STANDARD` ## Example CreateMultipartUpload request ```bash POST /publicbucket/mymultiloader?uploads=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: public-read x-amz-storage-class: STANDARD X-Amz-Date: 20230927T155204Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date;x-amz-storage-class, Signature=c4b61aa3aa192e1e569c5c6c458138b11f098cbbaaac9f7c88afeb37aa7500ef Content-Type: text/plain Content-Length: 22 "" ``` ## Example CreateMultipartUpload response ```xml publicbucket mymultiloader 2~vl8z2yj8-4JWQiQJZ1XiS-gUY9sIkcH ``` --- ### List multipart uploads > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/list-multipart-uploads.md # ListMultipartUploads [ListMultipartUploads - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html) **✅Supported Parameters** - `prefix` - `delimiter` - `key-marke` - `max-keys` - `max-uploads` - `upload-id-marker` ## Example ListMultipartUploads request ```bash GET /publicbucket?uploads=null HTTP/1.1 Host: [region].telnyxcloudstorage.com x-amz-acl: public-read x-amz-storage-class: STANDARD X-Amz-Date: 20230927T162150Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-acl;x-amz-date;x-amz-storage-class, Signature=3475df7d1f022226a816241819edc7a152691dc99f018f49a3a5023aed6da467 ``` ## Example ListMultipartUploads response ```xml publicbucket mymultiloader_2 2~xbDHpXAq1dlmdGM7Kuj7mL9gPDCYuZx 1000 false mymultiloader_1 2~3Y81uRI7FdyjpBLwnWlT_twccOWO5BB 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 STANDARD 2023-09-27T16:21:50.208Z mymultiloader_2 2~xbDHpXAq1dlmdGM7Kuj7mL9gPDCYuZx 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 STANDARD 2023-09-27T16:21:50.208Z ``` --- ### Upload parts > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/upload-part.md # UploadPart [UploadPart - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html) **✅Supported Parameters** - `partNumber` - `uploadId` ## Example UploadPart request ```bash PUT /publicbucket/mymultiloader?partNumber=1&uploadId=2~vl8z2yj8-4JWQiQJZ1XiS-gUY9sIkcH HTTP/1.1 Host: [region].telnyxcloudstorage.com Content-Type: image/png X-Amz-Date: 20230927T155504Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=7c96230e5ac9b1a3d9fdf95349c5eaadc78157b16321dcc5355727faf8aa1132 Content-Length: 22 "" ``` --- ### List parts > Source: https://developers.telnyx.com/docs/cloud-storage/api-reference/multipart-operations/list-parts.md # ListParts [ListParts - Amazon Simple Storage Service](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html) **✅ Supported Parameters** - `uploadId` - `max-parts` - `part-number-marker` ## Example ListParts request ```bsh GET /publicbucket/mymultiloader?uploadId=2~vl8z2yj8-4JWQiQJZ1XiS-gUY9sIkcH HTTP/1.1 Host: [region].telnyxcloudstorage.com X-Amz-Date: 20230927T160734Z Authorization: AWS4-HMAC-SHA256 Credential=YOUR_TELNYX_API_KEY/20230927/test/execute-api/aws4_request, SignedHeaders=host;x-amz-date, Signature=c2224c5a6a794e0e41f6aa962ab72f0fc2ccb9156b946d22fdb106dd1f95586b ``` ## Example ListParts response ```xml publicbucket mymultiloader 2~vl8z2yj8-4JWQiQJZ1XiS-gUY9sIkcH STANDARD 0 4 1000 false 27784a49-1f14-4209-a58d-27fe905efe58 27784a49-1f14-4209-a58d-27fe905efe58 2023-09-27T15:55:04.138Z 1 "2da8bc8e8133ec2af9268515aae59e7a" 22905 2023-09-27T15:55:30.828Z 2 "2da8bc8e8133ec2af9268515aae59e7a" 22905 2023-09-27T15:55:35.044Z 3 "2da8bc8e8133ec2af9268515aae59e7a" 22905 2023-09-27T15:55:38.630Z 4 "2da8bc8e8133ec2af9268515aae59e7a" 22905 ``` --- ## API Reference (Storage) ### Presigned Object URLs - [Create Presigned Object URL](https://developers.telnyx.com/api-reference/presigned-object-urls/create-presigned-object-url.md): Returns a timed and authenticated URL to download (GET) or upload (PUT) an object. This is the equivalent to AWS S3’s “presigned” URL. Please note that Telnyx… ### Bucket SSL Certificate - [Get Bucket SSL Certificate](https://developers.telnyx.com/api-reference/bucket-ssl-certificate/get-bucket-ssl-certificate.md): Returns the stored certificate detail of a bucket, if applicable. - [Add SSL Certificate](https://developers.telnyx.com/api-reference/bucket-ssl-certificate/add-ssl-certificate.md): Uploads an SSL certificate and its matching secret so that you can use Telnyx's storage as your CDN. - [Remove SSL Certificate](https://developers.telnyx.com/api-reference/bucket-ssl-certificate/remove-ssl-certificate.md): Deletes an SSL certificate and its matching secret. ### Bucket Usage - [Get API Usage](https://developers.telnyx.com/api-reference/bucket-usage/get-api-usage.md): Returns the detail on API usage on a bucket of a particular time period, group by method category. - [Get Bucket Usage](https://developers.telnyx.com/api-reference/bucket-usage/get-bucket-usage.md): Returns the amount of storage space and number of files a bucket takes up. ### Data Migration - [List Migration Source coverage](https://developers.telnyx.com/api-reference/data-migration/list-migration-source-coverage.md) - [List all Migration Sources](https://developers.telnyx.com/api-reference/data-migration/list-all-migration-sources.md) - [Create a Migration Source](https://developers.telnyx.com/api-reference/data-migration/create-a-migration-source.md): Create a source from which data can be migrated from. - [Get a Migration Source](https://developers.telnyx.com/api-reference/data-migration/get-a-migration-source.md) - [Delete a Migration Source](https://developers.telnyx.com/api-reference/data-migration/delete-a-migration-source.md) - [List all Migrations](https://developers.telnyx.com/api-reference/data-migration/list-all-migrations.md) - [Create a Migration](https://developers.telnyx.com/api-reference/data-migration/create-a-migration.md): Initiate a migration of data from an external provider into Telnyx Cloud Storage. Currently, only S3 is supported. - [Get a Migration](https://developers.telnyx.com/api-reference/data-migration/get-a-migration.md) - [Stop a Migration](https://developers.telnyx.com/api-reference/data-migration/stop-a-migration.md)