InbinGalleryPricingDocsAboutSign in
Reference
AuthenticationResourcesInboxesApplicationSchemasEventsQueryWebhook deliveryMCPFailure modes

API reference

Minimal REST. Seven concept-endpoints, four resources, no GraphQL, no realtime. Base URL https://api.inbin.dev/v1

Authentication

Every request carries your application’s API key as a bearer token. Keys are issued at onboarding and can be rotated without downtime. Create a new key, migrate, revoke the old one.

curl https://api.inbin.dev/v1/inboxes \
  -H "Authorization: Bearer ink_live_8we46jinhibs365yhztpo..."

Or use the official SDK, which wraps every endpoint and webhook verification:

npm i @inbin/core

import { Inbin } from "@inbin/core";
const inbin = new Inbin({ apiKey: process.env.INBIN_API_KEY });
const inbox = await inbin.inboxes.create({ name: "going-deals" });

Resources

Four objects. Nothing more.

ApplicationThe tenant. Owns inboxes, schemas, webhooks, API keys.
InboxA unique, permanent email address, <slug>@in.inbin.dev.
SchemaWhat to extract. Versioned, monotonic, one active per application.
EventThe output. One per email received; immutable once created.

Inboxes

POST/inboxes
GET/inboxes
GET/inboxes/:id
DELETE/inboxes/:id

Creating an inbox returns its address immediately. Slugs are six characters, globally unique. Deleting an inbox orphans its mail flow. Inbin still accepts, then drops.

POST /inboxes  {"name": "chicago-forwards"}

{
  "id": "ibx_a3f2c8",
  "address": "a3f2c8@in.inbin.dev",
  "application_id": "app_1234",
  "created_at": "2026-07-23T20:15:00Z"
}

Application

GET/apps
PATCH/apps
GET/health

The caller’s application: name, webhook URL, plan, usage this month. PATCH accepts name and webhook_url, so CI can point Inbin at a fresh endpoint in the same pipeline that deploys it. The webhook secret is never returned. /health is unauthenticated and checks the database: 200 healthy, 503 not. Point your uptime monitor at it.

Schemas

PUT/schemas
GET/schemas/current

JSON-Schema-like, deliberately constrained: no $ref, no oneOf, no recursion. A PUT replaces the schema and bumps the version. Invalid schemas are rejected at PUT time with a clear error. Old events are never re-parsed, the ledger is immutable. hallucination_guard (default on) drops any extracted value that does not appear in the email body.

PUT /schemas
{
  "extract": {
    "listings": {
      "type": "array",
      "items": {
        "address": { "type": "string", "required": true },
        "city":    { "type": "string", "required": true },
        "state":   { "type": "string", "required": true, "pattern": "^[A-Z]{2}$" },
        "zip":     { "type": "string", "nullable": true, "pattern": "^\\d{5}$" }
      }
    }
  },
  "hallucination_guard": true
}

Events

GET/events?inbox_id&status&since
GET/events/:id
POST/events/:id/redeliver

One event per email, whatever the extraction yielded. Status is one of pending, delivered, failed_delivery, dead_lettered. The raw email is kept 30 days behind a signed URL; extracted events are retained 90 days on Free and Builder, 365 days on Growth and Scale. Duplicate Message-IDs dedupe at ingest and return the same event.

Redeliver returns the same shape as a normal delivery: attempt number, response code, new status. Use it to replay dead-lettered events after fixing your endpoint.

Query

POST/query

Your inbox as a table. Filter, sort, project, flatten array records, group and aggregate over everything your schemas extracted. One request, no database on your side. Also available to agents as the query_events MCP tool.

POST /query
{
  "flatten": "deals",
  "where": [{ "field": "price_usd", "op": "lt", "value": 300 }],
  "group_by": "destination_city",
  "aggregate": [{ "fn": "avg", "field": "price_usd", "as": "avg_price" }]
}

{ "rows": [
    { "destination_city": "Lisbon", "avg_price": 274.5 },
    { "destination_city": "Madrid", "avg_price": 289.0 }
  ],
  "row_count": 2 }

Ops: eq, neq, gt, gte, lt, lte, contains, in, exists. Aggregates: count, sum, avg, min, max. Limit caps at 200.

Webhook delivery

When an event lands, Inbin POSTs the event object verbatim to your webhook URL. Verify the HMAC before trusting the body.

Content-Type: application/json
X-Inbin-Event-Id: evt_9x8y7z
X-Inbin-Signature: sha256=...   // HMAC of body with your secret

// verify with @inbin/core
import { verifyWebhook } from "@inbin/core";
const event = verifyWebhook(req.body, req.headers, secret);

Retries back off exponentially. 30s, 2m, 10m, 1h, 6h, 24h. After six failures the event is dead-lettered. Redeliver it from the dashboard or via POST /events/:id/redeliver.

MCP

Listed in the official MCP Registry · @inbin/mcp on npm

Every Inbin application is also an MCP server. Point an agent (Claude, ChatGPT, Cursor, custom) at https://inbin.dev/api/mcp with your Bearer API key and it can browse your parsed events without you writing a client. Transport is JSON-RPC 2.0 over HTTP (Streamable HTTP, MCP 2025-06-18).

list_inboxesInboxes on this app.
list_eventsFilter by inbox / status / since. Cursor paginated.
search_eventsCase-insensitive substring across id / subject / from / to.
get_eventFull event body including extracted JSON and delivery history.
describe_schemaThe current extraction schema for this app.
curl https://inbin.dev/api/mcp \
  -H "Authorization: Bearer ink_live_..." \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Connect from your MCP client

Two ways to talk to Inbin’s MCP surface:

  1. Remote (recommended): point your client at the URL directly with your API key as a Bearer header. No install, no local process.
  2. Local wrapper: install @inbin/mcpfrom npm and run it as a stdio server. Useful for clients that don’t yet support remote HTTP transport.

Claude Desktop

Edit ~/Library/Application Support/Claude/claude_desktop_config.json and add:

{
  "mcpServers": {
    "inbin": {
      "url": "https://inbin.dev/api/mcp",
      "headers": {
        "Authorization": "Bearer ink_live_..."
      }
    }
  }
}

Restart Claude Desktop, then look for the “inbin” tools in the tools menu.

Cursor

Open Cursor Settings → MCP → Add. Paste:

{
  "inbin": {
    "url": "https://inbin.dev/api/mcp",
    "headers": {
      "Authorization": "Bearer ink_live_..."
    }
  }
}

Windsurf, Zed, Cline

Any client that supports MCP’s Streamable HTTP transport takes the same shape. Endpoint + Authorization header. If your client only supports stdio, use the local wrapper:

# In your MCP client's server list
{
  "inbin": {
    "command": "npx",
    "args": ["-y", "@inbin/mcp"],
    "env": {
      "INBIN_API_KEY": "ink_live_..."
    }
  }
}

The wrapper reads INBIN_API_KEY and proxies stdio to the remote MCP endpoint.

Failure modes

WhenWhat happens
Model down / null extractionEvent is still created with extracted: null and an error. The webhook fires anyway.
Your endpoint is downThe retry queue holds events; the dashboard shows the backlog.
Broken schemaRejected at PUT time. A broken schema is never accepted.
Duplicate emailDeduped by Message-ID; the webhook fires once.
Provider rate limitsIngest queues; events deliver in order.