API
API reference
The Alaskan for Business API (v1). Signing in with email, linking a browser or an iPhone, workspaces and dogs, Decide and undo, the Ledger and its CSV export, templates and workflows.
The web app and the iPhone app use one API. Every call is a POST with a JSON body unless it says otherwise. Errors are {error} with a 4xx status.
Who's asking
Every /v1/workspace* and /v1/decisions* call (and /v1/link/list, /revoke, /join, /v1/auth/me and /signout) is made as a person:
- the iPhone app sends
X-Alaskan-User, - a browser sends
Authorization: Bearer <web token>, from an email sign-in or from a phone that linked it.
Neither, or a revoked, signed-out or unknown token, is a 401. A person without a workspace gets 404 from everything but /v1/workspace and /v1/workspace/create. Browsers may call these paths from the web app's own origin (CORS); no cookies are involved.
Signing in on the web
POST /v1/auth/email/start {email}(no auth) →{ok: true, email, expiresAt}. Emails a sign-in link and a 6-digit code, valid for 15 minutes, once. At most 5 an hour to one address and 20 an hour from one network (429);400for something that isn't an email.POST /v1/auth/email/verify {token}or{email, code}→{token, email, isNew}: a web token. The first sign-in for an address makes its account (isNew: true); later ones are the same person, on any browser.410for a used or expired link or code,401for a wrong code; five wrong codes end that sign-in (429).POST /v1/auth/me→{kind: "email", email}for an account made with an email,{kind: "phone"}for a browser signed in as a phone.POST /v1/auth/signout→{ok: true}; that token is a401from then on.
Links, codes and web tokens are stored only as hashes.
Linking a browser to a phone
POST /v1/link/start {label?}(no auth) →{code, display, expiresAt, pollToken}.codeis 8 characters with no 0, O, 1 or I;displayis the same asABCD-2345. Valid for 10 minutes, once.labelnames the browser in the phone's list (by default from its User-Agent, "Chrome on Mac").POST /v1/link/confirm {code, name?}(the phone only) →{ok: true, label}. Any case, with or without the dash.404for a wrong code,409used,410expired,403from a browser.POST /v1/link/poll {pollToken}→{status: "waiting" | "linked" | "expired", token?, name?}. Poll every couple of seconds. The token comes once; a poll after that saysexpired.POST /v1/link/list→{browsers: [{id, label, createdAt, lastSeenAt}]}.POST /v1/link/revoke {id}→{ok: true}; that browser's token is a401from then on.
Poll tokens and web tokens are stored only as SHA-256 hashes.
Bringing an iPhone into a workspace
POST /v1/link/join(someone in the workspace, usually from the web) →{code, display, expiresAt, pollToken}: the same kind of code, valid 10 minutes, once. The web shows it with a QR code.- The phone types it where it types any browser code and sends the usual
POST /v1/link/confirm {code, name?}. For a join code, the phone's person joins the workspace as amember→{ok: true, label, joined: {workspace}}.409if the phone already belongs to another workspace (one per person in v1). POST /v1/link/join/poll {pollToken}→{status: "waiting" | "joined" | "expired", member?: {id, name, role}}.- On the phone, the join shows in
/v1/link/listas "on the web"; revoking it takes the phone out of the workspace (an owner is never removed).
Workspace
POST /v1/workspace→{workspace: Workspace | null}.POST /v1/workspace/create {name, template?, ownerName?, timeZone?}→{workspace}, from a team template (defaultstarter) with its dogs, its workflows installed and sample work.timeZoneis IANA (default UTC).409if the person already has a workspace; one per person in v1.POST /v1/workspace/dog {id, rules?, name?, routines?: [{id, enabled}]}→{dog}.rulesreplaces all three lists.POST /v1/workspace/routine {dogId, id, enabled}→{dog}.POST /v1/workspace/hire {template, dogId}→{dog}: adds that team template's dog with its job, rules and routines. Up to 12 dogs;409when a dog of that name is on the team.POST /v1/workspace/turn {dogId, text}→{messages: [Message]}: what was typed and the dog's reply (withdecisionIdwhen it proposed something).POST /v1/workspace/messages {dogId}→{messages: [Message]}, oldest first, the last 100.POST /v1/workspace/sessions {dogId?}→{sessions: [Session]}, newest first.POST /v1/workspace/computer→{computer: Computer};/computer/start,/computer/stop.
Decisions and the Ledger
POST /v1/decisions {status?: "pending" | "all", dogId?}→{decisions: [Decision], counts: {pending, today}}.pending(the default) is the queue, oldest first;allis newest first.POST /v1/decisions/decide {id, option?, typed?}→{decision}.optionis an option'skey(1–4). The decision isdeclinedwhen that option'seffectisdecline, otherwiseapproved. A typed answer is kept exactly as typed and counts asapproved.undoUntilis 10 seconds on.409if it's already decided or expired.POST /v1/decisions/undo {id}→{decision}, only beforeundoUntil. A person's answer goes back topending; a rule's becomesundone.POST /v1/decisions/outcome {id, status: "good" | "bad" | "unknown", note?}→{decision}, on a decided one.POST /v1/decisions/events {id}→{events: [{id, at, actor: {kind: "person" | "rule" | "dog" | "system", name}, action, detail}]}: the decision's audit trail, oldest first. Append-only.GET /v1/decisions/export.csv→ the Ledger as CSV. See The Ledger.
Templates and workflows
GET /v1/templates(no auth) →{teams: [...], workflows: [...]}: every team template with its dogs, and every workflow template with its trigger, node count and apps.GET /v1/templates/team/<slug>,GET /v1/templates/workflow/<slug>→ the template itself.POST /v1/workspace/workflows→{workflows: [{id, slug, name, summary, for, dog, dogId, trigger, enabled, installedAt, nodes, apps, lastRun}]}.POST /v1/workspace/workflows/install {slug}→{workflow}. Installing twice keeps the first.POST /v1/workspace/workflows/run {id}→{session}, as it stands when the run finishes or waits at a Decide.
Alaskan bots
Bots built by others: the public marketplace (GET /v1/marketplace/bots), adding, running and removing a bot in a workspace (/v1/workspace/bots/*), and the creator calls (/v1/creators/*). They're all in the Alaskan bot reference.
Shapes
Workspace { id, name, plan: "trial" | "business", sample: boolean, template, timeZone, createdAt,
you: Member, members: [Member], dogs: [Dog], computer: Computer,
dashboard: {views: [View, with each metrics item's value]}, counts: {pending, today} }
Member { id, name, role: "owner" | "member", app: "web" | "iphone" }
Dog { id, key, name, job, breed: "malamute" | "husky" | "kleekai",
coat: "aurora" | "ember" | "glacier" | "twilight", lead: boolean, tagline, persona,
status: {working, needsYou, queued}, preview, lastActivityAt, screen,
rules: {justDo: [string], ask: [string], never: [string]},
routines: [{id, title, when, nextAt, enabled}], connectors: [string],
hoursThisWeek }
Session { id, dogId, title, status: "running" | "needs_you" | "queued" | "done", screen,
costCents, startedAt, endedAt?, steps: [{at, kind: "look" | "think" | "act" | "result",
text}], sample, workflowId?, runId? }
Decision { id, dogId, kind: "send" | "update" | "book" | "spend" | "publish" | "other",
title, summary, source, items: [{label, field, from?, to, flagged?}],
options: [{key: 1–4, label, detail, effect: "approve" | "decline", value?}], reasoning,
evidence: [{label, url?}], thread: [{from, at, text}], status: "pending" | "approved" |
"declined" | "auto" | "undone" | "expired", chosen?, typed?, decidedBy?: {kind:
"person" | "rule", name}, decidedAt?, undoUntil?, expiresAt?, outcome?: {status:
"pending" | "good" | "bad" | "unknown", note, checkAt?, checkedAt?}, createdAt, sample,
workflowId?, runId? }
Computer { provider, state: "demo" | "off" | "starting" | "on", screens: [{n, dogId, title,
activity}], costPerHourCents, hoursThisWeek, note?, error? }
Message { id, role: "user" | "dog", dogId, text, at, decisionId?, sample? }
value on an option is a workflow template's own key for it, when that isn't its number. A member's app is where they came in: an email account on the web, or the iPhone app. decidedBy.name is a person's name, or the rule with its kind (Just do: Refunds up to $50). screens[].activity is the dog's running session's latest step.
Limits
A workspace's people may send its dogs 400 messages a UTC day (fair use); past that, the dogs say so until midnight UTC.