REST endpoints for website in ServFlo: 25 operations with parameters, request and response fields, permissions and curl examples.
Base URL: https://app.servflo.ai/api. Every call needs Authorization: Bearer sfk_… (Authentication ); {organizationId} ($ORGANIZATION_ID in the examples) is your business's id .
GET /organizations/{organizationId}/website
The website with its draft pages (sections included), theme, business details, SEO, publish state and custom domains; null before one is made (POST /website). Read-only.
Permission website.read (Owner, Admin, Dispatcher)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool website_get (toolset marketing)
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website
Makes the business's website as a DRAFT (nobody outside sees it until POST /website/publish): Claude writes the copy from the business's own records (services, plans, place, booking mode) and invents no reviews or claims; without a model configured a template is used (generatedBy). Pages: home, services, plans (when there are plans), about, book, contact. 409 when one exists.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_create (toolset marketing)
Field Type Required Description subdomainstring No The site's address under the sites domain: lower-case letters, numbers and hyphens. Up to 40 characters. tradestring or null No The trade template: its style, curated banner and about photos, and copy for its customers. One of: hvac, plumbing, electrical, roofing, lawn-care, landscaping, tree-care, pest-control, house-cleaning, carpet-cleaning, window-cleaning, pressure-washing, pool-spa, painting, handyman, garage-doors, appliance-repair, locksmith, junk-removal, moving, flooring, remodeling, solar, septic-drain, chimney-fireplace, irrigation, car-detailing, other. Up to 40 characters. stylestring or null No A style from the gallery instead of the trade's own (POST /website/style lists them). Up to 40 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"subdomain":"string","trade":"string","style":"string"}'
201: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
PATCH /organizations/{organizationId}/website
Changes the fields sent in the draft: subdomain (409 when taken; a published site moves at once), theme, business profile (merged), SEO. Publish to show the changes on the live site (the subdomain change applies immediately).
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_update (toolset marketing)
Field Type Required Description subdomainstring No The site's address under the sites domain: lower-case letters, numbers and hyphens. Up to 40 characters. tradestring or null No The trade template: steers photo suggestions and the next fresh draft. Up to 40 characters. themeobject No theme.primaryColorstring No theme.accentColorstring No theme.fontenum No One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum No One of square, soft, round. theme.headerStyleenum No One of light, dark, brand. theme.stylestring No Up to 40 characters. profileobject No Merged into the business details: send only what changes (hours and links per day / network). profile.taglinestring No Up to 160 characters. profile.phonestring No Up to 40 characters. profile.emailempty string or string (email) No profile.addressstring No Up to 300 characters. profile.hoursobject No profile.hoursNotestring No Up to 200 characters. profile.licenseTextstring No Up to 200 characters. profile.serviceAreaTextstring No Up to 600 characters. profile.socialobject No profile.social.facebookempty string or string (uri) No profile.social.instagramempty string or string (uri) No profile.social.googleempty string or string (uri) No profile.social.yelpempty string or string (uri) No profile.social.nextdoorempty string or string (uri) No profile.logoUrlstring No Up to 2000 characters. profile.headerBrandenum No One of logoAndName, logo, name. profile.logoSizeenum No One of small, medium, large. profile.siteNamestring No Up to 120 characters. profile.privacyUrlempty string or string (uri) No profile.termsUrlempty string or string (uri) No profile.footerobject No profile.footer.showTaglineboolean No profile.footer.showContactboolean No profile.footer.showHoursboolean No profile.footer.showSocialboolean No profile.footer.showPoweredByboolean No profile.footer.copyrightstring No Up to 200 characters. seoTitlestring or null No Up to 70 characters. seoDescriptionstring or null No Up to 170 characters.
curl -X PATCH "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"subdomain":"string","trade":"string","theme":{"primaryColor":"string","accentColor":"string","font":"modern"}}'
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
DELETE /organizations/{organizationId}/website
DESTRUCTIVE and permanent: deletes the website with every page, custom domain and visitor stat; a published site goes offline at once (its addresses answer 404). The image library stays, and POST /website can build a new one. confirm must equal the site's subdomain (400 otherwise). Emits website.deleted.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_delete (toolset marketing)Approval Over MCP, this tool always waits for your approval in ServFlo. See Approvals .
Field Type Required Description confirmstring Yes The site's subdomain, typed by the user to confirm. Up to 60 characters.
curl -X DELETE "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description oktrue
POST /organizations/{organizationId}/website/regenerate
DESTRUCTIVE for the draft: replaces every draft page with a newly written set (theme, domains and filled-in business details stay). The published site is unchanged until published again.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_regenerate (toolset marketing)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/regenerate" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/style
Changes the draft's look in one step: the theme (colours unless keepColors, type, corners, header) and the layout of every block on every page. Words and photos stay; the live site changes when published. Styles: clean, bold, classic, friendly, elegant, fresh, cool, warm.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_applyStyle (toolset marketing)
Field Type Required Description stylestring Yes Up to 40 characters. keepColorsboolean No Keep the business's own primary and accent colours.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/style" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"style":"string"}'
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/publish
EXPOSES the draft to the public: freezes every page as it stands and serves it at the site's addresses (subdomain and active custom domains). Republishing replaces the live site. Emits website.published.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_publish (toolset marketing)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/publish" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/unpublish
The live site's addresses answer 404 until published again; the draft is kept. 409 when not published.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_unpublish (toolset marketing)Approval Over MCP, this tool asks for your OK first (in the AI app when it supports it, otherwise in ServFlo). See Approvals .
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/unpublish" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
GET /organizations/{organizationId}/website/preview
The draft site exactly as POST /website/publish would serve it, with the live services, plans and booking settings. Read-only.
Permission website.read (Owner, Admin, Dispatcher)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool website_preview (toolset marketing)
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/preview" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description subdomainstring canonicalHoststring or null publishedAtstring (date-time) siteobject site.themeobject site.theme.primaryColorstring site.theme.accentColorstring site.theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. site.theme.radiusenum One of square, soft, round. site.theme.headerStyleenum One of light, dark, brand. site.theme.stylestring Up to 40 characters. site.profileobject site.profile.taglinestring Up to 160 characters. site.profile.phonestring Up to 40 characters. site.profile.emailempty string or string (email) site.profile.addressstring Up to 300 characters. site.profile.hoursobject site.profile.hoursNotestring Up to 200 characters. site.profile.licenseTextstring Up to 200 characters. site.profile.serviceAreaTextstring Up to 600 characters. site.profile.socialobject site.profile.logoUrlstring Up to 2000 characters. site.profile.headerBrandenum One of logoAndName, logo, name. site.profile.logoSizeenum One of small, medium, large. site.profile.siteNamestring Up to 120 characters. site.profile.privacyUrlempty string or string (uri) site.profile.termsUrlempty string or string (uri) site.profile.footerobject site.seoTitlestring or null site.seoDescriptionstring or null site.pagesarray of object site.pages[].slugstring site.pages[].titlestring site.pages[].showInNavboolean site.pages[].seoTitlestring or null site.pages[].seoDescriptionstring or null site.pages[].sectionsarray of object site.photoCreditsarray of object Credits for the stock photos the site shows; the footer lists them. site.photoCredits[].providerstring site.photoCredits[].authorstring site.photoCredits[].authorUrlstring site.photoCredits[].sourceUrlstring organizationSlugstring For the booking form: /api/public/book/{organizationSlug}. businessNamestring customerSignInboolean Customers can sign in at /c/{organizationSlug}: the header shows Customer login. logostring or null timezonestring bookingobject booking.enabledboolean booking.modeenum One of REQUEST, SLOTS. booking.requiresZipboolean serviceZipsarray of string servicesarray of object services[].idstring services[].namestring services[].descriptionstring or null services[].priceCentsinteger services[].durationMinutesinteger plansarray of object plans[].idstring plans[].namestring plans[].descriptionstring or null plans[].priceCentsinteger plans[].billingFrequencystring plans[].termMonthsinteger plans[].serviceDiscountPercentnumber plans[].priorityboolean trackingNumbersarray of object Dynamic number insertion: tracking numbers by visitor source; the site's phone links show the matching one. trackingNumbers[].phonestring trackingNumbers[].isDefaultboolean trackingNumbers[].utmSourcestring or null trackingNumbers[].utmMediumstring or null trackingNumbers[].campaignIdstring or null webChatobject The website chat: the site shows its button while on. webChat.enabledboolean
GET /organizations/{organizationId}/website/stats
Page views per day and the top pages over days (default 30), and online requests by channel (booking page, widget, website). Read-only.
Permission website.read (Owner, Admin, Dispatcher)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool website_stats (toolset marketing)
Name In Type Required Description daysquery integer No 7–90.
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/stats" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description fromstring tostring viewsinteger daysarray of object days[].datestring days[].viewsinteger topPagesarray of object topPages[].pathstring topPages[].viewsinteger requestsobject requests.BOOKING_PAGEinteger requests.WIDGETinteger requests.WEBSITEinteger
POST /organizations/{organizationId}/website/image-upload-url
Step 1 of adding an image to a section: returns a signed URL to PUT the file to (with the same Content-Type) and the url to put in the section (hero, about, gallery).
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_createImageUploadUrl (toolset marketing)
Field Type Required Description contentTypeenum Yes One of image/jpeg, image/png, image/webp.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/image-upload-url" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"contentType":"image/jpeg"}'
200: the answer's fields Field Type Description signedUploadUrlstring (uri) urlstring
GET /organizations/{organizationId}/website/media
The business's uploaded images and the stock photos it has used, most recently used first, paged by cursor. stockProviders lists the photo libraries that can be searched (none: stock search is off). Read-only.
Permission website.read (Owner, Admin, Dispatcher)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool website_media (toolset marketing)
Name In Type Required Description cursorquery string No Up to 100 characters. limitquery integer No 1–200.
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/media" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description itemsarray of object items[].idstring items[].sourceenum One of UPLOAD, STOCK. items[].urlstring What to put in a section's image field. items[].thumbUrlstring or null items[].altstring items[].widthinteger or null items[].heightinteger or null items[].providerstring or null Stock: UNSPLASH or PEXELS.items[].providerIdstring or null items[].authorstring or null Stock: the photographer, credited on the site.items[].authorUrlstring or null items[].sourceUrlstring or null items[].createdAtstring (date-time) items[].lastUsedAtstring (date-time) nextCursorstring or null stockProvidersarray of enum
POST /organizations/{organizationId}/website/media/uploads
Step 2 of uploading, after the PUT to the signed URL: the image joins the library. url must be one POST /website/image-upload-url gave this business (404 otherwise).
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_confirmImageUpload (toolset marketing)
Field Type Required Description urlstring Yes Up to 300 characters. widthinteger or null No 1–20000. heightinteger or null No 1–20000. altstring or null No Up to 300 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/media/uploads" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}'
200: the answer's fields Field Type Description idstring sourceenum One of UPLOAD, STOCK. urlstring What to put in a section's image field. thumbUrlstring or null altstring widthinteger or null heightinteger or null providerstring or null Stock: UNSPLASH or PEXELS.providerIdstring or null authorstring or null Stock: the photographer, credited on the site.authorUrlstring or null sourceUrlstring or null createdAtstring (date-time) lastUsedAtstring (date-time)
GET /organizations/{organizationId}/website/stock-photos
Landscape photos for query from Unsplash (or Pexels when Unsplash is unavailable; provider picks one), free for commercial use with a credit the site shows. Searching uses nothing; POST /website/media/stock with a result's provider and id to use one. Rate-limited per business. Read-only.
Permission website.manage (Owner, Admin)Risk read, OAuth scope servflo.read. Read: reads only.MCP tool website_searchStockPhotos (toolset marketing)
Name In Type Required Description queryquery string Yes Up to 100 characters. pagequery integer No 1–50. providerquery enum No One of UNSPLASH, PEXELS.
curl "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/stock-photos?query=string" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description providerenum or null One of UNSPLASH, PEXELS. photosarray of object photos[].providerenum One of UNSPLASH, PEXELS. photos[].idstring Pass with provider to POST /website/media/stock to use it. photos[].urlstring photos[].thumbUrlstring photos[].widthinteger photos[].heightinteger photos[].altstring photos[].authorstring photos[].authorUrlstring photos[].sourceUrlstring pageinteger hasMoreboolean
POST /organizations/{organizationId}/website/media/stock
Adds a stock photo (by provider and id from GET /website/stock-photos) to the library with its credit and reports the use to the provider, as its licence asks. Answers the library item: put its url in a section. Using the same photo again answers the same item.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_useStockPhoto (toolset marketing)
Field Type Required Description providerenum Yes One of UNSPLASH, PEXELS. photoIdstring Yes Up to 100 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/media/stock" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"provider":"UNSPLASH","photoId":"photo_id"}'
201: the answer's fields Field Type Description idstring sourceenum One of UPLOAD, STOCK. urlstring What to put in a section's image field. thumbUrlstring or null altstring widthinteger or null heightinteger or null providerstring or null Stock: UNSPLASH or PEXELS.providerIdstring or null authorstring or null Stock: the photographer, credited on the site.authorUrlstring or null sourceUrlstring or null createdAtstring (date-time) lastUsedAtstring (date-time)
DELETE /organizations/{organizationId}/website/media/{mediaId}
Takes the image out of the library. Pages that already show it keep showing it (and keep its credit) until changed.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_deleteMedia (toolset marketing)Approval Over MCP, this tool always waits for your approval in ServFlo. See Approvals .
Name In Type Required Description mediaIdpath string Yes
curl -X DELETE "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/media/{mediaId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description oktrue
POST /organizations/{organizationId}/website/pages
Adds a draft page at the end of the navigation. sections is validated per type. 409 when the address is taken.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_createPage (toolset marketing)
Field Type Required Description slugstring Yes The page address: "" (home only) or words-with-hyphens. Up to 60 characters. titlestring Yes Up to 120 characters. showInNavboolean No seoTitlestring or null No Up to 70 characters. seoDescriptionstring or null No Up to 170 characters. sectionsarray of any No Every section of the page in order: { id, type, hidden, props }; replaces the list. Up to 30 items.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/pages" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"slug":"string","title":"string"}'
201: the answer's fields Field Type Description idstring slugstring The page address; "" is the home page. titlestring showInNavboolean sortOrderinteger seoTitlestring or null seoDescriptionstring or null sectionsarray of object sections[].idstring sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. sections[].hiddenboolean sections[].propsobject The section's fields; their schema per type is in. updatedAtstring (date-time)
PATCH /organizations/{organizationId}/website/pages/{pageId}
Changes the fields sent on a draft page; sections replaces the whole list (validated per type; a 400 names the field). The home page keeps its address.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_updatePage (toolset marketing)
Name In Type Required Description pageIdpath string Yes
Field Type Required Description slugstring No The page address: "" (home only) or words-with-hyphens. Up to 60 characters. titlestring No Up to 120 characters. showInNavboolean No seoTitlestring or null No Up to 70 characters. seoDescriptionstring or null No Up to 170 characters. sectionsarray of any No Every section of the page in order: { id, type, hidden, props }; replaces the list. Up to 30 items.
curl -X PATCH "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/pages/{pageId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"slug":"string","title":"string","showInNav":true}'
200: the answer's fields Field Type Description idstring slugstring The page address; "" is the home page. titlestring showInNavboolean sortOrderinteger seoTitlestring or null seoDescriptionstring or null sectionsarray of object sections[].idstring sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. sections[].hiddenboolean sections[].propsobject The section's fields; their schema per type is in. updatedAtstring (date-time)
DELETE /organizations/{organizationId}/website/pages/{pageId}
Destructive: removes the draft page (the home page cannot be deleted). The live site keeps it until published again.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_deletePage (toolset marketing)Approval Over MCP, this tool always waits for your approval in ServFlo. See Approvals .
Name In Type Required Description pageIdpath string Yes
curl -X DELETE "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/pages/{pageId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description oktrue
POST /organizations/{organizationId}/website/pages/order
Sets the navigation order: pageIds lists every page of the site once.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_reorderPages (toolset marketing)
Field Type Required Description pageIdsarray of string Yes Up to 50 items.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/pages/order" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"pageIds":["page_id"]}'
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/domains
Adds a domain (e.g. www.example.com ) as PENDING. The business then adds every record in records: the ownership TXT and a CNAME to cnameTarget (A records for a bare domain); the domain becomes ACTIVE (served, certificate on demand) once the checks pass, checked every ten minutes or with POST …/verify. Up to five per site.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_addDomain (toolset marketing)
Field Type Required Description hostnamestring Yes Up to 260 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/domains" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"hostname":"string"}'
201: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/domains/{domainId}/verify
Runs the DNS checks for one domain now; lastError says what is missing. ACTIVE domains serve the site.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_verifyDomain (toolset marketing)
Name In Type Required Description domainIdpath string Yes
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/domains/{domainId}/verify" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/domains/{domainId}/primary
The site's canonical address (search engines, sitemap) becomes this domain once it is ACTIVE.
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_setPrimaryDomain (toolset marketing)
Name In Type Required Description domainIdpath string Yes
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/domains/{domainId}/primary" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
DELETE /organizations/{organizationId}/website/domains/{domainId}
Destructive: the domain stops serving the site at once.
Permission website.manage (Owner, Admin)Risk sensitive, OAuth scope servflo.sensitive. Sensitive: moves money, deletes, sends or shows something to a customer, or grants or revokes access.MCP tool website_removeDomain (toolset marketing)Approval Over MCP, this tool always waits for your approval in ServFlo. See Approvals .
Name In Type Required Description domainIdpath string Yes
curl -X DELETE "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/domains/{domainId}" \
-H "Authorization: Bearer $SERVFLO_API_KEY "
200: the answer's fields Field Type Description idstring subdomainstring statusenum One of DRAFT, PUBLISHED, UNPUBLISHED. themeobject theme.primaryColorstring theme.accentColorstring theme.fontenum One of modern, classic, friendly, bold, elegant, geometric. theme.radiusenum One of square, soft, round. theme.headerStyleenum One of light, dark, brand. theme.stylestring Up to 40 characters. profileobject profile.taglinestring Up to 160 characters. profile.phonestring Up to 40 characters. profile.emailempty string or string (email) profile.addressstring Up to 300 characters. profile.hoursobject profile.hoursNotestring Up to 200 characters. profile.licenseTextstring Up to 200 characters. profile.serviceAreaTextstring Up to 600 characters. profile.socialobject profile.social.facebookempty string or string (uri) profile.social.instagramempty string or string (uri) profile.social.googleempty string or string (uri) profile.social.yelpempty string or string (uri) profile.social.nextdoorempty string or string (uri) profile.logoUrlstring Up to 2000 characters. profile.headerBrandenum One of logoAndName, logo, name. profile.logoSizeenum One of small, medium, large. profile.siteNamestring Up to 120 characters. profile.privacyUrlempty string or string (uri) profile.termsUrlempty string or string (uri) profile.footerobject profile.footer.showTaglineboolean profile.footer.showContactboolean profile.footer.showHoursboolean profile.footer.showSocialboolean profile.footer.showPoweredByboolean profile.footer.copyrightstring Up to 200 characters. seoTitlestring or null seoDescriptionstring or null publishedAtstring (date-time) or null generatedBystring or null AI (written by Claude) or TEMPLATE. tradestring or null The trade template it was built from (e.g. hvac, plumbing); null when none. defaultUrlstring or null https://{subdomain}.{sites domain}, when one is configured. pathstring /sites/{subdomain} on the app: always works. hasUnpublishedChangesboolean pagesarray of object pages[].idstring pages[].slugstring The page address; "" is the home page. pages[].titlestring pages[].showInNavboolean pages[].sortOrderinteger pages[].seoTitlestring or null pages[].seoDescriptionstring or null pages[].sectionsarray of object pages[].sections[].idstring pages[].sections[].typestring hero, trust, services, about, testimonials, booking, memberships, serviceArea, faq, cta, contact, gallery or text. pages[].sections[].hiddenboolean pages[].sections[].propsobject The section's fields; their schema per type is in. pages[].updatedAtstring (date-time) domainsarray of object domains[].idstring domains[].hostnamestring domains[].statusenum One of PENDING, ACTIVE, FAILED. domains[].verificationTokenstring The value of the TXT record at recordName. domains[].recordNamestring domains[].cnameTargetstring or null Where the domain's CNAME (or A records) must point. domains[].apexboolean A bare domain (example.com): A records instead of a CNAME. domains[].recordsarray of object Every DNS record to add: the ownership TXT, then the CNAME (or A records). domains[].records[].typeenum One of TXT, CNAME, A. domains[].records[].namestring Relative to the domain, as DNS providers ask: "@", "www", "_servflo.www". domains[].records[].fullNamestring domains[].records[].valuestring domains[].records[].purposeenum One of verify, route. domains[].verifiedAtstring (date-time) or null domains[].lastCheckedAtstring (date-time) or null domains[].lastErrorstring or null domains[].isPrimaryboolean domains[].createdAtstring (date-time) createdAtstring (date-time) updatedAtstring (date-time)
POST /organizations/{organizationId}/website/media/content
Adds a JPEG, PNG or WebP image to the website's library in one call: send contentBase64 or a public sourceUrl (up to 10 MB). Returns the library entry; put its url in a section's image field (hero, about, gallery) with website.updatePage. Needs a website (website.create first).
Permission website.manage (Owner, Admin)Risk write, OAuth scope servflo.write. Write: creates or changes records inside the business; nothing leaves it.MCP tool website_uploadImage (toolset marketing)
Field Type Required Description altstring or null No Alternative text describing the image. Up to 300 characters. fileNamestring No The file's name, e.g. receipt.jpg (default: from the URL, else 'file'). Up to 500 characters. contentTypestring No MIME type, e.g. image/jpeg or application/pdf. Optional: taken from a data: URL, the URL's answer or the file's first bytes. Up to 200 characters. contentBase64string No The file's bytes as base64 (a data: URL is accepted too). Up to 10 MB. Give this or sourceUrl. sourceUrlstring (uri) No A public http(s) URL ServFlo downloads the file from (up to 10 MB, 20 s, 3 redirects; private and internal addresses are refused). Give this or contentBase64. Up to 2000 characters.
curl -X POST "https://app.servflo.ai/api/organizations/ $ORGANIZATION_ID /website/media/content" \
-H "Authorization: Bearer $SERVFLO_API_KEY " \
-H "Content-Type: application/json" \
-d '{"alt":"string","fileName":"string","contentType":"string"}'
201: the answer's fields Field Type Description idstring sourceenum One of UPLOAD, STOCK. urlstring What to put in a section's image field. thumbUrlstring or null altstring widthinteger or null heightinteger or null providerstring or null Stock: UNSPLASH or PEXELS.providerIdstring or null authorstring or null Stock: the photographer, credited on the site.authorUrlstring or null sourceUrlstring or null createdAtstring (date-time) lastUsedAtstring (date-time)