Unlimited TTS API for AI Agents

Overview

https://api.unlimitedtts.com is a paid text-to-speech API for AI agents and automated systems. It offers 3 independent payment flows, all priced from the same per-character rate: pay each request directly in USDC over x402 with no account, prepay a USDC balance and authorize each request with a signature, or fund prepaid card credits through Stripe Checkout.

This page is generated from the API's own contract. Read the canonical OpenAPI document, the agent guide, and the voice list at integration time — they are authoritative, and a client should read them rather than hardcode anything below.

Choose a payment flow

FlowEndpointsIdentityMinimum
Card credits GET /tts
POST /tts
GET/POST /top-up
GET /credits/:accountId
x-credit-account bearer token 500 cents per top-up; request debits can be sub-cent.
Direct x402 GET /x402/tts
POST /x402/tts
No API account or prepaid balance; the payment credential authorizes the request. No application minimum and no top-up. The only lower bound is one atomic USDC unit (0.000001 USDC).
Prepaid x402 POST /x402/deposit
GET /x402/accounts/:address
GET /x402/tts
POST /x402/tts
The payer's public EVM address. This is not a bearer token: spending requires an EIP-712 signature from that address on every request.

Pick one flow per request and do not mix them. /x402/tts never accepts x-credit-account, and /tts never reads x402 payment headers. Stripe funds card credits only; it is not an x402 top-up.

x402 Quick Start

  1. Read GET https://api.unlimitedtts.com/openapi.json for the current contract.
  2. Verify GET /.well-known/x402-service-metadata against a public key you pinned out of band. Never bootstrap trust from the challenge itself.
  3. Choose a model from GET /tts/models and a voice from GET /tts/voices.
  4. Send your JSON body to POST /x402/tts with no payment header.
  5. On 402, Base64-decode PAYMENT-REQUIRED and select a compatible entry from accepts.
  6. Pay with @x402/fetch, or sign the x402 v2 payload yourself.
  7. Retry the identical method, URL, query, and body with PAYMENT-SIGNATURE.
  8. Accept 200 audio/mpeg and keep PAYMENT-RESPONSE as the settlement receipt.

Network and settlement

Production settles the exact EVM scheme in USDC (six-decimal atomic units) on Base mainnet (eip155:8453) through https://facilitator.payai.network. Treat the challenge as the authority for network, asset, recipient, amount, and timeout; never hardcode the receiving address.

Payment Identifier and replay

Every paid PaymentPayload must carry the official x402 Payment Identifier extension. It is the idempotency key: persist the identifier alongside the exact request, the audio, and the receipt. If a response is lost in transit, replaying the identical paid request within 24 hours returns the original audio and receipt with no second charge and no second synthesis.

PAYMENT_OUTCOME_UNKNOWN is the one exception: it is not retryable. An agent must not construct and pay a replacement request without explicit human approval.

Raw x402 v2 payload

A manual client Base64-encodes this JSON into PAYMENT-SIGNATURE:

{
  "x402Version": 2,
  "accepted": {
    "...": "the complete selected PAYMENT-REQUIRED.accepts entry, copied unmodified"
  },
  "payload": {
    "signature": "0x...",
    "authorization": {
      "...": "scheme-specific exact-EVM authorization"
    }
  },
  "extensions": {
    "payment-identifier": { "id": "your-stable-16-to-128-char-id" }
  }
}

accepted and the Payment Identifier extension are both required. Top-level scheme and network fields are the legacy v1 shape and are not substitutes for accepted. A malformed or legacy envelope returns 400 INVALID_PAYMENT_PAYLOAD before any verification or synthesis.

Quoting without disclosing text

The direct flow sends your text in the unpaid request. If an agent must not disclose text before payment, quote by hash instead: POST /x402/tts/quote takes only the character length and a SHA-256 digest, and returns a signed quoteToken. Send {quoteToken} alone to get the challenge, then {quoteToken, text} with the payment.

A quote is a price, not a ticket: read expiresAt from the response rather than assuming a fixed lifetime, and note that within that lifetime the same token can be spent more than once — each spend is charged. Payment is what is consumed, not the token. The length-and-digest binding is enforced at synthesis, where a mismatch returns 400 QUOTE_BODY_MISMATCH and charges nothing.

Prepaid x402

Deposit once with POST /x402/deposit using the ordinary x402 challenge and paid retry. The balance is credited to the paying EVM address after the transfer reaches the required confirmation depth on Base mainnet. Afterwards, /x402/tts requests skip the facilitator entirely.

