Skip to content

Start an Agent API

A live API that sells a worker: an agent that books meetings in each Customer's own inbox and CRM, billed by what each run consumes.

You need Node 20 and a GitHub account. The sample answers on meetings.apis.dev; your first deploy answers at once on a free Host, and your own domain is one line.

  1. Start the folder

    Terminal
    $ npx apis.dev init agent-api
    ✓ wrote definition.ts: an Agent API
      next: npx apis.dev dev

    init writes an Agent API with one job, a schedule and its rates.

  2. Write the file

    definition.ts
    18 lines
    import { define, agentic } from 'apis.dev'
    
    /** An agent that books three meetings a week with each Customer's leads, in their own inbox and CRM. */
    export default define({
      name: 'meetings', domain: 'meetings.apis.dev',
      sources: { inbox: { system: 'email', scope: 'customer' },  // Source: each Customer's own
                 crm:   { system: 'crm',   scope: 'customer' } },
      Meeting: {                                                // Noun: their records, in their space
        with: 'string', company: 'string', at: 'date',
        book: agentic('Book a meeting with the next lead in {crm}',  // Verb: the job
          { tools: ['inbox', 'crm'], returns: { meeting: 'string' } }),
      },
      on: { 'every Mon, Wed, Fri 09:00': 'Meeting.book' },      // Trigger: in each Customer's timezone
      offer: {                                                  // Offer: by use
        'Meeting.book': { per1000Tokens: 0.01, perMinute: 0.05 },
        'Meeting.get': 0, 'Meeting.list': 0,
      },
    })

    Each Customer connects their own inbox and CRM, and the agent works in that Customer's space alone. The schedule runs in each Customer's timezone.

  3. Try it locally

    Terminal
    $ npx apis.dev dev
    ✓ every Interface on http://localhost:8787, against your Test twin
      reloads on every save

    Run the job on localhost before any Customer connects. A run in your Test twin spends your allowance, and its books never post.

  4. Publish it

    Terminal
    $ npx apis.dev deploy
    ✓ signed in with GitHub
    ✓ definition.ts: meetings on meetings.apis.dev
    ✓ Stripe connected: each Customer pays into your own account
    ✓ 1 Noun, 2 Verbs, 2 Sources, 1 Trigger, 3 prices
        Meeting  get, list
        every Mon, Wed, Fri 09:00 → Meeting.book
        Meeting.book    0.01 per 1,000 tokens, 0.05 a minute
        Meeting.get     0 a call
        Meeting.list    0 a call
    ✓ published v1 to https://meetings.apis.dev: 11 Interfaces
        REST              /meetings
        CLI               npx meetings
        MCP               /mcp
        SDK               npm i meetings, pip install meetings
        Docs              /docs
        OpenAPI           /openapi.json
        llms.txt          /llms.txt
        agents.json       /.well-known/agents.json
        Pricing           /pricing
        Landing site      /
        Developer portal  /dashboard
    ✓ Test key: meetings_test_VAbB3nakU7UAZ64nbLV7XAeqznWaS7ed6ef9

    Meeting.book serves no path: the schedule starts it, so it is internal. Your Customers read what it booked with get and list.

  5. Read the price list

    /pricing
    14 lines
    {
      "currency": "USD",
      "rates": [
        { "name": "Meeting.get",
          "price": 0, "unit": "call" },
        { "name": "Meeting.list",
          "price": 0, "unit": "call" },
        { "name": "Meeting.book",
          "price": 0.01,
          "unit": "1000 tokens" },
        { "name": "Meeting.book",
          "price": 0.05, "unit": "minute" }
      ]
    }

    Your Customers and their agents read this before they connect anything: two rates for each run, and reads at 0.

  6. Miss a run with no credits

    GET meetings.apis.dev/actions/act_30
    Request
    curl https://meetings.apis.dev/actions/act_30 \
      -H "Authorization: Bearer $MEETINGS_KEY"
    Response
    HTTP/1.1 200 OK
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_15658b3bc7132da17d41
    
    {
      "id": "act_30",
      "verb": "Meeting.book",
      "status": "refused",
      "problem": {
        "type": "https://meetings.apis.dev/docs/errors#payment_required",
        "title": "Payment Required",
        "status": 402,
        "detail": "The credit balance is 0; each run draws from it.",
        "code": "payment_required",
        "instance": "req_07091d2bdc823fead0b7",
        "offers": [
          {
            "kind": "credits",
            "price": 10,
            "checkout": "https://meetings.apis.dev/checkout/credits-10"
          },
          {
            "kind": "credits",
            "price": 50,
            "checkout": "https://meetings.apis.dev/checkout/credits-50"
          },
          {
            "kind": "credits",
            "price": 200,
            "checkout": "https://meetings.apis.dev/checkout/credits-200"
          }
        ]
      }
    }

    A Customer connects their inbox and CRM in the developer portal. Monday's run finds no credits, so it is refused before it starts: no work, no charge, and packs to buy.

  7. Buy credits, and the next run books

    GET meetings.apis.dev/actions/act_31
    Request
    curl https://meetings.apis.dev/actions/act_31 \
      -H "Authorization: Bearer $MEETINGS_KEY"
    Response
    HTTP/1.1 200 OK
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_24fbbad973aa8085d69b
    
    {
      "id": "act_31",
      "verb": "Meeting.book",
      "status": "done",
      "output": { "meeting": "mtg_1" },
      "usage": { "tokens": 18400, "minutes": 6 },
      "cost": { "price": 0.484, "currency": "USD" }
    }

    After Checkout, the next run books a meeting. It ends done with what it consumed in usage, and what that cost in cost, metered once.

  8. Read the week's meetings

    GET meetings.apis.dev/meetings?week=2026-W44
    Request
    curl "https://meetings.apis.dev/meetings?week=2026-W44" \
      -H "Authorization: Bearer $MEETINGS_KEY"
    Response
    HTTP/1.1 200 OK
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_61566d5bcadb4268afbb
    
    {
      "items": [
        {
          "id": "mtg_1",
          "with": "Dana Ito",
          "company": "acme.com",
          "at": "2026-10-27T15:00:00Z",
          "createdAt": "2026-10-19T09:04:00Z",
          "updatedAt": "2026-10-19T09:04:00Z"
        },
        {
          "id": "mtg_2",
          "with": "Sam Okafor",
          "company": "globex.com",
          "at": "2026-10-29T16:30:00Z",
          "createdAt": "2026-10-21T09:06:00Z",
          "updatedAt": "2026-10-21T09:06:00Z"
        },
        {
          "id": "mtg_3",
          "with": "Lee Marsh",
          "company": "initech.com",
          "at": "2026-10-31T14:00:00Z",
          "createdAt": "2026-10-23T09:05:00Z",
          "updatedAt": "2026-10-23T09:05:00Z"
        }
      ],
      "total": 3,
      "next": null
    }

    This is what your Customer sees: the meetings the agent booked, in their own space, read at no charge.

  9. Get paid

    One run, metered once · USD
    One run, metered once · USD
    MeterUsage × rateAmount
    Tokens18,400 × 0.01 / 1,0000.184
    Minutes6 × 0.050.3
    Readsget and list0
    The runMeeting.book0.484

    Each run is one line on your Customer's Stripe receipt, its tokens and minutes at your rates. The money lands in your own Stripe account, and a failed run bills nothing.

Result

Your API answers on https://meetings.apis.dev: an agent that books meetings from each Customer's inbox and CRM, every Mon, Wed, Fri 09:00.

Each run keeps the Customer's timezone, is metered at $0.01 per 1,000 tokens and $0.05 a minute, and is charged once when it ends. A run with no credits is refused before it starts, at no charge. You wrote no scheduler, no meter and no connector to their tools.

Next steps