skip to content
iris
apisign instart freestart

iris API v1

build on iris - discover contacts, draft personalized messages with AI, and orchestrate multi-channel outreach from your own apps.

get your API keyquick exampleMCP serverCLIAPI referencewebhooksidempotencyagent paymentscredit packsllms.txtOpenAPI

getting started

create an API key

go to settings → API keys in your iris dashboard and click create key. give it a name and pick scopes, then copy the key immediately - it is shown only once.

store your key securely. keys begin with is_live_ and cannot be retrieved after creation. if you lose it, revoke and create a new one.

base URL

https://api.iris-ai.dev

all timestamps in API responses use ISO 8601 format in UTC (e.g. 2026-04-29T12:00:00.000Z).

make your first request

bash
curl https://api.iris-ai.dev/campaigns \
  -H "Authorization: Bearer is_live_YOUR_KEY"

quick example

create a campaign, discover contacts, check connected channels, and send a message - the minimum end-to-end flow.

step 1 - create a campaign

bash
curl -X POST https://api.iris-ai.dev/campaigns \
  -H "Authorization: Bearer is_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "April DJ outreach - Brooklyn",
    "objective_type": "venue_dj",
    "location": "Brooklyn, NY",
    "radius_miles": 10,
    "venue_types": ["bar", "club", "lounge"],
    "keywords": ["live music", "dj nights"],
    "max_results": 50,
    "outreach_channels": ["email", "instagram", "twitter"],
    "followup_days": [3, 7, 14],
    "status": "draft"
  }'
# response: { "success": true, "data": { "id": "<campaign_id>", ... } }

step 2 - discover contacts (synchronous)

bash
curl -X POST https://api.iris-ai.dev/discovery/search \
  -H "Authorization: Bearer is_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "keywords": ["bar", "lounge"],
    "location": "Brooklyn, NY",
    "radius_miles": 10,
    "max_results": 50,
    "campaign_id": "<campaign_id>",
    "enrich_emails": true
  }'
# returns synchronously - { "data": { "contacts": [...], "total_results": 50, ... } }

step 3 - check connected channels

bash
curl https://api.iris-ai.dev/channels/availability \
  -H "Authorization: Bearer is_live_YOUR_KEY"
# email is always available; twitter and instagram require an OAuth-connected account

step 4 - send a message (or approve a draft)

bash
# direct send to an existing conversation:
curl -X POST https://api.iris-ai.dev/channels/send \
  -H "Authorization: Bearer is_live_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "email",
    "conversation_id": "<conversation_id>",
    "recipient_id": "<contact_id>",
    "subject": "quick question about djing at {{venue}}",
    "content": "hi {{first_name}}, ...",
    "variables": { "first_name": "Alex", "venue": "The Bell House" }
  }'

# OR - list AI-drafted messages waiting for approval and approve one:
curl "https://api.iris-ai.dev/messages/pending?campaign_id=<campaign_id>" \
  -H "Authorization: Bearer is_live_YOUR_KEY"

curl -X POST https://api.iris-ai.dev/messages/<id>/approve \
  -H "Authorization: Bearer is_live_YOUR_KEY"

note: /channels/send requires a conversation_id and recipient_id that already exist. campaign activation creates these automatically. for AI-drafted message review, use the message-approval flow instead.

authentication & rate limits

authentication methods

the iris API accepts three authentication headers. send any one - the API tries them in order:

methodheaderuse case
API keyAuthorization: Bearer is_live_…accounted users (this section)
MPPAuthorization: Payment …AI agents using Stripe credits - see agent payments
x402X-PAYMENT: …AI agents paying USDC per call - see agent payments

bearer token format

Authorization: Bearer is_live_YOUR_KEY

invalid or revoked keys return 401 with error code APIKEY_001. missing scope returns 403 with APIKEY_004.

rate limits

scopelimitwindowpurpose
global (per key)120 req1 minuteoverall API request limit
burst (per key)20 req1 secondburst request protection
campaign mutations30 req1 minutePOST/PATCH/DELETE on /campaigns
contact mutations60 req1 minutePOST/PATCH/DELETE on /contacts
AI generation20 req1 minutePOST /ai/generate, /ai/analyze
discovery searches5 req1 hourPOST /discovery/search

