# Unformal > Replace forms with AI conversations. Create a Pulse, share a link, get structured data back. ## Quick Start 1. POST /api/v1/signup with {"email": "you@example.com"} — returns API key + 50 free credits 2. POST /api/v1/verify with {"email": "...", "code": "123456"} — verify email (check inbox) 3. POST /api/v1/pulses with {"intention": "..."} — creates a Pulse, returns shareable URL 4. Share the URL: https://unformal.ai/p/{slug} 5. GET /api/v1/pulses/{id}/conversations — get structured results That's it. One intention string creates a full conversational flow with AI-generated questions, adaptive inputs, and structured data extraction. ## Key Concepts - **Pulse** — A conversational flow you create. Like a form, but it's an AI conversation. Defined by an intention (what you want to learn). - **Conversation** — One person's response to a Pulse. Contains a full transcript and extracted data. - **Echo** — Structured data extracted from a conversation: fields you defined, summary, key quotes, sentiment score, subtext. - **Resonance** — Aggregate intelligence across all conversations for a Pulse: themes, consensus, divergence, recommended actions. - **Mode: Interview** — AI asks questions one at a time, adapting follow-ups. Best for deep qualitative research, discovery calls, qualification. - **Mode: Extract** — Respondent writes everything upfront, AI asks only about gaps. Best for intake forms, bug reports, data collection. ## Authentication All API calls (except signup) require: ``` Authorization: Bearer unf_xxxxx ``` Get an API key via POST /api/v1/signup or at https://unformal.ai/studio/settings ## API Base URL https://unformal.ai/api/v1 ## API Endpoints ### Account (no auth required) POST /api/v1/signup Body: {"email": "you@example.com"} Returns: {"data": {"api_key": "unf_xxx", "workspace_id": "...", "credits": 50, "status": "pending_verification"}} Note: API key shown once. Email verification required before key works. POST /api/v1/verify Body: {"email": "you@example.com", "code": "123456"} Returns: {"data": {"status": "verified", "message": "Email verified. Your API key is now active."}} POST /api/v1/resend-verification Body: {"email": "you@example.com"} Returns: {"data": {"status": "sent"}} ### Pulses (auth required) POST /api/v1/pulses — Create a Pulse Body: See "Create a Pulse" section below Returns: {"data": {"id": "...", "url": "https://unformal.ai/p/your-slug", "slug": "your-slug", "status": "active"}} GET /api/v1/pulses — List all Pulses Returns: {"data": [{"id": "...", "slug": "...", "status": "active", "intention": "...", "url": "...", "totalConversations": 5}], "meta": {"total": 1}} GET /api/v1/pulses/:id — Get Pulse details Returns: Full Pulse object with config, outputFields, topics, stats PATCH /api/v1/pulses/:id — Update Pulse config Body: Any subset of Pulse fields (intention, context, tone, mode, webhookUrl, etc.) Returns: {"data": {"id": "...", "updated": true}} DELETE /api/v1/pulses/:id — Archive a Pulse Returns: {"data": {"id": "...", "archived": true}} POST /api/v1/pulses/:id/publish — Publish a draft Pulse Returns: {"data": {"id": "...", "status": "active", "url": "..."}} ### Conversations (auth required) GET /api/v1/pulses/:id/conversations — List conversations for a Pulse Returns: {"data": [{"id": "...", "status": "completed", "echo": {...}, "metadata": {...}, "completedAt": 1234567890}], "meta": {"total": 3}} GET /api/v1/conversations/:id — Get full conversation with transcript Returns: {"data": {"id": "...", "pulseId": "...", "status": "completed", "transcript": [...], "echo": {...}, "metadata": {...}}} ### Usage (auth required) GET /api/v1/usage — Credit balance and usage stats Returns: {"data": {"credits": 47, "totalConversations": 3, "totalPulses": 1}} ## Create a Pulse (detailed) POST /api/v1/pulses Required fields: - intention (string) — What the AI should learn. e.g. "Understand what a new client needs before our first meeting" Optional fields: - context (string) — Background info for the AI, not shown to respondent - mode (string) — "interview" (default, guided Q&A) or "extract" (brain dump + gap fill) - tone (string) — "conversational" (default), "formal", "coaching", "casual", "custom" - maxDurationMin (number) — Max duration: 2, 5 (default), 10, 15 - maxQuestions (number) — Max questions: 3, 5, 8 (default), 12, 20 - linkType (string) — "multi" (default, unlimited responses) or "single" (one response only) - model (string) — "claude-sonnet" (default), "gpt-4o", "gemini" - welcomeTitle (string) — Custom title on the welcome screen - welcomeDescription (string) — Custom description on the welcome screen - webhookUrl (string) — URL to POST Echo data when a conversation completes - notifyEmail (string) — Email to notify on completion - dictationEnabled (boolean) — Allow voice dictation (default: true) - showInsights (boolean) — Show respondent their own insights on completion (default: false) - allowResearch (boolean) — AI web research during conversation, costs 2x credits (default: false) Example: ```json { "intention": "Qualify inbound leads for our B2B SaaS product", "context": "We sell project management software for agencies. Average deal size is $5k-50k/year. Key qualifiers: team size, current tools, budget, timeline.", "mode": "interview", "tone": "conversational", "maxQuestions": 8, "webhookUrl": "https://yourapp.com/webhooks/unformal", "welcomeTitle": "Quick chat before we meet", "welcomeDescription": "Help us understand your needs so we can make the most of our first call." } ``` Response: ```json { "data": { "id": "k57abc123def456", "url": "https://unformal.ai/p/qualify-inbound-leads", "slug": "qualify-inbound-leads", "status": "active" } } ``` ## Output Fields Output fields define the structured data extracted from every conversation. They're auto-generated from your intention but can be customized via PATCH. Types: "string", "number", "boolean", "array" Example output fields (auto-generated for lead qualification): ```json [ {"name": "company_size", "type": "string", "description": "Number of employees"}, {"name": "current_tools", "type": "array", "description": "Tools they currently use"}, {"name": "budget_range", "type": "string", "description": "Annual budget for this category"}, {"name": "timeline", "type": "string", "description": "When they want to start"}, {"name": "pain_points", "type": "array", "description": "Top challenges with current setup"}, {"name": "decision_makers", "type": "string", "description": "Who else is involved in the decision"} ] ``` ## Echo (Structured Output) When a conversation completes, Echo contains: ```json { "echo": { "fields": { "company_size": "50-100", "current_tools": ["Asana", "Slack", "Google Sheets"], "budget_range": "$10k-20k/year", "timeline": "Q3 2026", "pain_points": ["No time tracking", "Poor client visibility", "Manual reporting"], "decision_makers": "CTO and Head of Operations" }, "summary": "Strong fit. Mid-size agency struggling with manual workflows. Budget aligned, timeline Q3. Decision involves CTO.", "keyQuotes": [ "We spend 3 hours every Friday just compiling status reports", "Our clients keep asking for real-time dashboards" ], "subtext": "Enthusiastic but cautious about migration effort. Needs ROI proof.", "sentimentScore": 7 } } ``` ## Transcript Format Each conversation message: ```json { "role": "assistant" | "user", "content": "The message text", "uiHint": {"type": "slider", "config": {...}}, "timestamp": 1234567890 } ``` UI hint types: text, slider, multi-select, ranking, sentiment-spectrum, and more. These are shown to the respondent as adaptive input types. ## Webhook Integration Set webhookUrl on a Pulse. When a conversation completes, Unformal sends: POST {your webhookUrl} Headers: Content-Type: application/json X-Unformal-Signature: sha256=... (HMAC-SHA256 of body) Body: ```json { "event": "conversation.completed", "conversationId": "conv_123", "pulseId": "pls_456", "echo": { "fields": {...}, "summary": "...", "keyQuotes": [...], "sentimentScore": 7 }, "metadata": { "duration": 240, "messageCount": 12, "dictationUsed": false }, "completedAt": "2026-03-29T10:00:00Z" } ``` ## Real-Time Stream (SSE) GET /api/v1/pulses/:id/stream — Server-Sent Events stream for real-time notifications Headers: Authorization: Bearer unf_xxxxx Returns: SSE event stream (text/event-stream) Connect and receive events as conversations complete: \`\`\`bash curl -N -H "Authorization: Bearer unf_xxx" https://unformal.ai/api/v1/pulses/{id}/stream \`\`\` Events: - connected — sent on initial connection - conversation.completed — when a conversation finishes (includes echo data) - ping — keepalive every 15 seconds - timeout — connection timeout after 30 minutes (reconnect) Event format: \`\`\` event: conversation.completed data: {"conversationId":"abc123","pulseId":"xyz","echo":{"fields":{...},"summary":"...","keyQuotes":[...]},"summary":"Brief summary","completedAt":"2026-03-30T12:00:00Z","metadata":{...}} event: ping data: {"timestamp":"2026-03-30T12:00:15Z"} \`\`\` Limits: - Max 5 concurrent SSE connections per API key - Connection timeout: 30 minutes (client should reconnect) Test page: GET /api/v1/pulses/:id/stream/test — HTML page for debugging the stream ## Error Responses All errors follow: ```json {"error": {"code": "ERROR_CODE", "message": "Human-readable message"}} ``` Codes: - 400 BAD_REQUEST — Invalid JSON or missing fields - 401 UNAUTHORIZED — Missing or invalid API key - 402 OUT_OF_CREDITS — No credits remaining - 404 NOT_FOUND — Resource not found - 409 CONFLICT — Email already registered (signup) - 422 VALIDATION_ERROR — Invalid field values - 429 RATE_LIMIT_EXCEEDED — Too many requests ## Use Cases - Client onboarding — replace intake forms with a natural conversation - User research — gather deep qualitative insights at scale - Lead qualification — understand prospects before the first sales call - Employee check-ins — pulse surveys that feel like real conversations - Customer feedback — go beyond NPS with rich, contextual understanding - Event registration — conversational sign-ups that build engagement - Bug reports — extract structured reproduction steps conversationally ## Pricing - Free: 50 conversation credits on signup - Each conversation costs 1-2 credits (2 if allowResearch is enabled) - Credit packs available at https://unformal.ai/studio/settings ## Install as Skill For OpenClaw: npx clawhub install unformal-api For Claude Code / Cursor / Windsurf: Download https://unformal.ai/UNFORMAL.md and add to your project root For any AI agent: Read this file at https://unformal.ai/llms.txt ## Links - App: https://unformal.ai - API Docs: https://unformal.ai/docs/api - Integration Guide: https://unformal.ai/docs/integrate - Agent Discovery: https://unformal.ai/.well-known/ai-plugin.json - Contact: hello@unformal.ai