KaupiaMerchants

Kaupia merchant API

AI agents buy from your store through Kaupia. Kaupia takes the customer's payment and sends you the order; you ship it and add the tracking number, and the money moves to your Stripe balance. This API lets your systems do that without the dashboard: receive orders on a webhook, mark them shipped, and keep your catalog in sync.

Base URL https://api.kaupia.com/v1/merchant. JSON in, JSON out. Amounts are in US dollars.

Authentication

Create a secret key in Developers → API keys and send it as a bearer token. Keys start with kp_live_; keep them on your server.

curl "https://api.kaupia.com/v1/merchant/orders?status=to_ship" \
  -H "Authorization: Bearer $KAUPIA_API_KEY"

Orders

An order is one agent purchase from your store: what to send, where, by when, and what you receive for it.

GET/orders?status=to_ship|shipped|all&limit=50

GET/orders/{id}

The order object

{
  "id": "ko_8f2c1a7d90",
  "object": "order",
  "livemode": true,
  "status": "to_ship",
  "created": "2026-11-04T18:21:07Z",
  "ship_by": "2026-11-06",
  "items": [
    { "product_id": "kp:878d37c5-…", "title": "Reflective dog leash, 6 ft",
      "variant": "Blue", "quantity": 1, "unit_price": 24.0 }
  ],
  "shipping": {
    "name": "Jane Doe", "phone": "+1 415 555 0100",
    "address": { "line1": "1 Market St", "line2": null, "city": "San Francisco",
                 "state": "CA", "postal_code": "94105", "country": "US" },
    "method": "Standard", "price": 0.0
  },
  "amount_to_you": 24.0,
  "currency": "usd",
  "fulfillment": { "carrier": null, "tracking_number": null, "tracking_url": null, "shipped_at": null },
  "payout": { "status": "pending", "transfer_id": null, "amount": null }
}

status is to_ship, shipped, delivered or canceled. ship_by comes from your processing time in Settings. amount_to_you is your price times the quantity plus the shipping you charge. livemode is false for test orders.

Ship an order

POST/orders/{id}/ship

Send the carrier (usps, ups, fedex, dhl or other) and the tracking number. Kaupia charges the customer, moves amount_to_you to your Stripe balance, and tells the agent. Your bank receives it 7 days later. Calling it again updates the tracking number; you are paid once.

curl https://api.kaupia.com/v1/merchant/orders/ko_8f2c1a7d90/ship \
  -H "Authorization: Bearer $KAUPIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"carrier": "usps", "tracking_number": "9400111899223"}'

Products

Kaupia reads Shopify and WooCommerce catalogs and product feeds on its own. Use the API when your catalog lives in your own system, or to push price and stock changes the moment they happen. Products are upserted by your own external_id; up to 500 per call.

POST/products

GET/products?limit=50&offset=0

DELETE/products/{external_id}

curl https://api.kaupia.com/v1/merchant/products \
  -H "Authorization: Bearer $KAUPIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"products": [{"external_id": "LEASH-6-BLUE", "title": "Reflective dog leash, 6 ft",
        "price": 24.0, "in_stock": true, "url": "https://yourstore.com/products/leash"}]}'

Fields: external_id and title and price are required; in_stock, url, image_url (https), description, gtin, sku, category, brand, lead_days (business days before it ships) and note (shown to agents) are optional.

Webhooks

Add an endpoint in Developers → Webhook. Kaupia POSTs an event the moment something happens:

  • order.created: an agent placed an order; ship it.
  • order.shipped: the order was marked shipped (by you, in the dashboard or the API).
{
  "id": "evt_9c1f…",
  "object": "event",
  "type": "order.created",
  "created": 1793790067,
  "livemode": true,
  "data": { "object": { …the order object… } }
}

Answer with any 2xx within 10 seconds. Handle events idempotently by order id.

Verify signatures

Every request carries a Kaupia-Signature header. Check it before you trust the body.

