AI-NATIVE · MCP-FIRST · OPEN API

Build on FavCRM.
Powered by AI agents.

The all-in-one business OS — bookings, CMS, shop, loyalty, campaigns — exposed as an MCP endpoint and JavaScript SDK. Vibe-code a booking storefront in minutes. Replace Cal.com + Mailchimp + Shopify with one key.

60-SEC QUICKSTART

# 60-second quickstart

POST /v6/dev/signup   # send OTP to your email

POST /v6/dev/verify   # verify → get fav_mcp_* key

Authorization: Bearer fav_mcp_...

https://api.favcrm.io/mcp  # ~95 tools

JAVASCRIPT / TYPESCRIPT SDK

15 namespaces · OTP auth · works in Node.js, Edge, browser

npm install @favcrm/sdk npm
SETUP

Zero to first call in 4 steps.

Same path for humans and AI agents. Sandbox key in 60 seconds, no credit card.

Step 01 — Get an API key

Sandbox (new dev): email OTP, no card.

POST /v6/dev/signup   { "email": "you@example.com" }
POST /v6/dev/verify   { "email": "...", "otp": "123456" }
→ { apiKey: "fav_mcp_…", companyId, mcpEndpoint }

Existing merchant: app.favcrm.io/settings/mcp-keys → Create Key.

Step 02 — Connect

Pick one. All three accept the same Bearer token.

  • MCP — Cursor, Claude, Smithery
    https://api.favcrm.io/mcp
  • SDK — Node.js, Edge, browser
    npm i @favcrm/sdk
  • REST — anything else
    https://api.favcrm.io/v6/...

Step 03 — Authenticate

One header shape across every interface.

Authorization: Bearer fav_mcp_xxx

SDK: sdk.setToken('fav_mcp_xxx') — accepts API keys and JWT session tokens.

Step 04 — Smoke test

Verify auth before doing real work. Returns [] on a fresh sandbox — that's success.

curl https://api.favcrm.io/v6/merchant/bookings/services \
  -H "Authorization: Bearer fav_mcp_xxx"

# MCP equivalent
> Use list_services to list bookable services.
USE CASES

Three wedges. One platform.

FavCRM replaces multiple SaaS tools. Pick your wedge or use all three.

Wedge 01

Booking Storefront

Drop into Cursor or Claude:

"Use @favcrm/sdk to build a booking page. List services from sdk.bookings.listServices(), show available time slots for a selected date, and let users book with sdk.bookings.createBooking()."
import FavCRM from '@favcrm/sdk';

const sdk = new FavCRM({
  baseUrl: 'https://api.favcrm.io',
  companyId: process.env.FAVCRM_COMPANY_ID,
});

const services = await sdk.bookings.listServices();
const slots = await sdk.bookings.getTimeSlots(serviceId, {
  date: '2026-06-01',
});
const booking = await sdk.bookings.createBooking({
  serviceId,
  slotTime: slots[0].startTime,
  participants: 2,
});

Agent workflow

A · Merchant setup

One-time merchant setup. Fully MCP-native — same tool surface as the customer flow.

  1. 01 create_service_category({ name }) — Optional grouping ("Treatments", "Classes").
  2. 02 create_service({ name, durationMinutes, price, capacity, categoryId? }) — Define a bookable service. Add cancellationPolicy / requiresStaff / requiresResource as needed.
  3. 03 set_staff_availability({ memberId, dayOfWeek, startTime, endTime }) — Weekly working hours per staff member. Use date instead of dayOfWeek for one-off changes.
  4. 04 create_resource({ name, type }) + set_resource_availability(...) — (Optional) For room/equipment-bound bookings.

B · Customer flow

Customer-facing storefront. Works via MCP tools, SDK, or raw REST.

  1. 01 list_services — Render service cards with name, price, duration, capacity.
  2. 02 get_service_detail(serviceId) — (Optional) Show prep notes + cancellation policy on the detail page.
  3. 03 get_available_slots(serviceId, { startDate, endDate }) — Render date picker + open times. Returns [] if fully booked.
  4. 04 create_booking({ serviceId, slotTime, participants, customer }) — Confirm booking. Returns booking ID + status.
  5. 05 cancel_booking({ bookingId, reason? }) — Cancel flow. Server checks policy + computes refund eligibility.

Edge cases agents must handle

  • get_available_slots → [] : render "no availability" instead of erroring.
  • create_booking → 409 Conflict : another customer took the slot between fetch and book — refetch slots.
  • cancel_booking → cooldown error includes cancellationPolicy field — surface to user verbatim.
  • Capacity > 1 services : let user pick participants count up to service.capacity.

Wedge 02

Headless CMS / Blog

Drop into Cursor or Claude:

"Fetch blog posts from FavCRM using @favcrm/sdk and render them in my Next.js site. Use sdk.blog.listPosts() for the index and sdk.blog.getPostBySlug() for each post. Render each block in post.blocks."
// Blog index
const posts = await sdk.blog.listPosts({
  status: 'published',
  limit: 10,
});

// Single post with blocks
const post = await sdk.blog.getPostBySlug('my-article');

// Render blocks
post.blocks.forEach(block => {
  if (block.type === 'heading') renderHeading(block.props);
  if (block.type === 'paragraph') renderText(block.props);
  if (block.type === 'image') renderImage(block.props);
});

