Agent Builder
Build a custom agent from scratch: no marketplace template required. Pick your own skill set, preview the live tier price, and deploy in one call.
Overview
Wiro's agent runtime supports two deploy paths:
| Path | When to use | Endpoint |
|---|---|---|
| Template deploy | The marketplace already has an agent that does what you need (Instagram Manager, Push Notifications, App Review Support, …). You inherit the template's default skill set + configuration. | POST /UserAgent/Deploy with agentguid |
| Custom build | You want a unique skill combination: for example a custom support bot that watches Gmail, publishes a daily digest to WordPress, and uses Wiro's image generator. No marketplace template fits. | POST /UserAgent/Deploy with custom: true |
The two paths produce the same useragent shape at the end (same customskills, scheduledskills, credentials, subscription, tokenRates, etc.). The only differences are:
| Aspect | Template deploy | Custom build |
|---|---|---|
| Linked marketplace template | The template you deployed | None |
| Pricing recipe | Computed from the template's skill set, plus any skill you change after deploy | Computed from the skills you toggled on |
agent.tiers on the response |
Template's tier numbers | Live-resolved per-instance tier numbers |
agent.cover on the response |
Template's cover image | The cover you sent at Deploy (or a placeholder) |
| Cascade updates | When Wiro updates the template, your useragent reconciles | No template: the agent is fully owned by you |
Custom builds don't share a marketplace listing. They are private to your account; nothing about a custom agent appears on
/Agent/Listor/Agent/Detail. Discovery happens through your own product surface.
Step 1: Browse Available Skills
Custom builds start from the skill registry, the catalogue of every skill the platform supports. Browse it with POST /Skills/List and inspect details with POST /Skills/Detail.
Both endpoints are public, so no authentication is required.
# Browse all integration skills
curl -X POST "https://api.wiro.ai/v1/Skills/List" \
-H "Content-Type: application/json" \
-d '{ "category": "int" }'
Pick the skill names you want to enable. Each skill descriptor tells you:
name: the canonical skill key you'll send inskills/skillOverridescategory:int(integration with a third-party service) orutil(utility, no credential to connect)credential_key: which credential the skill needs (nullforutilor platform-managed skills)requires_credentials: boolean, whether the user must supply a credential before the skill can rundepends_on: array of skill names that must also be enabled (Wiro auto-enables transitive deps)conflicts_with: array of skill names that cannot coexist with this onepricing: the per-skill pricing recipe (monthly_price_weight_usd,monthly_credits_weight,billing_model: "tokens")
Use
POST /Skills/Capabilitiesto discover the closed-set capability vocabulary (the high-level tasks skills can perform). Useful when you want to find every skill that can "post-content" or "send-email".
Step 1b: Discover Communication Channels
The same POST /Skills/List response includes a top-level channels[] catalog. Channel discovery is registry-driven and does not depend on the marketplace template.
{
"result": true,
"channels": [
{
"id": "telegram",
"credential_key": "telegram",
"title": "Telegram",
"required_fields": ["bottoken", "allowedusers"],
"capabilities": {
"direct": true,
"rooms": true,
"threads": true,
"roles": false,
"command_menu": true
},
"credential": {
"key": "telegram",
"credential_schema": ["..."]
}
}
]
}
The current external channel IDs are telegram, slack, and discord. channels[] is returned in full even when the request filters skills[]. Render forms from credential.credential_schema and require each row's required_fields before connecting it. A channel activates automatically when every required value is complete.
Web chat and the Messaging API are always available. External channels have no separate enablement parameter: pass a complete channel group in Deploy's credentials object, or add it later with POST /UserAgent/CredentialUpsert. The channel activates automatically when all required_fields are complete. Channels do not add skills or change agent pricing.
Step 2: Live Pricing Preview
Before you commit, fetch the live tier price for the proposed skill set with POST /UserAgent/PricingPreview. The draft mode runs without touching any DB state.
curl -X POST "https://api.wiro.ai/v1/UserAgent/PricingPreview" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"draft": true,
"tier": "pro",
"skills": ["int-gmail-check", "int-wordpress-post", "int-wiro-aimodels"]
}'
Response
{
"result": true,
"errors": [],
"tier": "pro",
"tiermultiplier": 10,
"totalPriceUsd": 60,
"totalMonthlyCredits": 6000,
"starterFloorUsd": 4,
"skillBreakdown": [
{ "skill": "int-gmail-check", "priceUsd": 1, "credits": 100, "billing_model": "tokens" },
{ "skill": "int-wordpress-post", "priceUsd": 4, "credits": 400, "billing_model": "tokens" },
{ "skill": "int-wiro-aimodels", "priceUsd": 1, "credits": 100, "billing_model": "tokens" }
],
"enabledSkills": ["int-gmail-check", "int-wordpress-post", "int-wiro-aimodels"],
"directSkills": ["int-gmail-check", "int-wordpress-post", "int-wiro-aimodels"],
"agentBase": { "priceUsd": 0, "credits": 0 },
"tokenRates": {
"default_model": "openai/gpt-5.6-sol",
"fallback_rate": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "cache_write_per_1m": 781.25 },
"models": {
"openai/gpt-5.6-sol": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "cache_write_per_1m": 781.25, "selectable": true, "label": "GPT-5.6 Sol", "tier": "premium" },
"openai/gpt-5.6-terra": { "input_per_1m": 250, "output_per_1m": 1500, "cached_input_per_1m": 25, "cache_write_per_1m": 312.5, "selectable": true, "label": "GPT-5.6 Terra", "tier": "balanced" },
"openai/gpt-5.6-luna": { "input_per_1m": 25, "output_per_1m": 150, "cached_input_per_1m": 2.5, "cache_write_per_1m": 31.25, "selectable": true, "label": "GPT-5.6 Luna", "tier": "cheap" },
"openai/gpt-5.5": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "selectable": true, "label": "GPT-5.5", "tier": "premium" },
"openai/gpt-5.4": { "input_per_1m": 312.5, "output_per_1m": 1875, "cached_input_per_1m": 31.25, "selectable": true, "label": "GPT-5.4", "tier": "balanced" }
}
},
"tiers": {
"starter": { "priceUsd": 6, "credits": 600 },
"pro": { "priceUsd": 60, "credits": 6000 }
}
}
Read the response:
tiers.starter.priceUsdandtiers.pro.priceUsd→ what your wallet will be charged for each tier.tiers.starter.creditsandtiers.pro.credits→ monthly credit allocation.tokenRates→ per-model token rates (credits per 1M input / output / cached-input tokens). Each conversation turn is metered against these (see token billing).skillBreakdown[]→ per-skill contribution to the total. Use this to see which skill is the most expensive.enabledSkills→ final closure (includes any transitively-enableddepends_on).
agentBaseis always{ priceUsd: 0, credits: 0 }: pricing is fully skill-driven and the field is kept on the response so callers don't have to null-check. The agent's Starter price = Σ(skill weights), bumped to thestarterFloorUsdfloor ($4/month by default) if the raw sum lands below it (credits scale up by the same ratio). Pro = Starter ×tiermultiplier(default10). Per-turn conversation cost is metered separately against the agent'stokenRates(see token billing).
Step 3: Deploy the Custom Agent
Send the same skill set you previewed to POST /UserAgent/Deploy with custom: true and useprepaid: true. The selected tier is debited immediately.
curl -X POST "https://api.wiro.ai/v1/UserAgent/Deploy" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"custom": true,
"title": "Inbox Watcher",
"description": "Watches inbound Gmail and forwards a summary to Telegram every 4 hours.",
"useprepaid": true,
"tier": "pro",
"skills": {
"int-gmail-check": true,
"int-wordpress-post": true,
"int-wiro-aimodels": true
},
"credentials": {
"gmail": { "account": "agent@company.com", "apppassword": "xxxx xxxx xxxx xxxx" },
"telegram": {
"bottoken": "123456:ABC-DEF...",
"allowedusers": ["123456789"]
}
},
"customskills": [
{
"key": "cs-cron-summarize-inbox",
"value": "Every 4 hours, scan all unread Gmail messages from the past 4 hours, summarize each in 1 sentence, and post the digest to Telegram.",
"interval": "0 */4 * * *",
"enabled": true,
"_user_created": true,
"description": "Inbox summary digest"
}
]
}'
Response (excerpt)
{
"result": true,
"errors": [],
"useragents": [
{
"guid": "f8e7d6c5-b4a3-2190-fedc-ba0987654321",
"agentguid": null,
"title": "Inbox Watcher",
"description": "Watches inbound Gmail and forwards a summary to Telegram every 4 hours.",
"tier": "pro",
"tiermultiplier": 10,
"status": 2,
"setuprequired": false,
"monthlycredits": 6000,
"monthlypriceusd": 60,
"remainingcredits": 6000,
"renewalcredits": 6000,
"creditperiod": "2026-05",
"tokenRates": {
"default_model": "openai/gpt-5.6-sol",
"fallback_rate": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "cache_write_per_1m": 781.25 },
"models": {
"openai/gpt-5.6-sol": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "cache_write_per_1m": 781.25, "selectable": true, "label": "GPT-5.6 Sol", "tier": "premium" },
"openai/gpt-5.6-terra": { "input_per_1m": 250, "output_per_1m": 1500, "cached_input_per_1m": 25, "cache_write_per_1m": 312.5, "selectable": true, "label": "GPT-5.6 Terra", "tier": "balanced" },
"openai/gpt-5.6-luna": { "input_per_1m": 25, "output_per_1m": 150, "cached_input_per_1m": 2.5, "cache_write_per_1m": 31.25, "selectable": true, "label": "GPT-5.6 Luna", "tier": "cheap" },
"openai/gpt-5.5": { "input_per_1m": 625, "output_per_1m": 3750, "cached_input_per_1m": 62.5, "selectable": true, "label": "GPT-5.5", "tier": "premium" },
"openai/gpt-5.4": { "input_per_1m": 312.5, "output_per_1m": 1875, "cached_input_per_1m": 31.25, "selectable": true, "label": "GPT-5.4", "tier": "balanced" }
}
},
"agentModel": {
"chatModel": "openai/gpt-5.6-sol",
"cronModel": "openai/gpt-5.4-mini",
"voicePrepModel": "openai/gpt-5.4-mini",
"voicePostcallModel": "openai/gpt-5.4"
},
"skills": ["int-gmail-check", "int-wordpress-post", "int-wiro-aimodels"],
"customskills": [],
"scheduledskills": [
{
"key": "cs-cron-summarize-inbox",
"value": "Every 4 hours, scan all unread Gmail messages from the past 4 hours, summarize each in 1 sentence, and post the digest to Telegram.",
"interval": "0 */4 * * *",
"enabled": true,
"_source": "user-created",
"_editable": true,
"_user_created": true
}
],
"communicationChannels": [
{ "id": "telegram", "credentialkey": "telegram", "title": "Telegram", "required_fields": ["bottoken", "allowedusers"], "enabled": true, "configured": true, "missingfields": [] }
],
"enabledChannels": ["telegram"],
"teamsessionmode": "private",
"credentials": {
"gmail": { "_connected": false, "optional": false, "extra": false, "account": "agent@company.com", "apppassword": "xxxx xxxx xxxx xxxx" },
"telegram": { "_connected": false, "optional": false, "extra": false, "bottoken": "123456:ABC-DEF...", "allowedusers": ["123456789"] }
},
"agent": {
"custom": true,
"title": "Inbox Watcher",
"tiermultiplier": 10,
"tiers": {
"starter": { "priceUsd": 6, "credits": 600 },
"pro": { "priceUsd": 60, "credits": 6000 }
},
"extracreditpacks": [
{ "packkey": "small", "credits": 30000, "priceusd": 300, "enabled": true },
{ "packkey": "medium", "credits": 60000, "priceusd": 600, "enabled": true },
{ "packkey": "large", "credits": 120000, "priceusd": 1200, "enabled": true }
]
}
}
]
}
Notes on the response:
agentguid: nullconfirms this is a custom build with no marketplace template.agent.custom: trueis the synthesized template placeholder. Same shape as a template'sagentblock but noslug/cover/categories(custom builds aren't in the marketplace).scheduledskillsalready contains the cron from the Deploy body. Deploy storescustomskillskeys exactly as sent, so give each entry its full key:cs-<slug>for a strategy,cs-cron-<slug>for a scheduled task.status: 2means Deploy auto-queued the instance becauseuseprepaid: trueprovisioned a subscription in the same call. Wiro starts the agent from the queue; you do not need to callPOST /UserAgent/Startafter a prepaid deploy.- Communication-channel credentials are validated independently from
skills. Every channel group present incredentialsmust contain all of itsrequired_fieldsor Deploy fails without leaving a partial agent behind.
Step 4: Refine Skills After Deploy
Toggle skills on/off after deploy with POST /UserAgent/SkillsApply. Even when you only want to flip a single skill, send it as a one-entry skills map. The endpoint charges the wallet once, triggers exactly one agent restart, and rolls back atomically on payment failure. Template deploys accept the same call.
Single-skill enable
curl -X POST "https://api.wiro.ai/v1/UserAgent/SkillsApply" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "f8e7d6c5-b4a3-2190-fedc-ba0987654321",
"idempotencyKey": "550e8400-e29b-41d4-a716-446655440001",
"skills": {
"int-instagram-post": true
}
}'
The response includes the new pricing snapshot and the prorated wallet debit:
{
"result": true,
"errors": [],
"tier": "pro",
"prepaidWalletDelta": 5.0,
"usedCreditsUsd": 0,
"restartTriggered": true,
"restartedAt": 1714694520,
"pricing": {
"previousPriceUsd": 60,
"newPriceUsd": 70,
"deltaUsd": 10,
"previousMonthlyCredits": 6000,
"newMonthlyCredits": 7000,
"deltaCredits": 1000,
"creditsNow": 500,
"creditsThisPeriod": 6500,
"creditsFromRenewal": 7000,
"periodEnd": 1715990520,
"enabledSkills": ["int-gmail-check", "int-wordpress-post", "int-wiro-aimodels", "int-instagram-post"]
}
}
prepaidWalletDelta is the USD amount debited from your wallet for the rest of the current period: the monthly difference for the time left, by the second, rounded up to the cent, and at least one day's worth. The added credits come for that same time (pricing.creditsNow), and every renewal gives the whole allowance (pricing.creditsFromRenewal). If you disable a paid skill mid-period the delta is negative and rounds down to the cent: what the time left is worth goes back to the balances that paid for the period, less 1 cent for each credit already used above what the period keeps (usedCreditsUsd); the period keeps the credits the days already gone paid for until the next renewal. Each balance keeps the end date of the credit or deposit that paid; a part whose source has ended since lasts until the period ends.
Batch toggle + tier upgrade in one call
When the user stages many toggles in your UI and commits them all together, send everything in one SkillsApply call:
curl -X POST "https://api.wiro.ai/v1/UserAgent/SkillsApply" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"useragentguid": "f8e7d6c5-b4a3-2190-fedc-ba0987654321",
"tier": "pro",
"idempotencyKey": "550e8400-e29b-41d4-a716-446655440000",
"skills": {
"int-gmail-check": true,
"int-wordpress-post": true,
"int-wiro-aimodels": true,
"int-instagram-post": true,
"int-metaads-manage": false
}
}'
idempotencyKey is required: use a UUID per "user clicks Save" event. A retry of the same key returns the cached response without applying the change again.
Common Recipes
A. Email-driven Telegram digest
{
"custom": true,
"title": "Email Digest Bot",
"useprepaid": true,
"tier": "starter",
"skills": { "int-gmail-check": true, "int-wordpress-post": true },
"credentials": {
"gmail": { "account": "agent@company.com", "apppassword": "xxxx xxxx xxxx xxxx" },
"telegram": { "bottoken": "123456:ABC-DEF...", "allowedusers": ["123456789"] }
},
"customskills": [
{
"key": "cs-cron-email-digest",
"value": "Twice a day, summarize unread Gmail messages in one Telegram message.",
"interval": "0 9,17 * * *",
"enabled": true,
"_user_created": true,
"description": "Daily email digest"
}
]
}
B. WordPress publisher with weekly research
{
"custom": true,
"title": "Blog Research & Publish",
"useprepaid": true,
"tier": "pro",
"skills": { "int-wordpress-post": true, "int-wiro-aimodels": true },
"credentials": {
"wordpress": { "url": "https://blog.example.com", "user": "admin", "apppassword": "xxxx xxxx xxxx xxxx" },
"var-website": { "urls": "[{\"websitename\":\"Wired\",\"url\":\"https://www.wired.com/feed/rss\"}]" }
},
"customskills": [
{
"key": "cs-content-strategy",
"value": "## Writing Style\nShort, punchy, technical. Always include code examples.\n\n## Sources\nWired, ArsTechnica, Hacker News.\n\n## Cadence\nOne 600-word article every Monday.",
"_user_created": false
},
{
"key": "cs-cron-weekly-blog",
"value": "Every Monday morning, scan the websites listed under your var-website credential, draft one 600-word article, and publish to WordPress as a draft.",
"interval": "0 9 * * 1",
"enabled": true,
"_user_created": true,
"description": "Weekly WordPress publish"
}
]
}
C. Multi-channel social poster (Pro tier)
{
"custom": true,
"title": "Cross-Channel Social",
"useprepaid": true,
"tier": "pro",
"skills": {
"int-twitterx-post": true,
"int-instagram-post": true,
"int-linkedin-post": true,
"int-facebookpage-post": true,
"int-wiro-aimodels": true
},
"credentials": {}
}
OAuth providers are connected later via POST /UserAgentOAuth/OAuthConnect with the provider's credentialkey (see Agent Credentials).
Subscription & Billing for Custom Builds
Subscriptions for custom builds work exactly like template deploys:
- A 30-day prepaid subscription row (
plan: "agent",tier: <starter|pro>,provider: "prepaid") is inserted at Deploy. POST /UserAgent/CancelSubscriptionschedules cancel-at-period-end.POST /UserAgent/RenewSubscriptioneither undoes a pending cancel (no charge) or creates a fresh 30-day period (wallet charged).POST /UserAgent/UpgradeTierupgrades Starter → Pro with a prorated wallet debit.
When you toggle a skill on or off, the active subscription is automatically prorated (see Step 4 above). The new monthly amount becomes your charge at next renewal.
Limits & Notes
- Every build costs at least the floor. Starter costs at least the
starterFloorUsdfloor, $4 and 400 credits a month, and a build made only of free skills pays that floor too. - Conflict / dependency violations are surfaced eagerly. If you toggle on two mutually-exclusive skills,
SkillsApplyreturns code102with aconflicts[]array; if adepends_onis missing, code101withdeps[]. Resolve in the UI before committing. - Custom builds receive the same auto-restart on configuration changes as template deploys (status
3/4→ status1, then re-queued). - Cover image: custom builds can ship a
coverURL in the Deploy body, or upload one later viaPOST /UserAgent/Cover. - The agent's persona is editable via the standard
customskillsflow. Add acs-personastrategy viaCustomSkillUpsertto set the agent's voice, role, and constraints.
What's Next
- Agent Skills: Discover the skill registry, browse credentials per skill, and configure preferences + scheduled tasks
- Agent Credentials: Connect OAuth providers and set API-key credentials
- Agent Messaging: Chat with your custom agent
- Agent Transactions: Audit credit deductions, renewals, and grants