subba.pro
Start free

Docs

Point your form at https://api.subba.pro/f/{formId}. subba filters spam, classifies the enquiry, replies in your voice, and books meetings, all from one request. There is also a JSON booking API and an MCP server for AI agents.

Which script does what

There are four ways to put subba on your site. They all feed the same place, your Inbox and your Customers CRM, so mix and match per job.

WhatHowReach for it when
Native contact formYour own HTML form, styled to match your site, POSTs to /f/{formId}You want the form to look exactly like your site (this is what we run on rolandfarkas.com & polarize.ltd)
Form embed script<script src="…/f/{formId}/embed.js"> drops subba’s own styled contact formFastest drop-in when you don’t want to style anything yourself
Chat widget script<script src="…/f/{formId}/chat.js"> drops the AI chat bubbleYou want a 24/7 assistant that answers, quotes and can book, on every page
Booking widget script<script src="…/b/{slug}/embed.js"> drops the booking calendarYou want customers to pick a service & time and pay, inline on your site

Rule of thumb: use the native form when the form should look like your site, the embed scripts when you just want to drop something in and go. Find each id in your dashboard, the form id under your form’s Embed tab, the booking slug under Booking settings.

Connect a form

Drop your form id into the action. Classic HTML forms work as-is (no JavaScript needed):

<form action="https://api.subba.pro/f/{formId}" method="POST">
  <input name="name" />
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <!-- Honeypot: keep it hidden and empty. Bots fill it; real people never see it. -->
  <input name="hp_website" tabindex="-1" autocomplete="off"
         style="position:absolute;left:-9999px" aria-hidden="true" />
  <button>Send</button>
</form>

Or POST JSON from your own frontend:

POST /f/{formId} HTTP/1.1
Host: api.subba.pro
Content-Type: application/json

{
  "name": "Sam",
  "email": "[email protected]",
  "message": "Do you have space in a beginner class next week?"
}

Either way you get:

HTTP/1.1 200 OK
{ "ok": true, "status": "processed" }

Only email and message are required; name, subject, and phone are used when present. Your form must POST from its registered origin.

Reply modes

notifysubba drafts a reply and alerts you. You send it. Safest to start with.
draftsubba drafts and stores a one-tap reply, plus the owner alert.
autosubba sends the reply itself and, on Managed and up with a connected calendar, books the meeting with a Google Meet link.

Start on notify, move up as you learn to trust it. You are always in control.

Chat widget

Drop a chat assistant on your site with one line. It sits as a bubble in the corner, or opens from any element with a data-subba-chat attribute.

<script src="https://api.subba.pro/f/{formId}/chat.js" defer></script>

The assistant answers visitor questions and can take a booking or start a membership, all in the chat window. To keep it accurate, open your form in the dashboard and click Analyse my website and fill knowledge: subba reads your site and drafts an editable knowledge base (services, prices, hours, policies) that the assistant is grounded in. Edit it and save.

It never books or charges on its own. When a visitor wants to book or subscribe, the assistant shows a confirmation card with the exact service, time, and price; the visitor adds their name and email and taps to confirm. Paid bookings and memberships open Stripe checkout on your own connected account.

How we keep the AI safe

  • Grounded, not guessing: it answers only from your knowledge and live availability, and offers to pass anything it is unsure of to your team.
  • Double-checked: a second AI pass verifies each reply is on-topic and supported before it is shown, with a safe fallback if not.
  • Actions are validated, not spoken into being: prices and times come from your data, never the chat text. Every booking is re-checked against live availability at confirm time, and money moves only through Stripe checkout after a human taps confirm.
  • Injection-resistant: visitor text is treated as data, not instructions, and replies render as plain text only, so nothing typed in chat can change the assistant's behaviour or run code.
  • Abuse limits: origin-locked to your site, rate limited, with an optional Cloudflare Turnstile bot check.

Worked example: how we run our own sites

We put our money where our mouth is and run subba on rolandfarkas.com and polarize.ltd. Here is exactly how, so you can copy it.

1. A contact form that matches the site

Both are consultancies, so the form has to look like the brand, not like a widget. We wrote a normal HTML form, styled it to each site, and pointed it straight at subba, no iframe, no subba styling. Every field is required on our sites (that is your choice, per form):

<!-- Your own form, styled however you like -->
<form id="lead">
  <input name="name"    required />
  <input name="email"   type="email" required />
  <input name="phone"   type="tel"   required />
  <textarea name="message" required></textarea>
  <button>Send</button>
</form>

<script>
  document.getElementById('lead').addEventListener('submit', async (e) => {
    e.preventDefault();
    const f = e.target;
    const res = await fetch('https://api.subba.pro/f/{formId}', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        name:    f.name.value,
        email:   f.email.value,
        phone:   f.phone.value,
        message: f.message.value,
      }),
    });
    if (res.ok) f.reset(); // then show your own "thanks!" state
  });
