Skip to content

Start a Marketplace

A live API that sells work many suppliers do under your brand, each sale charged when the buyer accepts it and split on Stripe.

You need Node 20 and a GitHub account. The examples use research.apis.dev, which stands for your domain; 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 marketplace
    ✓ wrote definition.ts: a Marketplace
      next: npx apis.dev dev

    init writes a Marketplace with one kind of supplier, one kind of order and your share.

  2. Write the file

    definition.ts
    22 lines
    import { define } from 'apis.dev'
    
    /** Company research from verified researchers, ordered in one call and paid when you accept it. */
    export default define({
      name: 'research', domain: 'research.apis.dev',
      Researcher: {                                 // a supplier: verified, paid on Stripe
        supplier: { verify: ['identity', 'tax'], payout: 'stripe' },
        name: 'string', orders: '<-Order.researcher',
      },
      Order: {                                      // Noun: what the buyer orders and watches
        researcher: '->Researcher.orders', company: 'url', answer: 'string?',
        status: {
          place: [], fill: { in: 'placed', role: 'researcher' },
          accept: 'filled', contest: 'filled',
        },
      },
      offer: {                                      // Offer: charged once, when accepted
        'Order.place': { price: 40, when: 'accepted', accept: 'customer',
                         acceptWithin: '5d', remedy: 'refund' },
        take: 0.15,                                 // your share of each sale, split on Stripe
      },
    })

    A Researcher is a supplier: verified for identity and tax, and paid out on Stripe. take is your share of every sale.

  3. Try it locally

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

    Place, fill and accept an Order on localhost. In your Test twin you play the researcher, and no sale splits.

  4. Publish it

    Terminal
    $ npx apis.dev deploy
    ✓ signed in with GitHub
    ✓ definition.ts: research on research.apis.dev
    ✓ Stripe connected: each sale splits between your account and the supplier's
    ✓ 1 Noun, 9 Verbs, 1 price
    ✓ Researcher: a supplier, verified for identity and tax, paid out on Stripe
        Order    place, get, list, update, delete, restore, fill, accept, contest
        Order.place     40 once, when accepted
        take            15% of each sale, split on Stripe
    ✓ published v1 to https://research.apis.dev: 11 Interfaces
        REST              /orders
        CLI               npx research
        MCP               /mcp
        SDK               npm i research, pip install research
        Docs              /docs
        OpenAPI           /openapi.json
        llms.txt          /llms.txt
        agents.json       /.well-known/agents.json
        Pricing           /pricing
        Landing site      /
        Developer portal  /dashboard
    ✓ Test key: research_test_ktzmZSU8e7mt2MYSTYd7nt4SXSRTc73b1e09

    Each researcher signs up in the developer portal, is verified, and connects a Stripe account before taking an Order.

  5. Read the price list

    /pricing
    8 lines
    {
      "currency": "USD",
      "rates": [
        { "name": "Order.place",
          "price": 40, "unit": "outcome",
          "when": "accepted" }
      ]
    }

    Buyers and their agents read one price, and when it is charged: on acceptance, refunded in full when a contest is upheld.

  6. Order with no credits

    POST research.apis.dev/orders
    Request
    curl https://research.apis.dev/orders \
      -H "Authorization: Bearer $RESEARCH_KEY" \
      -H "Prefer: code=402" \
      --json '{"company":"acme.com"}'
    Response
    HTTP/1.1 402 Payment Required
    Content-Type: application/problem+json
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_56f0e5df9bfe58ff57bb
    
    {
      "type": "https://research.apis.dev/docs/errors#payment_required",
      "title": "Payment Required",
      "status": 402,
      "detail": "The credit balance is 0; Order.place holds 40 until accepted.",
      "code": "payment_required",
      "instance": "req_56f0e5df9bfe58ff57bb",
      "offers": [
        {
          "kind": "credits",
          "price": 50,
          "checkout": "https://research.apis.dev/checkout/credits-50"
        },
        {
          "kind": "credits",
          "price": 200,
          "checkout": "https://research.apis.dev/checkout/credits-200"
        }
      ]
    }

    An Order holds its price from the buyer's credits until they accept. With none to hold, it answers 402 at price 0, with packs that cover it.

  7. Buy credits and order

    POST research.apis.dev/orders
    Request
    curl https://research.apis.dev/orders \
      -H "Authorization: Bearer $RESEARCH_KEY" \
      --json '{"company":"acme.com"}'
    Response
    HTTP/1.1 201 Created
    Location: /orders/order_1
    X-Action-Id: act_1
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_0dd03e1e44bf1e4dd4e7
    
    {
      "id": "order_1",
      "company": "acme.com",
      "status": "placed",
      "createdAt": "2026-10-26T09:00:00Z",
      "updatedAt": "2026-10-26T09:00:00Z"
    }

    After Checkout, the Order answers 201 at price 0 and holds $40. A verified researcher takes it.

  8. A researcher fills it

    POST research.apis.dev/orders/order_1/fill
    Request
    curl https://research.apis.dev/orders/order_1/fill \
      -H "Authorization: Bearer $RESEARCH_KEY" \
      --json '{"answer":"Dana Ito, head of sales"}'
    Response
    HTTP/1.1 200 OK
    X-Action-Id: act_3
    X-Cost: price=0, currency="USD"
    X-Request-Id: req_c4a0aa61c4cc556666f6
    
    {
      "id": "order_1",
      "researcher": "researcher_7",
      "company": "acme.com",
      "answer": "Dana Ito, head of sales",
      "status": "filled",
      "createdAt": "2026-10-26T09:00:00Z",
      "updatedAt": "2026-10-26T13:20:00Z"
    }

    The researcher fills the Order with their own Key; only the researcher Role can. The buyer sees the answer and who wrote it.

  9. Accept it, and the sale splits

    POST research.apis.dev/orders/order_1/accept
    Request
    curl -X POST https://research.apis.dev/orders/order_1/accept \
      -H "Authorization: Bearer $RESEARCH_KEY"
    Response
    HTTP/1.1 200 OK
    X-Action-Id: act_4
    X-Cost: price=40, currency="USD"
    X-Request-Id: req_465afb1378d7d52735fc
    
    {
      "id": "order_1",
      "researcher": "researcher_7",
      "company": "acme.com",
      "answer": "Dana Ito, head of sales",
      "status": "accepted",
      "createdAt": "2026-10-26T09:00:00Z",
      "updatedAt": "2026-10-26T15:05:00Z"
    }

    Acceptance charges the held $40 once. A buyer who contests instead brings it to you, and a contest upheld refunds it in full.

  10. Get paid

One sale, split once · USD
One sale, split once · USD
LineShareAmount
The buyer paysOrder.place, accepted40.00
The supplier's Stripe account85%34.00
Your Stripe account15%6.00
Stripe receipt · October 2026 · USD
Order.place     1 × 40        40.00
───────────────────────────────────
Total                         40.00
Paid from 50.00 of credits    40.00
Balance                       10.00

Stripe splits the one charge: the researcher is paid out on their own account, and your take lands in yours. The buyer's receipt shows one line.

Result

Your API answers on https://research.apis.dev: Orders that verified researchers fill, charged $40 once, when the buyer accepts.

Stripe splits each charge: $34 to the researcher and $6 to you. You wrote no supplier onboarding, no held funds and no payout code.

Next steps

  • Start a Dataset API → sell the facts about a thing, priced per answer.
  • Marketplace: suppliers and their catalog, an order from placed to paid, and the split.
  • Commerce: charges, holds, splits and payouts on Stripe.