# Agent API

Everything an AI shopping agent needs to read our catalogue, prepare an order and track it to completion. Catalogue version 2026-08-20.

## How ordering works

An agent never handles money. You send us the plan key and the buyer's details, we create a pending order and hand you back a hosted checkout link. The human buyer enters their own card details on our payment provider's page. The plan activates, the workspace is created and the welcome email goes out the moment payment clears.

1. `GET /api/public/storefront` to read valid plan keys and prices. No key needed.
2. Show the buyer the price, the VAT position and the commercial terms below.
3. `POST /api/public/agent/orders` with your API key, the plan key, buyer details, an idempotency key and `terms_disclosed: true`.
4. Give the buyer the `checkout_url` you get back.
5. `GET /api/public/agent/orders/{order_id}` to poll payment and fulfilment status.

## Getting a key

Request one at https://mesmerise.marketing/contact. Tell us who you are, which plans you expect to sell and roughly what volume you expect. We issue a key of the form `msm_agent_...`, shown to you exactly once at creation. We store only a hash of it, so a lost key is replaced, never recovered.

Each key carries:

- a status (`active`, `paused` or `revoked`),
- an hourly request limit (60 by default),
- an optional allow-list of plan keys. When set, the key can only order those plans.

Keep the key server side. Never ship it in browser code, a prompt, or a tool description a third party can read.

## Authentication

Send the key on every call to `/api/public/agent/*`. Either header works:

```http
Authorization: Bearer msm_agent_your_key_here
```

```http
X-Agent-Key: msm_agent_your_key_here
```

The storefront endpoint is public and ignores the header.

Every request, successful or not, is written to our audit log with the endpoint, status and outcome. Rate limits are a sliding one-hour window counted from that log.

## Required terms flags

`terms_disclosed: true` is mandatory on every order. Sending it is your confirmation that you showed the buyer the terms below before ordering. An order without it is rejected with `422 validation_failed`, and we treat repeated omissions as grounds to revoke a key.

- All prices exclude VAT. UK VAT at 20% is added at checkout where applicable.
- Every monthly subscription runs an initial 3 month proving period, then rolling monthly.
- Pauses are allowed after month 3 only, up to 2 monthly pauses in any rolling 12 months.
- No set-up, onboarding or activation fees on any plan.
- Each price covers one service, for one brand, in one sector or product category, at the fixed monthly volumes listed.
- Google ad spend is paid to Google directly on the client's own account and is never marked up.
- Cancellation is available from month 4 with 30 days notice, in writing from the account holder.
- Orders always finish on a Stripe-hosted checkout page completed by the buyer. An agent can prepare an order but can never complete a payment on the buyer's behalf.

## Idempotency

Every order needs a unique idempotency key, either `idempotency_key` in the body or an `Idempotency-Key` header. Reuse the same value for retries of the same intended order: you get the original order back with `reused: true` and HTTP 200 rather than a duplicate order and a second checkout link. Keys are scoped to your API key, so two agents can safely use the same string. Use a fresh key for a genuinely new order.

## Plan keys

| Plan key | Name | Price | Billing | Agent orderable |
| --- | --- | --- | --- | --- |
| `ignite` | Ignite Growth Bundle | £2,610 per month + VAT | subscription | yes |
| `compound` | Compound Growth Bundle | £4,320 per month + VAT | subscription | yes |
| `dominate` | Dominate Growth Bundle | £6,750 per month + VAT | subscription | yes |
| `seo-launch-ai` | SEO Launch AI | £1,250 per month + VAT | subscription | yes |
| `seo-pro-ai` | SEO Pro AI | £2,200 per month + VAT | subscription | yes |
| `seo-ultimate-ai` | SEO Ultimate AI | £3,950 per month + VAT | subscription | yes |
| `email-launch` | Email & SMS Launch | £800 per month + VAT | subscription | yes |
| `email-growth` | Email & SMS Growth | £1,300 per month + VAT | subscription | yes |
| `email-scale` | Email & SMS Scale | £1,750 per month + VAT | subscription | yes |
| `content-launch` | Creative Launch | £1,150 per month + VAT | subscription | yes |
| `content-campaign` | Creative Growth | £1,800 per month + VAT | subscription | yes |
| `content-partnership` | Creative Partner | £2,850 per month + VAT | subscription | yes |
| `ads-starter` | Google Ads Starter | £850 per month + VAT | subscription | yes |
| `ads-growth` | Google Ads Growth | £1,300 per month + VAT | subscription | yes |
| `ads-scale` | Google Ads Scale | £1,800 per month + VAT | subscription | yes |
| `hosting-care` | Hosting & Maintenance Care | £79 per month + VAT | subscription | yes |
| `hosting-pro` | Hosting & Maintenance Pro | £149 per month + VAT | subscription | yes |
| `hosting-enterprise` | Hosting & Maintenance Enterprise | £299 per month + VAT | subscription | yes |
| `web-build-launch` | Website Design Launch | £2,750 one-off build fee + VAT (£1,375 deposit charged at checkout, balance on completion) | one_off | yes |
| `web-build-store` | Website Design Store | £4,950 one-off build fee + VAT (£2,475 deposit charged at checkout, balance on completion) | one_off | yes |
| `web-build-ecommerce` | Website Design Scale | £8,750 one-off build fee + VAT (£4,375 deposit charged at checkout, balance on completion) | one_off | yes |