</script>

That is the whole integration. subba filters spam, runs a honeypot and a per-IP rate limit, classifies the enquiry, and, because these are consultancies with no fixed services, the reply simply captures the lead and offers a quote rather than booking anything. The lead lands in your Inbox and becomes a customer in your CRM, keyed by email.

Note: the API itself only requires email and message; name, phone and subject are used when present. Requiring all of them (like we do) is done in your own form.

2. The AI chat, quote-only

One line drops the chat bubble on every page. Because there are no bookable services, the assistant answers questions and collects details for a quote, it never books or charges. Add exactly the same line for a barber or clinic and it will book, because it has services to book, that is the only difference.

<script src="https://api.subba.pro/f/{formId}/chat.js" defer></script>

Both the form and the chat feed the same Inbox and CRM, so every lead lands in one place regardless of how it came in.

Calendar booking

Connect Google Calendar once (/oauth/google/start?form={formId}). In auto mode on Managed and up, a booking-intent enquiry is scheduled automatically with a Google Meet link, and both you and the customer are notified.

Booking API

Every business with booking enabled gets a public slug. These JSON endpoints power the hosted widget, the embeddable widget, and any client you build.

GET /api/b/{slug}/services lists bookable services:

{
  "business": "Zen Yoga Studio",
  "services": [
    { "id": "svc_1", "name": "Beginner class", "type": "class",
      "duration": 60, "price": 1400, "currency": "gbp", "requiresPayment": true }
  ]
}

GET /api/b/{slug}/slots?service={id}&date=YYYY-MM-DD returns open appointment slots (start in epoch ms), or upcoming sessions with seats left for a class.

POST /api/b/{slug}/book creates the booking:

POST /api/b/{slug}/book
Content-Type: application/json

{ "service": "svc_1", "start": 1756713600000,
  "name": "Sam", "email": "[email protected]" }
{ "ok": true, "bookingId": "bk_123",
  "checkoutUrl": "https://checkout.stripe.com/...", "confirmed": false }

For a class, send sessionId instead of start. When the service requires payment, follow checkoutUrl to Stripe; otherwise the booking is confirmed straight away. Embed the widget on any site with <script src="https://api.subba.pro/b/{slug}/embed.js"></script>.

Payments

Take payment for bookings straight into your own Stripe account. In the dashboard you can connect an existing Stripe account (OAuth) or set up new payouts (Stripe hosted onboarding). When a service requires payment or a deposit, /book returns a Stripe checkoutUrl and the funds settle to your connected account. subba takes no fee from your payments; Stripe charges its own processing fee. Your customers get their receipt from Stripe, in your business's name.

Analytics events

Every subba widget on your site reports each step to the analytics you already run, with no setup: the booking page, chat, contact and quote forms, shop, click and collect, the manage page and quote payments.

  • Google Analytics 4 (gtag.js): each step is sent with gtag('event', …), so it shows in GA4 straight away. Mark subba_booking_complete and subba_booking_paid as key events.
  • Google Tag Manager: each step is pushed to the dataLayer as an event called subba_…. Add a Custom Event trigger matching ^subba_ (regex) and a GA4 Event tag with the event name {{Event}}. If the page also has gtag.js, set window.subbaGtag = false so nothing is counted twice.
  • Plausible and Matomo: sent as custom events when their script is on the page.
  • Anything else: listen for the subba:event event on document; event.detail is { name, params }.

Every event carries subba_widget and subba_business (your booking page slug), plus the details below. Events never include names, email addresses, phone numbers or messages, and they follow your page's own cookie consent: subba only hands them to the analytics your page already loads.

WidgetEventsDetails
Booking pagesubba_booking_view, subba_booking_location, subba_booking_service, subba_booking_staff, subba_booking_date, subba_booking_time, subba_booking_submit, subba_booking_payment, subba_booking_complete, subba_booking_paid, subba_booking_payment_cancelled, subba_booking_error, subba_waitlist_joinService name and count, value and currency, the date and time picked, whether "any" or a chosen staff member, whether they said yes to offers, the error code.
Chatsubba_chat_open, subba_chat_close, subba_chat_start, subba_chat_message, subba_chat_booking_offer, subba_chat_booking_confirm, subba_chat_payment, subba_chat_booking_complete, subba_chat_booking_error, subba_chat_paidBooking or membership, its name, value and currency, how many messages so far, whether they said yes to offers.
Contact formsubba_contact_view, subba_contact_sent, subba_contact_errorWhether they said yes to offers, the error code.
Quote formsubba_quote_view, subba_quote_sent, subba_quote_errorWhether they said yes to offers, the error code.
Quote paymentsubba_quote_pay_view, subba_quote_pay_start, subba_quote_paidAmount due and currency, full, deposit or balance.
Shopsubba_shop_view, subba_shop_add, subba_shop_checkout, subba_shop_payment, subba_shop_complete, subba_shop_paid, subba_shop_payment_cancelled, subba_shop_errorProduct name, quantity, value and currency, number of items, collection or delivery.
Click and collectsubba_order_view, subba_order_add, subba_order_checkout, subba_order_payment, subba_order_complete, subba_order_errorItem name, quantity, value and currency, number of items, collection or delivery.
Manage pagesubba_manage_view, subba_manage_signin, subba_manage_cancel, subba_manage_reschedule, subba_manage_offersWhich view opened, whether they said yes or no to offers.

