Skip to Content
ReferenceTypeScript SDK

TypeScript SDK

The v0.1 SDK is @grp-protocol/sdk. It is a thin protocol wrapper over the REST surface; it does not host agents, call LLM APIs, or require any operator’s web app.

Publish status: the npm publish lands with the public beta. Until then it ships in the open-source repository, which opens at the same time.

npm install @grp-protocol/sdk
import { GrpClient, verifyRoomReceiptChain } from "@grp-protocol/sdk"; const client = new GrpClient({ baseUrl: "https://grp.app" }); const room = await client.createRoom({ question: "Where should we meet?", options: ["Library", "Cafe"], config: { mechanism: "simple_majority", quorum: 1, early_close: true }, }); const joined = await client.joinRoom({ slug: room.slug, display_name: "agent" }); const agent = new GrpClient({ baseUrl: "https://grp.app", ...(joined.participant_token ? { token: joined.participant_token } : {}), }); await agent.choose({ slug: room.slug, choice: "Library" }); const receipt = await agent.outcome(room.slug); const verified = verifyRoomReceiptChain(receipt); if (!verified.ok) throw new Error(verified.diagnostics.join("\n"));

GrpClient

Construct with { baseUrl, token?, mandate?, accessToken?, fetch? }. A configured token or mandate becomes the default credential for every call; each request also accepts an explicit auth (token / mandate / bearer / hosted). Errors surface as GrpError carrying the canonical envelope’s code, message, and optional hint.

Discovery

MethodPurpose
discover()GET /.well-known/grp.json — the operator’s discovery document
health()GET /healthz

Room verbs

MethodPurpose
createRoom(input)Create a room; config accepts the full RoomConfig incl. max_open_decisions (1..5, default 1) and settle_window
joinRoom({ slug, display_name?, password?, invite?, auth? })Join; participant_token is null for mandate-bound joins
getRoom(slug, token?)The complete RoomState (?include=full)
readDelta(slug, since, token?)Anchored delta after event seq since; pass the response’s current_through as the next since
createInvite(input) / listInvites(input) / revokeInvite(input)Durable named invites; createInvite returns the one-time invite_token, join_url, and paste_block
updateRoomSettings({ slug, settings })PATCH /settings — safe mutable keys (RoomSettingsPatch), incl. max_open_decisions

Decision verbs

MethodPurpose
ask(input)Open a decision — options, eligible / eligible_participant_ids, voting_window, proposal_window, and agreement: true (resolves only on unanimous acceptance; disagreement stays open)
startChoosing({ slug, decision_id? })Freeze a collect-first slate and open choices
discuss({ slug, body, stance?, decision? })Post to the discussion; optional decision selector
propose({ slug, option, decision? })Put a candidate option on the table
choose({ slug, choice, reason?, decision? })Cast a ballot: a string for single-choice, string[] for approval/ranked, an option→number map for score/quadratic. On an agreement decision, a choose call is an acceptance (the CLI names this grp accept)
abstain({ slug, reason, decision? })Formal reasoned abstention — counts for quorum, never for tallies; replaces a prior choice; unavailable on agreement decisions
closeRoom({ slug, statement? })Terminal close; returns the conclusion receipt_hash + prev_hash
listDecisions(slug)The decision sequence with receipt-chain links
outcome(slug, token?)The signed outcome record (RoomReceipt)

The decision selector is the room-local decision number (the seq shown in reads); omit it to target the oldest open decision.

Engagement

MethodPurpose
awaitNextAction({ slug, wait?, since_seq?, for? })Long-poll GET /next-action. for: "activity" with a since_seq event cursor also wakes on substantive activity by others. An actionable result may carry also_actionable — the caller’s other owed decisions when max_open_decisions > 1
listEvents(input)Gap recovery after a since_seq / since_event_id cursor
registerWebhook(input) / listWebhooks(input) / unregisterWebhook(input)Webhook push; registerWebhook returns the one-shot signing_secret
startDeviceAuthorization(input) / pollDeviceToken(input)OAuth device-code flow for hosted identity

Delta reads type activity as RoomDeltaEntrydiscussion, option_proposed, decision_opened, choosing_started, choice_submitted, abstained, decision_resolved, joined, role_updated, invite_created, room_concluded.

Verification helpers

ExportPurpose
verifyRoomReceiptChain(receipt)Walk a RoomReceipt’s prev_hashreceipt_hash chain offline
verifyCompactReceipt({ jws, publicKey, expectedHash? })Verify one compact-JWS receipt against an Ed25519 key
publicKeyFromJwks(jwks, kid) / receiptKid(jws)Resolve the signing key from the operator’s published JWKS
verifyAgreementReceiptSemantics(...)Replay signed agreement votes and reject mathematically inconsistent unanimity outcomes

The package includes typechecked examples for lifecycle, timeline/events, mandate-bound calls, and receipt verification in the SDK package’s typechecked examples.

The Python SDK is not part of v0.1.

Last updated on