smara.studio API v1
Home Studio Get an API key

Smara API

A real-time conversational avatar you embed with one script tag, and that can operate your website using actions you taught it by clicking, not by writing code.

One tag

The widget, its knowledge and its skills load from a single script element. No build step, no npm.

Metered, not unlimited

Session seconds, synthesis characters and tool actions are counted per key, with concurrency caps.

Teach by demonstration

Name an action in plain English, click the control that performs it. The avatar replays it for visitors.

Survives redesigns

Each step stores a ranked locator ensemble and a semantic fingerprint, and repairs itself when markup changes.


Quick start

Create a key in the Studio, then paste one tag before </body>.

HTML
<script src="https://www.smaralive.com/embed.js"
  data-api-key="sk_live_…"
  data-brand-name="Acme"
  data-accent-color="#F97316"
  data-position="bottom-right"
  data-greeting="Hi, ask me anything about this page."></script>

That tag is the whole install. It loads the skill runtime itself, so she can operate the page without you adding anything else, and the teach recorder is fetched only when you open your own page with a teach token, visitors never download it.

If you want her to talk but never click anything, turn the runtime off:

HTML
<script src="https://www.smaralive.com/embed.js"
  data-api-key="sk_live_…"
  data-actions="off"></script>

Authentication

There are three credential types, deliberately separated so a leak of one is not a leak of everything.

CredentialPrefixGrantsLifetime
API keysk_live_ / sk_test_ Sessions, reading skillsUntil revoked
Teach tokentk_ Authoring skills for one site. Cannot start sessions.1 hour
Operator tokenn/a Key management, usage across all sites1 hour

Send an API key or teach token as a header, or as ?key= on WebSocket connections where headers are impractical.

cURL
curl https://www.smaralive.com/v1/usage \
  -H "X-Smara-Key: sk_live_…"
Keys are stored as SHA-256 digests. The secret is returned exactly once, at creation. It cannot be recovered, if it is lost, revoke and issue a new one.

Errors

Every failure returns the same envelope. Branch on code, never on the message, messages are written for humans and will change.

422
{
  "error": {
    "code": "quota_exceeded",
    "message": "Monthly session seconds quota exhausted (3600 of 3600).",
    "type": "rate_limit_error",
    "details": { "used": 3600, "limit": 3600, "resets_in_sec": 419200 },
    "request_id": "3ea9d20ff3b94c01"
  }
}
CodeHTTPMeaning
missing_api_key401No key supplied
invalid_api_key401Unknown or revoked
api_key_disabled403Key exists but is switched off
quota_exceeded429Period quota spent. Retry-After is set
concurrency_exceeded429Too many simultaneous sessions
trial_exhausted403Anonymous demo already used
enforcement_unavailable503Usage could not be verified, so the request was refused rather than allowed
skill_exists409An action with that name is already taught
unresolved404A taught element no longer exists on the page
Enforcement fails closed. If the usage store is unreachable the API refuses rather than serving unmetered. Set SMARA_ENFORCEMENT=permissive to invert that in development only.

Embed attributes

AttributeDefaultNotes
data-api-keyn/aRequired. Without it the widget disables itself.
data-brand-nameSmara AIShown in the panel header.
data-accent-color#6366f1Any CSS colour.
data-positionbottom-rightbottom-left also supported.
data-size64Collapsed bubble size in pixels.
data-themedarklight also supported.
data-greetingemptySilent text bubble on first load.
data-fab-offset24Distance from the viewport edge.

First impression

A common request is for the avatar to greet visitors out loud the moment the page opens. It is worth knowing why that mostly does not work before choosing it.

Browsers block audio until the visitor interacts with the page. Chrome, Safari and Firefox all enforce this. An avatar that tries to speak on load is silent for most people, and still spends synthesis quota generating audio nobody hears.

ModeBehaviourRecommended
badgeSilent text bubble plus a soft pulse ring. Noticed without interrupting, and unaffected by autoplay policy.Yes, the default
offSits quietly until clicked.Low-friction pages
voiceAttempts speech on load.Only where arrival follows a click
What we suggest: show the silent badge on load, then speak the greeting on the visitor's first click or tap. That is the moment audio is permitted, and it converts a blocked autoplay into a greeting that is actually heard.

Voice and text

The widget opens in whichever mode the visitor last used, remembered per browser. Switching is non-destructive: the conversation is one thread, and moving between modes never clears it.

