This is the full developer documentation for EchoValue API # Introduction > echoValue API - lightweight backend utilities for freelancers and small projects **echoValue** is a set of lightweight backend utilities designed for freelancers and small projects. No server setup, no infrastructure to manage — just a token and an HTTP call. It provides two main services: * **Key-Value Store** — persist and retrieve string data organized in named groups * **Mail2Webhook** — receive emails at a dedicated address and forward them as JSON to your webhook Caution echoValue is not intended for sensitive data, large-scale applications, or as a replacement for production databases. ## Quick Start [Section titled “Quick Start”](#quick-start) **1. Generate a token** (free, includes 100 credits): ```sh curl 'https://api.echovalue.dev/token' -d 'token=new' # → a1b2c3d4e5f6g7h8i9j0... ``` **2a. Store and retrieve a value:** ```sh curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: YOUR_TOKEN' \ -d 'hello world' # → OK curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: YOUR_TOKEN' # → hello world ``` **2b. Or configure an email-to-webhook bridge:** ```sh curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: YOUR_TOKEN' \ -H 'Content-Type: application/json' \ -d '{"url":"https://yourdomain.com/webhook"}' # → OK # Emails sent to YOUR_TOKEN@hook.echovalue.dev now POST to your URL ``` ## Services [Section titled “Services”](#services) | Service | Description | | -------------------- | ------------------------------------------------------------------------------- | | **Key-Value Store** | Store, retrieve, and delete key-value pairs organized in groups | | **Mail2Webhook** | Receive emails at `@hook.echovalue.dev` and forward them to your webhook | | **Logs** | Inspect your recent API call history | | **Token Management** | Check your credit balance and recharge | ## Pricing [Section titled “Pricing”](#pricing) All operations consume credits from your wallet. New tokens include **100 free credits**. | Operation | Cost | | -------------------- | --------------------------- | | Generate token | Free (100 credits included) | | Check wallet balance | 1 credit | | Get recharge link | Free | | Set key/value | 1 credit | | Get key/value | 1 credit | | Delete key/value | 1 credit | | Configure webhook | 1 credit | | Get webhook config | 1 credit | | Delete webhook | 1 credit | | Email processed | 1 credit | | Logs | 1 credit per entry returned | ## LLM Access [Section titled “LLM Access”](#llm-access) This documentation is available in machine-readable format for AI assistants and LLMs: * [`/llms.txt`](https://docs.echovalue.dev/llms.txt) — index of all documentation pages * [`/llms-full.txt`](https://docs.echovalue.dev/llms-full.txt) — full documentation in a single file ## Limits [Section titled “Limits”](#limits) | Constraint | Value | | -------------------------------- | --------------------------- | | Max key/group name length | 30 characters | | Max value length | 1000 characters (\~1 KB) | | Max TTL | 2,592,000 seconds (30 days) | | Default TTL (if omitted) | 30 days | | Log retention | 7 days | | Token inactivity before deletion | 2 years | # Authentication > How to authenticate requests to the echoValue API using x-token header All API requests must include an `x-token` header with your API token. ```plaintext x-token: YOUR_TOKEN ``` Note Don’t have a token yet? Generate one for free on the [Token Management](/token/) page. ## Example [Section titled “Example”](#example) * cURL ```sh curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/kv/default/mykey', { headers: { 'x-token': 'mytoken' } }); ``` * Python ```python import requests requests.get('https://api.echovalue.dev/kv/default/mykey', headers={'x-token': 'mytoken'} ) ``` * PHP ```php ``` * Go ```go package main import "net/http" func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/kv/default/mykey", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} client.Do(req) } ``` ## Response Headers [Section titled “Response Headers”](#response-headers) Every API response includes these headers: | Header | Description | | ----------- | --------------------------------------------------- | | `x-cost` | Credits deducted from your wallet for this request | | `x-balance` | Credits remaining in your wallet after this request | Note Use `x-balance` to monitor your credit balance — it’s available on every response at no extra cost, making it more efficient than calling the balance endpoint separately. ## Error Responses [Section titled “Error Responses”](#error-responses) | Status | Meaning | | ---------------------- | ------------------------------------------------------- | | `401 Unauthorized` | The `x-token` header is missing or the token is invalid | | `402 Payment Required` | Your wallet has no credits remaining | See the [Errors](/errors/) page for the full list of error codes. # Errors > HTTP error codes returned by the echoValue API The API uses standard HTTP status codes. Error responses are returned as plain text with a short description. **Example error response:** ```plaintext Key Not Found ``` Note Requests that result in errors are still counted as API calls and consume credits, to prevent misuse. ## 4xx Client Errors [Section titled “4xx Client Errors”](#4xx-client-errors) | Code | Name | When it occurs | | ----- | ------------------ | ------------------------------------------------------- | | `400` | Bad Request | The request is malformed or missing required parameters | | `401` | Unauthorized | The `x-token` header is missing or invalid | | `402` | Payment Required | Your wallet has no credits remaining | | `403` | Forbidden | You don’t have permission to access this endpoint | | `404` | Not Found | The key, webhook, or resource does not exist | | `405` | Method Not Allowed | The HTTP method is not supported for this endpoint | | `406` | Not Acceptable | The requested response format is not supported | | `418` | I’m a Teapot | — | | `429` | Too Many Requests | You have exceeded the rate limit | ## 5xx Server Errors [Section titled “5xx Server Errors”](#5xx-server-errors) | Code | Name | When it occurs | | ----- | --------------------- | ---------------------------------------------------- | | `500` | Internal Server Error | Unexpected server-side failure — try again later | | `501` | Not Implemented | Endpoint exists but is not yet available | | `503` | Service Unavailable | The service is temporarily offline — try again later | ## Common Scenarios [Section titled “Common Scenarios”](#common-scenarios) | Situation | Status code | | -------------------------------------- | ----------- | | Missing `x-token` header | `401` | | Token doesn’t exist | `401` | | No credits left | `402` | | GET on a key that was never set | `404` | | DELETE on a key that doesn’t exist | `404` | | GET webhook when none is configured | `404` | | Token generation faster than 1 req/10s | `429` | # Key-Value Store > Store, retrieve, and delete key-value pairs with the echoValue API The key-value store lets you persist string data organized in named groups. All operations require authentication via the `x-token` header. **Base URL:** `https://api.echovalue.dev/kv//` | URL Parameter | Description | Max length | | ------------- | ------------------------------------------- | ------------- | | `group` | Logical namespace for keys (e.g. `default`) | 30 characters | | `key` | Key identifier | 30 characters | *** ## Set Key/Value [Section titled “Set Key/Value”](#set-keyvalue) `POST https://api.echovalue.dev/kv//` Stores a value for the given key. If the key already exists, its value is overwritten. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Query parameters:** | Parameter | Type | Description | Default | | --------- | ------- | ------------------------------------------------------------ | ------- | | `ttl` | integer | Time-to-live in seconds. Min: `1`. Max: `2592000` (30 days). | 30 days | **Request body** (`text/plain`): The value to store. Max **1000 characters**. **Response:** `200 OK` ```plaintext OK ``` **HTTP status codes:** | Status | Meaning | | ------ | ------------------------- | | `200` | Value stored successfully | | `400` | Malformed request | | `401` | Invalid token | | `402` | Insufficient credits | | `429` | Rate limit exceeded | * cURL ```sh curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: mytoken' \ -d 'hello world' # With 30-second TTL curl 'https://api.echovalue.dev/kv/default/mykey?ttl=30' \ -H 'x-token: mytoken' \ -d 'hello world' ``` * JavaScript ```js fetch('https://api.echovalue.dev/kv/default/mykey', { method: 'POST', headers: { 'x-token': 'mytoken' }, body: 'hello world' }); // With 30-second TTL fetch('https://api.echovalue.dev/kv/default/mykey?ttl=30', { method: 'POST', headers: { 'x-token': 'mytoken' }, body: 'hello world' }); ``` * Python ```python import requests requests.post('https://api.echovalue.dev/kv/default/mykey', headers={'x-token': 'mytoken'}, data='hello world' ) # With 30-second TTL requests.post('https://api.echovalue.dev/kv/default/mykey?ttl=30', headers={'x-token': 'mytoken'}, data='hello world' ) ``` * PHP ```php ``` * Go ```go package main import ( "net/http" "strings" ) func main() { body := strings.NewReader("hello world") req, _ := http.NewRequest("POST", "https://api.echovalue.dev/kv/default/mykey", body) req.Header.Set("x-token", "mytoken") client := &http.Client{} client.Do(req) } ``` Note **Cost:** 1 credit *** ## Get Key/Value [Section titled “Get Key/Value”](#get-keyvalue) `GET https://api.echovalue.dev/kv//` Retrieves the stored value for a key. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Response:** `200` — The stored value as plain text. ```plaintext hello world ``` **HTTP status codes:** | Status | Meaning | | ------ | --------------------------------- | | `200` | Value returned | | `401` | Invalid token | | `402` | Insufficient credits | | `404` | Key does not exist or has expired | | `429` | Rate limit exceeded | * cURL ```sh curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/kv/default/mykey', { headers: { 'x-token': 'mytoken' } }) .then(response => response.text()) .then(data => console.log(data)); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/kv/default/mykey', headers={'x-token': 'mytoken'} ) print(response.text) ``` * PHP ```php ``` * Go ```go package main import ( "io" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/kv/default/mykey", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) println(string(body)) } ``` Note **Cost:** 1 credit *** ## Delete Key/Value [Section titled “Delete Key/Value”](#delete-keyvalue) `DELETE https://api.echovalue.dev/kv//` Deletes a key and its associated value. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Response:** `200 OK` ```plaintext OK ``` **HTTP status codes:** | Status | Meaning | | ------ | ------------------------ | | `200` | Key deleted successfully | | `401` | Invalid token | | `402` | Insufficient credits | | `404` | Key does not exist | | `429` | Rate limit exceeded | * cURL ```sh curl 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: mytoken' \ -X DELETE ``` * JavaScript ```js fetch('https://api.echovalue.dev/kv/default/mykey', { method: 'DELETE', headers: { 'x-token': 'mytoken' } }); ``` * Python ```python import requests requests.delete('https://api.echovalue.dev/kv/default/mykey', headers={'x-token': 'mytoken'} ) ``` * PHP ```php ``` * Go ```go package main import "net/http" func main() { req, _ := http.NewRequest("DELETE", "https://api.echovalue.dev/kv/default/mykey", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} client.Do(req) } ``` Note **Cost:** 1 credit # Logs > Retrieve API call history for your echoValue token ## Retrieve Logs [Section titled “Retrieve Logs”](#retrieve-logs) `GET https://api.echovalue.dev/token/logs` Returns a list of recent API calls made with your token. Logs have a TTL of 7 days and are deleted within 24 hours after expiration. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Query parameters:** | Parameter | Type | Description | Default | | --------- | ------- | -------------------------------------------- | ------- | | `n` | integer | Number of log entries to retrieve. Min: `1`. | `5` | **Response:** `200` — JSON object. ```json { "logs": [ { "id": "jd9kImh8U4In3odfNeKf", "method": "GET", "path": "/default/mykey", "error": "Key Not Found", "timestamp": "2023-12-07T12:14:16.124481Z", "expiration": "2023-12-14T12:14:16.12448Z", "cost": 1, "balance": 97 } ], "n": 1 } ``` | Field | Type | Description | | ------ | ------- | ----------------------------------- | | `n` | integer | Number of entries actually returned | | `logs` | array | Array of log entries | **Log entry fields:** | Field | Type | Description | | ------------ | ----------------- | --------------------------------------------------- | | `id` | string | Unique log entry ID | | `method` | string | HTTP method used (`GET`, `POST`, `DELETE`) | | `path` | string | API path called | | `error` | string | Error message, if any (omitted on success) | | `timestamp` | string (ISO 8601) | When the request was made | | `expiration` | string (ISO 8601) | When this log entry expires (7 days after creation) | | `cost` | integer | Credits deducted for that request | | `balance` | integer | Wallet balance after that request | **HTTP status codes:** | Status | Meaning | | ------ | -------------------- | | `200` | Logs returned | | `401` | Invalid token | | `402` | Insufficient credits | * cURL ```sh curl 'https://api.echovalue.dev/token/logs?n=5' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/token/logs?n=5', { headers: { 'x-token': 'mytoken' } }) .then(response => response.json()) .then(data => console.log(data)); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/token/logs', headers={'x-token': 'mytoken'}, params={'n': 5} ) print(response.json()) ``` * PHP ```php ``` * Go ```go package main import ( "encoding/json" "io" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/token/logs?n=5", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var result map[string]interface{} json.Unmarshal(body, &result) println(result) } ``` Note **Cost:** 1 credit per log entry returned (equal to the `n` value in the response). The actual number returned may be less than requested if fewer entries are available. # Mail2Webhook Service > Forward emails to your webhook URL using echoValue's Mail2Webhook service The Mail2Webhook service assigns each wallet a dedicated email address at `@hook.echovalue.dev`. Emails sent to that address are forwarded as JSON POST requests to your configured webhook URL. Each wallet supports one webhook configuration. *** ## Configure Webhook [Section titled “Configure Webhook”](#configure-webhook) `POST https://api.echovalue.dev/webhook` Creates or updates the webhook for your wallet (upsert). **Request headers:** | Header | Description | | -------------- | -------------------------- | | `x-token` | Your API token | | `Content-Type` | Must be `application/json` | **Request body** (`application/json`): | Field | Type | Description | Required | | --------- | ------ | ------------------------------------------------- | -------- | | `url` | string | Callback URL (must be HTTPS, publicly reachable) | Yes | | `headers` | object | Custom headers to include in the callback request | No | **Response:** `200 OK` ```plaintext OK ``` **HTTP status codes:** | Status | Meaning | | ------ | -------------------------------- | | `200` | Webhook saved | | `400` | Invalid URL or malformed request | | `401` | Invalid token | | `402` | Insufficient credits | * cURL ```sh curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken' \ -H 'Content-Type: application/json' \ -d '{"url":"https://yourdomain.com/webhook","headers":{"Authorization":"Bearer secret"}}' ``` * JavaScript ```js fetch('https://api.echovalue.dev/webhook', { method: 'POST', headers: { 'x-token': 'mytoken', 'Content-Type': 'application/json' }, body: JSON.stringify({ url: 'https://yourdomain.com/webhook', headers: { 'Authorization': 'Bearer secret' } }) }); ``` * Python ```python import requests requests.post('https://api.echovalue.dev/webhook', headers={ 'x-token': 'mytoken', 'Content-Type': 'application/json' }, json={ 'url': 'https://yourdomain.com/webhook', 'headers': { 'Authorization': 'Bearer secret' } } ) ``` * PHP ```php 'https://yourdomain.com/webhook', 'headers' => ['Authorization' => 'Bearer secret'] ]); $ch = curl_init('https://api.echovalue.dev/webhook'); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'x-token: mytoken', 'Content-Type: application/json' ]); curl_exec($ch); curl_close($ch); ?> ``` * Go ```go package main import ( "bytes" "encoding/json" "net/http" ) func main() { payload := map[string]interface{}{ "url": "https://yourdomain.com/webhook", "headers": map[string]string{"Authorization": "Bearer secret"}, } jsonData, _ := json.Marshal(payload) req, _ := http.NewRequest("POST", "https://api.echovalue.dev/webhook", bytes.NewBuffer(jsonData)) req.Header.Set("x-token", "mytoken") req.Header.Set("Content-Type", "application/json") client := &http.Client{} client.Do(req) } ``` Caution The webhook URL must be HTTPS and publicly reachable. Localhost and private IP addresses are not accepted. Note **Cost:** 1 credit *** ## Get Webhook Configuration [Section titled “Get Webhook Configuration”](#get-webhook-configuration) `GET https://api.echovalue.dev/webhook` Returns the current webhook configuration for your wallet. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Response:** `200` — JSON object. If a webhook is configured: ```json { "webhook": "https://yourdomain.com/webhook", "headers": { "Authorization": "" }, "email": "mytoken@hook.echovalue.dev", "hash": "a1b2c3d4e5f6..." } ``` If no webhook is configured, only `email` and `hash` are returned: ```json { "email": "mytoken@hook.echovalue.dev", "hash": "a1b2c3d4e5f6..." } ``` | Field | Type | Description | | --------- | ------ | ------------------------------------------------------------------ | | `webhook` | string | Your configured callback URL | | `headers` | object | Custom headers (values are redacted) | | `email` | string | The email address that triggers this webhook | | `hash` | string | SHA256 hash of your token — use this to identify incoming payloads | **HTTP status codes:** | Status | Meaning | | ------ | ---------------------- | | `200` | Configuration returned | | `401` | Invalid token | | `402` | Insufficient credits | * cURL ```sh curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/webhook', { headers: { 'x-token': 'mytoken' } }) .then(response => response.json()) .then(data => console.log(data)); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/webhook', headers={'x-token': 'mytoken'} ) print(response.json()) ``` * PHP ```php ``` * Go ```go package main import ( "fmt" "io" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/webhook", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } ``` Note **Cost:** 1 credit *** ## Delete Webhook [Section titled “Delete Webhook”](#delete-webhook) `DELETE https://api.echovalue.dev/webhook` Removes the webhook configuration from your wallet. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Response:** `200 OK` ```plaintext OK ``` **HTTP status codes:** | Status | Meaning | | ------ | --------------------- | | `200` | Webhook deleted | | `401` | Invalid token | | `402` | Insufficient credits | | `404` | No webhook configured | * cURL ```sh curl 'https://api.echovalue.dev/webhook' \ -H 'x-token: mytoken' \ -X DELETE ``` * JavaScript ```js fetch('https://api.echovalue.dev/webhook', { method: 'DELETE', headers: { 'x-token': 'mytoken' } }); ``` * Python ```python import requests requests.delete('https://api.echovalue.dev/webhook', headers={'x-token': 'mytoken'} ) ``` * PHP ```php ``` * Go ```go package main import "net/http" func main() { req, _ := http.NewRequest("DELETE", "https://api.echovalue.dev/webhook", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} client.Do(req) } ``` Note **Cost:** 1 credit *** ## Webhook Payload [Section titled “Webhook Payload”](#webhook-payload) When an email arrives at `@hook.echovalue.dev`, echoValue sends a `POST` request to your webhook URL with this JSON body: ```json { "externalMessageId": "", "receivedAt": "2026-04-04T09:21:35.218Z", "from": { "email": "john@gmail.com", "name": "John Snow" }, "to": { "hash": "a1b2c3d4e5f6..." }, "subject": "Alert: Server down", "text": "Server #3 is not responding", "html": "
Server #3 is not responding
", "headers": {}, "attachments": [ { "filename": "attachment.pdf", "contentType": "application/pdf", "size": 33380, "downloadUrl": "", "downloadUrlExpiresAt": "2026-04-04T09:26:35.218Z" } ] } ``` ### Payload Fields [Section titled “Payload Fields”](#payload-fields) | Field | Type | Description | | ------------------- | ----------------- | ---------------------------------------- | | `externalMessageId` | string | Unique identifier for the email message | | `receivedAt` | string (ISO 8601) | When the email was received | | `from` | object | Sender: `email` and optional `name` | | `to` | object | Recipient: `hash` (SHA256 of your token) | | `subject` | string | Email subject line | | `text` | string | Plain text body | | `html` | string | HTML body (if present) | | `headers` | object | Raw email headers as key-value pairs | | `attachments` | array | File attachments (empty array if none) | ### Attachment Fields [Section titled “Attachment Fields”](#attachment-fields) | Field | Type | Description | | ---------------------- | ----------------- | -------------------------------------- | | `filename` | string | Original filename | | `contentType` | string | MIME type | | `size` | integer | File size in bytes | | `downloadUrl` | string | Presigned URL to download the file | | `downloadUrlExpiresAt` | string (ISO 8601) | When the download URL expires (1 hour) | Note **Cost:** 1 credit per email processed (in addition to webhook operation costs). Note Use the `to.hash` field to verify that incoming webhook requests originate from echoValue without exposing your raw token. # OpenAPI Specification > Download and use the echoValue OpenAPI 3.0 specification The echoValue API is fully documented using the **OpenAPI 3.0** specification format. ## Download [Section titled “Download”](#download) 📥 **[Download openapi.yaml](/openapi.yaml)** ## View & Test Interactively [Section titled “View & Test Interactively”](#view--test-interactively) **Swagger UI:** [Open in Swagger UI](https://petstore.swagger.io/?url=https://docs.echovalue.dev/openapi.yaml) *** ## Use Cases [Section titled “Use Cases”](#use-cases) ### Generate Client SDKs [Section titled “Generate Client SDKs”](#generate-client-sdks) Use [OpenAPI Generator](https://openapi-generator.tech/) to generate client libraries: ```sh openapi-generator-cli generate \ -i https://docs.echovalue.dev/openapi.yaml \ -g javascript \ -o ./echovalue-client ``` Supported languages include Java, Ruby, PHP, C#, TypeScript, Rust, and [many more](https://openapi-generator.tech/docs/generators). ### Import into API Tools [Section titled “Import into API Tools”](#import-into-api-tools) | Tool | Steps | | ------------ | ---------------------------------------------- | | **Postman** | File → Import → Link → Paste OpenAPI URL | | **Insomnia** | Create → Import From → URL → Paste OpenAPI URL | | **Paw** | File → Import → Paste OpenAPI URL | | **HTTPie** | Import → OpenAPI → Paste OpenAPI URL | ### API Validation in Tests [Section titled “API Validation in Tests”](#api-validation-in-tests) ```js // Example with jest-openapi const jestOpenAPI = require('jest-openapi'); jestOpenAPI('https://docs.echovalue.dev/openapi.yaml'); test('GET /default/mykey returns valid response', async () => { const response = await fetch('https://api.echovalue.dev/kv/default/mykey', { headers: { 'x-token': 'mytoken' } }); expect(response).toSatisfyApiSpec(); }); ``` ### Mock Server [Section titled “Mock Server”](#mock-server) ```sh # Using Prism npx @stoplight/prism-cli mock \ https://docs.echovalue.dev/openapi.yaml # Mock server runs at http://127.0.0.1:4010 ``` *** The OpenAPI specification is automatically updated with each documentation release. Always use the latest version from: **** Note The specification is version-controlled alongside the documentation. Check the [GitHub repository](https://github.com/njoylab/docs.echovalue.dev) for the full history of changes. # Response Headers > Standard response headers returned by the echoValue API Every API response includes these headers: | Header | Type | Description | | ----------- | ------- | --------------------------------------------------- | | `x-cost` | integer | Credits deducted from your wallet for this request | | `x-balance` | integer | Credits remaining in your wallet after this request | Note `x-balance` is the most efficient way to monitor your balance — it’s included on every response at no extra cost, so you don’t need to call the balance endpoint separately. ## Reading Headers [Section titled “Reading Headers”](#reading-headers) * cURL ```sh # Use -i to show response headers curl -i 'https://api.echovalue.dev/kv/default/mykey' \ -H 'x-token: mytoken' # Output includes: # x-cost: 1 # x-balance: 99 ``` * JavaScript ```js fetch('https://api.echovalue.dev/kv/default/mykey', { headers: { 'x-token': 'mytoken' } }) .then(response => { console.log('Cost:', response.headers.get('x-cost')); console.log('Balance:', response.headers.get('x-balance')); return response.text(); }); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/kv/default/mykey', headers={'x-token': 'mytoken'} ) print('Cost:', response.headers.get('x-cost')) print('Balance:', response.headers.get('x-balance')) ``` * PHP ```php ``` * Go ```go package main import ( "fmt" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/kv/default/mykey", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() fmt.Println("Cost:", resp.Header.Get("x-cost")) fmt.Println("Balance:", resp.Header.Get("x-balance")) } ``` # Token Management > Generate, check balance, and recharge your echoValue API token ## Generate Token [Section titled “Generate Token”](#generate-token) `POST https://api.echovalue.dev/token` Generates a new API token. No authentication required. **Request body** (`application/x-www-form-urlencoded`): | Parameter | Value | Description | | --------- | ----- | -------------------------------- | | `token` | `new` | Must be the literal string `new` | **Response:** `200` — The new token as plain text. ```plaintext a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6 ``` * cURL ```sh curl 'https://api.echovalue.dev/token' \ -d 'token=new' ``` * JavaScript ```js fetch('https://api.echovalue.dev/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: 'token=new' }) .then(response => response.text()) .then(token => console.log(token)); ``` * Python ```python import requests response = requests.post('https://api.echovalue.dev/token', data={'token': 'new'} ) print(response.text) ``` * PHP ```php ``` * Go ```go package main import ( "io" "net/http" "strings" ) func main() { body := strings.NewReader("token=new") resp, _ := http.Post("https://api.echovalue.dev/token", "application/x-www-form-urlencoded", body) defer resp.Body.Close() token, _ := io.ReadAll(resp.Body) println(string(token)) } ``` Note New tokens include **100 free credits**. Note **Rate limit:** 1 request every 10 seconds. Caution Tokens unused for two years are automatically deactivated and all associated data is deleted. *** ## Check Wallet Balance [Section titled “Check Wallet Balance”](#check-wallet-balance) `GET https://api.echovalue.dev/token` Returns remaining credits and token metadata. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Response:** `200` — JSON object. ```json { "wallet": 12345, "created": "2023-08-09T15:40:09.77Z", "hash": "a1b2c3d4e5f6..." } ``` | Field | Type | Description | | --------- | ----------------- | --------------------------------------------------------------------------------- | | `wallet` | integer | Remaining credit balance | | `created` | string (ISO 8601) | Date when the token was created | | `hash` | string | SHA256 hash of your token — use this in webhook payloads instead of the raw token | * cURL ```sh curl 'https://api.echovalue.dev/token' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/token', { headers: { 'x-token': 'mytoken' } }) .then(response => response.json()) .then(data => console.log(data)); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/token', headers={'x-token': 'mytoken'} ) print(response.json()) ``` * PHP ```php ``` * Go ```go package main import ( "encoding/json" "io" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/token", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) var result map[string]interface{} json.Unmarshal(body, &result) println(result) } ``` Note **Cost:** 1 credit. For ongoing balance monitoring, use the `x-balance` response header instead — it’s available on every request at no extra cost. *** ## Recharge Wallet [Section titled “Recharge Wallet”](#recharge-wallet) `GET https://api.echovalue.dev/recharge` Returns a Stripe payment link to add credits to your wallet. **Request headers:** | Header | Description | | --------- | -------------- | | `x-token` | Your API token | **Query parameters:** | Parameter | Type | Description | Default | | --------- | ------ | ----------------------------------------------------------------- | ------- | | `amount` | string | Number of million operations to add. Accepted values: `1` or `3`. | `1` | **Response:** `200` — Stripe payment URL as plain text. ```plaintext https://buy.stripe.com/?client_reference_id=mytoken ``` * cURL ```sh curl 'https://api.echovalue.dev/recharge?amount=1' \ -H 'x-token: mytoken' ``` * JavaScript ```js fetch('https://api.echovalue.dev/recharge?amount=1', { headers: { 'x-token': 'mytoken' } }) .then(response => response.text()) .then(url => window.open(url)); ``` * Python ```python import requests response = requests.get('https://api.echovalue.dev/recharge', headers={'x-token': 'mytoken'}, params={'amount': '1'} ) print(response.text) ``` * PHP ```php ``` * Go ```go package main import ( "fmt" "io" "net/http" ) func main() { req, _ := http.NewRequest("GET", "https://api.echovalue.dev/recharge?amount=1", nil) req.Header.Set("x-token", "mytoken") client := &http.Client{} resp, _ := client.Do(req) defer resp.Body.Close() body, _ := io.ReadAll(resp.Body) fmt.Println(string(body)) } ``` Follow the returned URL to complete the payment. Note The card transaction will appear as **nJoyLab** on your statement.