when rate-limited you receive a 429 response with a Retry-After header (seconds):

json
{
  "success": false,
  "error": {
    "code": "RATE_001",
    "message": "too many requests. please try again in 12 seconds.",
    "requestId": "req_abc123"
  },
  "retryAfter": 12,
  "limit": 60,
  "remaining": 0
}

response headers

X-Request-ID is set on every response. The X-RateLimit-* headers are set on 429 rate-limited responses, alongside Retry-After.

headerdescription
X-RateLimit-Limitrequests allowed per window
X-RateLimit-Remainingrequests remaining in window
X-RateLimit-ResetUnix timestamp in milliseconds when window resets
X-Request-IDcorrelation ID for support and Sentry - included on every response

scopes

API keys can be created with specific scopes to limit their permissions. defense-in-depth - even if a key is compromised, it can only perform operations within its granted scopes. use * for full access on trusted integrations.

available scopes

scopedescription
readview all resources (campaigns, contacts, conversations, messages, analytics, billing)
writecreate, update, and (soft-)delete business data (campaigns, contacts, conversations, notifications). DELETE routes gate on this scope — iris uses soft-deletes everywhere, so there is no separate `delete` scope.
generatecostly external API calls (Claude AI generation, Apify discovery searches)
sendsend and approve outbound messages (email, instagram DM, twitter DM)
adminmanage API keys and webhooks

missing scope error

requests without the required scope receive a 403 response:

json
{
  "success": false,
  "error": {
    "code": "APIKEY_004",
    "message": "API key missing required scope: write",
    "requestId": "req_abc123"
  }
}

recommended scopes by use case

use casescopes
AI agents / MCPread, write, generate, send
read-only dashboardsread
inbound automationread, write, send
full access (admin tools)* (wildcard)

audit logging

destructive and sensitive operations performed via the API are automatically written to api_audit_log with the API key ID, user ID, action, resource ID, and a metadata JSON blob.

audited operations

actiondescription
create_campaigncreates a new campaign envelope
update_campaignmodifies campaign metadata or status
delete_campaignsoft-deletes a campaign
create_contact / bulk_create_contactscreates one or many contacts
update_contactmodifies contact data
delete_contact / bulk_delete_contactssoft-deletes contacts
create_keyissues a new API key (raw value shown once)
revoke_keypermanently revokes an API key
create_webhook / update_webhook / delete_webhookmanages webhook endpoint registration
test_webhookdelivers a synthetic event to a webhook URL
send_channel_messagesends a message via /channels/send
approve_message / reject_message / retry_messagehuman-in-the-loop message decisions
discover_contacts / discover_campaign_contactsruns a discovery search
generate_ai_content / generate_campaign_content / analyze_aiAI generation and analysis runs

idempotency

mutating endpoints (POST /campaigns, POST /agent/credits) accept an Idempotency-Key request header. on a timed-out network retry, the second call with the same key returns the cached response without re-executing — critical for agent-pay endpoints where re-execution would double-charge USDC or double-charge a Stripe credit pack.

idempotency is opt-in: requests without the header execute fresh. cached responses ship for 24 hours and only 2xx outcomes are cached (errors re-execute on retry).

bash
curl -X POST https://api.iris-ai.dev/campaigns \
  -H "Authorization: Bearer is_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: my-unique-key-12345" \
  -d '{"name": "Q2 outreach", "objective_type": "product_promotion"}'

