# Wiro API Integration > Wiro is a unified API platform for running AI models (video, image, audio, LLM, 3D) and deploying autonomous AI agents through a single API. Pay-per-use pricing, real-time streaming via WebSocket, webhook callbacks, and 9-language code examples. - Base URL: `https://api.wiro.ai/v1` - WebSocket: `wss://socket.wiro.ai/v1` - Dashboard: https://wiro.ai/panel - Models: https://wiro.ai/models - Full docs: https://wiro.ai/docs ## Docs - [Introduction](https://wiro.ai/docs/introduction): Platform overview and getting started - [Authentication](https://wiro.ai/docs/authentication): API key and HMAC signature auth methods - [Run a Model](https://wiro.ai/docs/run-a-model): Execute any AI model with a single POST call - [Tasks](https://wiro.ai/docs/tasks): Track model runs, check status, get outputs - [WebSocket](https://wiro.ai/docs/websocket): Real-time streaming for model outputs - [LLM & Chat Streaming](https://wiro.ai/docs/llm-chat-streaming): Token-by-token LLM response streaming - [Realtime Voice](https://wiro.ai/docs/realtime-voice-conversation): Two-way audio conversations with AI - [Realtime Text to Speech](https://wiro.ai/docs/realtime-text-to-speech): Stream synthesized speech over WebSocket — server → client only - [Realtime Speech to Text](https://wiro.ai/docs/realtime-speech-to-text): Stream mic audio, receive live transcripts — client → server audio, JSON back - [Files](https://wiro.ai/docs/files): Upload files for model inputs - [Pricing](https://wiro.ai/docs/pricing): Pay-per-use credit system - [Error Reference](https://wiro.ai/docs/error-reference): Error codes and troubleshooting ## Agent API Docs - [Agent Overview](https://wiro.ai/docs/agent-overview): Deploy and manage autonomous AI agents (tiers, token billing, model selection, lifecycle, all UserAgent endpoints) - [Agent Builder](https://wiro.ai/docs/agent-builder): Build a custom agent from scratch (no template — pick your own skill set), live pricing previews, custom: true Deploy - [Agent Messaging](https://wiro.ai/docs/agent-messaging): Send messages and stream agent responses - [Agent WebSocket](https://wiro.ai/docs/agent-websocket): Real-time agent response streaming - [Agent Webhooks](https://wiro.ai/docs/agent-webhooks): Receive agent responses via HTTP callbacks - [Agent Credentials](https://wiro.ai/docs/agent-credentials): Integration catalog hub + generic OAuth flow + Credentials/List + CredentialFieldHistory - [Agent Skills](https://wiro.ai/docs/agent-skills): Configure preferences and scheduled automation tasks; Skills/List + Skills/Detail + Skills/Capabilities + SkillsApply + CustomSkillHistory + CustomSkillRevert - [Agent Transactions](https://wiro.ai/docs/agent-transactions): Per-instance credit ledger (deductions, renewals, purchases, grants) - [Agent Logs](https://wiro.ai/docs/agent-logs): Per-instance activity feed (tool calls, cron runs, message exchanges) - [Agent Use Cases](https://wiro.ai/docs/agent-use-cases): Deployment patterns + pre-built agent catalog (Social Manager, Blog Content Editor, Google/Meta Ads Manager, Newsletter Manager, Lead Generation Manager, App Review Support, App Event Manager, Push Notification Manager, Voice Receptionist) + 7 live web showcases at wiro.ai/agents/usecase/* ## Integration Guides OAuth integrations: - [Meta Ads](https://wiro.ai/docs/integration-metaads-skills): own-mode setup, no App Review needed (Dev Mode + App Roles) - [Facebook Page](https://wiro.ai/docs/integration-facebook-skills): OAuth + multi-page selection via SetPickerAccounts - [Instagram](https://wiro.ai/docs/integration-instagram-skills): Business account + Facebook Page linkage required - [LinkedIn](https://wiro.ai/docs/integration-linkedin-skills): Company Page publishing + Community Management API - [Twitter / X](https://wiro.ai/docs/integration-twitter-skills): OAuth 2.0 PKCE, one-click Wiro mode available - [TikTok](https://wiro.ai/docs/integration-tiktok-skills): Content Posting API - [Google Ads](https://wiro.ai/docs/integration-googleads-skills): Developer Token + MCC + customer ID selection - [HubSpot](https://wiro.ai/docs/integration-hubspot-skills): CRM object management - [Mailchimp](https://wiro.ai/docs/integration-mailchimp-skills): OAuth or direct API key - [Google Drive](https://wiro.ai/docs/integration-googledrive-skills): Per-user service account, folders shared with SA email. `POST /UserAgentOAuth/GoogleDriveListFolders` accepts optional `parentid` for subfolder discovery (omit → root listing via `sharedWithMe`; provide → children of that folder via `'' in parents`; SA permission cascade applies). - [Google Calendar](https://wiro.ai/docs/integration-google-calendar-skills): Per-user service account + per-calendar sharing. Read availability, draft events. Used by appointment-booking and voice-receptionist agents. API key integrations: - [Gmail](https://wiro.ai/docs/integration-gmail-skills): App Password via IMAP/SMTP - [Telegram](https://wiro.ai/docs/integration-telegram-skills): Bot Token + allowed users - [Firebase](https://wiro.ai/docs/integration-firebase-skills): FCM push notifications via service account - [WordPress](https://wiro.ai/docs/integration-wordpress-skills): Application Password over REST API - [App Store Connect](https://wiro.ai/docs/integration-appstore-skills): ES256 API key + .p8 private key - [Google Play](https://wiro.ai/docs/integration-googleplay-skills): Service account + Play Console permissions - [Apollo.io](https://wiro.ai/docs/integration-apollo-skills): Lead gen + sequence management - [Lemlist](https://wiro.ai/docs/integration-lemlist-skills): Cold email campaign management - [Brevo](https://wiro.ai/docs/integration-brevo-skills): Transactional + marketing email - [SendGrid](https://wiro.ai/docs/integration-sendgrid-skills): Transactional + marketing email - [Twilio Voice Integration](https://wiro.ai/docs/integration-twiliovoice-skills): Inbound phone calls via Twilio Voice Webhooks + Media Streams. Account SID + Auth Token, hold media (text/audio/music + 20 named TTS voices), max-duration timer. CredentialUpsert auto-configures each number's VoiceUrl and returns `twilioWebhooksUpdated` / `twilioWebhookSkipped` / `twilioWebhooksFailed` (or `twilioWebhookError` on full-flow failure). Includes `POST /UserAgent/TwilioCallHistory/List` — returns BOTH Twilio + Web channel sessions; `status` mirrors `agentmessages.metadata.type` (`realtime_session_*` prefix; bare `realtime_session` = ended cleanly), `endReason` is server-side codes (`wiro_completed`, `max_duration`, `browser_disconnect`, etc.), `callerProfile` is always `null` (free-form prep summary lives in `metadata.prepSummary`, exposed via `Message/Detail`). - [Web Voice Integration](https://wiro.ai/docs/integration-webvoice-skills): Browser-embedded realtime voice via `util-web-channel`. POST /UserAgent/Realtime/WebStart issues a 300-second JWT-LIKE token (2-segment `.` — standard JWT libs reject it as malformed) + WebSocket URL (`wss://socket.wiro.ai/v1/AgentRealtime/Web`); browser sends `{type:"session_start", sessionToken}` as the first WS frame within 10s, then streams 24kHz Int16 PCM mono prefixed with `|`. **Server sends binary audio with the SAME prefix — strip it before playback.** Server text frames: `connecting`, `ready`, `transcript {role: "user"|"ai", text, ts}`, `clear` (barge-in flush), `resume`, `session_end {reason, message?, error?}` — there is no `error` frame and no `audio` JSON form (errors ride inside `session_end` instead). Browser→server frames: `interrupt`, `end` (mute is client-side only — server has no handler). Bundled on Voice Receptionist / Voice Sales Rep. 60 sessions/hour per operator (hashed key), Origin allow-list on Bearer auth path: `https://wiro.ai`, `https://www.wiro.ai`, `http://localhost:3000`, `http://localhost:8080` (other dev ports rejected). Realtime/Cancel tears down agent prep when browser can't reach WS handshake. ## Organizations & Teams - [Overview](https://wiro.ai/docs/organizations-overview): Workspace hierarchy — personal, organization, and team contexts - [Managing Teams](https://wiro.ai/docs/organizations-managing-teams): Create organizations, invite members, roles, transfers - [Team Billing](https://wiro.ai/docs/organizations-billing): Team wallets, spend limits, model access controls, budget alerts - [Team API Access](https://wiro.ai/docs/organizations-api-access): Context resolution via API keys, resource filtering, agent context guards ## Integrations - [MCP Server](https://wiro.ai/docs/wiro-mcp-server): Model Context Protocol server for AI assistants - [Self-Hosted MCP](https://wiro.ai/docs/mcp-self-hosted): Run MCP server locally via npx - [Node.js Library](https://wiro.ai/docs/nodejs-library): Standalone API client for Node.js/TypeScript - [n8n Integration](https://wiro.ai/docs/n8n-wiro-integration): Wiro AI nodes for n8n workflows ## Optional - [Model Parameters](https://wiro.ai/docs/model-parameters): Parameter types and input formatting - [Concurrency Limits](https://wiro.ai/docs/concurrency-limits): Task limits based on balance - [Code Examples](https://wiro.ai/docs/code-examples): Examples in 9 languages - [FAQ](https://wiro.ai/docs/faq): Frequently asked questions --- ## Authentication Two methods (chosen when creating a project — cannot be changed afterward): ### Signature-Based (Recommended) HMAC-SHA256 for enhanced security. Ideal for client-side/mobile apps. Headers: - `x-api-key`: Your project API key - `x-signature`: HMAC-SHA256(key=API_KEY, message=API_SECRET + NONCE) - `x-nonce`: Unix timestamp or random integer ### API Key Only (Simple) Single header for server-side applications. Headers: - `x-api-key`: Your project API key ## Projects Create a project at https://wiro.ai/panel/project/new to get API key and secret. Each project has its own API key, optional API secret, and usage tracking. ## Endpoints ### List Models POST /Tool/List ```json { "start": "0", "limit": "20", "search": "", "categories": ["image-generation"], "hideworkflows": true, "summary": true } ``` ### Model Detail POST /Tool/Detail ```json { "slugowner": "stability-ai", "slugproject": "sdxl" } ``` Returns model info including `parameters` array with input definitions (types: text, textarea, select, range, fileinput, multifileinput, combinefileinput). ### Run a Model POST /Run/{owner-slug}/{model-slug} Content-Type: `application/json` (text inputs) or `multipart/form-data` (file inputs) Use JSON when model has no file parameters. Use multipart when model requires file uploads. File parameter URL rules: - `fileinput`/`multifileinput`: use `{paramId}Url` suffix for URLs (e.g., `inputImageUrl`). Send empty `{paramId}` when using URL, empty `{paramId}Url` when uploading file. - `combinefileinput`: pass URLs directly in `{paramId}` — no suffix needed. Files and URLs share the same field. - Any file parameter also accepts a URL directly in `{paramId}` if `{paramId}Url` doesn't exist. All models support optional `callbackUrl` for webhook notifications on completion. JSON example: ```json { "prompt": "A futuristic city at sunset", "width": 1024, "height": 1024 } ``` Multipart example: ``` -F "inputImage=@photo.jpg" -F "scale=4" ``` Response: ```json { "result": true, "errors": [], "taskid": "2221", "socketaccesstoken": "eDcCm5yyUfIvMFspTwww49OUfgXkQt" } ``` ### Task Detail POST /Task/Detail ```json { "tasktoken": "eDcCm5yyUfIvMFspTwww49OUfgXkQt" } ``` Or by ID: `{ "taskid": "534574" }` Response includes: `id`, `status`, `pexit`, `debugoutput`, `outputs`, `elapsedseconds`, `totalcost`, `modeldescription`, `modelslugowner`, `modelslugproject`. **Determining success:** Check `pexit` field. `"0"` = success, any other value = error. This is the most reliable indicator. For LLM models, the response is available as structured content in `outputs` (with `contenttype: "raw"` containing `prompt`, `raw`, `thinking`, `answer`) and as merged plain text in `debugoutput`. ### Cancel Task (queued only) POST /Task/Cancel — `{ "tasktoken": "..." }` ### Kill Task (running) POST /Task/Kill — `{ "tasktoken": "..." }` ### Delete Task Files (completed/cancelled only) POST /Task/InputOutputDelete — `{ "tasktoken": "..." }` Deletes all output and input files for a completed task from S3, local storage, and database. Invalidates CDN cache. Task must be in terminal state (task_postprocess_end or task_cancel). Idempotent. Errors: `task-not-exist`, `Task must be completed or cancelled before deleting files`. ### Create Folder POST /File/FolderCreate — `{ "name": "my-folder" }` (optional `parentid` for nested folders) ### Upload File POST /File/Upload (multipart/form-data) — Fields: `file`, `folderid`. Max 100MB. Response: `{ result, list: [{ id, name, contenttype, size, url, ... }] }` ## Agent Endpoints POST /Agent/List - List available agent templates (public, no auth required) - returns tiers + tiermultiplier per row POST /Agent/Detail - Get agent template details by guid or slug (public) - returns tiers + tiermultiplier + tokenRates + skills + skillsmeta + credentials._schema POST /Skills/List - Browse the skill registry (public, no auth) POST /Skills/Detail - Get a single skill descriptor by name (public, no auth) POST /Skills/CredentialSchema - Get the credential entry for a skill (public, no auth) POST /Skills/Capabilities - Closed-set capability vocabulary (public, no auth) POST /Credentials/List - Browse the credential registry (public, no auth) POST /Credentials/Detail - Get a single credential schema by key (public, no auth) POST /UserAgent/Deploy - Deploy a new agent instance (template via agentguid OR custom build via custom: true). useprepaid: true + tier: starter|pro for API. Every fresh deploy lands at status:6 (Setup Required) first; prepaid deploys auto-queue to status:2 once the subscription provisions (no manual Start needed). 10-second `(uuid, agentid, teamguid)` dedup window — duplicate calls reject with `errors[0].code: 99` AND a top-level `existingUserAgentGuid` field for adoption. POST /UserAgent/MyAgents - List your deployed agent instances POST /UserAgent/Detail - Get agent instance details (full composed shape: credentials, customskills, scheduledskills, skills, tokenRates, agentModel, enabledCommands, subscription, agent.tiers, agent.extracreditpacks) POST /UserAgent/Update - Update agent scalar fields (title, description, categories, cover URL) POST /UserAgent/UpdateSettings - Update per-agent preference toggles (admin / team-admin only). Fields: timezone (IANA id; null/""/UTC clears back to system default), teamsessionmode ("collaborative"|"private", team-owned agents only), per-agent model overrides chatmodel / cronmodel / voiceprepmodel / voicepostcallmodel (string|null, lowercase on write; null/"" clears to operator default; read back camelCase under agentModel.{chatModel,cronModel,voicePrepModel,voicePostcallModel}), and enabledcommands (string[] slash-command allowlist, no leading slash; [] hides the menu; read back camelCase as enabledCommands, null=all enabled; catalog: agent_help, new_session, agent_status, agent_limits, last_scan, last_heartbeat, agent_restart, clear_all_sessions, clear_history). Partial updates supported; running/starting agents auto-restart to apply. POST /UserAgent/Cover - Upload a cover image (multipart, image field) POST /UserAgent/CredentialUpsert - Write one or more credential fields per provider POST /UserAgent/CredentialFileUpload - Multipart upload for credential fileinput fields (e.g. Twilio voice MP3). Validates mimetype + size against the registry's filetypes[] / maxsize. POST /UserAgent/CredentialFieldHistory - Read credential edit history (oauth_session never appears; clientsecret REDACTED in entries) POST /UserAgent/CustomSkillUpsert - Write a single custom skill's value/interval/enabled (server normalises to cs-* / cs-cron-*) POST /UserAgent/CustomSkillRename - Rename a user-created custom skill's key (+ optional description). Flavour preserved (cs-cron-* stays cron); preset rows rejected; history migrated under the new key POST /UserAgent/CustomSkillAlternatives - List alternative starter templates for a given skillkey (read-only; apply via CustomSkillUpsert) POST /UserAgent/CustomSkillDelete - Delete a user-created cron skill (preset-owned crons rejected with disable-via-upsert suggestion) POST /UserAgent/CustomSkillHistory - Read version history for a custom skill (with preset_default baseline) POST /UserAgent/CustomSkillRevert - Revert to preset default OR a specific historical version POST /UserAgent/SkillsApply - Single or batch skill toggle + optional tier change (idempotency-key required, atomic, ONE restart, prorated wallet delta). Custom builds only for non-admin callers. POST /UserAgent/PricingPreview - Live tier-pricing preview. Two modes: (1) draft: true + skills[] for Builder; (2) useragentguid + skillOverrides for existing UA. POST /UserAgent/Start - Start an agent instance. Rejects with `Subscription required — please subscribe to this agent before starting it.` if the row has no active subscription AND no spendable extras (most often hit after a subscription expires with empty extras — call `RenewSubscription` with `useprepaid: true` to continue). Admin role bypasses this guard. POST /UserAgent/Stop - Stop an agent instance POST /UserAgent/Delete - Soft-delete a useragent (status 0/5/6 only; no active subscription; idempotent) POST /UserAgent/Pin - Pin / unpin an agent POST /UserAgent/PinnedAgents - List pinned agents (header dropdown) POST /UserAgent/PinnedUnread - Latest message guid per pinned agent (unread badge) POST /UserAgent/Realtime/WebStart - Start a browser realtime voice session. Returns sessionId + wsUrl + 5-min JWT-like 2-segment session token (not a standard JWT). Requires agent in status 4 with `util-web-channel` enabled. 60 sessions/hour per operator (fixed window). Live call audio is billed through `int-wiro-aimodels` against the operator's own Wiro AI Models balance — not the agent credit pool. POST /UserAgent/Realtime/Cancel - Cancel a pending realtime session before WS handshake. Requires { sessionId, sessionToken }; JWT must match. Idempotent. POST /UserAgent/TwilioCallHistory/List - Last N realtime call sessions (Twilio AND Web channels — both share `agentmessages.metadata.type startsWith "realtime_session"`). Default 50, max 200. wss://socket.wiro.ai/v1/AgentRealtime/Web - Browser realtime WebSocket. First frame (TEXT, within 10s of open): `{type:"session_start", sessionToken:""}`. Binary audio frames (both directions): `|` — the `|` prefix is on incoming server audio too; strip it before playback. Browser → server text frames: `{type:"interrupt"|"end"}` (`mute` is client-side only — server has no handler). Server → browser JSON frames: `{type:"connecting"}`, `{type:"ready"}`, `{type:"transcript", role:"user"|"ai", text, ts}`, `{type:"clear"}` (barge-in flush), `{type:"resume"}`, `{type:"session_end", reason, message?, error?}`. There is no `audio` JSON frame and no `error` frame — errors ride inside `session_end` (`reason: "rejected" | "start_error"` + a `message` or `error` sibling). POST /UserAgent/CreateSubscriptionCheckout - Subscribe a not-yet-subscribed useragent (always pass useprepaid: true from API — wallet is debited and the agent is auto-queued) POST /UserAgent/CreateExtraCreditCheckout - Purchase extra credits (supports prepaid wallet). Pack keys: small | medium | large. POST /UserAgent/CancelSubscription - Cancel a prepaid subscription at period end POST /UserAgent/UpgradeTier - Upgrade Starter → Pro (targetTier required; downgrade rejected). Wallet is debited the prorated upgrade fee synchronously, subscription + useragent are updated, agent runtime restarted. POST /UserAgent/RenewSubscription - Renew expired prepaid subscription or undo cancel (snapshot-driven pricing, no tier param) POST /UserAgent/TransactionList - Read agent credit ledger (paginated, 50 default 500 max). Returns summary (+ byModel token rollup) + transactions[] with type/action/amount/metadata/user/sessionkey (+ agentsessionkey alias); action:"tokens" deduct rows carry per-turn token columns + tokencost + model. POST /UserAgent/Logs - Per-instance activity feed live tail (newest-first; last N events for date) POST /UserAgent/LogsList - List dates with activity files POST /UserAgent/LogsFile - Read full JSONL file for a date POST /UserAgent/LogsDelete - Delete one date's activity file (idempotent) POST /UserAgent/Message/Send - Send a message to an agent (async, returns agenttoken; optional model body param overrides the chat model for this turn, echoed back as modelChangeMarker) POST /UserAgent/Message/Detail - Get message details by guid or agenttoken (optional sessionkey scopes the read to one session for shared-owner agents) POST /UserAgent/Message/History - Get conversation history with pagination POST /UserAgent/Message/Sessions - List conversation sessions (each row may carry an optional `name` overlay; named-but-empty sessions also surface) POST /UserAgent/Message/RenameSession - Set a session's display `name` (≤40 chars; sessionkey + memory unchanged). Calling it with a new sessionkey before any Send creates a named-but-empty session. POST /UserAgent/Message/DeleteSession - Hard delete (`DELETE FROM useragentmessages`) of every message row in the session belonging to the caller's uuid. Optional `rotate: true` also rotates the memory bucket so the agent forgets the cleared turns. For non-admin callers the delete is always uuid-scoped — even in collaborative team sessions, you can only purge your own contributions. Admin role bypasses the uuid filter and wipes the session for every participant. Reserved sessionkeys (`voice-prep*`, `voice-call-*`, `cs-cron-*`, `wiro:api`) reject with `Session not found` for non-admin callers. POST /UserAgent/Message/Delete - Bulk per-side soft-delete: { items: [{ messageguid, side: "user"|"agent"|"both" }] } POST /UserAgent/Message/Cancel - Cancel an in-progress message (optional sessionkey scopes the cancel to one session) POST /UserAgent/Message/SystemInsert - Insert a finished system message into the conversation history (runtime-only auth: useragentguid + uuid pair; never triggers a model call) POST /UserAgentOAuth/OAuthConnect - Start OAuth flow for a provider (credentialkey selects the provider) POST /UserAgentOAuth/OAuthDisconnect - Disconnect OAuth provider POST /UserAgentOAuth/OAuthStatus - Check OAuth connection status + selected accounts POST /UserAgentOAuth/SetPickerAccounts - Save the user's account/page/customer selection after the OAuth callback (multi-select for Google Ads, Meta Ads, Merchant Center, YouTube, GA4, Facebook Pages) POST /UserAgentOAuth/GoogleDriveListFolders - Discover Drive folders accessible to the agent's service account. Body: { useragentguid, serviceaccountjson?, parentid? }. Without parentid → root listing (folders sharedWithMe). With parentid → children of that folder (SA permission cascade applies). Returns { result, serviceAccountEmail, parentId, folders: [{ id, name, modifiedTime, ownerName }] }. ## Task Statuses task_queue → task_accept → task_preprocess_start → task_preprocess_end → task_assign → task_start → task_output → task_output_full → task_end → task_postprocess_start → task_postprocess_end Additional: task_error (interim stderr log, not final failure), task_error_full (full stderr log), task_cancel Realtime only: task_stream_ready, task_stream_end, task_cost ## WebSocket Connect: `wss://socket.wiro.ai/v1` Register task: ```json { "type": "task_info", "tasktoken": "YOUR_SOCKET_ACCESS_TOKEN" } ``` Receive status messages as the task progresses. Listen for `task_postprocess_end` to get final results. ## LLM & Chat Streaming LLM responses are available in both `outputs` (structured, with `contenttype: "raw"`) and `debugoutput` (merged plain text). Streaming `task_output` messages contain structured objects: ```json { "type": "task_output", "message": { "raw": "full text...", "thinking": ["reasoning..."], "answer": ["response text..."], "isThinking": false, "speed": "12.4", "speedType": "words/s", "elapsedTime": "3s" } } ``` - `raw`: full accumulated output including thinking tags - `thinking`: chain-of-thought reasoning (may be empty) - `answer`: user-facing response - `isThinking`: whether the model is currently in a thinking phase - Both `thinking` and `answer` are arrays that grow with each streaming update ### Multi-turn Conversations Use `session_id` (UUID) to maintain chat history across requests. Server stores conversation context per session. ```json { "prompt": "What is quantum computing?", "session_id": "550e8400-e29b-41d4-a716-446655440000", "user_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7" } ``` Reuse the same `session_id` for follow-ups. New UUID = fresh conversation. Available LLM models: https://wiro.ai/models (filter by LLM category) ## Realtime Voice Conversation For two-way audio conversations with AI models. Flow: Run task → Connect WebSocket (task_info) → Wait for task_stream_ready → Stream mic audio as binary → Receive AI audio as binary → End with task_session_end Audio format: PCM Int16, 24kHz, mono. Binary frame: `tasktoken|pcm_audio_data` Events: task_stream_ready, task_stream_end, task_cost, task_output (TRANSCRIPT_USER:/TRANSCRIPT_AI: prefixes), task_end End session: ```json { "type": "task_session_end", "tasktoken": "YOUR_SOCKET_ACCESS_TOKEN" } ``` Parameters vary per model. Available realtime models: - https://wiro.ai/models/openai/gpt-realtime-mini - https://wiro.ai/models/openai/gpt-realtime - https://wiro.ai/models/elevenlabs/realtime-conversational-ai ## Realtime Text to Speech For one-way streaming TTS: text prompt in via POST /Run, audio chunks stream back over WebSocket. No mic, server → client only. Flow: Run task (text in params) → Connect WebSocket (task_info) → Wait for task_stream_ready → Receive binary PCM chunks → task_stream_end → task_postprocess_end → close. Audio format: PCM Int16, 24kHz, mono. Binary frame: `tasktoken|pcm_audio_data` (server → client only). Events: task_stream_ready, task_stream_end, task_cost, task_end, task_postprocess_end. No task_output (no transcripts — input text is already known). Stream often ends naturally when synthesis completes; task_session_end is optional but good practice for early stop or clean shutdown. Browse models: https://wiro.ai/models (filter by Realtime TTS). ## Realtime Speech to Text For one-way streaming ASR: mic audio in via WebSocket binary frames, transcripts back as task_output. Client → server audio, server → client JSON only. Flow: Run task → Connect WebSocket (task_info) → Wait for task_stream_ready → Stream mic PCM chunks → Receive task_output with TRANSCRIPT_USER: prefix → End with task_session_end. Audio format: PCM Int16, 24kHz, mono. Always send 24kHz — server resamples to model's native rate (e.g. 16kHz for Voxtral). Binary frame: `tasktoken|pcm_audio_data` (client → server only, no server binary frames). Transcript format: `{ "type": "task_output", "message": "TRANSCRIPT_USER:" }` — progressive, word-by-word. No TRANSCRIPT_AI: prefix. Events: task_stream_ready, task_output (TRANSCRIPT_USER: prefix), task_stream_end, task_cost, task_end, task_postprocess_end. Browse models: https://wiro.ai/models (filter by Realtime STT). ## Parameter Types | Type | Description | |------|-------------| | text | Single-line text | | textarea | Multi-line text (prompts) | | select | Dropdown options | | range | Numeric slider | | fileinput | Single file or URL | | multifileinput | Multiple files/URLs | | combinefileinput | Up to N entries (files, URLs, or mixed) | Use /Tool/Detail to discover parameters for any model. ## Quick Start (curl) ```bash export API_KEY="your-api-key" # Run a model curl -X POST "https://api.wiro.ai/v1/Run/{owner-slug}/{model-slug}" \ -H "Content-Type: application/json" \ -H "x-api-key: ${API_KEY}" \ -d '{"prompt": "Hello, world!"}' # Check result curl -X POST "https://api.wiro.ai/v1/Task/Detail" \ -H "Content-Type: application/json" \ -H "x-api-key: ${API_KEY}" \ -d '{"tasktoken": "TOKEN_FROM_RUN_RESPONSE"}' ``` ## Quick Start (Python) ```python import requests API_KEY = "your-api-key" headers = {"x-api-key": API_KEY, "Content-Type": "application/json"} # Run a model run = requests.post( "https://api.wiro.ai/v1/Run/{owner-slug}/{model-slug}", headers=headers, json={"prompt": "Hello, world!"} ).json() # Check result detail = requests.post( "https://api.wiro.ai/v1/Task/Detail", headers=headers, json={"tasktoken": run["socketaccesstoken"]} ).json() print(detail) ``` ## Quick Start (Node.js) ```javascript const axios = require('axios'); const API_KEY = 'your-api-key'; const headers = { 'x-api-key': API_KEY, 'Content-Type': 'application/json' }; // Run a model const run = await axios.post( 'https://api.wiro.ai/v1/Run/{owner-slug}/{model-slug}', { prompt: 'Hello, world!' }, { headers } ); // Check result const detail = await axios.post( 'https://api.wiro.ai/v1/Task/Detail', { tasktoken: run.data.socketaccesstoken }, { headers } ); console.log(detail.data); ``` ## Supported Languages Code examples in 9 languages: curl, Python, Node.js, PHP, C#, Go, Swift, Kotlin, Dart ## Error Codes All API responses return HTTP 200. Check `result` field and error `code`: - Code 0: General/validation errors (missing params, server errors) - Code 1: Not found (model, task) - Code 96: Concurrent task limit reached - Code 97: Insufficient balance - Code 98: Authentication required (sign in) - Code 99: Bearer token invalid/expired Auth errors return HTTP 401: invalid API key, missing signature, IP not allowed. ## Pricing Prepaid credits, pay-per-use. Pricing info in `dynamicprice` field of Tool/List and Tool/Detail responses. Billing methods: - Fixed-rate: cpr (per request), cps (per second), cpo (per output), cpt (per token) - Usage-based: cp-pixel (per pixel tier/1MP), cp-audiosecondslength (per audio second), cp-promptlength (per character), cp-outputVideoLength (per output video second) - Special: cp-realtimeturn (per realtime voice turn), cp-readoutput (model-reported cost) Dynamic pricing: `dynamicprice` field contains pricing tiers with `inputs` (parameter combo), `price` (USD), `priceMethod` (billing code), optional `priceExtra` and `priceInput`. Empty inputs = flat rate. Fallback: when no dynamicprice, cost = elapsed_seconds × cps. `approximatelycost` field = average run time × cps (pre-run estimate). Only successful runs billed (pexit "0"). Server errors, queue time, cancelled tasks = free. Pricing page: https://wiro.ai/product/pricing ## Concurrency Limits Limits apply when balance is $250 or below. Concurrent tasks = max(1, floor(balance * 0.10)). Examples: $50 = 5 concurrent, $150 = 15 concurrent, $251+ = unlimited. Error code 96 returned when limit reached. Error code 97 for insufficient balance. ## MCP Server Wiro provides an MCP (Model Context Protocol) server for AI assistants. ### Hosted (mcp.wiro.ai) Endpoint: https://mcp.wiro.ai/v1 Transport: Streamable HTTP (stateless) Auth: `Authorization: Bearer apiKey:apiSecret` (signature) or `Bearer apiKey` (apikey-only) — plain text, no base64 ### Self-Hosted (npx) ```json { "command": "npx", "args": ["-y", "@wiro-ai/wiro-mcp"], "env": { "WIRO_API_KEY": "...", "WIRO_API_SECRET": "..." } } ``` ### MCP Tools (11 total) - `search_models`: Search/browse models by keyword, category, or owner (POST /Tool/List) - `get_model_schema`: Get model parameters, types, and pricing (POST /Tool/Detail). Use clean model slug - `recommend_model`: Describe what you want to build, get models ranked by relevance (POST /Tool/List) - `explore`: Browse curated models organized by category (POST /Tool/Explore). No parameters needed. - `run_model`: Run any model, wait for result or get task token (POST /Run/{cleanslugowner}/{cleanslugproject}) - `get_task`: Check task status, outputs, cost (POST /Task/Detail) - `get_task_price`: Get cost of a completed task — only successful tasks (pexit "0") are billed (POST /Task/Detail) - `cancel_task`: Cancel a queued task (POST /Task/Cancel) - `kill_task`: Kill a running task (POST /Task/Kill) - `upload_file`: Upload a file from URL to Wiro for model input (POST /File/Upload) - `search_docs`: Search Wiro documentation for guides, API references, and examples ## Node.js Library Use `WiroClient` from `@wiro-ai/wiro-mcp/client` as a standalone API client in Node.js/TypeScript — no MCP required. ```bash npm install @wiro-ai/wiro-mcp ``` ```javascript import { WiroClient } from '@wiro-ai/wiro-mcp/client'; const client = new WiroClient('API_KEY', 'API_SECRET'); const run = await client.runModel('google/nano-banana-pro', { prompt: '...' }); const result = await client.waitForTask(run.socketaccesstoken); ``` Methods: `searchModels()`, `getModelSchema()`, `explore()`, `runModel()`, `waitForTask()`, `getTask()`, `cancelTask()`, `killTask()`, `uploadFile()`. ## Agent API Autonomous AI agents in isolated containers. Two layers: Agent templates (catalog) and UserAgent instances (your deployments). Two deploy paths: template (`agentguid`) and custom build (`custom: true`). Same auth (`x-api-key`). Lifecycle: Browse → Deploy (`useprepaid: true` + `tier`) → Configure credentials → Start → Running → Chat Statuses: 0=Stopped, 1=Stopping, 2=Queued, 3=Starting, 4=Running, 5=Error, 6=Setup Required ### Pricing Model Pricing is fully derived from the agent's enabled skill set + per-template `tiermultiplier`. Two tiers: Starter (default) and Pro. `pro.priceUsd = starter.priceUsd × tiermultiplier`, `pro.credits = starter.credits × tiermultiplier`. Default `tiermultiplier = 10`, snapshotted onto each instance at deploy time and fixed for that instance's lifetime. Starter has a $4/month floor; sub-$4 raw weight sums get bumped to $4 with credits scaled up proportionally so the user gets more credits, not a free upgrade. Agents with zero paid skills stay at $0/0. Default Pro on a $4-floor agent = $40/month. Skill registry weights cluster into 4 buckets: ZERO ($0 / 0 — utility/rule-only), LIGHT ($1 / 25 credits/month), HEAVY ($2 / 50 credits/month), PREMIUM ($4 / 100 credits/month). Every paid skill is 25 credits per $1. NO per-skill Pro overrides — Pro is always `Starter × tiermultiplier` (default `10`); a $4 starter floor applies when raw weight sum is lower (credits scaled proportionally, e.g. $1/25 → $4/100). Per-turn token billing (no per-action costs): the monthly tier buys a credit pool; each turn (chat / cron / voice-prep / voice-postcall) deducts credits metered by the model's `tokenRates` (credits per 1,000,000 tokens; 1 credit = $0.01). `tokencost = ceil(input × input_per_1m / 1e6) + ceil(output × output_per_1m / 1e6) + ceil(cached × cached_input_per_1m / 1e6)` — three independent ceils; cached is additive and `input` already excludes cached reads. The runtime reports usage after each turn → Wiro writes an `action: "tokens"` deduct row, bumps `usedcredits`, derives `remainingcredits`. Per-turn counts + cost ride on each assistant message and on the `agent_usage_report` WebSocket frame. Live realtime voice audio is billed separately through `int-wiro-aimodels` against the operator's own Wiro AI Models balance — not the agent credit pool; only the post-call text turn is a normal token deduct. Extra credit packs are per-useragent: derived as 5x / 10x / 20x of the instance's monthly allocation (both credits and price scaled linearly). Pack keys: `small`, `medium`, `large`. Pro tier only. Agent subscription plan is `"agent"` with separate `tier` field (`"starter"` | `"pro"`). ### Catalog & Registries (Public, No Auth) POST /Agent/List — `{ search, category, sort, order, limit, start }` → `{ result, total, agents: [{ guid, title, slug, headline, cover, categories, samples, tiermultiplier, tiers: { starter: { priceUsd, credits }, pro: { priceUsd, credits } }, status }] }`. The `id` / `totalrun` / `activerun` columns are stripped for the public role. POST /Agent/Detail — `{ guid, slug, type? }` → agent row with `tiermultiplier` + `tiers` + `tokenRates` + `skills` (string[] of enabled preset skill names) + `skillsmeta` (registry metadata for each enabled skill: title/icon/category/credential_key) + `credentials` (template schema with `optional`/`extra` flags + `_editable` map + `_schema` registry descriptor). Pass `type: "full"` to also include `customskills` and `scheduledskills`. `_connected` flag is instance-scoped and only on UserAgent/Detail. `extracreditpacks` is `[]` here — populated only on UserAgent/Detail. POST /Skills/List — `{ category?, capability?, user_invocable?, requires_credentials?, wiro_connect_pending?, name_in?[] }` → `{ result, total, skills: [{ name, title, description, icon, brand_color, brand_text_color, brand_logo_filter, category, version, docs_url, credential_key, additional_credential_keys?, requires_credentials, user_invocable, deprecated, replacement, depends_on[], conflicts_with[], capabilities[], pricing: { monthly_price_weight_usd, monthly_credits_weight, billing_model: "tokens" } }] }`. Categories: `int` (third-party integration) or `util` (utility / rule-only). `additional_credential_keys` only present when set. POST /Skills/Detail — `{ name }` → `{ result, skill }` — same shape as List rows. Errors: `skill-not-found` (404-style) when the canonical name doesn't resolve. POST /Skills/CredentialSchema — `{ name }` → `{ result, credential }` — convenience: returns the credential entry for the skill. POST /Skills/Capabilities — `{}` → `{ result, capabilities: [{ name, description }] }` — closed-set snake_case vocabulary covering reporting (`direct_reporting`, `attribution_cross_check`, `cross_check`, `campaign_reporting`, `markdown_reporting`), campaigns (`campaign_management`, `approval_flow`, `recommendation_ledger`, `recommendation_execution`), generation (`content_generation`, `creative_generation`, `image_generation`, `video_generation`, `audio_generation`, `realtime_conversation`, `vision`, `human_copywriting`, `anti_ai_tone`), publishing (`web_publishing`, `email_publishing`, `social_publishing`, `push_notification`), outreach + reviews (`store_review_response`, `outreach_compliance`, `lead_enrichment`, `sequence_automation`, `multi_platform_detection`), data ops (`memory_management`, `holiday_discovery`, `product_feed_management`, `review_monitoring`, `app_metadata`, `event_management`, `file_asset_management`), voice (`voice_call_handling`, `caller_identification`, `live_transcript`, `voice_persona`, `phone_inbound`, `browser_voice`, `realtime_session_prep`), calendar (`appointment_management`, `calendar_lookup`). POST /Credentials/List — `{ credential_mode?, wiro_connect_pending? }` → `{ result, total, credentials: [{ key, title, icon, brand_color, brand_text_color, credential_mode, connection_modes, oauth_provider?, docs_url, wiro_connect_pending, credential_schema: [{ key, label, type, required?, pattern?, help?, show_toggle?, oauth_managed?, auto_filled_by_oauth?, readonly_when_connected?, only_in_modes?, options? }] }] }`. credential_mode: oauth | sa | api_key | multi_api_key | hybrid | imap_credentials | jwt_sa | rule_only. POST /Credentials/Detail — `{ key }` → `{ result, credential }`. ### Management (Auth Required) POST /UserAgent/Deploy — Two shapes: (a) template `{ agentguid, title, useprepaid: true, tier: "starter"|"pro", credentials?, customskills?, skills?, description?, cover? }`; (b) custom build `{ custom: true, title, useprepaid: true, tier, ... }`. When `useprepaid: true`, deducts the chosen tier price from your wallet and creates a 30-day subscription (`plan: "agent"`, `provider: "prepaid"`). Returns the composed useragent shape. Every fresh Deploy lands pinned (`pinned: 1`) — pinning is server-managed, not a writable parameter; toggle later via `POST /UserAgent/Pin`. **Every fresh Deploy lands at `status: 6` first**, then auto-queues to `status: 2` once the prepaid subscription provisions (no manual Start needed for prepaid). 10-second `(uuid, agentid, teamguid)` dedup window — second call within that window rejects with `result: false`, `errors[0].code: 99`, and a TOP-LEVEL `existingUserAgentGuid` field so callers can adopt the row that already won the race. POST /UserAgent/MyAgents — `{ sort, order, limit, start, category? }` → `{ result, useragents }` — same row shape as PinnedAgents. POST /UserAgent/Detail — `{ guid }` → composed instance: `tier`, `tiermultiplier`, `monthlypriceusd`, `monthlycredits`, `extracredits`, `usedcredits`, `remainingcredits`, `creditperiod`, `creditsyncat`, `tokenRates`, `agentModel`, `enabledCommands` (slash-command allowlist, null=all), `credentials` (with `_connected`/`optional`/`extra`/`_editable`/`_schema`), `customskills` (preference + non-cron user-created), `scheduledskills` (cron skills), `skills`, `subscription` (`plan: "agent"`, `provider`, `amount`, `currentperiodend`, `pendingdowngrade`), `agent` (template summary with `tiers` + `tiermultiplier` + `extracreditpacks`). POST /UserAgent/Update — `{ guid, title?, description?, categories?, cover? }` → Scalar-only update. Running agents auto-restart on success. POST /UserAgent/Cover — multipart `{ useragentguid, image }` → `{ result, cover, useragents }`. Uploads to S3 + writes URL to useragents.cover. POST /UserAgent/CredentialUpsert — `{ useragentguid, fields: [{ credentialkey, fieldname, fieldvalue, fieldstatus?, parentfield?, ordinal? }] }` → `{ result, applied, errors }`. Only `fieldstatus: "user"` writable from API role. POST /UserAgent/CredentialFileUpload — multipart `{ useragentguid, credentialkey, fieldname, file }` → `{ result, url, credentialkey, fieldname }`. For credential schema fields whose `type` is `"fileinput"` only (S3-backed reference; the `fileinput-base64` family stays inline via `CredentialUpsert`). Validates mimetype against `filetypes[]` and size against `maxsize` (KB; default cap 10240 KB / 10 MB). Triggers daemon restart on success. POST /UserAgent/CredentialFieldHistory — `{ useragentguid, credentialkey, startdate?, enddate? }` → `{ result, entries }`. clientsecret REDACTED in entries; oauth_session never appears. POST /UserAgent/CustomSkillUpsert — `{ useragentguid, skillkey, value?, interval?, enabled?, description?, usercreated? }` → `{ result }`. Server auto-normalises skillkey to canonical `cs-*` / `cs-cron-*` based on `interval` presence (or explicit prefix). `usercreated` is admin-only — non-admin callers have it ignored; INSERT writes `true`, UPDATE preserves the row's current source. `enabled` is writable for BOTH strategies (`cs-*`) and crons (`cs-cron-*`) — a disabled strategy is suppressed end-to-end (IDE shows it; runtime drops it from ``; `SKILL.md` write skipped). `interval` only persists on `cs-cron-*` rows. Description-only edits skip the agent restart. POST /UserAgent/CustomSkillRename — `{ useragentguid, oldskillkey, newskillkey, description? }` → `{ result, newskillkey }`. User-created rows only (`usercreated: true`). Flavour preserved — `cs-cron-*` ↔ `cs-*` rejected with `agent-customskill-rename-flavour-mismatch`. Preset rows reject with `agent-customskill-rename-preset-forbidden`. Collision → `agent-customskill-rename-collision`. Version history migrates under the new key + a `rename` audit entry is appended. Triggers daemon restart. POST /UserAgent/CustomSkillAlternatives — `{ useragentguid, skillkey }` → `{ result, alternatives: [{ title, description, value, intervalexpr? }] }`. Read-only template list for the panel's "Browse alternatives" picker; apply via `CustomSkillUpsert` on the SAME `skillkey` (alternatives don't carry their own `key` — they're addressed by index). `intervalexpr` only present on cron-flavoured alternatives. Empty `alternatives[]` is a success. POST /UserAgent/CustomSkillDelete — `{ useragentguid, skillkey }` → `{ result }`. User-created rows only. Preset-owned rows rejected with `suggestion: "disable-via-upsert"` AND registry-owned rows on custom builds (`agentid IS NULL`) also rejected with the same suggestion (custom builds carry registry-seeded scaffolding like `cs-approval-policy` / bundled `cs-cron-*` clones whose runtime contract the agent depends on). POST /UserAgent/CustomSkillHistory — `{ useragentguid, skillkey, startdate?, enddate? }` → `{ result, entries, preset_default }`. POST /UserAgent/CustomSkillRevert — `{ useragentguid, skillkey, source: "preset"|"history", versionguid? }` → `{ result, action, current_value, current_interval, current_enabled }`. POST /UserAgent/SkillsApply — `{ useragentguid, skills: { "int-skillname": bool }, tier?, idempotencyKey }` → `{ result, tier, prepaidWalletDelta, restartTriggered, restartedAt, pricing: { previousPriceUsd, newPriceUsd, deltaUsd, previousMonthlyCredits, newMonthlyCredits, deltaCredits, enabledSkills } }`. **No-op short-circuit:** when every entry in `skills` already matches the persisted state and `tier` is unchanged, the response is `{result:true, errors:[], noOp:true}` with no other fields populated — no DB write, no wallet movement, no restart. Treat `noOp:true` as the signal to skip your own post-apply UI churn. The ONLY skill-toggle endpoint API consumers should use — even single-skill toggles go through this. Atomic batch with one charge + one restart, idempotent. Custom builds only — template UAs reject with code 100 `Cannot edit skills on a template agent — only custom-built agents support skill editing.`. Tier downgrade Pro→Starter rejected. Error codes: 100 `skillsapply-template-only`, 101 `skillsapply-deps-violation`, 102 `skillsapply-conflict`, 103 `skillsapply-insufficient-wallet`, 104 `skillsapply-in-progress`, 105 `skillsapply-tier-downgrade`, 106 `skillsapply-subscription-inactive`, 108 `skillsapply-db-tx-failed`. POST /UserAgent/PricingPreview — Two body shapes: (a) draft `{ draft: true, tier?, skills: [...] }` for Builder; (b) existing `{ useragentguid, tier?, skillOverrides? }`. Returns `{ tier, tiermultiplier, totalPriceUsd, totalMonthlyCredits, tokenRates, skillBreakdown[] (each `{ skill, priceUsd, credits, billing_model: "tokens" }`), enabledSkills, directSkills, agentBase, starterFloorUsd, tiers: { starter, pro } }`. POST /UserAgent/CreateSubscriptionCheckout — `{ useragentguid, useprepaid: true, tier? }` → `{ result, subscriptionId, monthlypriceusd, monthlycredits }`. API consumers always pass useprepaid: true (wallet-backed). Rejects if useragent already has an active subscription. POST /UserAgent/Start — `{ guid }` → Queues agent (status 2). Requires monthlycredits + extracredits > usedcredits. Rejects with `Subscription required — please subscribe to this agent before starting it.` if the row has no active subscription AND no spendable extras (`extracredits - usedcredits ≤ 0`) — most often hit after a subscription expires with empty extras; call `RenewSubscription` (`useprepaid: true`) to continue. Admin role bypasses this guard. POST /UserAgent/Stop — `{ guid }` → Stops or moves to Stopping. POST /UserAgent/Delete — `{ useragentguid }` (or `guid`) → `{ result, useragent: { guid, deletedat } }`. Soft-delete (deletedat + deletedby stamped, audit trail preserved). Requires status `0`/`5`/`6` (running rejected with `useragent-delete-running`) and no active subscription (`useragent-delete-sub-active`). Owner or team admin only. Idempotent: replays no-op via `AND deletedat IS NULL`. POST /UserAgent/Pin — `{ useragentguid, pinned }` → `{ result }`. POST /UserAgent/PinnedAgents — `{}` (uses tokenUUID / teamGUID header) → `{ result, useragents }`. POST /UserAgent/PinnedUnread — `{}` → `{ result, data: [{ useragentguid, lastmessageguid }] }`. POST /UserAgent/CreateExtraCreditCheckout — `{ useragentguid, pack: "small"|"medium"|"large", useprepaid: true }` → `{ result }`. Deducts pack price from wallet, activates credits immediately, expires 6 months. POST /UserAgent/CancelSubscription — `{ guid }` → `{ result, cancelsAt }`. Prepaid-only cancel-at-period-end. Reverse with RenewSubscription (no charge). POST /UserAgent/UpgradeTier — `{ guid, targetTier: "pro" }` → `{ result, tier, previousTier, newPriceUsd, newMonthlyCredits, proratedCharge }`. Wallet debited the prorated upgrade fee. Starter → Pro only; downgrade rejected. POST /UserAgent/RenewSubscription — `{ guid }` → either `{ action: "undo-cancel" }` (no wallet charge) or `{ action: "renewed", plan: "agent", amount, monthlycredits }` (wallet charged the snapshot price, expired sub rolled forward into a fresh 30-day active period; agents in status 0/5 are auto-queued back to 2). Renewal pricing is snapshot-driven from useragents.monthlypriceusd / monthlycredits — registry weight changes between renewals do NOT propagate. POST /UserAgent/TransactionList — `{ useragentguid, limit?, start? }` → `{ result, total, summary, transactions }`. summary: `{ monthlycredits, extracredits, usedcredits, remainingcredits, creditperiod, creditsyncat, byModel: [{ model, inputtokens, outputtokens, cachereadtokens, cachewritetokens, totaltokens, tokencost, turncount }] }`. Each transaction: `{ guid, type, action, amount, balanceafter, description, sessionkey?, agentsessionkey? (alias of sessionkey), messageguid?, provider, providerref?, metadata?, uuid?, user?, createdat }` — `action: "tokens"` deduct rows also carry `{ inputtokens, outputtokens, cachereadtokens, cachewritetokens, totaltokens, tokencost, processedms, model }`. type: deduct | renewal | purchase | grant | expired | refund. (No `"cancel"` type — subscription-end credit revocation appears as `type: "expired"`, `action: "subscription"`.) action: `"tokens"` (per-turn deduct) | message/create/modify/regenerate (legacy deduct) | subscription | small | medium | large (purchase). POST /UserAgent/Logs — `{ useragentguid, date?, lines? }` → `{ result, date, totalLines, events }`. Live tail. Cached 30s for non-admin. `totalLines` is the file-level row count (not the page size). Events are NEWEST-FIRST (descending by `ts`). Each event: `{ ts: ISO-8601 string, kind, tool?, title, summary?, durationMs?, ok?, error?, userUuid?, user? }`. `kind` values: `tool_started`, `tool_completed`, `turn_started`, `turn_ended`, `cron_started`, `cron_finished`, `session_start`, `session_end`, `user_message`, `agent_reply`, `token_usage`, `token_usage_idempotent`, `balance_gate_blocked`. `token_usage` events add `{ model, tokens: { input, output, cacheRead, cacheWrite, total }, tokencost, durationMs, calls, remainingcredits }`. `tool` (only on `tool_*`): `read|write|edit|exec|web_fetch|web_search|sessions_spawn|message`. `summary` is opaque structured payload (plugin pre-redacts secrets — apikey/apppassword/bearer/token). POST /UserAgent/LogsList — `{ useragentguid }` → `{ result, dates: [{ date, sizeBytes, compressed }] }` sorted newest-first. POST /UserAgent/LogsFile — `{ useragentguid, date }` → `{ result, date, truncated, events }`. Full JSONL file read. Same event shape as /Logs. POST /UserAgent/LogsDelete — `{ useragentguid, date }` → `{ result, date, removed: { plain, gz } }`. ### Messaging POST /UserAgent/Message/Send — `{ useragentguid, message, sessionkey?, callbackurl?, model? }` → `{ result, messageguid, agenttoken, status: "agent_queue", modelChangeMarker? }`. `model` (optional) overrides the agent's chat model for this turn only — must be a `selectable` slug from `tokenRates.models`; when it differs from the current model the response includes `modelChangeMarker: { messageguid, model, status: "agent_done" }` (a synthetic marker row inserted into history). POST /UserAgent/Message/Detail — `{ messageguid }` or `{ agenttoken }` (optional `sessionkey` scopes the read to one session) → `{ result, data: { guid, uuid, user, sessionkey, content, response, debugoutput, status, metadata, attachments, deletestatus, createdat, startedat, endedat, inputtokens, outputtokens, cachereadtokens, cachewritetokens, totaltokens, model, tokencost, processedms } }`. Assistant rows carry the flat lowercase token columns + `model` + `tokencost` (credits) + `processedms`; `metadata.tokenCount` is a separate bridge-reported count, not the billed total. `user` is server-decorated `{ uuid, firstname, lastname, email, username, avatar, avatarinitials }` from agentmessages.uuid; `null` for system rows. POST /UserAgent/Message/History — `{ useragentguid, sessionkey?, limit?, before? }` → `{ result, data: { messages, count, hasmore } }`. Each message row carries the same shape as Message/Detail (including `uuid` sender + decorated `user` object + token columns). Per-turn model switches surface as synthetic `model_change` marker rows (`status: "agent_done"`, `metadata.type: "model_change"`). Collaborative team mode returns rows from all team members; private mode filters by caller uuid. POST /UserAgent/Message/Sessions — `{ useragentguid }` → `{ result, data: { sessions: [{ sessionkey, messagecount, updatedat, lastmessage, name? }] } }`. `name` is the optional display-name overlay (set via RenameSession); `model_change` marker rows are excluded from session counts / lastmessage; named-but-empty sessions surface with messagecount 0. POST /UserAgent/Message/RenameSession — `{ useragentguid, sessionkey, name }` → `{ result, errors }`. Sets a display `name` (sanitized, ≤40 chars) on the session in an overlay table; the `sessionkey` and the agent's memory are unchanged. Calling it with a brand-new sessionkey before any Send creates a named-but-empty session that immediately lists. Reserved system keys reject with `"Session not found"` for non-admin callers. POST /UserAgent/Message/DeleteSession — `{ useragentguid, sessionkey, rotate? }`. Hard delete (`DELETE FROM useragentmessages`). `rotate: true` (default false) also rotates the memory bucket so the agent forgets the cleared turns; the `name` overlay is dropped. For non-admin callers the WHERE clause includes `AND uuid = caller_uuid`, so the call only purges the caller's own rows — even in a collaborative team session, you can't wipe another participant's history. Admin role drops the uuid filter and wipes the whole session. Non-admin callers passing reserved sessionkeys (`voice-prep`, `voice-prep-`, `voice-call-`, `cs-cron-`, `wiro:api`) get `"Session not found"` instead of a delete (no info-leak shape). POST /UserAgent/Message/Delete — `{ useragentguid, items: [{ messageguid, side: "user"|"agent"|"both" }] }`. Per-side soft-delete via the `deletestatus` bitmask: user → 1, agent → 3, both → 3 (agent collapses to 3 because total-disappearance is the user-facing intent — pure-2 admin-moderation semantic no longer reachable here). `Message/History` filters using `deletestatus = 0` (any bit set hides the row); admin-only `includeDeleted: true` opts back in for the xyz audit page. Best-effort across the items array. POST /UserAgent/Message/Cancel — `{ messageguid }` or `{ agenttoken }` (optional `sessionkey` scopes the cancel to one session). Only cancellable in agent_queue/agent_start/agent_output. POST /UserAgent/Message/SystemInsert — runtime-only auth: `{ useragentguid, uuid, content, sessionkey? }` → `{ result, messageguid, sessionkey }`. Inserts a verbatim message into agentmessages with status='agent_end' and metadata.type='system' — never queues, never calls the model. sessionkey defaults to "auto" (resolved to last session, falls back to "default"). Used by agent runtime, cron skills, and external chat-platform bridges (Telegram/Slack relays). Message statuses: agent_queue → agent_start → agent_output (multiple) → agent_end. Also: agent_error, agent_cancel. `agent_done` is used only on synthetic `model_change` marker rows. ### Agent WebSocket Same server: wss://socket.wiro.ai/v1. Subscribe per-turn: `{ "type": "agent_info", "agenttoken": "..." }`. Subscribe with your `sessionkey` as the token to also receive `agent_wiroai_runtask` run-discovery frames for that session. Events: agent_subscribed (status + debugoutput), agent_start, agent_output (streaming: raw, thinking, answer, isThinking, speed, tokenCount, wordCount), agent_end (final), agent_usage_report (arrives after agent_end on the same channel: `{ messageguid, model, inputtokens, outputtokens, cachereadtokens, cachewritetokens, totaltokens, tokencost, remainingcredits }`), agent_error (string or object), agent_cancel. agent_wiroai_runtask (fires when the agent itself launches a Wiro model run mid-turn — e.g. image/video via int-wiro-aimodels; broadcast on the sessionkey channel with `{ taskid, socketaccesstoken, slugowner, slugproject, categories, status }`; subscribe to its socketaccesstoken via `task_info` to stream task_queue→task_postprocess_end and collect media outputs; NOT emitted for /Run calls you make yourself). `result: true` for success events, `false` for error/cancel. Output contains full accumulated text (replace, don't append). ### Agent Webhooks Include `callbackurl` in Message/Send. Wiro POSTs when agent finishes: `{ messageguid, status, content, response, debugoutput, metadata: { raw, thinking, answer, speed, wordCount, ... }, endedat }` For error/cancel: `metadata` is `{}`. Retry: 3 attempts, 2s delay. Must return HTTP 200. ### Credentials API Key: Set via `POST /UserAgent/CredentialUpsert` with `fields[]`. One row per field: `{ credentialkey: "", fieldname: "", fieldvalue: "" }`. Nested arrays (`firebase.accounts`, `google-drive.folders`, `apple-appstore.apps`, `google-play.apps`) use `parentfield` (dotted path) + `ordinal` (index). Services and their registry credentialkeys: brevo (apikey), sendgrid (apikey), wordpress (url, user, apppassword), firebase (accounts[] with appname + serviceaccountjson + apps[].id/platform + topics[].topickey), gmail (account, apppassword), apollo (apikey, masterapikey), lemlist (apikey), telegram (bottoken, allowedusers JSON array, sessionmode), var-website (urls[] of {websitename, url}), var-support-email (value), apple-appstore (keyid, issuerid, privatekey, apps[] with appname+appid), google-play (serviceaccountjson, apps[] with appname+packagename). OAuth: All OAuth integrations share four unified endpoints. The provider is selected via a `credentialkey` body parameter (e.g. `"google-ads"`, `"twitter"`, `"facebook-pages"`). Per-provider `*Callback` GET URLs remain per-provider since external OAuth platforms redirect to fixed URLs. POST /UserAgentOAuth/OAuthConnect — `{ useragentguid, credentialkey, redirecturl, authmethod: "wiro"|"own" }` → `{ result, errors, authorizeUrl }`. White-label: user sees only your app + provider consent screen, never wiro.ai. Credential keys: `twitter`, `tiktok`, `instagram`, `facebook-pages`, `linkedin`, `google-ads`, `meta-ads`, `google-merchant-center`, `youtube`, `ga4`, `hubspot`, `mailchimp`. POST /UserAgentOAuth/OAuthStatus — `{ useragentguid, credentialkey }` → `{ result, errors, connected, accounts: [{id, name}], connectedat, tokenexpiresat }`. `accounts[]` carries one entry per selected account (multi-select pickers — Google Ads, Meta Ads, Merchant Center, YouTube, GA4, Facebook Pages) or a single entry with the connected user's identifier (Twitter/X, TikTok, Instagram, LinkedIn, HubSpot, Mailchimp). Empty `[]` when nothing is selected. POST /UserAgentOAuth/OAuthDisconnect — `{ useragentguid, credentialkey }` → `{ result, errors }` POST /UserAgentOAuth/TokenRefresh — `{ useragentguid, provider }` → `{ accesstoken, refreshtoken }`. API users typically don't call this — every running agent container runs its own token refresh cron jobs (20 min for HubSpot, 45 min for Google Ads/Drive, 90 min for Twitter/X, daily for others) that call this endpoint internally. Manual calls are for debugging only. Not supported for Mailchimp (tokens don't expire). Post-callback account selection (unified): POST /UserAgentOAuth/SetPickerAccounts — `{ useragentguid, credentialkey, accounts: [{...item_fields_to_save}] }` → `{ result, errors, accounts: [{id, name}] }`. Single registry-driven dispatcher for the per-credential picker shape. Per-credential `accounts[]` entry shape: `google-ads` → `{ customerid, customerdescriptivename }`; `meta-ads` → `{ adaccountid, adaccountname }`; `google-merchant-center` → `{ merchantid, accountname }`; `youtube` → `{ channelid, channeltitle }`; `ga4` → `{ propertyid, propertydisplayname }`; `facebook-pages` → `{ pageid, fbpagename }` (per-page access tokens pulled from the 15-min OAuth pending cache automatically). Client-side only receives `{id, name}` pairs via the redirect-URL query params (e.g. `fb_pages`, `gads_accounts`, `metaads_accounts`). Meta Platforms (Meta Ads, Facebook Page, Instagram): wiro mode coming soon while shared app pending Meta review. Use own mode with your own Meta Developer App in Development Mode — no App Review required when users connecting are added to the app's Roles as Testers/Developers. ## Organizations & Teams Wiro supports personal and team workspaces. Personal is the default. Organizations group teams; teams hold projects, agents, and wallets. Context resolution: API key determines context automatically. Team project API key → team context. Personal project API key → personal context. No extra headers needed. Roles: Owner (org creator — full control), Admin (team settings, invites, transfers), Member (run models, message agents, view spending). Endpoints: - POST /Organization/Create — `{ name }` → creates org, caller becomes owner - POST /Organization/List — returns all orgs with teams, roles, wallet balances - POST /Organization/Remove — `{ organizationguid }` — soft-delete, transfers agents+projects to owner personal - POST /Organization/Restore — `{ organizationguid }` — reactivates org, teams, accepted members - POST /Team/Create — `{ organizationguid, name }` — creates team with own wallet - POST /Team/Update — `{ teamguid, name?, spendlimit?, modelaccess?, allowedmodelids?, blockedmodelids? }` - POST /Team/Remove — `{ teamguid }` — owner only, transfers agents+projects to personal - POST /Team/Member/Invite — `{ teamguid, email, role }` — sends email invite, expires 7 days - POST /Team/Member/Accept — `{ token }` — accept invite link - POST /Team/Member/List — `{ teamguid }` → members with roles, statuses, avatars - POST /Team/Member/Remove — `{ teamguid, useruuid }` - POST /Team/Member/UpdateRole — `{ teamguid, useruuid, role }` - POST /Team/TransferAgent — `{ useragentguid, targetteamguid }` — empty string for personal - POST /Team/TransferProject — `{ projectapikey, targetteamguid }` — empty string for personal - POST /Team/TransferCredit — `{ amount, sourceteamguid, targetteamguid }` — transfer credit between wallets, preserves expiry - POST /Team/SpendingSummary — `{ teamguid }` → teamTotal, playgroundTotal, apiTotal, memberSpent, limits Model access: `modelaccess` field — `"all"` (default, no restrictions), `"allowlist"` (only allowedmodelids), `"blocklist"` (block blockedmodelids). Checked at /Run endpoint only. Spend limits: Team-level (spendlimit on team) and member-level (spendlimit on member). Budget alert email at 80%. Agent context guards: Agent operations (Message/Send, Deploy, ExtraCredit, Cancel/Renew/Upgrade) enforce context match — project team must equal agent team. Mismatch returns error. Resource isolation: Project/List, UserAgent/MyAgents, Task/List, Task/Stat, Wallet/List, Coupon/UserList all filter by active context. ## Links - [Wiro Platform](https://wiro.ai): Main website - [Dashboard](https://wiro.ai/panel): Manage projects and API keys - [Create Project](https://wiro.ai/panel/project/new): Get API key and secret - [Explore Models](https://wiro.ai/models): Browse all available AI models - [Full Documentation](https://wiro.ai/docs): Interactive API documentation - [Full Markdown Export](https://raw.githubusercontent.com/wiroai/Wiro-Docs/main/markdown/full-documentation.md): All docs in a single markdown file - [MCP GitHub](https://github.com/wiroai/Wiro-MCP): MCP server source code - [MCP npm](https://www.npmjs.com/package/@wiro-ai/wiro-mcp): MCP server package