The balance is not a bearer token. Spending requires an EIP-712 PrepaidRequest signature from the owning address on every request, binding the method, path, body hash, maximum amount, nonce, and expiry. EOA signers only — EIP-1271 smart-account signatures are rejected, matching the exact scheme's EIP-3009 requirement.

Card Quick Start

  1. Choose a model and voice from GET /tts/models and GET /tts/voices.
  2. Send a request to POST /tts, or the GET /tts fallback.
  3. With no funded balance the API returns 402 carrying a topUpUrl.
  4. Open topUpUrl, complete Stripe Checkout, and save the returned x-credit-account value.
  5. Retry /tts with the x-credit-account header. Only the exact synthesis price is debited.
  6. For async jobs, poll /tts/jobs/:jobId and download from the returned link.
  7. Check the remaining balance at GET /credits/:accountId.

An individual debit can be far below one cent; the $5 minimum applies only to a funding transaction. Failed card-credit requests restore the exact debit to the balance. On Stripe Checkout, confirm the country selector matches the card's billing country — proxy geolocation often picks the wrong default.

Models & Voices

Model idNameMax charactersPrice per characterAvailable
openai/tts-1 OpenAI TTS-1 4096 $0.000018 Yes
openai/tts-1-hd OpenAI TTS-1 HD 4096 $0.000036 Yes

Voice ids

openai_alloy, openai_ash, openai_coral, openai_echo, openai_fable, openai_onyx, openai_nova, openai_sage, openai_shimmer

The default voice for openai/tts-1 is openai_alloy. Read GET /tts/voices?model=… for the current list per model.

Endpoints

Service

Service metadata.

MethodPathSummary
GET/Get service health and endpoint links.

Documentation

Machine-readable documentation endpoints.

MethodPathSummary
GET/docsGet the legacy machine-readable payment and agent guide.
GET/.well-known/x402-service-metadataGet signed x402 network, asset, payee, pricing, and rotation metadata.
GET/openapi.jsonGet the canonical OpenAPI 3.0.3 contract.

TTS

Text-to-speech operations.

MethodPathSummary
GET/tts/voicesList supported public voice ids and current pricing.
GET/tts/modelsList selectable TTS models, limits, voices, and current pricing.
POST/ttsSynthesize speech using prepaid card credits.
GET/ttsSynthesize speech using a GET fallback and prepaid card credits.
POST/x402/tts/quoteCreate a hash-bound x402 TTS quote without disclosing text.
POST/x402/ttsSynthesize speech using an exact per-request x402 USDC payment.
GET/x402/ttsSynthesize speech using a GET fallback and x402 USDC payment.

TTS jobs

Asynchronous TTS job polling and audio retrieval.

MethodPathSummary
GET/tts/jobs/{jobId}Get an asynchronous TTS job.
GET/tts/jobs/{jobId}/audioDownload audio for a completed asynchronous TTS job.

Card credits

Prepaid Stripe-funded credit accounts.

MethodPathSummary
GET/top-upOpen the Stripe Checkout top-up launcher.
POST/top-upCreate a Stripe Checkout Session.
GET/top-up/completeVerify a returned Stripe Checkout Session and credit the account.
GET/top-up/statusCheck whether a credit account is active after Checkout.
GET/credits/{accountId}Get the balance of a prepaid credit account.

x402 prepaid

Signature-authenticated prepaid USDC balances that remove facilitator and settlement latency from each request.

MethodPathSummary
POST/x402/depositFund a prepaid x402 balance with one confirmed USDC payment.
GET/x402/accounts/{address}Get a prepaid x402 balance.

Examples

Voice ids always use the provider_voice form; bare upstream names like nova are rejected.

x402: initial POST challenge

POST https://api.unlimitedtts.com/x402/tts
Content-Type: application/json

{
  "text": "Hello from an AI agent",
  "model": "openai/tts-1",
  "voice": "openai_alloy",
  "speed": 1
}

x402: paid POST retry — same method, same URL

POST https://api.unlimitedtts.com/x402/tts
Content-Type: application/json
PAYMENT-SIGNATURE: <base64-x402-v2-payment-payload>

{
  "text": "Hello from an AI agent",
  "model": "openai/tts-1",
  "voice": "openai_alloy",
  "speed": 1
}

x402: GET challenge, then the paid GET retry

GET https://api.unlimitedtts.com/x402/tts?text=Hello%20world&voice=openai_alloy