key requirements

  • 1–255 characters, allowlist [A-Za-z0-9._-]
  • scoped per-(api-key, endpoint) — same key value across different endpoints is safe
  • invalid keys (too long, bad chars) → 400 SERVER_BAD_REQUEST (don't retry — fix the value)
  • concurrent retry while first call still in-flight → 409 SERVER_CONFLICT with Retry-After: 1

replay detection

replayed responses carry the Idempotent-Replayed: true response header so the client can distinguish a fresh execution from a cached replay.

MCP server

the model context protocol (MCP) lets AI agents interact with external tools. the iris MCP server gives agents like Claude Code and Cursor the ability to manage campaigns, contacts, conversations, messages, AI drafting, discovery, channels, webhooks, and more - 66 tools across 13 categories, all from your editor.

install

bash
npx -y -p @jclvsh/iris iris-mcp

the package ships two binaries - iris-mcp (MCP server, used below) and iris (CLI).

Claude Code

json
{
  "mcpServers": {
    "iris": {
      "command": "npx",
      "args": [
        "-y",
        "-p",
        "@jclvsh/iris",
        "iris-mcp"
      ],
      "env": {
        "IRIS_API_KEY": "is_live_YOUR_API_KEY"
      }
    }
  }
}

add to .claude/settings.json

Cursor

json
{
  "mcpServers": {
    "iris": {
      "command": "npx",
      "args": [
        "-y",
        "-p",
        "@jclvsh/iris",
        "iris-mcp"
      ],
      "env": {
        "IRIS_API_KEY": "is_live_YOUR_API_KEY"
      }
    }
  }
}

add to .cursor/mcp.json

available tools

categorytoolscount
campaignslist, create, get, update, delete, set status, list contacts, target profiles, usage, analyze11
contactslist, create, get, update, delete, bulk import, bulk delete, conversations8
conversationslist, get, get messages, mark read, engagement5
messageslist pending, approve, reject, retry, feedback, bulk6
AIgenerate, generate campaign, analyze, usage4
discoverysearch, search campaign, get job, list sources4
analyticsoverview, campaigns, performance, response time, contact types5
channelslist accounts, availability, send3
notificationslist, update, delete, read all4
webhookslist, create, get, update, delete, test, deliveries, rotate secret9
keysme, list, create, revoke4
billinglist plans1
agent creditsbalance, purchase pack2

recommended scopes for AI agents: read, write, read, write, read, send, generate, generate, send.

for machine-readable API references, see api.iris-ai.dev/llms.txt (plain text for LLMs) and api.iris-ai.dev/openapi.json (OpenAPI 3.1 spec).

CLI

the iris CLI lets you manage campaigns, contacts, messages, and more from your terminal. same API and same shape as the MCP server - just a different interface.

install

bash
npm install -g @jclvsh/iris

or run directly with npx: npx @jclvsh/iris campaigns list

commands

groupcommandscount
campaignslist, create, get, update, delete, contacts, usage, analyze8
contactslist, create, get, update, delete, bulk-import, bulk-delete7
conversationslist, get, messages, mark-read, engagement5
messagespending, approve, reject, retry, feedback, bulk-approve, bulk-reject7
aigenerate, generate-campaign, analyze, usage4
discoverysearch, search-campaign, jobs, sources, get-job5
analyticsoverview, campaigns, performance, response-time, contact-types, summary6
channelsaccounts, availability, send, list4
notificationslist, update, delete, read-all, mark-read5
webhookslist, create, get, update, delete, test, deliveries, rotate-secret8
keysme, list, create, revoke, rotate, rename6
billingplans, current2
creditsbalance, purchase, history3

70 total commands.

examples

bash
# list your campaigns
iris campaigns list

# create a campaign
iris campaigns create --name "Q2 outreach" --objective product_promotion

# discover contacts and add to a campaign
iris discovery search --keywords "coffee shop" --location "Brooklyn, NY" --campaign <id>

# review pending message drafts
iris messages pending --campaign <id>

# approve a draft
iris messages approve <message-id>

# check your API key
iris keys me

# table output
iris --format table campaigns list

run iris --help or iris campaigns --help for the full command reference.

API reference

all endpoints are relative to https://api.iris-ai.dev. send Authorization: Bearer is_live_… on every request. responses follow the shape { success, data, meta? } on success and { success: false, error: { code, message, requestId } } on error.

authentication

verify your API key and view its metadata.

get information about the currently authenticated API key

API keys

programmatically manage API keys. all routes in this group (except `/keys/me`) require an API key with the `admin` scope. `/keys/me` returns metadata for the currently-authenticated key and works without any scope.

list all API keys for your account

create a new API key. the raw key is only returned once.

rename an API key. only the display label is updated; the secret, scopes, and expiry are untouched.

revoke an API key. this action is irreversible.

rotate an API key — revokes the old key and creates a new one with the same name and scopes. the new raw key is returned exactly once. update stored credentials immediately — the old key stops authenticating as soon as this returns. cannot rotate the key being used for the request itself (would lock the caller out mid-rotation).

campaigns

create and manage outreach campaigns.

list all campaigns

create a new campaign

get a specific campaign with full details

update a campaign

soft-delete a campaign (sets status to 'deleted')

list contacts in a campaign

get campaign usage statistics

trigger AI product analysis for a campaign

list target profiles for a campaign

create a target profile for a campaign

delete a target profile

contacts

manage contacts and import leads.

list all contacts

create a single contact. idempotent on email — if a contact with the same email already exists for this user, returns 201 with the existing record (merging any new fields you supply) instead of 409.

get a specific contact

update a contact

soft-delete a contact (sets deleted_at timestamp)

bulk import contacts (up to 500 per request)

bulk soft-delete contacts by ID

get contact usage for the current billing period

get conversations for a specific contact

conversations

manage conversations across all channels.

list all conversations

get a conversation with details

get messages for a conversation

mark a conversation as read

get engagement metrics across conversations

messages

manage message approval workflow and sending.

list messages pending approval

approve a pending message for sending

reject a pending message

retry a failed message

submit feedback to revise a message with AI

bulk approve or reject messages

AI

AI-powered content generation and analysis.

generate AI content (email subject + body)

generate campaign-level outreach content (email sequence, templates) from an inline brief. content-first: pass the strategy directly, no campaign id required

analyze an inbound message (email or DM) for intent, sentiment, key points, and a suggested reply

get AI generation counts for the current billing period, broken down by generation_type. iris does not enforce a separate AI quota - generations are bounded implicitly by the campaign envelope, so no limit field is exposed.

discovery

search for and discover new contacts.

run a synchronous contact discovery search across configured sources (Google Maps, social platforms via Apify)

run discovery search using campaign target profiles

get the status of a discovery job

list available discovery data sources

analytics

campaign performance metrics and reporting.

get overall analytics overview across all campaigns

get analytics for a specific campaign

get performance metrics over time

get average response time metrics

get contact type distribution

billing

view billing plans and subscription information.

get available billing plans and their features

channels

manage connected accounts and multi-channel messaging.

list connected social accounts

check which channels are available for messaging

send a message through a specific channel into an existing conversation

notifications

manage user notifications.

list notifications

update a notification (e.g. mark as read)

delete a notification

mark all notifications as read

webhooks

manage webhook endpoints for receiving real-time event notifications. all routes in this group require an API key with the `admin` scope (round-6 audit closed a privilege-escalation gap where a non-admin key could create or rotate webhooks).

list all webhook endpoints

create a new webhook endpoint

get a specific webhook endpoint

update a webhook endpoint

delete a webhook endpoint

send a test event to a webhook endpoint

list recent webhook deliveries

rotate the signing secret for a webhook. the new secret is returned once and the old secret is invalidated immediately. update HMAC verification on the receiver side before the next delivery, otherwise signature checks will fail.

agent credits

credit-based payments for AI agents using x402 (USDC on Base) or MPP (Stripe). 1 credit = 1 campaign (30 contacts, 240 messages, AI drafting bundled in). no subscription required.

check the agent's current credit balance

purchase 5 credits with x402 or MPP payment

webhook delivery

register a webhook via POST /webhooks with an HTTPS URL and an event filter. iris signs every delivery with HMAC-SHA256 using the secret returned at creation.

event types

eventfired when
campaign.createda new campaign was created
campaign.updateda campaign was updated
campaign.deleteda campaign was soft-deleted
contact.createda new contact was created or imported
contact.updateda contact was updated
contact.deleteda contact was soft-deleted
conversation.createda new conversation was started
conversation.reply_receiveda reply was received in a conversation
message.senta message was sent
message.delivereda message was confirmed delivered
message.openeda message was opened by the recipient
message.bounceda message bounced
message.approveda pending message was approved
message.rejecteda pending message was rejected
discovery.completeda discovery search completed successfully
discovery.faileda discovery search failed

payload format

every delivery wraps the event-specific data in an envelope:

json
{
  "id": "evt_a1b2c3d4e5f6...",
  "event": "campaign.created",
  "timestamp": "2026-04-29T12:00:00.000Z",
  "created_at": "2026-04-29T12:00:00.000Z",
  "data": { "id": "uuid", "name": "Q2 outreach", "status": "draft", "objective_type": "product_promotion" }
}

headers

headerdescription
Content-Typeapplication/json
X-Iris-SignatureHMAC-SHA256 hex digest of {timestamp}.{body}
X-Iris-TimestampUnix epoch seconds at delivery time — included in the signed payload to prevent replay. (The event-payload timestamp field is ISO-8601 — different format, different purpose.)
X-Iris-Deliveryunique delivery ID for idempotency. (Use this as the dedup key on your side — read the event type from the body's event field.)
User-AgentIris-Webhooks/1.0

signature verification

verify the X-Iris-Signature header using your webhook secret to ensure the request is from iris:

javascript
import crypto from "node:crypto";

// in your webhook handler
export async function POST(request: Request) {
  const signature = request.headers.get("x-iris-signature");
  const timestamp = request.headers.get("x-iris-timestamp");
  const body = await request.text();

  // reconstruct the signed payload
  const signed = `${timestamp}.${body}`;
  const expected = crypto
    .createHmac("sha256", process.env.IRIS_WEBHOOK_SECRET)
    .update(signed)
    .digest("hex");

  // timing-safe compare
  if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) {
    return new Response("invalid signature", { status: 401 });
  }

  const event = JSON.parse(body);
  // dispatch on event.event - "campaign.created", "message.delivered",
  // "conversation.reply_received", etc. (full list at /docs/api#webhooks)
  return new Response("ok");
}

retry behavior

  • up to 3 retries with exponential backoff (via QStash)
  • 30-second timeout per delivery attempt
  • return 2xx to acknowledge - any other status code triggers retry
  • use the X-Iris-Delivery header as an idempotency key to avoid processing the same event twice

agent payments

autonomous AI agents can use the iris API without an account or subscription via two payment protocols: x402 (crypto, USDC on Base) and MPP (Stripe via the Machine Payments Protocol).

iris does not offer an agent free tier. every agent campaign requires payment - the free user plan is generous enough that agents bypassing payment would cannibalize subscription revenue.

how it works

  • •each campaign creation costs $2.25 via x402 (USDC) or 1 credit via MPP ($2.40 effective from a 5-credit pack)
  • •discovery, AI drafting, and message sends run automatically inside the campaign workflow as internal jobs (30 contacts, 240 messages allotment) — agents never call /discovery/search, /ai/generate, or /channels/send directly
  • •payment proofs identify the agent - settlement only occurs on the campaign-creation request
  • •agent-created campaigns are owned by an internal system user and can only be operated on by the agent identity

protocols

x402 (crypto)MPP (Stripe)
headerX-PAYMENT: <base64>Authorization: Payment <base64url>
payment methodUSDC on BaseStripe charge
settlementon-chain transfer (per-campaign)credit pack purchase, then 1 credit/campaign
402 challengePAYMENT-REQUIRED header + JSON bodyWWW-Authenticate: Payment header + JSON body
identitywallet addresspayer credential source

supported endpoints

endpointchargenotes
POST /campaigns$2.25 x402 / 1 credit MPPcreates the campaign envelope
POST /agent/credits$12.00 MPP (pack)buys 5 credits via Stripe - MPP only

these are the only two endpoints that accept agent auth (x402 / MPP). discovery, AI drafting, and message sends are not separately callable — they run automatically inside the campaign workflow as internal QStash jobs. all other endpoints (reads, listings, analytics, webhooks, keys, plus /discovery/search, /ai/generate, /channels/send) require an API key — no agent auth path. issue a key from /settings/api.

example flow

1. request with no payment proof

bash
curl -X POST https://api.iris-ai.dev/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Q2 outreach",
    "objective_type": "product_promotion",
    "outreach_channels": ["email"]
  }'

