Package Exports
- @craftedxp/sdk-node
Readme
@craftedxp/sdk-node
Node.js / TypeScript SDK for the voice agent platform. Use it from your backend to mint short-lived call tokens, manage agents, query calls, and upload knowledge-base docs.
Pairs with
@craftedxp/voice-rn(the React Native client SDK). Your app callsfetchToken→ your backend uses this SDK → the platform mints act_token → returned to the app. Thesk_API key only ever lives on your backend.
Zero runtime dependencies. Node 18+.
Install
npm install @craftedxp/sdk-nodeQuick start — minting a call token
The most common use:
import { PlatformClient } from '@craftedxp/sdk-node'
const client = new PlatformClient({
apiKey: process.env.VOICE_AGENT_SK!, // never ship this to a client
baseUrl: 'https://api.your-server.com', // or http://localhost:8080 for dev
})
// In your "/voice-token" route handler — called by the RN SDK's fetchToken:
async function mintForCall({ agentId, userId, context, metadata }) {
const { token } = await client.callTokens.mint({
agentId,
ttlSeconds: 600, // 10 min default; up to 3600 (60 min)
contactId: userId, // optional → cross-call memory
context, // optional arbitrary JSON, lowered into agent's system prompt
metadata, // optional opaque keys round-tripped on call.ended webhook (≤1 KB)
})
return { token } // hand to the RN SDK
}The full call-token surface:
client.callTokens.mint({ agentId, ttlSeconds, context, metadata, contactId, vars, allowedOrigins })
client.callTokens.list({ includeRevoked, includeExpired, limit })
client.callTokens.revoke(tokenId)Other resources
client.me.get() // the org behind the sk_
client.agents.create({ name, systemPrompt, ... }) // CRUD on agents
client.agents.list({ limit, cursor })
client.agents.get(agentId)
client.agents.update(agentId, patch)
client.agents.delete(agentId)
client.agents.webhooks(agentId).create({ url, secret, events })
client.agents.webhooks(agentId).list()
// ...
client.calls.list({ agentId, status, limit, cursor }) // call records
client.calls.listAll({ agentId }) // async iterator across pages
client.calls.get(callId)
client.knowledgeBases.create({ name }) // KB CRUD + uploads
client.knowledgeBases.list()
client.knowledgeBases.uploadFile(kbId, filePath)
client.knowledgeBases.delete(kbId)
client.credits.getBalance() // billing
client.credits.getLedger({ limit, cursor })
client.webhooks.deliveries({ agentId, callId, webhookId }) // org-wide delivery logWebhook signature verification
import express from 'express'
import { verifyWebhookSignature } from '@craftedxp/sdk-node'
const app = express()
app.post(
'/webhooks/voice-agent',
// Raw body — we need the exact bytes to recompute the HMAC.
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.header('X-Platform-Signature-256') ?? ''
if (!verifyWebhookSignature(req.body, sig, process.env.VOICE_AGENT_WEBHOOK_SECRET!)) {
return res.status(401).send('invalid signature')
}
const event = JSON.parse(req.body.toString('utf8'))
// ...handle event
res.status(200).end()
},
)The function is timing-safe; copy it into your middleware verbatim. No PlatformClient instance required — verifyWebhookSignature is a standalone helper so any framework (Koa, Next.js route handlers, Hono, etc.) can use it.
Errors
All HTTP errors throw a typed PlatformError:
import { PlatformError } from '@craftedxp/sdk-node'
try {
await client.callTokens.mint({ agentId })
} catch (err) {
if (err instanceof PlatformError) {
console.error(err.code, err.status, err.message, err.field, err.docsUrl)
}
throw err
}The HTTP layer auto-retries 429 (honouring Retry-After) and 5xx responses with exponential backoff. Default maxRetries = 2 (3 total attempts); pass 0 to new PlatformClient({ maxRetries: 0 }) to disable.
Pagination
Cursor-based. Use the listAll async iterator if you want every page without managing the cursor manually:
for await (const call of client.calls.listAll({ agentId })) {
// process each call across all pages
}What's NOT in this SDK
- Voice / WebSocket / audio streaming. Use
@craftedxp/voice-rn(React Native) for the call path itself. - Browser-side use. This SDK assumes a server-side environment with native
fetch. Thesk_API key must never reach a browser. - Phone numbers, outbound dialling. Telephony is on the platform roadmap; the SDK will surface it when the server endpoints land.
Migration from @voxline/node@0.1.0
@voxline/node was a pre-launch internal name. This package replaces it under the @craftedxp org. API surface is unchanged except for the Phase 12 additions (context / metadata / contactId on callTokens.mint).
- import { PlatformClient } from '@voxline/node'
+ import { PlatformClient } from '@craftedxp/sdk-node'
const client = new PlatformClient({ apiKey })
- await client.callTokens.mint({ agentId, vars: { name: 'Arun' } })
+ await client.callTokens.mint({ agentId, context: { name: 'Arun', orders: [/* nested ok */] } })vars is still accepted server-side for backward compatibility.