The embed scripts (embed.js, chat.js, form.js, manage.js and the shop's embed.js) pass the events on for you. If you put a subba page in your own <iframe> instead, add this line to the page too:

<script src="https://book.subba.pro/events.js" async></script>

AI agents & MCP

subba is agent-ready. An MCP server (Streamable HTTP, JSON-RPC 2.0) is available at https://api.subba.pro/mcp with the tools list_services, check_availability, and create_booking. Add it to any MCP-capable client:

POST https://api.subba.pro/mcp
Content-Type: application/json

{ "jsonrpc": "2.0", "id": 1, "method": "tools/list" }

Every business gets its own machine manifest at https://api.subba.pro/b/{slug}/ai2w (also served on the business's own domain at /ai2w), so an agent can discover exactly how to book it. There is also an ACP product feed at https://api.subba.pro/acp/feed.jsonl (each bookable service as a product, in the OpenAI/Agentic Commerce Protocol schema), and a per-business feed at /b/{slug}/acp/feed.jsonl.

The same MCP server powers a ChatGPT app (Apps SDK): the create_booking tool renders an inline card with a secure-payment button. Agents can also discover subba through /AGENTS.md, /llms.txt, the /ai2w manifest, and /.well-known/agent.json. Native in-chat payment (ACP shared payment token, AP2) settles on Stripe and is planned; today payment completes on the Stripe Checkout link that create_booking returns.

Phone receptionist

Add a 24/7 AI that answers your phone with the same brain as your website chat: it greets callers, quotes your real prices, checks live availability, books straight into your diary and takes messages, in a natural voice. We provision a UK number for you automatically when you subscribe, so there is nothing to set up.

It is a metered add-on on top of any plan:

TierPriceIncludedOverage
Starter£29.99 / mo100 minutes (~50 calls)Calls forward or pause at cap
Growth£74.99 / mo300 minutes (~150 calls)Calls forward or pause at cap
Scale£119.99 / mo600 minutes (~300 calls)Optional 30p/min pay-as-you-go

In Billing you choose what happens when a month's minutes run out: forward callers to your own phone (set a fall-back number), or play a short "call back later" message. On the Scale plan you can also keep the AI answering and pay 30p per extra minute. You can hear it live, call our own AI receptionist on +44 7577 359660.

There is also an SMS reminders & follow-ups add-on (from £9.99/mo for 250 texts up to £99.99 for 2,500). Texts get read far more than email, so they cut no-shows harder; we fall back to email when you run out.

Plans & limits

PlanPriceEnquiriesIncludes
Starter£9.99 / mo50 AI enquiriesAnswers enquiries, books into your diary, deposits & payments, reminders, automatic Google review requests
Managed£19.99 / mo150 AI enquiriesEverything in Starter, plus automatic follow-ups and more room to grow
Pro£49.99 / mo300 AI enquiriesEverything in Starter, plus multiple staff & services, follow-ups, priority support
Studio£99.99 / mo750 AI enquiriesEverything in Pro, plus multiple forms & locations, team alerts

Enquiries are metered per calendar month; spam does not count. If you reach your limit subba still captures the lead and alerts you, then pauses auto-replies until you upgrade. Change plan any time from the dashboard.

Need a website? The done-for-you website is a £200 one-off add-on on any plan: we build your booking site, register and manage your .co.uk domain and wire subba in, usually live in about 5 working days. One business per website, per account; larger or specialist sites, for example a big ecommerce store, may need a revised quote.

Errors

StatusCodeMeaning
400invalid_email / invalid_messageRequired fields missing or malformed.
403origin_not_allowedRequest Origin did not match the form’s registered origin.
404form_not_found / service_not_foundUnknown form, business, or service id.
409slot unavailableThe slot or class session is no longer free.
413payload_too_largeBody exceeded the size cap.
429rate_limitedPer-form, per-IP rate limit hit.

Security

  • Endpoints are locked to your form’s origin; spam is filtered before any AI runs.
  • Customer emails are stored in the audit log only as salted hashes.
  • Per-form, per-IP rate limits, plus a Cloudflare edge rate rule.
  • Stripe webhooks are signature-verified; calendar tokens are never exposed.
  • Append-only submission log; no stack traces on errors.