2. 402 response (includes both challenges)

the body contains both x402 and mpp challenge objects, plus a credits alternative for MPP agents.

http
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: <base64-encoded x402 v2 envelope>
WWW-Authenticate: Payment realm="www.iris-ai.dev", challenge_id="...", price_cents=240, ...
Access-Control-Expose-Headers: PAYMENT-REQUIRED, PAYMENT-RESPONSE, X-PAYMENT-RESPONSE, WWW-Authenticate

{
  "error": {
    "code": "PAYMENT_001",
    "message": "payment required: $2.25 USDC (x402) or $2.40 via Stripe (MPP)"
  },
  "x402": {
    "version": 2,
    "scheme": "exact",
    "network": "eip155:8453",
    "asset": "USDC",
    "amount": "2.25",
    "receiver": "0x...",
    "resource": "POST /campaigns"
  },
  "mpp": {
    "version": 1,
    "method": "stripe",
    "intent": "charge",
    "currency": "usd",
    "amount_cents": 240,
    "resource": "POST /campaigns"
  },
  "credits": {
    "purchase_endpoint": "POST /agent/credits",
    "packs": [{ "id": "pack_5", "credits": 5, "price_usd": "12.00" }]
  }
}

3a. pay with x402 (per-campaign USDC)

bash
curl -X POST https://api.iris-ai.dev/campaigns \
  -H "Content-Type: application/json" \
  -H "X-PAYMENT: <base64-encoded EIP-3009 signed payload>" \
  -d '{
    "name": "Q2 outreach",
    "objective_type": "product_promotion",
    "outreach_channels": ["email"]
  }'

