cd /news/ai-agents/i-built-a-french-ai-voiceover-api-th… Β· home β€Ί topics β€Ί ai-agents β€Ί article
[ARTICLE Β· art-112793] src=dev.to β†— pub= topic=ai-agents verified=true sentiment=Β· neutral

I Built a French AI Voiceover API That Only Accepts Payment From Robots

A developer built a French text-to-speech API called voixoff that only accepts payment from AI agents, using the x402 protocol to make payment the authentication layer. The service, which launched with zero customers, charges under 10 cents per call and is designed for autonomous agents that hold wallets and need instant, machine-payable API access.

read9 min views2 publishedAug 27, 2026

Nobody signed up for my API. Nobody generated an API key. Nobody clicked "Subscribe." And that's by design β€” because the only customers I actually want are AI agents with a wallet and a job to do.

Let me back up.

If you've ever tried to monetize a small API, you know the funnel: landing page β†’ sign up β†’ verify email β†’ generate API key β†’ add a credit card β†’ hit a rate limit β†’ maybe, eventually, get paid a few cents per call. That funnel was built for humans. It makes no sense for a machine.

Increasingly, the "user" hitting your endpoint isn't a person filling out a form β€” it's an autonomous agent that decided, mid-task, that it needs a French voiceover for a video it's assembling, or a phone greeting for an IVR flow it's configuring for a client. That agent doesn't want to create an account. It doesn't have an email inbox to verify. It can't solve a CAPTCHA in any meaningful sense, and honestly, why should it have to? It has a wallet. It has stablecoins. It has a task with a deadline measured in seconds, not the three business days your KYC provider needs to approve a new merchant account.

So I built something that skips all of that: a pay-per-call French TTS API where the entire authentication layer is "did you pay for this specific request." No signup. No API key. No dashboard. Payment is the auth.

I'm building this in public and I want to be upfront: this launched with zero customers. No revenue to report, no growth chart, no "I made $X in a week" nonsense. This is an honest write-up of the architecture, the protocol, and the trade-offs β€” for other developers who might want to build something similar, or who are curious what machine-payable APIs actually look like in practice.

Back in 1997, HTTP/1.1's spec reserved status code 402 Payment Required and then... never defined what to do with it. It's sat there for almost three decades as the most famous unused corner of the HTTP spec.

The x402 protocol resurrects it for exactly the machine-to-machine payment problem I described above. The flow is deceptively simple:

402 Payment Required

with a JSON body describing exactly how much to pay, in what currency, to what address.No accounts. No sessions. No stored payment methods. Every single request carries its own proof of value. For a human this is mildly annoying β€” go get a wallet, buy some USDC, wait for a transaction to confirm. For an autonomous agent that already holds a wallet and treats USDC as a fungible resource, it's just... another tool call.

That asymmetry is the entire bet: x402 is a worse UX for humans and a better UX for machines than any existing payment rail. I wanted to build for the audience that rail is actually good for.

The service is called voixoff (French for "voiceover"), and it does one thing: turns text into French audio, on demand, per call, for pocket change. Three products:

Product Description Price
30s ad spot Short-form commercial voiceover $0.05 USDC
60s audiobook narration Longer narrative-style read $0.05 USDC
15s IVR / phone greeting Short phone-system prompt $0.03 USDC

Prices are deliberately, almost comically low β€” under 10 cents per call β€” because right now the entire goal is bootstrapping the first sales, not maximizing margin. When your marginal cost per generation is close to zero (more on that below), you can afford to give the market a reason to try you before you try to extract value from it.

Under the hood, the stack is unglamorous on purpose:

x402-voixoff

) keeping it alive on a cheap VPS8402

β€” yes, that's a deliberate nod to the 402 status codehttp://187.77.111.249:8402

That last point is an honest limitation, not a flex β€” I'll get to the full list of caveats later.

Here's the shape of the Flask route that gates generation. The first request (no payment proof) gets a 402 with everything the client needs to pay:

from flask import Flask, request, jsonify
import time

app = Flask(__name__)

WALLET_ADDRESS = "0x3f979b1203Fc3C3BBeAA73Dbec519C08c55dB074"
PRICES = {
    "pub": 0.05,        # 30s ad spot
    "audiobook": 0.05,  # 60s narration
    "ivr": 0.03,        # 15s phone greeting
}

seen_tx_hashes = set()  # anti-replay: never accept the same proof twice

@app.route("/generate", methods=["POST"])
def generate():
    body = request.get_json(force=True)
    product = body.get("type")
    proof = request.headers.get("X-Payment-Proof")

    if product not in PRICES:
        return jsonify({"error": "unknown product"}), 400

    if not proof:
        return jsonify({
            "error": "payment_required",
            "amount": PRICES[product],
            "currency": "USDC",
            "network": "base",
            "pay_to": WALLET_ADDRESS,
            "memo": f"voixoff:{product}:{int(time.time())}",
        }), 402

    if proof in seen_tx_hashes:
        return jsonify({"error": "payment_already_used"}), 402

    ok, reason = verify_onchain_payment(
        tx_hash=proof,
        expected_amount=PRICES[product],
        expected_recipient=WALLET_ADDRESS,
    )
    if not ok:
        return jsonify({"error": "payment_invalid", "reason": reason}), 402

    seen_tx_hashes.add(proof)
    audio_path = run_tts_pipeline(body.get("text"), product)
    return send_file(audio_path, mimetype="audio/mpeg")

And here's what the client-side handshake looks like from curl

