# Reletter API — full reference > The newsletter data API. Search 6M+ email newsletters, fetch metadata, contacts, social accounts and rankings, and search the full text of newsletter issues. Built for integration with apps and AI agents. This is the full API reference, optimized for LLM and agent consumption. For a shorter index, see [/llms.txt](/llms.txt). For the human-friendly portal, see [/developers](/developers). We also provide: - An official **Python client** and `reletter` CLI: `pip install reletter`. Source: https://github.com/getreletter/reletter-python - A remote **MCP server** at `https://mcp.reletter.com` for Claude, ChatGPT, Cursor, and any other MCP client. Source: https://github.com/getreletter/reletter-mcp --- ## API host **All API endpoints are on `https://api.reletter.com`, not `https://reletter.com`.** The apex domain serves the marketing site; hitting `reletter.com/api/...` will return an HTML 404. Every `/api/*` path in this document — including the unauthenticated `/api/payments/bundles/` and `/api/payments/buy/` bootstrap endpoints — must be prefixed with `https://api.reletter.com`. Quick verify: ```sh curl https://api.reletter.com/api/payments/bundles/ ``` --- ## Authentication All `/api/*` endpoints require the header: ``` x-reletter-api-key: YOUR_API_KEY ``` The two payment bootstrap endpoints — `GET /api/payments/bundles/` and `POST /api/payments/buy/` — are the only exceptions. They are unauthenticated because they exist to mint a key in the first place. There are two ways to get an API key: 1. **Sign up at https://reletter.com**, pick a plan, add the API add-on. Key appears in your account settings. This is the standard human flow with monthly billing. 2. **Pay with Stripe Shared Payment Tokens** programmatically — no signup, no human interaction. The agent posts to `POST https://api.reletter.com/api/payments/buy/`, gets back an HTTP 402 challenge, pays with an SPT, and the response contains an API key bound to a freshly-provisioned team. This is the agent-native flow described under "Pay-per-bundle" below. All responses are JSON over HTTPS. (Reminder: the host is `api.reletter.com`, not `reletter.com` — see "API host" above.) ## Pay-per-bundle (HTTP 402 / MPP) For AI agents that want to buy API access without going through a browser-based signup, Reletter implements the **Machine Payments Protocol** ([mpp.dev](https://mpp.dev), IETF draft `draft-ryan-httpauth-payment`). ### Flow 1. **Discover the catalogue** (no auth): ``` GET https://api.reletter.com/api/payments/bundles/ ``` Returns the live catalogue — request quotas, prices in USD cents, currency, and human-readable display strings. The catalogue is the source of truth for pricing; treat any prices in this doc as illustrative. Response shape: ```json { "bundles": [ {"quota": , "amount_cents": , "currency": "usd", "amount_display": "$X.XX", "description": "..."}, ... ], "purchase_endpoint": "/api/payments/buy/", "payment_methods": ["stripe", "tempo"] } ``` 2. **Request a purchase** for the tier you want, with no `Authorization` header: ``` POST https://api.reletter.com/api/payments/buy/ Content-Type: application/json {"quota": 5000} ``` The server replies `402 Payment Required` with **two** advertised settlement methods, comma-joined into one `WWW-Authenticate` header: ``` HTTP/1.1 402 Payment Required WWW-Authenticate: Payment id="...", realm="api.reletter.com", method="stripe", intent="charge", request="", expires="...", opaque="...", Payment id="...", realm="api.reletter.com", method="tempo", intent="charge", request="", expires="...", opaque="..." Content-Type: application/problem+json {"type":"https://paymentauth.org/problems/payment-required","title":"Payment Required","status":402,"detail":"...","challengeId":"..."} ``` Each `Payment ...` chunk is a complete challenge for one settlement method (named per the IETF MPP method registry): - `method="stripe"` — Shared Payment Token (card/wallet, synchronous one-shot) - `method="tempo"` — USDC on Tempo (async; agent gets a deposit address back and polls) Pick whichever your client supports. The Tempo path is what `mppx`, `pympp`, and `link-cli` speak natively. Both methods end up as a Stripe PaymentIntent in our balance — Stripe runs the chain monitoring for the Tempo path on our behalf. 3. **For the SPT path: mint an SPT** with your Stripe-side wallet for the bundle's amount and the seller's `networkId` (decoded from the challenge's `request` field). For the Tempo path: just retry with an empty payload — the server creates the PaymentIntent and gives you a deposit address. 4. **Retry with the credential**: ``` POST https://api.reletter.com/api/payments/buy/ Authorization: Payment Content-Type: application/json {"quota": 5000} ``` The credential JSON envelope (before base64url-encoding) is: ```json { "challenge": { /* echo every field from the WWW-Authenticate header */ }, "source": "your-agent-or-payer-id", "payload": { "spt": "spt_..." } } ``` `payload.spt` is the field name from the stripe.charge MPP method spec — what `mppx`, `link-cli`, and `pympp` send. The legacy aliases `sharedPaymentGrantedToken` and `shared_payment_granted_token` are also accepted. 5. **Receive your API key (SPT path: synchronous)**: ``` HTTP/1.1 200 OK Payment-Receipt: stripe:pi_<...> Content-Type: application/json { "api_key": "", "quota": 5000, "used": 0, "remaining": 5000, "expires_at": null, "bundle_id": 123, "payment_intent_id": "pi_...", "base_url": "https://api.reletter.com", "api_key_header": "x-reletter-api-key" } ``` **Tempo path (asynchronous):** the first retry returns `202 Accepted` with a deposit address: ```json { "status": "awaiting_funds", "payment_intent_id": "pi_...", "deposit_address": "0x...", "deposit_token": "0x20c0...", "deposit_network": "tempo", "amount": "", "currency": "usd" } ``` Send the funds on-chain. Then re-POST `/api/payments/buy/` with the **same challenge id** and `payload.paymentIntentId` set to the value from the 202. The server checks Stripe; if funds have confirmed, you get the same 200 + `api_key` shape as the SPT path. If still waiting, you get another 202 — poll until done. Use the returned `api_key` in the standard `x-reletter-api-key` header for all `/api/*` calls. Each call consumes one request from the bundle until it's exhausted. ### Edge cases - **Same SPT source buys again**: re-uses the same team and API key, just adds another bundle of quota. - **Bundle exhaustion**: subsequent `/api/*` calls return `400` with `code: "bundle_exhausted"` and a hint to buy another at `POST /api/payments/buy/`. - **Tampered or expired challenge**: `401 invalid_credential`. Refetch with a no-auth POST to get a fresh challenge. - **Unknown tier**: `400 unknown_tier`. Fetch `/api/payments/bundles/` for the catalogue. - **Recurring**: not currently supported. Stripe Shared Payment Tokens are one-shot — once redeemed, they auto-deactivate, and the cloned PaymentMethod can't be reattached for a Subscription. Each cycle would need a fresh SPT from the agent's wallet. Buy a new bundle when you need more quota; we'll add proper recurring once the right primitives exist. ### Receipt The `Payment-Receipt` response header on the success path carries the Stripe PaymentIntent ID. Verify it against your own Stripe records. ### Quickstart with Stripe link-cli Want to try it without writing code? Stripe ships a CLI that handles the SPT minting + 402 dance for you: ```bash # 1. Install + auth npm i -g @stripe/link-cli link-cli auth login # 2. Mint a sandbox SPT for a 5,000-request bundle link-cli spend-request create \ --merchant-name "Reletter" \ --merchant-url "https://api.reletter.com" \ --context "Buy 5,000 API requests" \ --amount 5900 \ --line-item "name:5k bundle,unit_amount:5900,quantity:1" \ --total "type:total,display_text:Total,amount:5900" \ --credential-type "shared_payment_token" \ --test --request-approval # capture the spend-request id (lsrq_...) # 3. Pay /api/payments/buy/ link-cli mpp pay https://api.reletter.com/api/payments/buy/ \ --spend-request-id lsrq_xxxxx \ --method POST \ --data '{"quota":5000}' ``` The response is JSON containing your `api_key`. Use it on `/api/*` calls in the standard `x-reletter-api-key` header. ## Errors Errors return an HTTP status code (4xx or 5xx) and a JSON body of the form: ```json { "error": "Human-readable message", "code": "machine_code_optional" } ``` Common codes: - `401` — `API key is unknown or inactive.` (invalid or missing key) - `400` `api_quota_exceeded` — Monthly request quota reached (subscription customers). - `400` `bundle_exhausted` — Pay-per-bundle quota used up. Buy another at `POST /api/payments/buy/`. - `429` `api_rate_limited` — Burst limit exceeded; back off and retry. - `401` `invalid_credential` — MPP credential is missing fields or doesn't echo a real challenge. Refetch with a no-auth POST to get a fresh challenge. - `402` `payment_declined` — Stripe declined the SPT redemption. - `400` — Various validation errors with a human-readable message. ## Quotas - **Monthly subscription customers**: 10,000 requests per calendar month, resets on day 1. - **Hourly burst**: 2,000 requests per team per hour, sliding window. - **Pay-per-bundle (MPP) customers**: bundle quota is total, not monthly. Drains on every API call until exhausted. To check your usage: ```bash curl -H "x-reletter-api-key: YOUR_API_KEY" \ https://api.reletter.com/api/accounts/quota/ ``` Response: ```json { "usage": 1284, "quota": 10000 } ``` --- ## Search ### `GET /api/search/publications/` Search the Reletter index for newsletters by topic, title or author. Supports rich filters for language, subscriber count, engagement, platform and more. See "Search filters" below for the full list. **Query parameters:** - `query` (string, required) — Search query. - `mode` (string, optional, default `topics`) — One of `topics`, `titles`, `authors`. - `page` (integer, default 1) — Page number. - `per_page` (integer, default 25, max 100) — Results per page. - `filters` (string, optional) — Comma-separated filters. Each filter is `name:operator:value`. Examples: `active:is:true`, `engagement:gte:50`, `subscribers:gte:5000`, `languages:any:en`, `platforms:any:substack-beehiiv-kit`. Maximum 20 filters per request. **Example:** ```bash curl -H "x-reletter-api-key: YOUR_API_KEY" \ "https://api.reletter.com/api/search/publications/?query=climate&mode=topics&filters=engagement:gte:50,subscribers:gte:5000,languages:any:en" ``` **Response:** ```json { "page": 1, "per_page": 25, "count": 124, "more": true, "spelling_suggestion": null, "exact_matches": [], "publications": [ { "id": "doomberg", "platform": "substack", "url": "https://newsletter.doomberg.com", "name": "Doomberg", "description": "A lateral-thinking approach to energy, finance, and geopolitics.", "founded": "2021-04-21T18:58:46Z", "subscribers": 373000, "est_subscribers": null, "est_subscribers_source": null, "engagement": 92, "language": "en", "issue_frequency": "twiceweekly", "publishing_model": "freemium", "num_issues": 496, "active": true, "sponsored": false, "seo_keyword_count": 5045, "seo_organic_etv": 234121 } ] } ``` `est_subscribers` and `est_subscribers_source` are populated for publications where the platform doesn't expose a precise count (e.g. some Beehiiv/Ghost/Kit newsletters); `est_subscribers_source` is one of `"self_reported"` or `"similarweb_modeled"`. For most Substack and LinkedIn newsletters `subscribers` is the live count and `est_subscribers` is `null`. `seo_keyword_count` and `seo_organic_etv` summarize how the publication ranks on Google search, refreshed every ~180 days. See "SEO reach" under the publication endpoint for the full keyword list. ### `GET /api/search/issues/` Full-text search across the body and titles of every newsletter issue Reletter has indexed. Returns highlighted snippets when `highlight=true`. Accepts the **same `filters` parameter as publication search** — filters apply to the parent publication, so you can scope issue search to e.g. issues from active English Substack newsletters with 5k+ subscribers. **Query parameters:** - `query` (string, required) — Search query. - `highlight` (boolean) — Include highlighted snippets. - `threshold` (integer) — Only include issues newer than this many seconds (max 14 days = 1209600). - `page` (integer, default 1). - `per_page` (integer, default 25, max 100). - `filters` (string, optional) — Same syntax and filter set as the publication search. Filters are evaluated against the parent publication. Example: `active:is:true,subscribers:gte:5000,languages:any:en`. See "Search filters" below. **Example:** ```bash curl -H "x-reletter-api-key: YOUR_API_KEY" \ "https://api.reletter.com/api/search/issues/?query=tariffs&highlight=true&filters=subscribers:gte:5000,languages:any:en" ``` **Response:** ```json { "page": 1, "per_page": 25, "count": 12, "more": false, "spelling_suggestion": null, "issues": [ { "id": "pdh-the-coal-paradox", "title": "The Coal Paradox", "contributors": ["Doomberg"], "published": "2026-04-22T13:01:00Z", "num_likes": 412, "num_comments": 28, "url": "https://newsletter.doomberg.com/p/the-coal-paradox", "image_url": "https://substackcdn.com/image/...", "type": "newsletter", "substack_slug": "the-coal-paradox", "substack_podcast_url": null, "beehiiv_slug": null, "kit_slug": null, "text": "... full body text ...", "highlight": { "title": null, "text": ["... rising coal demand ..."] }, "publication": { "id": "doomberg", "platform": "substack", "name": "Doomberg" } } ] } ``` For Beehiiv issues, `beehiiv_slug` is set and the others are `null`. For Kit issues, `kit_slug` is set and the others are `null`. The inverse holds for Substack issues. LinkedIn and Ghost issues have all platform-specific slugs as `null`. --- ## Search filters Both `/api/search/publications/` and `/api/search/issues/` accept the same `filters` query parameter. It's a comma-separated list of filters in the form `name:operator:value`. Filters combine with AND. Maximum 20 filters per request. Multi-value filters use a hyphen-separated list (max 25 values). Human-readable version: [/developers/search-filters](/developers/search-filters). ### Range filters (`gte`, `lte`) Numeric range filters. Combine `gte` and `lte` for a between-style range. | Filter | Underlying field | Notes | | ---------------- | --------------------- | --------------------------------------------------- | | `subscribers` | `subscribers` | Live or estimated subscriber count. | | `engagement` | `engagement` | Engagement score (0–100). | | `monthlyvisits` | `est_monthly_visits` | Estimated monthly site visits (Similarweb-modeled). | | `issues` | `num_issues` | Total issues published by the newsletter. | | `founded` | `founded` | Founding date as a Unix timestamp in seconds. | Examples: ``` subscribers:gte:5000 subscribers:gte:5000,subscribers:lte:250000 engagement:gte:75 monthlyvisits:gte:10000 issues:gte:100 founded:gte:1640995200 # founded on or after 2022-01-01 ``` ### Boolean filters (`is`) | Filter | Values | Notes | | ----------- | ----------------- | -------------------------------------------------- | | `active` | `true` / `false` | Newsletters that have published an issue recently. | | `sponsored` | `true` / `false` | Newsletters that accept sponsorships. | Examples: ``` active:is:true sponsored:is:true ``` ### Choice filters (`any`) Multi-value filters; values are hyphen-separated. #### `languages` ISO 639 language codes. Refer to `GET /api/misc/languages/` for the full list. Common codes: `en`, `es`, `fr`, `de`, `pt`, `it`, `nl`, `ja`, `zh-cn`, `zh-tw`. (`zhtw` and `zhcn` are accepted as aliases for `zh-tw` and `zh-cn`.) ``` languages:any:en languages:any:en-es-fr ``` #### `platforms` Allowed values: `substack`, `linkedin_newsletter`, `ghost`, `beehiiv`, `kit`. ``` platforms:any:substack platforms:any:substack-beehiiv-kit ``` #### `pubmodels` Publishing model. Allowed values: - `free` — fully free - `freemium` — free with a paid tier - `paid` — paid subscription required ``` pubmodels:any:free-freemium ``` #### `frequencies` Issue cadence. Allowed values: - `daily` - `twiceweekly` - `weekly` - `monthly` - `infrequently` ``` frequencies:any:daily frequencies:any:daily-weekly ``` ### Sort (`eq`) Pass a single `sort:eq:` filter to control ordering. Allowed values: - `subscribers_relevance` — default for publication search; balances relevance and subscriber count - `subscribers` — most subscribers first - `monthly_visits` — most estimated monthly visits first - `engagement` — highest engagement first - `issues` — most issues published first - `newest` — newest first (default for issue search with an empty query) - `oldest` — oldest first ``` sort:eq:subscribers ``` ### `GET /api/search/autocomplete/` Autocomplete suggestions for the start of a query. Designed for type-ahead UIs. **Query parameters:** - `query` (string, required) — Query prefix. - `mode` (string, required) — `topics`, `titles`, `authors`, `issues`. **Response:** ```json { "suggestions": [], "publications": [ { "id": "doomberg", "name": "Doomberg", "platform": "substack" }, { "id": "noahpinion", "name": "Noahpinion", "platform": "substack" } ] } ``` --- ## Publications ### `GET /api/publications//` Full metadata for a single publication: subscribers, engagement, social, contributors, rankings, latest issues, badges, about page text. **Query parameters:** - `exclude` (string, optional) — Comma-separated list of fields to drop from the response. Allowed: `subscribers`, `engagement`, `social`, `rankings`, `recommendations`, `badges`, `latest_issues`, `sponsored`, `est_monthly_visits`, `contributors.social`, `estimated_ad_cost`. Useful for slimming down responses. **Response:** ```json { "publication": { "id": "doomberg", "platform": "substack", "url": "https://newsletter.doomberg.com", "name": "Doomberg", "short_name": "Doomberg", "description": "A lateral-thinking approach to energy, finance, and geopolitics.", "artwork_url": "https://substackcdn.com/image/...", "founded": "2021-04-21T18:58:46Z", "subscribers": 373000, "est_subscribers": null, "est_subscribers_source": null, "added": "2023-02-08T12:45:40Z", "active": true, "language": "en", "engagement": 92, "sponsored": false, "estimated_ad_cost": { "min_cpm": 1000, "max_cpm": 3000, "min_cost": 373000, "max_cost": 1119000 }, "est_monthly_visits": 63308, "issue_frequency": "twiceweekly", "num_issues": 496, "publishing_model": "freemium", "contributors": [{ "id": "doomberg", "name": "Doomberg", "platform": "substack" }], "social": [{ "channel": "twitter", "identifier": "DoombergT", "followers": 162000 }], "rankings": [{ "platform": "substack", "category": "finance", "position": 4 }], "badges": ["top-100"], "latest_issues": [ { "id": "pdh-the-coal-paradox", "title": "The Coal Paradox", "published": "2026-04-22T13:01:00Z", "url": "https://newsletter.doomberg.com/p/the-coal-paradox" } ], "seo_keyword_count": 5045, "seo_organic_etv": 234121, "seo_keywords": [ { "keyword": "doomberg", "rank": 1, "search_volume": 4400, "etv": 1320 }, { "keyword": "doomberg substack", "rank": 1, "search_volume": 880, "etv": 264 }, { "keyword": "doomberg newsletter", "rank": 2, "search_volume": 320, "etv": 64 } ], "about": "... long-form publication about page ..." } } ``` `est_subscribers` is set instead of `subscribers` when the platform doesn't expose a precise count (some Beehiiv, Ghost and Kit newsletters). `est_subscribers_source` is one of `"self_reported"` or `"similarweb_modeled"`. #### SEO reach `seo_keyword_count`, `seo_organic_etv`, and `seo_keywords` describe how the publication ranks on Google search. Refreshed every ~180 days. Coverage is limited to the top ~10K publications by `est_monthly_visits`, `est_subscribers`, and `num_issues`. - `seo_keyword_count` (int, nullable) — Total ranked keywords across all SERP positions. `null` if the publication is not in the eligible set or has not been scraped yet. The total is **not** the length of `seo_keywords` (which is capped at 10). - `seo_organic_etv` (int, nullable) — Sum of estimated monthly visits across all ranked keywords. - `seo_keywords` (array, always present) — Up to 10 best-ranked keywords, sorted by `rank` ascending. Each entry has: - `keyword` (string) — The search query. - `rank` (int) — Google rank position, 1-indexed. - `search_volume` (int, nullable) — Monthly searches for the keyword. - `etv` (int, nullable) — Estimated monthly clicks for this keyword. `search_volume` and `etv` are independently nullable — treat as "unknown", not zero. `seo_keywords` is **always** an array (possibly empty), never `null`. A `seo_keyword_count` of `0` indicates the publication has been scraped but no ranked keywords were found. ### `GET /api/publications/?publication_ids=,,...` Batch lookup. Returns full metadata for up to 100 publications in one call. Pass IDs as a comma-separated `publication_ids` query string, or POST a JSON body `{"publication_ids": ["doomberg", "noahpinion"]}`. **Query parameters:** - `publication_ids` (string, required) — Comma-separated Reletter publication IDs (or POST as a JSON list). - `include` (string, optional) — Comma-separated extras: `social`, `email-contacts`, `contributors-social`. - `exclude` (string, optional) — Same field list as the single-publication endpoint. - `ignore_missing` (boolean) — If `true`, missing IDs are silently skipped instead of returning a 400. - `suggest` (boolean) — If `true`, include a `suggestions` array of similar publications. **Response:** ```json { "publications": [ /* same shape as single-publication response */ ], "suggestions": [ /* present when suggest=true */ ] } ``` --- ## Issues ### `GET /api/issues/?publication_id=` Recent issues for a given publication, in chronological order (newest first). Returns up to 100 issues. **Query parameters:** - `publication_id` (string, required). **Response:** ```json { "issues": [ { "id": "pdh-the-coal-paradox", "title": "The Coal Paradox", "contributors": ["Doomberg"], "published": "2026-04-22T13:01:00Z", "num_likes": 412, "num_comments": 28, "url": "https://newsletter.doomberg.com/p/the-coal-paradox", "image_url": "https://substackcdn.com/image/...", "type": "newsletter", "substack_slug": "the-coal-paradox", "substack_podcast_url": null, "beehiiv_slug": null, "kit_slug": null, "text": "... full body text ..." } ] } ``` ### `GET /api/issues//` Full data for a single issue, including the body text and the publication it belongs to. **Response:** ```json { "issue": { "id": "pdh-the-coal-paradox", "title": "The Coal Paradox", "contributors": ["Doomberg"], "published": "2026-04-22T13:01:00Z", "num_likes": 412, "num_comments": 28, "url": "https://newsletter.doomberg.com/p/the-coal-paradox", "image_url": "https://substackcdn.com/image/...", "type": "newsletter", "substack_slug": "the-coal-paradox", "substack_podcast_url": null, "beehiiv_slug": null, "kit_slug": null, "text": "... full body text ...", "publication": { "id": "doomberg", "platform": "substack", "name": "Doomberg", "subscribers": 373000 } } } ``` --- ## Contacts ### `GET /api/contacts/?publication_id=` Email contacts, social accounts, and contributor profiles for a publication. **Response:** ```json { "fetchable": false, "contacts": { "email": [ { "full_name": "Doomberg Editorial", "email": "editorial@doomberg.com", "category": "general", "verification_status": "valid" } ], "social": [ { "channel": "twitter", "identifier": "DoombergT", "url": "https://twitter.com/DoombergT", "added": "2023-02-08T12:45:40Z" } ], "contributors": [ { "id": "doomberg", "platform": "substack", "name": "Doomberg", "bio": "A lateral-thinking team writing on energy and markets.", "social": [], "owner": true } ] } } ``` --- ## Charts ### `GET /api/charts/` Index of available chart platforms and their categories. Use the returned slugs with `/api/charts///`. **Response:** ```json { "reletter": [{ "id": "top-50", "name": "Reletter Top 50", "variants": null }], "linkedin": [{ "id": "top-50", "name": "LinkedIn Top 50", "variants": null }], "substack": [ { "id": "top-50", "name": "Substack Top 50", "variants": null }, { "id": "finance", "name": "Finance", "variants": ["paid", "free"] } ] } ``` ### `GET /api/charts///` Chart rankings on a given platform / category. Each entry is a full publication dict, ordered by rank. **Query parameters:** - `variant` (string, optional) — `paid`, `free`, `rising`, etc. (where supported). **Response:** ```json { "name": "Finance", "platform": "substack", "variant": null, "publications": [ { "id": "doomberg", "platform": "substack", "name": "Doomberg", "subscribers": 373000, "engagement": 92 } ] } ``` --- ## Misc ### `GET /api/misc/languages/` Reference list of every language code recognized by the Reletter index. Use these codes with the `languages` search filter. **Response:** ```json { "languages": [ { "id": "en", "name": "English" }, { "id": "es", "name": "Spanish" }, { "id": "fr", "name": "French" } ] } ``` ### `GET /api/misc/stats/` Global Reletter index statistics. Cached for 24 hours. **Response:** ```json { "stats": { "publications": 7012345, "active_publications": 412345, "sponsored_publications": 38421, "issues": 41203456, "social_accounts": 624123 } } ``` --- ## Account ### `GET /api/accounts/quota/` Returns your current usage and quota for the calendar month. **Response:** ```json { "usage": 1284, "quota": 10000 } ``` --- ## Terms of use By using the Reletter API you agree that: 1. You will not use the API to build a product that competes directly with Reletter. 2. You will not resell direct API access. 3. You will not store API responses permanently on your servers. Short-term caching for performance is fine. Temporary storage for analysis or model inference is allowed. 4. We may revoke API access for any application that breaks these terms. 5. You can email support@reletter.com to discuss exemptions.