3b. pay with MPP (deduct from credit pack)

bash
curl -X POST https://api.iris-ai.dev/campaigns \
  -H "Content-Type: application/json" \
  -H "Authorization: Payment <base64url-encoded mppx credential>" \
  -d '{
    "name": "Q2 outreach",
    "objective_type": "product_promotion",
    "outreach_channels": ["email"]
  }'

SDKs: the @x402/client npm package handles x402 signing, and mppx handles MPP. both follow the same retry-on-402 pattern: catch the 402, sign the challenge, replay the request.

credit packs

MPP (Stripe) agents purchase credit packs to prepay for campaigns in bulk. instead of paying per-campaign individually, buy 5 credits for $12.00 in a single Stripe charge. credits are deducted automatically when creating campaigns - no payment credential needed for each request after purchase.

credit packs are MPP-only. x402 (crypto) agents already have low transaction fees on Base and pay per-campaign in USDC instead - no pack needed.

pricing

packcreditspriceper campaign
pack_55$12.00$2.40

how it works

  • check balance - GET /agent/credits returns your current credit balance and the available pack.
  • purchase - POST /agent/credits with an MPP credential for $12.00 adds 5 credits.
  • auto-deduction - when you create a campaign with credits available, 1 credit is deducted instead of charging Stripe again.
  • out of credits - if credits run out, the next campaign returns 402 with purchase instructions. buy another pack to continue.
  • refunds - if campaign creation fails after credit deduction, the credit is refunded automatically.
  • no expiration - credits never expire.