Read the live catalogue rather than hardcoding this table. A plan whose payment configuration is temporarily unavailable is returned with `agent_orderable: false` and will refuse orders.

## Example: create an order

```http
POST /api/public/agent/orders HTTP/1.1
Host: mesmerise.marketing
Authorization: Bearer msm_agent_your_key_here
Content-Type: application/json

{
  "plan": "ignite",
  "buyer": {
    "email": "jane@example.com",
    "name": "Jane Buyer",
    "business": "Example Ltd",
    "domain": "example.com"
  },
  "partner_code": null,
  "idempotency_key": "agent-7f3c1a9e",
  "terms_disclosed": true
}
```

```json
{
  "ok": true,
  "order_id": "6f2b1c44-9c2f-4c1e-8b0a-1f7d0e4a55c1",
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_a1b2c3",
  "reused": false,
  "status": "pending",
  "plan": {
    "key": "ignite",
    "name": "Ignite Growth Bundle",
    "price_pence": 261000,
    "price_display": "£2,610 per month + VAT",
    "interval": "month",
    "minimum_term_months": 3
  },
  "expires_in_seconds": 86400,
  "action_required": "human_payment",
  "instructions": "Give the buyer this checkout link. They enter their own card details on our payment provider's page."
}
```

A retry with the same idempotency key returns the same body with `"reused": true` and HTTP 200.

## Example: read order status

```http
GET /api/public/agent/orders/6f2b1c44-9c2f-4c1e-8b0a-1f7d0e4a55c1 HTTP/1.1
Host: mesmerise.marketing
Authorization: Bearer msm_agent_your_key_here
```

```json
{
  "ok": true,
  "order_id": "6f2b1c44-9c2f-4c1e-8b0a-1f7d0e4a55c1",
  "plan": { "key": "ignite", "name": "Ignite Growth Bundle", "price_pence": 261000, "interval": "month", "minimum_term_months": 3 },
  "business": "Example Ltd",
  "payment_status": "pending",
  "fulfilment_status": "pending",
  "partner_code": null,
  "next_step": "Awaiting payment. The buyer must complete the Stripe checkout link to activate the plan."
}
```

`payment_status` becomes `paid` once the buyer completes checkout, and `fulfilment_status` moves to `provisioned` when the workspace and dashboard are live. A key can only read its own orders: someone else's order id returns 404.

## Partner codes

If you are a referral partner, send your code as `partner_code`. It is attached to the order at creation and drives commission in the partner dashboard. Codes are normalised, so case and stray spaces do not matter. An unrecognised code is stored but earns nothing.

## Errors

Every failure returns `{ "ok": false, "error": "<code>", "message": "<plain English>" }`. Branch on `error`, show `message` to the buyer.

| Status | Error code | What to do |
| --- | --- | --- |
| 400 | `missing_idempotency_key` | Add a unique idempotency key and retry. |
| 400 | `invalid_json` | Fix the body. It must be JSON. |
| 401 | `missing_api_key` | Send the key header. |
| 401 | `invalid_api_key` | The key is wrong or has been replaced. |
| 403 | `key_not_active` | The key is paused or revoked. Contact us. |
| 403 | `plan_not_permitted` | This key cannot order that plan. |
| 404 | `unknown_plan` | Re-read the storefront for valid plan keys. |
| 404 | `not_found` | Unknown order, or not one of yours. |
| 409 | `quote_required` | Price on application. Send the buyer to https://mesmerise.marketing/contact. |
| 422 | `validation_failed` | Check `issues` in the response. Usually a missing `terms_disclosed`. |
| 429 | `rate_limited` | Wait `retry_after_seconds` and retry. |
| 502 | `checkout_failed` | Our payment provider refused. Safe to retry with the same idempotency key. |
| 503 | `payments_unavailable` | Ordering is temporarily off. Retry later. |

Only 429, 502 and 503 are worth retrying. Everything else needs a change to the request or a word with us.

## Endpoints at a glance

| Purpose | Method and path | Auth |
| --- | --- | --- |
| Catalogue | `GET /api/public/storefront` | none |
| Create order | `POST /api/public/agent/orders` | API key |
| Order status | `GET /api/public/agent/orders/{order_id}` | API key |
| Manifest | `GET /.well-known/agent.json` | none |
| These docs as markdown | `GET /api/public/agent/docs` | none |

Questions, key requests or a higher rate limit: hello@mesmerise.marketing.