Agent workflow

A · Merchant setup

Optional content-model setup. Skip if the default post type fits.

  1. 01 create_category({ name, slug? }) — Organize posts ("News", "Tutorials"). Skip if you only need a flat blog.
  2. 02 create_post_type({ key, label }) — Define a custom content type beyond the default `post` (e.g. `case_study`).
  3. 03 create_post_type_field({ postTypeId, key, label, fieldType }) — Add typed custom fields (text, number, image, etc.) to a post type.

B · Customer flow

Author + render flow. Fully MCP-native — no REST fallback needed.

  1. 01 create_post({ type, title, slug?, blocks }) — Create a post with starting blocks. Slug auto-generated from title if omitted.
  2. 02 append_post_block({ postId, type, props }) — Append heading / paragraph / image / button / divider / video / gallery / form blocks.
  3. 03 update_post({ postId, status: "published" }) — Flip from draft to published when ready.
  4. 04 list_posts({ status: "published", categoryId?, limit, offset }) — Storefront index page.
  5. 05 get_post({ slug }) — Storefront single-page view. Returns post + ordered blocks array.

Edge cases agents must handle

  • Block shape: { id, version, type, data } — id is a unique block UUID, version is an integer, data is the block-specific payload.
  • Block types: paragraph, heading, image, list, quote, code, divider, embed, file, faq, callout, gallery, cta, accordion, product.
  • Slug collision → 409 Conflict. Either auto-suffix client-side or omit slug to let server generate.
  • append_post_block reorder: use `reorder_post_blocks` for full reorder, or `replace_post_block({ index })` for in-place edits.
  • Draft posts (status: "draft") are not returned by list_posts unless authed as the author.

Wedge 03

Replace Cal + Mailchimp + Shopify

Drop into Cursor or Claude:

"Use FavCRM MCP to run my whole business: list_bookings for today, list_orders for pending fulfilment, create_campaign + create_promotion to launch a flash sale to VIP members. My MCP key is fav_mcp_..."
// One platform — bookings + shop + campaigns + promos
const [bookings, products, campaigns] = await Promise.all([
  sdk.bookings.list({ status: 'confirmed' }),
  sdk.shop.listProducts({ inStock: true }),
  sdk.campaigns.list({ status: 'active' }),
]);

// Launch a flash sale to a VIP segment
const promo = await sdk.promotions.create({
  name: 'VIP Flash 20%', code: 'VIP20',
  type: 'percentage', value: '20',
  endsAt: '2026-06-30T23:59:00Z', onlineEnabled: true,
});

const campaign = await sdk.campaigns.create({
  name: 'VIP Flash Sale',
  channel: 'email',
  recipientSource: 'segment',
  segmentId: 'vip-segment-id',
  channelConfig: { subject: '20% off this weekend', html: '...' },
});

Agent workflow

A · Merchant setup

Provision the catalog + audience once. Fully MCP-native.

  1. 01 create_product_category({ name }) + create_product({ name, price, ... }) — Build the shop catalog. Use list_product_categories first if you want to attach to existing groups.
  2. 02 list_customer_segments + create_customer_segment(...) — Define audience segments (VIP, recent buyers, lapsed) for campaign targeting.
  3. 03 create_promotion({ name, code, type, value, ...channelFlags }) — Create promo / coupon codes. Toggle bookingEnabled / onlineEnabled / posEnabled to scope.
  4. 04 create_service + set_staff_availability — See Wedge 01 for booking-side setup.

B · Customer flow

Daily ops + marketing automation. All MCP-native today (campaign send still REST — see edge cases).

  1. 01 list_bookings({ status: "confirmed", date }) + list_orders({ status: "pending" }) — Daily dashboard / fulfilment queue.
  2. 02 create_shop_order({ accountId, items, promotionCode? }) — Create orders programmatically (e.g. from a chat agent or quote-to-order flow).
  3. 03 validate_promotion({ promotionCode, channel, amount }) — Pre-check coupon at checkout — returns isValid + discountAmount.
  4. 04 create_campaign({ name, channel, recipientSource: "segment", segmentId, channelConfig }) — Stage an email/SMS/WhatsApp campaign in DRAFT.
  5. 05 POST /v6/merchant/campaigns/{id}/send — Trigger send (REST only — MCP send tool needs queue binding, coming next).

Edge cases agents must handle

  • send_campaign requires NOTIFICATIONS queue access — currently REST-only (POST /v6/merchant/campaigns/:id/send). MCP tool tracked in claudedocs/mcp-tools-gap.md.
  • create_promotion: code is uppercased server-side. Collisions return a unique-constraint error — surface as "code already used".
  • validate_promotion: amount is in major units (dollars, not cents). Returns errorCode: PROMOTION_NOT_FOUND / EXPIRED / USAGE_LIMIT_REACHED / etc.
  • create_campaign: status defaults to DRAFT. SCHEDULED requires a future scheduledAt. Cannot delete after status=SENT.
  • list_orders + create_shop_order respect the company's active currency — multi-currency mixed orders not supported in v1.

Ready to build?

Get a sandbox API key in 60 seconds. No credit card. Pre-seeded with demo data.