# EchoRelay — Integration Guide EchoRelay is a multi-tenant HTTP relay. A caller makes a single authenticated HTTP request to an EchoRelay endpoint; EchoRelay authenticates it, validates it, applies rate limiting and billing, then fans it out to one or more downstream HTTP targets — delivering each with at-least-once semantics, automatic retries with exponential backoff, and a dead-letter queue for permanent failures. This document is the complete reference for *calling* EchoRelay. Configuration of tenants, lines, endpoints, targets and API keys can be done through any of three equivalent surfaces: - **Panel** (humans): https://echorelay.dev - **REST API** (programmatic): https://api.echorelay.dev — `Authorization: Bearer er_mcp_…` - **MCP server** (AI agents): https://mcp.echorelay.dev — JSON-RPC, same tools as REST All three call into the same write services; what you do in one is visible in the other two. See https://docs.echorelay.dev/ for the full integrator docs. ## Concepts - **Tenant** — a customer account. Identified by a `slug` used in URLs (e.g. `acme`). - **Line** — a versioned API surface a tenant exposes, e.g. `v1`, `v2`. - **Endpoint** — a path under a line, e.g. `/webhook`. Each endpoint has its own API keys, optional validators and transformers, and one or more targets. - **Target** — a single downstream HTTP destination. An endpoint with multiple targets fans every incoming request out to all of them. ## The request flow ``` Caller ──POST──▶ EchoRelay endpoint ──▶ queue ──▶ targets (one HTTP call each) │ └─ authenticate · validate · rate-limit · bill · enqueue · 202 ``` EchoRelay accepts your request and returns `202` immediately. Delivery to the targets happens asynchronously — a `202` means "accepted and queued", not "delivered". ## Making a request ### URL ``` https://{tenant}.echorelay.cloud/{line}/{endpoint} ``` For example, tenant `acme`, line `v1`, endpoint `/webhook`: ``` https://acme.echorelay.cloud/v1/webhook ``` ### Method Use the HTTP method the endpoint is configured for (most relay endpoints use `POST`). ### Authentication Send the endpoint's API key as a Bearer token: ``` Authorization: Bearer ``` API keys are project-level — one key works on every endpoint in the project. Each key carries a mode: `live` debits the paid credit pool, `test` debits the testing pool (250 RPM cap, separate balance). Create / rotate / revoke via the panel, the REST API (`https://api.echorelay.dev/keys`), or MCP (`create_api_key` / `rotate_api_key` / `revoke_api_key`). A missing or unknown key results in `404`; a manually revoked key returns `401 key_revoked`; a key past its 24-hour grace returns `401 key_expired`. See https://docs.echorelay.dev/keys for the full lifecycle. ### Body Send your payload as the request body — typically JSON with `Content-Type: application/json`. The body is relayed to the targets; an endpoint may be configured with transformers that modify it before delivery. ## Responses ### Success — `202 Accepted` ```json { "status": "queued", "tenant": "acme", "line": "v1", "endpoint": "/webhook", "targets": 2, "requestId": "9B8C7F00-32D7-4835-B4B9-8F9CFB9628A6" } ``` - `targets` — how many downstream targets the request was fanned out to. - `requestId` — a unique id for this request; keep it for correlation and support. ### Errors EchoRelay uses a deliberately small set of status codes: | Status | Meaning | |--------|---------| | `402 Payment Required` | The tenant is out of prepaid credits. Top up to resume. | | `429 Too Many Requests` | The endpoint's rate limit was exceeded. Retry later. | | `404 Not Found` | Unknown tenant, line or endpoint — **or** a missing/invalid API key. | EchoRelay **never returns `401`**. An authentication failure is reported as `404`, so the existence of an endpoint is not revealed to unauthenticated callers. ## Fan-out An endpoint can have any number of targets. A single request you send is delivered to **every** target as an independent HTTP call. Each target is delivered, retried and dead-lettered independently — one slow or failing target does not affect the others. The `targets` count in the `202` response is how many deliveries your request created. ## Delivery & reliability Delivery is **at-least-once**: - A target returning `2xx` is considered delivered. - A target returning `5xx`, or failing to connect, is **retried** with exponential backoff (with jitter). - A target returning `4xx` is treated as a permanent failure and sent to the **dead-letter queue** — it is not retried. - After the configured maximum number of attempts, a request is moved to the dead-letter queue. Because delivery is at-least-once, **targets should be idempotent** — design them to tolerate the same request being delivered more than once. The `requestId` can be used to de-duplicate. ## Rate limits An endpoint can be configured with a rate limit — a number of requests per time window. Exceeding it returns `429`. Rate limits are per endpoint. ## Billing EchoRelay is prepaid: each accepted request consumes credits from the tenant's balance. When the balance reaches zero, requests are rejected with `402` until the tenant tops up. Pricing and top-ups are in the customer panel. ## Examples ### curl ```bash curl -X POST https://acme.echorelay.cloud/v1/webhook \ -H "Authorization: Bearer $ECHORELAY_API_KEY" \ -H "Content-Type: application/json" \ -d '{"event": "order.created", "id": "12345"}' ``` Response: ```json {"status":"queued","tenant":"acme","line":"v1","endpoint":"/webhook","targets":2,"requestId":"…"} ``` ### JavaScript / TypeScript ```ts const res = await fetch("https://acme.echorelay.cloud/v1/webhook", { method: "POST", headers: { Authorization: `Bearer ${process.env.ECHORELAY_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ event: "order.created", id: "12345" }), }); if (res.status === 202) { const { requestId, targets } = await res.json(); // accepted — queued for delivery to `targets` destination(s) } else if (res.status === 402) { // out of credits — top up the EchoRelay account } else if (res.status === 429) { // rate limited — back off and retry } ``` ## Managing configuration Tenants, lines, endpoints, targets, API keys, billing and usage are managed through any of three equivalent surfaces — see the top of this document for URLs. The data-plane API documented above is only for *calling* your configured endpoints; the management surface is separate (`api.echorelay.dev` / `mcp.echorelay.dev` / panel).