, to make the two-step dance concrete:

bash
curl -s -X POST http://187.77.111.249:8402/generate \
  -H "Content-Type: application/json" \
  -d '{"type": "ivr", "text": "Bonjour, vous Γͺtes bien chez..."}'


curl -s -X POST http://187.77.111.249:8402/generate \
  -H "Content-Type: application/json" \
  -H "X-Payment-Proof: 0xabc123...realTxHash" \
  -d '{"type": "ivr", "text": "Bonjour, vous Γͺtes bien chez..."}' \
  --output greeting.mp3

### Why verify on-chain myself instead of using a facilitator

x402 implementations often delegate verification to a "facilitator" service that checks payments for you and returns a simple yes/no. I skipped that for now and verify directly against the Base RPC: fetch the transaction by hash, confirm the recipient address matches my wallet, confirm the USDC amount clears the price, and check the hash isn't already in my `seen_tx_hashes` set (that's the whole anti-replay mechanism β€” dead simple, and sufficient at single-process scale). 

The reason is mostly about reducing moving parts while I'm the only thing running this service: one fewer external dependency, one fewer thing that can silently drift out of sync with what's actually on-chain, and one fewer party that needs to be trusted. If volume ever justified it, a facilitator would be a reasonable trade of simplicity for offloaded verification work. At zero customers, that trade isn't worth making yet.

### Why per-call pricing instead of a subscription

The whole appeal of x402 is that a request can carry its own proof of payment with no persistent relationship to the server. A subscription reintroduces the exact thing I'm trying to avoid β€” an account, a billing cycle, a thing to log into. Fixed per-call pricing keeps the API stateless from the client's perspective: an agent that has never talked to this server before can pay, generate, and never come back, and the system works exactly the same as it would for a "regular" caller. That statelessness is the point.

## The generation pipeline

Once payment clears, the actual TTS work is almost anticlimactic β€” `edge-tts` does the heavy lifting for free, streaming neural audio in the requested French voice. But I didn't want to just pipe raw TTS output back to a paying caller (even a robot deserves quality control), so there's a small `ffmpeg`/` ffprobe` gate before anything gets returned:

- **Duration check** β€” does the output roughly match the promised product length (30s, 60s, 15s)?
- **Clipping detection** β€” `ffmpeg`'s `volumedetect` filter flags any sample hitting 0 dB
- **Silence detection** β€” catches generations that came back truncated or empty
- **Loudness normalization** β€” EBU R128 loudness metering, so a 15s IVR greeting isn't jarringly louder or quieter than the 30s ad spot next to it

Every demo in the catalog passed through this gate before going live. Cheap insurance for a product whose entire value proposition is "trustworthy enough that a machine will pay for it sight-unseen."

## The honest limitations

I said upfront this is zero-hype, so here's the actual state of things:

- **Zero customers so far.** This is freshly launched. I have no usage data, no revenue, nothing to report except that the code runs.
- **x402 adoption is early.** The pool of agents that actually know how to do this handshake is small. This is a bet on where things are going, not where they are.
- **Raw IP, no TLS, no domain.** `http://187.77.111.249:8402` is not a URL that inspires confidence, and it isn't supposed to yet β€” it's the address of a live experiment, not a finished product.
- **edge-tts is "good for free," not studio-grade.** It's a genuinely solid neural voice, reverse-engineered from Microsoft Edge's read-aloud feature, at zero marginal cost. It is not ElevenLabs. I don't have an ElevenLabs key, and their free tier explicitly forbids commercial use anyway, so this was a deliberate cost/quality trade, not an oversight.
- **The price experiment might just not work.** Under-10-cent pricing is a hypothesis, not a proven strategy. It might attract zero traffic just as easily as it might attract volume. I won't know until agents actually start calling it.

The upside of all those constraints: because the TTS engine is free and the VPS is nearly free, my margin per call is close to 100%. There's no unit economics problem to solve β€” the problem is entirely demand-side. That's a much better problem to have than a cost problem, but it's still a real one.

## What I'd do differently

If I were starting over, I'd put a domain and TLS cert in front of this before writing a single line of the payment gate β€” agents (and the humans configuring them) are going to be understandably wary of POSTing a payment proof to a bare IP over plain HTTP, and that's a fixable trust problem I created for myself by prioritizing the protocol logic first. I'd also consider exposing the x402 service description (`GET /`) in whatever emerging discovery format agents end up standardizing on, so this shows up in agent tool-registries rather than only being reachable if someone already has the URL.

For now, though, the protocol layer works, the generation pipeline works, and the whole thing runs for effectively $0 in infrastructure cost beyond the VPS I'd be paying for anyway. The next step is just getting a single agent, anywhere, to actually pay for a voiceover.

## Try it

- **API**: `http://187.77.111.249:8402` β€” `GET /` returns the service card (products, prices, wallet address); `POST /generate` starts the 402 handshake described above.
- **Portfolio / human-facing samples**: [voixoff-fr.surge.sh](https://voixoff-fr.surge.sh) β€” a static, zero-JS page with 9 audio samples across the three product types, hosted free on surge.sh, for anyone who wants to hear the voices before an agent does the paying.

If you're experimenting with agent wallets, x402, or machine-payable APIs of your own, I'd genuinely like to compare notes.
── more in #ai-agents 4 stories Β· sorted by recency
── more on @voixoff 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/i-built-a-french-ai-…] indexed:0 read:9min 2026-08-27 Β· β€”