Sess SDK
Ask a person a question from your server and continue with their verified answer.
Create and run a small agent:
What you'll see: a Sess link. Answer two questions on your phone and your plan prints in the
terminal with a verified receipt.
Install the SDK in your own server project:
Ask a person
Use a developer API key from the Sess developer portal. Keep it on the server.
The hosted no-signup demo is a separate trial flow; a Sess link or trial credential
is not an owner API key. You need no LLM, agent framework, Docker or Sess source checkout.
sess.ask() checks the question locally, creates the Session once and returns its Sess link
before anything waits. The link is a bearer capability: deliver it only to the person, never to
logs or analytics. answer() waits for the person (ten minutes by default), verifies the signed
receipt against the exact question, checks that the answer is still the current step, completes the
Session and returns the values typed from your fields. Completion closes the Session: the link no
longer accepts answers. Field types are text, number, integer, boolean, choice and
multi_choice (API reference).
If the wait times out (wait_ended, code WAIT_TIMEOUT) or you abort it, nothing changes remotely:
call answer() again on the same handle. An error with outcome: "unknown" means completion is not
confirmed; calling answer() again replays the same completion. The handle lives in memory only. To
resume after a restart, persist sessionId and revision and continue with the API below
(Integration).
If Sess refuses a call, the error says what happened and what to do. A key Sess does not accept
prints: "Sess did not accept your API key. Check SESS_API_KEY and the portal you made it on." The
message comes first; the code and request ID follow it:
Keep it short
A person reads the page on a phone, so Sess keeps every piece of it short. Lengths count
characters (Unicode code points), and Sess never truncates:
There are at most 5 buttons. A value over its limit fails with a SessError that names it:
field is a JSON pointer such as /question, limit is the most it may have and length is
what it has. The message says how to fix it: "The title can be at most 80 characters. Keep it
to a short heading, about 40." for the title, and for anything else, for example
"/fields/0/label is 72 characters; the limit is 60. Shorten it to at most 60 characters." Nothing
was created (outcome is not_sent or rejected), so shorten the value and ask again:
Release status: 0.1.1 is the current release, served under the latest dist-tag. Its API is
that of 0.1.0, the first stable release. next stays at the last release candidate, 0.1.0-rc.10. The changelog describes
each version; npm view @sess.si/sdk dist-tags shows what the registry serves now.
Commerce
Sess takes no payment: the person approves a bill on a Sess page, and moving the money stays with
you and your payment processor.
Three things you will meet first:
- Short rows. A row name has at most 80 characters and its detail at most 160. A longer value
is refused, never trimmed: the
SessError names it by its pointer, such as
/interaction/source/components/1/rows/0/name, with limit and length.
- Whole minor units. Amounts are integers in the currency's smallest unit: cents for USD, yen
for JPY, fils for BHD.
money(1250, 'USD') is $12.50; money(12.5, 'USD') throws, because Sess
never rounds or converts.
- Exact totals. The builders compute the subtotal, total and amount due from your rows and
lines. An items component you write by hand whose subtotal is not the sum of its rows is refused
with HTTP 400:
invoice(), receipt(), quote(), refund() and purchaseOrder() each return an ordinary
interactive Surface for sess.sessions.create({ interaction }): the bill as an items card, the
document's reference under a plain name, and the buttons the person needs (Approve and Decline;
Continue on a receipt; Accept on a quote). refund() states positive amounts under "Refund total".
A row quantity lets the person change it and adds a Request changes button; your agent replies
with a new revision and updated amounts. items() builds just the card, and lintText() finds a
Markdown table in text, which the person would see as pipes. See the
API reference.
What Sess does not do: take or move payment, convert currencies, compute tax or prices, show your
logo or branding, or let another site frame the page (frame-ancestors 'none').
Advanced: the full Surface API
Verification checks that the receipt was issued for your workspace. Sess names your workspace on
authenticated responses (the Sess-Workspace-Id header), so you set nothing. If a runtime does not
send it, set expectedWorkspaceId from trusted deployment settings; otherwise verification fails
with VERIFICATION_CONTEXT_MISSING. The SDK never takes the workspace from the unverified receipt.
The quickstart function includes a private delivery callback.
Three-round continuation persists mutation intent and checks that an
answer is still the current expected business step before publishing or completing. Its store
and worker lease are application-owned. See Integration.
Check a decision bundle
A decision bundle is one accepted decision that its owner chose to share: the signed receipt, the
exact Surface and input, and the issuer's public keys. Check it on your own computer, with keys you
trust (never the keys inside the bundle):
The sess command first ships in 0.1.0-rc.5; any later version, 0.1.1 included, has it.
You'll see Valid decision bundle. and what was accepted, when, on which revision; or Invalid
and the first reason. Exit status is 0 valid, 1 invalid, 2 usage error; add --json for the full
result. Nothing is sent anywhere. In code, use verifyDecisionBundle from @sess.si/sdk/receipts
(Security). Formats: receipt-v1 and
bundle-v1.
Show the link as a QR code
When the person is at a laptop and would answer on their phone, draw the link as a QR code, locally,
with no network call:
Use it where a person sees a screen but not their phone: a desktop chat window, a dashboard, a kiosk,
print. Skip it in SMS, or when the person is already on their phone. Sess never shows or sends the
code; your agent chooses. printQr prints nothing without a TTY, in CI (CI set), in production
(NODE_ENV=production), with --no-qr or with { qr: false }, and draws without colour under
NO_COLOR. The code is the private link in another form: keep it wherever you keep the link, and
never in logs, analytics or a URL.
Runtime and imports
Supported: maintained Node 22 releases at or above 22.14, and Node 24 (recommended).
TypeScript consumer declarations target 5.9 and current stable. JavaScript consumers need no compiler.
The package contains one ESM build. CommonJS applications use await import('@sess.si/sdk'), as in the
CommonJS example; synchronous require is not a supported contract.
Entry points are @sess.si/sdk, @sess.si/sdk/receipts, @sess.si/sdk/webhooks and @sess.si/sdk/qr. Importing or constructing
the SDK does not contact a service, start a server, read credential files or log data.
Errors and retries
Errors are SessError with stable kind, API code, status, requestId, attempts and write
outcome fields when applicable. Server bodies and request secrets are omitted from default errors.
Session creation is attempted once. An unknown outcome may mean a Session exists whose private
URL was lost. Never automatically create again. If a valid creation body arrived with defective
headers, explicitly inspect error.getRecoveryResult() and protect that capability.
Publish and complete require a strong quoted ifMatch. Persist the body, original ETag and explicit
idempotencyKey before a durable write. Internal retries retain those values and the same resolved
credential. A 409 or 412 is returned to the caller; the SDK never refreshes an ETag to force a write.
Direct HTTP remains supported
The same create operation is available without the SDK:
Here interaction.json contains the same { "interaction": ... } request body. The response
contains a private human URL; protect terminal output and disable request tracing. The complete
contract is served at OpenAPI.
Guides
Sess renders the page the person sees; this SDK has no appearance settings.
Contribute · Security reporting · Apache-2.0