purchase example

send an MPP credential for $12.00 (1200 cents) to the purchase endpoint:

bash
curl -X POST https://api.iris-ai.dev/agent/credits \
  -H "Content-Type: application/json" \
  -H "Authorization: Payment <base64url-credential-for-1200-cents>" \
  -d '{ "pack": "pack_5" }'

# response:
# {
#   "success": true,
#   "data": {
#     "balance": 5,
#     "credits_added": 5,
#     "pack": "pack_5"
#   }
# }

check balance

bash
curl https://api.iris-ai.dev/agent/credits \
  -H "Authorization: Payment <base64url-credential>"

# response:
# {
#   "success": true,
#   "data": {
#     "balance": 3,
#     "identity_id": "uuid"
#   }
# }

error handling

error response shape

every error response includes a stable code, a human-readable message, and a requestId for support correlation:

json
{
  "success": false,
  "error": {
    "code": "CAMP_001",
    "message": "campaign not found",
    "requestId": "req_a1b2c3d4"
  }
}

error codes

authentication

codeHTTPmeaning
AUTH_001401unauthorized - invalid or missing API key
AUTH_002403forbidden - insufficient permissions
AUTH_003401session expired

API keys

codeHTTPmeaning
APIKEY_001401invalid or missing API key
APIKEY_002401API key expired
APIKEY_003401API key revoked
APIKEY_004403scope not granted for this operation
APIKEY_005429API key creation limit reached
APIKEY_006404API key not found