signature header:  Kaupia-Signature: t=1793790067,v1=5f2b…
signed payload:    "<t>.<raw request body>"
algorithm:         HMAC-SHA256 with your webhook signing secret (whsec_…), hex digest
accept if:         digest == v1 (constant-time compare) and |now - t| <= 300 seconds

Node (Express)

import express from 'express';
import { Kaupia } from './kaupia.mjs';

const kaupia = new Kaupia(process.env.KAUPIA_API_KEY);
const app = express();

// 1. Orders arrive here the moment an agent places them
app.post('/kaupia/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
  let event;
  try {
    event = Kaupia.constructEvent(req.body, req.get('Kaupia-Signature'), process.env.KAUPIA_WEBHOOK_SECRET);
  } catch (err) {
    return res.status(400).send(err.message);
  }
  if (event.type === 'order.created') {
    const order = event.data.object;          // items, shipping.address, ship_by, amount_to_you
    await createOrderInMySystem(order);       // your code
  }
  res.sendStatus(200);
});

// 2. You shipped it: send tracking and you're paid
export async function onShipped(orderId, trackingNumber) {
  await kaupia.orders.ship(orderId, { carrier: 'usps', tracking_number: trackingNumber });
}

app.listen(3000);

Python (Flask)

from flask import Flask, request
from kaupia import Kaupia, construct_event

kaupia = Kaupia()                    # KAUPIA_API_KEY
app = Flask(__name__)

@app.post("/kaupia/webhook")
def kaupia_webhook():
    try:
        event = construct_event(request.get_data(), request.headers.get("Kaupia-Signature"))
    except ValueError as err:
        return str(err), 400
    if event["type"] == "order.created":
        create_order_in_my_system(event["data"]["object"])   # your code
    return "", 200

def on_shipped(order_id, tracking_number):
    kaupia.ship_order(order_id, carrier="usps", tracking_number=tracking_number)

Test orders

A test order goes through everything a real one does (email, dashboard, webhook with livemode: false) and nothing is charged or paid out. Create one from Developers or the API:

POST/test_orders

curl -X POST https://api.kaupia.com/v1/merchant/test_orders \
  -H "Authorization: Bearer $KAUPIA_API_KEY"

WooCommerce

The Kaupia plugin turns agent orders into WooCommerce orders and tells Kaupia when you ship.

  1. Download kaupia-woocommerce.zip, then in WordPress go to Plugins → Add New → Upload Plugin and activate it.
  2. WooCommerce → Kaupia shows your webhook URL. Add it in Developers → Webhook, then paste the signing secret and a secret API key back into the plugin.
  3. Send a test order from Developers: it appears in WooCommerce → Orders, matched to your product by its id or SKU.
  4. To ship, enter the carrier and tracking number in the order's Kaupia shipment box and set the order to Completed. Tracking from the WooCommerce Shipment Tracking extension works too.

Shopify

We read Shopify catalogs automatically, and orders reach you by email, in the dashboard and on your webhook. Connecting your Shopify admin, so Kaupia orders appear in Shopify → Orders and fulfilling them there gets you paid, is coming soon.

SDKs

Single files with no dependencies. Download one next to your code:

curl -sO https://merchants.kaupia.com/sdk/kaupia.mjs     # Node 18+, Bun, Deno
curl -sO https://merchants.kaupia.com/sdk/kaupia.py      # Python 3.8+

kaupia.mjs · kaupia.py

Build it with AI

Paste this into Claude Code, Cursor, Lovable, Replit or any coding agent that works on your store. It contains everything the agent needs. Signed-in merchants get it with their store name filled in under Developers.

Errors

Errors use HTTP status codes and a JSON body: {"error": {"type": "invalid_request_error", "message": "…"}}. 401 means a missing or revoked key, 404 an order or product that isn't yours, 400 a request we couldn't use, 429 too many requests (120 a minute). Questions: hello@kaupia.com.