GET https://api.unlimitedtts.com/x402/tts?text=Hello%20world&voice=openai_alloy
PAYMENT-SIGNATURE: <base64-x402-v2-payment-payload>

x402: quote by hash without disclosing text

POST https://api.unlimitedtts.com/x402/tts/quote
Content-Type: application/json

{
  "textLength": 11,
  "textSha256": "<lowercase-sha256-hex-of-trimmed-utf8-text>",
  "model": "openai/tts-1",
  "voice": "openai_alloy"
}

Prepaid x402: signature-authenticated request

POST https://api.unlimitedtts.com/x402/tts
Content-Type: application/json
x-x402-account: <your-evm-address>
x-x402-nonce: <unique-per-request>
x-x402-expiry: <unix-seconds>
x-x402-max-amount: <micro-usd-ceiling>
x-x402-signature: <eip-712-signature>

{
  "text": "Hello world",
  "voice": "openai_alloy"
}

Card credits: synchronous POST

POST https://api.unlimitedtts.com/tts
Content-Type: application/json
x-credit-account: <your-account-uuid>

{
  "text": "Hello world",
  "model": "openai/tts-1",
  "voice": "openai_alloy",
  "speed": 1
}

Card credits: async job with no audio retention

POST https://api.unlimitedtts.com/tts?async=true&storeAudio=false
Content-Type: application/json
x-credit-account: <your-account-uuid>

{
  "text": "Hello world",
  "voice": "openai_alloy"
}

Pricing & Limits

These values change. Read GET /openapi.json and GET /tts/models rather than hardcoding them in a client.

Error codes

Errors return a structured body with a stable code. The full set:

CONFIG_ERROR, INVALID_JSON, INVALID_REQUEST, UNKNOWN_TTS_MODEL, INVALID_VOICE, INVALID_SPEED, TEXT_TOO_LONG, TTS_PROVIDER_NOT_CONFIGURED, INVALID_PAYMENT_PAYLOAD, INVALID_QUOTE, QUOTE_EXPIRED, QUOTE_BODY_MISMATCH, UNSUPPORTED_CONTENT_TYPE, PAYMENT_REQUIRED, PAYMENT_ERROR, PAYMENT_IDENTIFIER_CONFLICT, PAYMENT_REPLAY_PENDING, PAYMENT_OUTCOME_UNKNOWN, REPLAY_CACHE_UNAVAILABLE, RATE_LIMITED, NOT_FOUND, UNAUTHORIZED, JOB_NOT_READY, AUDIO_NOT_STORED, TTS_UPSTREAM_ERROR, TTS_UNAVAILABLE, INTERNAL_ERROR

Privacy & Storage

FAQ

Can an AI agent pay without creating an account?

Yes. The direct x402 flow pays each /x402/tts request in USDC with no API account, bearer token, checkout, prepaid balance, or top-up.

What network and token does x402 use?

Production uses USDC on Base mainnet (eip155:8453) with the x402 v2 exact EVM scheme. Always treat the PAYMENT-REQUIRED challenge as authoritative for the network, asset, recipient, amount, and timeout, and verify the signed service metadata against a pinned key before trusting a payee.

Does x402 require a Coinbase account?

No. The API requires no Coinbase, CDP, or facilitator account. A buyer needs a compatible Base wallet holding USDC and an x402 v2 exact-EVM signer.

Can I use x402 without @x402/fetch?

Yes. @x402/fetch is an optional JavaScript convenience. Any client can implement the raw HTTP flow: read PAYMENT-REQUIRED, sign the selected challenge entry, and retry with a valid x402 v2 PaymentPayload carrying the required Payment Identifier extension in PAYMENT-SIGNATURE.

Does a paid GET retry become a POST?

No. Retry the identical method and URL. A GET challenge is paid with a second GET carrying PAYMENT-SIGNATURE; it never changes to POST.

What happens if the response is lost after I paid?

Replay the identical paid request with the same Payment Identifier within 24 hours. The API returns the original audio and settlement receipt without verifying, synthesizing, or charging again. Do not automatically retry PAYMENT_OUTCOME_UNKNOWN — that one requires explicit approval.

How does pricing work?

Every flow uses the same USD per-character rate for the selected model, rounded up to the nearest micro-dollar. openai/tts-1 is $0.000018 per character. The $5 minimum applies only to a card funding transaction, never to x402 or to an individual synthesis.

Is my text or audio stored?

Direct and prepaid x402 responses are synchronous and do not enter the async storage workflow. Card-credit async audio is retained temporarily by default; storeAudio=false disables that retention.