campaigns

codeHTTPmeaning
CAMP_001404campaign not found
CAMP_002500campaign creation failed
CAMP_003500campaign update failed
CAMP_005409campaign already active
CAMP_007400campaign has no contacts
CAMP_008400invalid campaign status transition
CAMP_009429campaign limit reached for billing period

contacts

codeHTTPmeaning
CONTACT_001404contact not found
CONTACT_003400invalid email address
CONTACT_007500bulk import failed
CONTACT_009429contact limit reached for billing period

conversations

codeHTTPmeaning
CONVERSATION_001404conversation not found
CONVERSATION_002500conversation update failed
CONVERSATION_003500message send failed

messages

codeHTTPmeaning
MESSAGE_001500message send failed
MESSAGE_004409message already approved
MESSAGE_005404message not found
MESSAGE_015429message limit reached for billing period

AI

codeHTTPmeaning
AI_001503AI service unavailable
AI_002500AI generation failed
AI_003500AI analysis failed
AI_004429AI rate limit exceeded
AI_005400AI content filtered

discovery

codeHTTPmeaning
DISCOVERY_001500discovery job failed
DISCOVERY_002404discovery job not found
DISCOVERY_006429discovery rate limited
DISCOVERY_008429discovery quota exceeded

webhooks

codeHTTPmeaning
HOOK_001400invalid webhook signature
HOOK_003400invalid webhook payload
WEBHOOK_001404webhook not found

agent payments

codeHTTPmeaning
PAYMENT_001402payment required — agent must send X-PAYMENT (x402) or Authorization: Payment (MPP) header
PAYMENT_002402x402 payment verification failed
PAYMENT_003402MPP credential verification failed
PAYMENT_004500settlement failed after payment was charged — contact support
PAYMENT_005402insufficient credit balance — purchase a credit pack via POST /agent/credits
PAYMENT_006400invalid credit pack id
PAYMENT_007500credit purchase failed — if payment was charged, contact support

billing

codeHTTPmeaning
BILLING_004402payment failed (Stripe charge declined)
BILLING_010429plan usage limit reached — upgrade to continue (alias of BILLING_USAGE_EXCEEDED)
BILLING_011402active subscription required for this operation

rate limiting

codeHTTPmeaning
RATE_001429too many requests
RATE_002429API rate limit exceeded

server

codeHTTPmeaning
SERVER_001500internal server error
SERVER_002400request validation failed (also returned for invalid Idempotency-Key)
SERVER_003404resource not found
SERVER_004405method not allowed
SERVER_005422invalid input (validation failed)
SERVER_006500database error
SERVER_008504request timeout
SERVER_009503service temporarily unavailable
SERVER_016409conflict — concurrent retry with same Idempotency-Key in flight

every response includes an X-Request-ID header and a requestId field on errors - quote it when filing a support ticket.

iris

products

built by jclvsh

resources

blogguideschannelscompare

developers

API documentationMCP serverOpenAPI spec

support

help & FAQsemail feedbacktwitter @jclvsh

legal

privacy policyterms of servicedata deletion

© 2026 iris. all rights reserved.