Perslis Accessibility
02 / THE API

Five calls. That is the whole conversation.

If you can make an HTTP request, you can put a working AAC conversation inside your app this afternoon. Everything below is the complete surface — there is no second, harder API underneath it.

STEP 1

Open a session.

One session per conversation. It holds the languages, the reading level and the memory, and you keep its id for as long as you are talking.

# $TINKYSPEAK_API_URL is the endpoint we issue with your key.
curl $TINKYSPEAK_API_URL/v1/sessions \
  -H "Authorization: Bearer $TINKYSPEAK_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"language":"en","partnerLanguage":"en","profile":{"level":"sentence","choices":6}}'

{ "id": "sess_8f2c…", "choices": [], "history": [] }
STEP 2

Send what the other person said.

This is the only thing you ever have to send us. You do not send the person's own words, their history or their symbols — we already hold the thread.

curl $TINKYSPEAK_API_URL/v1/sessions/sess_8f2c…/hear \
  -H "Authorization: Bearer $TINKYSPEAK_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"text":"Would you like tea or coffee?"}'

What comes back is ready to draw. Each choice is a whole sentence, a short label for the tile, an emoji fallback and an id you select by:

{ "choices": [
    { "id": "ch_1", "label": "Tea",    "sentence": "I'd like tea, please.",    "emoji": "🍵" },
    { "id": "ch_2", "label": "Coffee", "sentence": "I'd like coffee, please.", "emoji": "☕" },
    { "id": "ch_3", "label": "Water",  "sentence": "Water, please.",           "emoji": "💧" }
  ] }
STEP 3

Draw them however you like.

This is your app. Three across, nine across, photographs, your own symbol set, a switch scanner, eye gaze — none of it is our business. We never fetch or draw anything. Use choice.id to tell us which one was chosen.

STEP 4

Deliver it, then tell us it happened.

We hand you the exact words and the language. Your voice engine speaks them, your screen shows them, your device does whatever it does — and then you report back, because only delivered words enter the memory.

// the person taps a tile in YOUR interface
POST /v1/sessions/ID/select        {"choiceId":"ch_1"}   → a draft
POST /v1/sessions/ID/speak         {"draftId":"…"}      → the exact words + language

// YOUR voice engine says them, then you report what happened
POST /v1/sessions/ID/confirm-speech {"speechId":"…","outcome":"spoken"}
STEP 5

Carry on.

Send the next thing the partner said and it continues from the words that were actually spoken. Nothing else to manage — no prompt to assemble, no history to ship back and forth.

YOUR SYMBOLS

Upload nothing. Point at what you already have.

There is no symbol upload, and that is deliberate: your artwork stays on your servers or in your app bundle, where you already version and licence it. You hand us nothing — you map a choice to your own library at render time.

// Your library, your rules. Called for every choice before you draw it.
function artworkFor(choice) {
  const hit = myLibrary.find(choice.label, choice.sentence);
  return hit ? { kind: 'symbol', library: 'my-set', id: hit.id, alt: hit.alt }
             : null;            // null → the emoji stays as a fallback
}

A choice carries its words and its identity; what it looks like is yours. Return null for anything your set does not cover and the emoji stays, so a gap in your library is never a blank tile. Changing artwork never changes which words get spoken.

EVERY ROUTE

The complete surface.

RouteWhat it does
POST /v1/sessionsStart a conversation. Set the two languages and the profile.
POST …/hearWhat the other person said. Returns the choices.
POST …/selectThe tile the person picked. Returns a draft.
POST …/composeThe person's own words instead of a choice.
POST …/speakTurn the draft into the exact words and language to deliver.
POST …/confirm-speechspoken, displayed, failed or cancelled.
POST …/scanPhotos from your camera. Returns tiles about what is in them.
POST …/more · /rejectAnother set of choices, or dismiss them.
POST …/profile · /languagesChange reading level, tile count or either language mid-conversation.
POST …/reset · DELETE …Clear the memory, or end the session.

Errors come back as {"error":{"code","message"}}. Selection, draft and speech ids are single-use, so a stale tap cannot deliver the wrong sentence. Two actions at once return 409 session_busy.

Get an API keyTry the board first
ContinueTry it

Everything Perslis