Getting started

Quickstart

Integrating Speechineer into a form you already have is a straightforward process. In this guide, you will configure a form in your workspace, create an Unsigned API key, add one button to talk to the form in your app, and speak your first values into it. Each step also names the page to read when you want more — a form defined in code, Signed keys behind a login, accounts and quotas — so you can treat this page as both the shortest path and a map of what else you can set up.

1. Create a workspace

Open Workspaces and create one for the piece of software you are integrating — an app, a service, a component. Everything you do next lives inside it: the forms, the API keys and signing keys, the accounts, and the limits, so that usage is reported per piece of software.

Note

You do not need one workspace per environment: development, staging and production share it and are told apart by their API keys.
The Workspaces page with the Create workspace button highlighted
Workspaces → Create workspace. One workspace per piece of software.

2. Create the form and publish a version

Open Forms and create a form.

The Forms page with the Create form and Import buttons highlighted
Forms → Create form, or Import a form you already have.

Add one field per input your form has, give every field a short prompt that says what to extract, then save. The only thing that must match your code is each field's id.

Warning

Recognized values come back keyed by the field id, and an id that matches nothing in your form fills nothing — silently.
The form editor with Add field, the Field ID input and Save highlighted
Add field, set the Field ID to the id your code uses, then save the version.

Alternatively, if you already have this form in your codebase, you can import it instead of retyping it: paste the prompt below into your AI coding agent together with the form — a component file, a screenshot, a schema — and it returns the import JSON with your real field ids; then click Import next to Create form and drop that JSON in.

text
You are converting an existing form into a Speechineer form-import JSON. The form is
whatever I give you as context: a screenshot, an HTML/JSX/Vue/Angular/Svelte template, a
form-library schema, a database table, or a description. If I gave you a repository, find
the form and read the real field names.

Return one JSON document per form: {"name": "...", "fields": [...]} — with per field:
- "field_id" (required): the identifier my application already uses for that field — the
  name/id attribute, the form-control key, the column name. Copy it EXACTLY, including
  camelCase; never tidy it into another style. It must start with a letter and contain
  only letters, digits or underscores. Only invent an id (from the label, snake_case)
  when I gave you no code.
- "label": the human name of the field.
- "type": one of text, textarea, email, phone, url, integer, float, checkbox, date, time,
  datetime, select, multiselect, slider. The control wins over the meaning: an
  <input type="range"> is a slider even when it counts something.
- "options": the exact stored values for select/multiselect (the value, not the display
  label) — required for those types, at least one. Otherwise null.
- "range": [min, max] for slider — required for it. Otherwise null.
- "code_defined_config": true ONLY when the values are not fixed at design time (options
  from my database, or that change per user or language). Still include representative
  options/range — the form is tested against them in the workspace; at runtime my code
  supplies the real ones. When torn, use false.

Do not include prompts in the JSON — the import carries the form's shape only; extraction
prompts are written in the workspace afterwards. Instead, list under the JSON one suggested
extraction prompt per field (one sentence: what to pull out and how to resolve what a
speaker says — units, formats, relative dates), for me to paste into the workspace.

Skip fields nobody would speak: passwords, one-time codes, card numbers, captchas, file
uploads. Name what you skipped. Make reasonable choices instead of asking questions, and
list the assumptions you made.

After saving, open the Engineer tab to write and test the prompts. A prompt is the instruction that tells extraction what to put in a field — "the caller's full name", "the appointment date, as a date" — and Engineer lets you speak against the form and watch what lands, before any code exists.

The Engineer tab, with the tab and a field's prompt highlighted
Engineer → Field prompts: write each field's prompt, then click the orb, speak and check what lands.

Finally, publish the version.

Warning

Only a published version serves sessions, and your code pins it by its key — a draft is never picked up by accident.
A form's header with the Publish (this version) button highlighted
Publish (this version) makes the version your code names available to sessions.

3. Create an API key

Open API keys and create a key.

The API keys page with the Create API key button highlighted
API keys → Create API key.

In the dialog, choose Unsigned. An Unsigned key rides in your frontend, which is what you want for development and for public pages where nobody is logged in anyway.

The key identifies your workspace in every call. When you later put a form behind a login, you will create a Signed key instead and mint short-lived tokens in your backend with a signing key.

The Create API key dialog with the Unsigned mode highlighted
Choose Unsigned for this quickstart.

4. Integrate the SDK

Install the package for your framework:

bash
npm install @speechineer/react

Then add one session and one button to your form. Use the switch to compare an example form as it is today with the same form once Speechineer is in — your markup renders exactly as before, because Speechineer never renders anything of its own.

With Speechineer
tsx
import { useForm } from "react-hook-form";
import { useSpeechToForm } from "@speechineer/react";
export function IntakeForm() {
const { register, handleSubmit, setValue } = useForm();
const voice = useSpeechToForm({
form: { source: "workspace", key: "spnr_a1b2c3d", version: "v1", language: "en" },
onFieldValue: (id, value) => setValue(id, value),
});
return (
<form onSubmit={handleSubmit(save)}>
<label>Full name <input {...register("full_name")} /></label>
<label>Email <input type="email" {...register("email")} /></label>
<label>Insurance
<select {...register("insurance")}>
<option>None</option><option>Public</option><option>Private</option>
</select>
</label>
<button type="submit">Save</button>
<button type="button" onClick={voice.isListening ? voice.stop : () => void voice.start()}>
{voice.isListening ? "Stop" : "Speak"}
</button>
</form>
);
}

added · changed — everything else is untouched.

Then create the client once, at the root of your app, with the API key from step 3 and the account of the current user. The framework you selected above is selected here as well.

tsx
// main.tsx — once, around your app.
import { SpeechineerProvider } from "@speechineer/react";

<SpeechineerProvider
  apiKey={import.meta.env.VITE_SPEECHINEER_API_KEY}             // the Unsigned API key
  account={{ key: currentUser.id, pseudonym: currentUser.name }} // who this end user is
>
  <App />
</SpeechineerProvider>

Note

The account the client names is the end user a session runs for — a stable id you choose, such as your user id or a tenant id, never a shared constant. Every unit consumed is attributed to it, and limits can be set per account. It is also what usage is tracked by in your Speechineer dashboard.

Warning

The field ids in the snippet — full_name, email and so on — are the ids of the workspace form you created in step 2. That is the whole contract between the two.

Additional information in

5. Test

You are ready to speak your first values into the form:

  1. Serve your app over HTTPS or on http://localhost.
  2. Press the button you added. The browser asks for the microphone once.
  3. Talk. The session connects, and finished values arrive one by one — a refined value replaces the earlier one.

Warning

Browsers only expose the microphone on a secure origin, so a LAN address such as http://192.168.… will not work.

Tip

You can also test the prompts without your app in the loop: the form's Engineer tab lets you speak against the same configuration and watch what lands.