Get started
Quickstart
By the end of this page you will have an agent, an API key, and a web page that talks to the agent out loud.
Make an agent
Create an account and open the studio. A new workspace starts with one agent already in it; open it, or make your own with New agent. Press Test agent to talk to it in the browser until it sounds right.
You will need the agent’s ID, which looks like
ua_3f9a1c2b. Copy it from the more menu at the top of the agent’s page, or read it from List agents.Create an API key
In the studio, open API keys and choose Create API key. The key starts with
ck_and is shown once, so copy it straight into your server’s environment:Terminalexport CRACKLE_API_KEY="ck_your_key_here"Check it works. This should answer with your workspace:
curl "https://goblins-call-api.onrender.com/v1/me" \ -H "Authorization: Bearer $CRACKLE_API_KEY"Start a call from your server
Send the agent’s ID to
POST /v1/calls.participant.identityis your own name for the caller; use whatever identifies them in your system.curl -X POST "https://goblins-call-api.onrender.com/v1/calls" \ -H "Authorization: Bearer $CRACKLE_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "agentId": "YOUR_AGENT_ID", "participant": { "identity": "customer_123" } }'The answer is everything a client needs to join:
Response · 201 Created{ "callId": "8f1c2c1e-7b1a-4e0a-9c55-2f6f0d3b1a90", "roomName": "call_8f1c2c1e7b1a", "livekitUrl": "wss://…", "token": "eyJhbGciOiJIUzI1NiJ9…", "participantIdentity": "customer_123" }In a real app this request sits behind an endpoint of your own, so the page never sees the key:
server.jsimport express from 'express'; const app = express(); // Your page asks your server for a call; your server asks Crackle. app.post('/api/start-call', async (req, res) => { const response = await fetch('https://goblins-call-api.onrender.com/v1/calls', { method: 'POST', headers: { Authorization: `Bearer ${process.env.CRACKLE_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ agentId: 'YOUR_AGENT_ID', participant: { identity: 'customer_123' }, }), }); if (!response.ok) return res.status(502).json(await response.json()); // Only what the page needs to join. The API key stays here. const { callId, livekitUrl, token } = await response.json(); res.json({ callId, livekitUrl, token }); }); app.listen(3000);Join from your page
Calls run over WebRTC, on LiveKit. Install its client and connect with the
livekitUrlandtokenyou were given:Terminalnpm install livekit-clientcall.jsimport { Room, RoomEvent } from 'livekit-client'; export async function talkToAgent() { const session = await fetch('/api/start-call', { method: 'POST' }).then((r) => r.json()); const room = new Room(); // Play the agent's voice as soon as it arrives. room.on(RoomEvent.TrackSubscribed, (track) => { if (track.kind === 'audio') document.body.appendChild(track.attach()); }); await room.connect(session.livekitUrl, session.token); await room.localParticipant.setMicrophoneEnabled(true); return room; // room.disconnect() hangs up }Call
talkToAgent()from a button press: browsers hold a page’s sound back until the visitor has clicked or tapped. The agent greets you once you are in.See what happened
Hang up with
room.disconnect(), then read the call back. It has the transcript, how long the call lasted and what it cost. The same call is in the studio under Call logs.curl "https://goblins-call-api.onrender.com/v1/calls/YOUR_CALL_ID" \ -H "Authorization: Bearer $CRACKLE_API_KEY"