1. A 10-line proxy that holds your key

Browsers can call the API directly, but a key in a public page can be copied and spent by anyone. Put this in front of it (Cloudflare Worker shown; the same three steps work in a Next.js route, Express or a Firebase Function):

worker.js
// Your server keeps the key; the browser talks to /assess on your domain.
// Cloudflare Worker (or any fetch-capable runtime). 10 lines.
export default {
  async fetch(request, env) {
    if (request.method !== 'POST') return new Response('POST only', { status: 405 });
    const upstream = await fetch('https://api.toneperfect.app/v1/assess', {
      method: 'POST', body: await request.formData(),
      headers: { Authorization: `Bearer ${env.TONEPERFECT_API_KEY}`,
        'Idempotency-Key': request.headers.get('Idempotency-Key') || crypto.randomUUID(),
        'TonePerfect-Response': 'compact' } });
    return new Response(upstream.body, { status: upstream.status, headers: { 'Content-Type': 'application/json' } });
  },
};

2. One tag where the button goes

HTML
<div class="toneperfect-check" data-endpoint="https://your-site.example/assess"
     data-text="你好" data-language="zh-CN"></div>
<script src="https://api.toneperfect.app/static/embed.js" defer></script>

The script adds a record button, records with the browser's microphone, sends the recording to your endpoint, and shows the score with the words or syllables to review. For Mandarin it shows which tone was expected and which was heard. It is about 5 KB, has no dependencies and asks for the microphone only when the learner presses record.

3. What your learners see

  • An overall score from 0 to 100 and each word coloured by its score.
  • The units to review (for Mandarin: "tone: expected 3, heard 2").
  • A small "Powered by TonePerfect" link under the result. Please keep it; it is how other builders find us.

Cost

One credit per recording up to 15 seconds; failed or unassessable recordings are free. While you wire it up, put a test key (tp_test_…) in the proxy: it returns a fixed example result and spends nothing. The 50 free credits then cover real testing, then plans start at $10 for 2,500 recordings. Building a free tool for learners? Tell us about it at nik@toneperfect.app.

Styling and events

The widget uses a .toneperfect-check container and plain class names (.tp-record, .tp-score, .tp-word) so your CSS wins. It dispatches a toneperfect:result event with the compact result on the container, so you can save progress in your own app.