TransitionWhat happens
Text → voiceMicrophone permission is requested on the first attempt only. If denied, the widget stays in text mode and says so once rather than re-prompting.
Voice → textAny in-flight speech stops immediately, the mouth returns to rest, and the transcript remains.
InterruptionSpeaking while the avatar is talking cuts playback and starts listening, the same way people interrupt each other.
Tab hiddenFrames stop rendering and audio pauses, so a backgrounded tab does not burn session seconds.

Browser events

The widget emits DOM events so you can react without polling.

JavaScript
window.addEventListener('smara:tool_call', e => {
  // { action, args }, fired after a taught skill runs
  console.log(e.detail.action, e.detail.args);
});

// Programmatic control
window.Smara.open();
window.Smara.send('What is your return policy?');
window.Smara.onAction((action, args) => { /* … */ });

How skills work

A skill is recorded once by demonstration and replayed deterministically after that. The expensive reasoning happens at teach time, which runs once per site rather than once per visitor, that is what keeps runtime free and fast.

The model only ever chooses an action name from the taught list. It never receives selectors and never composes one from visitor input, so a visitor cannot talk the avatar into clicking something arbitrary.

What happens when your site changes

Each step stores a ranked ensemble of locators and a semantic fingerprint, and resolution walks tiers until one succeeds.

TierMethodTypical costTriggered by
-1Native platform API (Shopify, WooCommerce)0 ms, freeKnown platform
0Compiled locator~3 ms, freeNormal traffic
1Local semantic rematch against the fingerprint~15 ms, freeClass names or copy changed
2Server-side match, then written back~500 ms, onceLarger restructure
3Decline and flag for re-teachingn/aControl genuinely removed
Repairs are cached. A healed locator is written back to the skill, so the next visitor is served at tier 0 again. Healing costs once per site change, not once per visitor. If nothing resolves, the skill is withheld from the avatar entirely, it declines in words rather than clicking an approximate match on your storefront.

Endpoints

GET /v1/healthNo auth

Liveness plus which store and enforcement mode are active.

{ "status": "ok", "store": "RedisStore", "enforcement": "strict" }
GET /v1/sessionAPI key optional

Call before opening a socket so the widget can show an accurate state instead of discovering refusal mid-connection. With a key it returns quota; without one it returns the anonymous demo allowance.

{ "mode": "api", "site_id": "acme",
  "usage": { "session_seconds": 412.5, "tts_chars": 18320 },
  "remaining": { "session_seconds": 3187.5 },
  "max_concurrent": 3 }
GET /v1/usageAPI key

Current period usage against the key's limits.

GET /v1/skillsAPI key

The compiled plan the browser replays. Only enabled, non-broken skills are returned, one that stopped resolving is withheld until repaired rather than handed out to fail on every visitor.

POST /v1/skillsscope: skills:write

Normally called by the recorder rather than by hand.

{
  "action": "add_to_cart",
  "description": "Add a product to the cart",
  "steps": [{
    "action": "click",
    "locators": [
      { "strategy": "testid", "value": "add-to-cart" },
      { "strategy": "role_name", "value": "button|Add to Cart" }
    ],
    "fingerprint": { "role": "button", "name": "Add to Cart" }
  }],
  "requires_confirmation": false
}

Actions named checkout, pay, delete and similar are flagged for confirmation automatically, whatever this field says.

PATCH /v1/skills/:idscope: skills:write

Edit description, phrases, enabled state, or replace the steps. Supplying new steps resets the health counters, a re-taught skill starts clean.

DELETE /v1/skills/:idscope: skills:write

Returns 204.

POST /v1/skills/reportAPI key

The browser reports whether a replay worked. Without this the system cannot know your site changed until someone complains; with it, a degraded skill surfaces the first time it misses.

{ "skill_id": "skl_…", "ok": false,
  "error": "step 0 (click) could not be resolved" }
POST /v1/skills/healAPI key

Writes back a repaired locator, inserted at the front of the ensemble with the originals kept behind it in case a redesign is reverted.

GET /v1/skills/healthAPI key

Counts and a needs_attention list. This is what the Studio's attention panel renders.

Operator

POST /v1/admin/token?secret=

Exchanges the bootstrap secret for a one-hour operator token, so the Studio never holds a long-lived credential.

GET /v1/admin/keysoperator

Key records without hashes. Digests never leave the server.

POST /v1/admin/keysoperator

Creates a key and returns secret, the only time it exists outside the caller's hands.

POST /v1/admin/teach-tokenoperator

Mints a teach credential scoped to one site. The teach link is pasted into an address bar, so it must not carry a permanent key, this expires and cannot start sessions.