@syncsuite/sdk
v0.1.0
Published
Client SDK for SyncSuite — discover + call any service, connection, env var, custom tool, or agent with one verb.
Maintainers
Readme
@syncsuite/sdk
The customer-code SDK for SyncSuite. Two verbs (discover, call) give your
code access to every SyncSuite capability — services (email, SMS, storage,
AI…), OAuth connections, env vars, your own custom tools, and agent
handoffs — all behind one consistent shape.
You never need to update this SDK when new services launch. Capability names are strings; the catalog is fetched at runtime. The shape only changes if we change the dispatcher itself (rare).
Install
pnpm add @syncsuite/sdk
# or
npm install @syncsuite/sdkSetup
The default singleton reads two env vars on first use:
| Env var | Required? | Default | Description |
|---|---|---|---|
| SYNCSUITE_API_KEY | Yes | — | Your ssk_… key. Already injected into every SyncSuite project VM. |
| SYNCSUITE_SERVICES_URL | No | https://app.syncsuite.com | Internal vSwitch bridge URL for SyncSuite-hosted VMs; auto-injected. |
Both are pre-set inside SyncSuite-managed customer VMs. For local dev or custom deployments, set them yourself.
Quick start
import { sync } from "@syncsuite/sdk";
// What can my account do right now?
const caps = await sync.discover();
// → [{ fqn: "service:email.send_personal", … }, { fqn: "agent:billing-bot", … }, …]
// Send an email (billed to wallet):
const r = await sync.call("service:email.send_personal", {
to: "[email protected]",
from: "[email protected]",
subject: "Welcome",
body: "Glad you're here.",
});
if (!r.ok) throw new Error(r.error);
// Get authenticated headers for a connected provider (your code does the fetch):
const conn = await sync.call("connection:google");
const r2 = await fetch("https://www.googleapis.com/...", {
headers: (conn.data as { headers: Record<string, string> }).headers,
});
// Hand off to a specialty agent on your account:
const refund = await sync.call("agent:billing-bot", {
message: "User wants a refund on invoice #1234",
});
// Pause-resume on external signal (e.g. waiting for a webhook):
const inbox = await sync.call("core:await_external", {
reason: "Stripe webhook for refund",
ttlSeconds: 3600,
});
// inbox.data.callback_url → give to Stripe
// Later:
const status = await sync.call("core:check_external", { token: inbox.data.token });Capability namespaces
| Prefix | What | Example |
|---|---|---|
| service: | SyncSuite-managed, wallet-billed | service:email.send_personal |
| connection: | OAuth or API-key passthrough — returns headers | connection:google |
| env: | Read from the account env vault | env:STRIPE_KEY (params: { key: "STRIPE_KEY" }) |
| custom: | User-defined HTTP endpoints in your project | custom:my-pdf-builder |
| agent: | Handoff to another agent | agent:billing-bot |
| core: | Built-in verbs (fanout, await_external, etc.) | core:fanout |
Call sync.discover() to see what's actually granted to your account.
Why this shape
- Strings as identifiers = adding a new service on the SyncSuite side doesn't require an SDK release. Your day-1 SDK works forever.
- Single
call()verb = one mental model. No need to rememberuseConnection()vsservices.send()vsprocess.env.X. - Same surface the AI uses internally = if you've taught the AI to do
something with
call, you can do it the same way from your code. - Wallet billing is automatic —
callreturns{ ok, data, cost?, error }and the wallet ledger is updated server-side on each successful service invocation.
Advanced: multiple accounts / custom config
import { SyncSuite } from "@syncsuite/sdk";
const customerA = new SyncSuite({ apiKey: "ssk_aaa..." });
const customerB = new SyncSuite({ apiKey: "ssk_bbb..." });
await customerA.call("service:email.send_personal", { ... });TypeScript
Result shapes are typed loosely (data: unknown) because capability
payloads vary by FQN. Pass a generic to call<T>() when you know the
shape:
const r = await sync.call<{ messageId: string }>(
"service:email.send_personal",
{ to, from, subject, body },
);
if (r.ok) console.log("Sent:", r.data.messageId);What changed from the legacy v1 API
The old surface had three different shapes:
// OLD: services
await fetch(`${SYNCSUITE_SERVICES_URL}/api/services/email/send_personal`, {
method: "POST",
headers: { Authorization: `Bearer ${process.env.SYNCSUITE_API_KEY}` },
body: JSON.stringify({ params: { to, body } }),
});
// OLD: connections
await fetch(`${SYNCSUITE_SERVICES_URL}/api/me/connections/google`, ...);
// OLD: env
process.env.STRIPE_KEY;All three (and agent invocation + custom tools) now go through sync.call.
The legacy routes still work — feel free to migrate at your pace.
