Site Creation API
The Site Creation API queues a full website build for one business and lets you check on it until it finishes. It uses the same API keys and the same credit balance as the Lead Gen API.
Base URL
Send requests to the same domain you use for your dashboard. Every path on this page is relative to it.
Authentication
Send your API key as a bearer token on every request:
Authorization: Bearer YOUR_API_KEY
Keys start with lgen_. To create one, open API Keys in your dashboard, type a name in the Key label box (up to 64 characters), and click + Create New Key. The full key is shown once, in the Your new API key window. Copy it before you click Done. If you lose it, revoke it and create a new one.
A missing, unknown or revoked key gets 401 with "Missing or invalid bearer API key."
Create a site
POST /api/provision
A valid request queues the build, uses 1 site credit, and returns 202. You need at least 1 credit on your account.
Required fields
| Field | Type | Rules |
|---|---|---|
businessName | string | Must not be blank. |
Optional fields
| Field | Type | Rules and default |
|---|---|---|
phone | string | If sent: at least 10 digits for a US business. For a business in Mexico, Guatemala, Peru, Colombia, Ecuador, Costa Rica or Argentina, 8 to 12 digits. For any other country, 7 to 15 digits. |
address | string | Free text. A full street address such as 100 Main St, Springfield, IL 62701, or just a city or service area such as Springfield. Built from the fields below when you leave it out. |
addressLine1, addressLine2 | string | Street address and suite, unit or floor. Up to 200 characters each. |
addressCity, addressRegion, addressPostalCode | string | City, state or region, and postal code. |
countryCode | string | Two-letter country code such as US or GB. Any country. |
hasPublicBusinessAddress | boolean | Default true. When false, the street lines and postal code are dropped and never appear on the site. City, region and country stay. Same as publicAddress. |
googlePlaceId | string | The business's Google Place ID. Kept with the site's business details. |
look | string | classic or bold. Default classic. An unknown value is built as classic. |
themeId | string | Same as look. Send the themeId from GET /api/templates. |
industry | string | The type of business, such as Plumbing. |
email | string | The business email. |
businessWebsite | string | Must start with http:// or https://. |
aboutBusiness | string | A description of the business. |
services | string[] | Services the business offers. The site shows up to 12. |
serviceAreas | string[] | Towns or areas the business serves. Up to 12. |
businessHours | string | Opening hours as free text, or as a JSON-encoded string keyed by day, such as {"monday":{"open":"09:00","close":"17:00"},"sunday":"closed"}. |
businessHoursMode | string | weekly, open_24_hours or do_not_display. Same as hoursMode (weekly, always_open, hidden). |
businessHoursByDay | object[] | Up to 7 entries. Each has day (mon to sun) and either open and close (such as "9:00 AM" or "17:00") or "closed": true. |
logoUrl | string | Must start with http:// or https://. |
primaryColor | string | Six-digit hex color such as #2F6B55. If you leave it out, a default color is used and a warning is added to the build. |
secondaryColor | string | Six-digit hex color. |
backgroundTheme | string | light or dark. |
primaryLanguage | string | en, es, fr, de, it, ro or tr. Default en. The site's content, page addresses, navigation and forms are written in this language. Any other value is rejected with a 400. |
country | string | Up to 60 characters. Filled from countryCode when you leave it out. |
customerModel | string | visit_business, travel_to_customers, hybrid or remote_online (or visit, travel, remote). Default travel_to_customers. visit_business and hybrid need a public address. |
reviews | object[] | Up to 10. Each needs author, text and rating (a whole number from 1 to 5). source, date and url are optional. |
skipImages | boolean | Default false. When true, image generation is skipped and the build lists a warning. |
priceTool | boolean | Adds a price tool to the site. On by default when priceToolCalcId is set or the industry matches a trade that has a price tool. Send false to leave it off. See Price tools. |
priceToolCalcId | string | One of decks, fencing, gutters, home_construction, house_cleaning, hvac, landscaping, painting, pest_control, plumbing, windows_doors. |
createServicePages | boolean | Default true. false: no page for each service; the services are listed on the home page and the services page. |
createServiceAreaPages | boolean | Default true. Service-area pages are built for travel_to_customers and hybrid; false leaves them out. |
createLocationPages | boolean | Default true. Location pages are built for visit_business and hybrid; false leaves them out. |
locations | list | Up to 12, one page each: name (required), address, phone, email, hours, hoursMode, mapUrl, description, content. With none sent, the business address is the one location. |
Example request
curl -X POST "https://YOUR_DOMAIN/api/provision" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"businessName": "Example Plumbing",
"industry": "Plumbing",
"email": "owner@example.com",
"phone": "(555) 010-0100",
"address": "100 Main St, Springfield, IL 62701",
"aboutBusiness": "Example Plumbing repairs and installs residential plumbing.",
"services": ["Drain cleaning", "Water heater installation", "Leak repair"],
"serviceAreas": ["Springfield", "Riverton", "Chatham"],
"look": "classic",
"primaryColor": "#2F6B55",
"backgroundTheme": "light"
}'
Response
Status 202:
{
"slug": "example-plumbing",
"siteId": "3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6f",
"previewUrl": null,
"statusUrl": "/api/provision/3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6f"
}
slug is made from the business name. If that slug is already taken, a number is added, such as example-plumbing-2. Keep siteId: you need it to check the build.
When builds are paused
Sometimes a valid request is not queued. You then get status 200 with "paused": true and a message. No site is queued and no credit is used. Try again later.
{
"ok": true,
"paused": true,
"message": "Today's free builds are used up — try again tomorrow."
}
The message is either "Today's free builds are used up — try again tomorrow.", which applies to accounts that have only ever had signup credits, or "Free tests are paused right now — check back soon."
Check a build
GET /api/provision/{siteId}
Only the key that created the build can read it. Any other key gets the same 404 as an unknown ID.
curl "https://YOUR_DOMAIN/api/provision/3f2a9c1e-5b7d-4e8a-9c0f-1a2b3c4d5e6f" \
-H "Authorization: Bearer YOUR_API_KEY"
{
"status": "complete",
"currentStep": "Complete",
"progressPct": 100,
"previewUrl": "https://example-plumbing.example.com/",
"adminUrl": "https://example-plumbing.example.com/wp-admin/",
"warnings": [],
"error": null,
"liveAt": "2026-10-01T15:04:10.000Z",
"enhancingStartedAt": "2026-10-01T15:04:11.000Z",
"completedAt": "2026-10-01T15:06:30.000Z",
"enhancementError": null,
"creditRefunded": false
}
Response fields
| Field | Meaning |
|---|---|
status | One of queued, provisioning, live, enhancing, complete, failed. complete and failed are final. The preview link works from live: the main pages are published first, and the other pages and the photos are added during enhancing. |
currentStep | A short description of the step in progress. |
progressPct | Progress from 0 to 100. |
previewUrl | The site's address. null until the build reports it. |
adminUrl | The site's WordPress admin address. |
warnings | A list of strings. Each one names a value that was defaulted, ignored or skipped. |
error | Why the build failed, or null. |
liveAt | When the build first reached live. |
enhancingStartedAt | When the build first reached enhancing. |
completedAt | When the build reached complete or failed. |
enhancementError | An error from the enhancing step, or null. The site stays live and the build still ends complete; no credit is returned. |
creditRefunded | true when a failed build's credit has been returned to your account. A failed build returns its credit once, on its own. |
There is no endpoint that lists your sites. Keep the siteId of each build you create.
List templates
GET /api/templates
Returns the templates a new site can use, as a JSON list. No key is needed; a key that is sent must be valid. Send a template's templateId (and its themeId, when it has one) to POST /api/provision.
[
{ "id": "classic", "templateId": "template6", "themeId": "classic", "name": "Classic",
"description": "Clean and modern, our standard look", "version": "2.0.0",
"hasServices": true, "hasServiceAreas": true,
"featureImage": "/img/look-picker/classic.jpg", "previewUrl": "/templates/ultimate?look=classic" }
]
Check a build from a workflow
POST /api/integrations/site-status
For workflow tools that can only send POST. Send {"siteId": "..."} with the same key. The answer is the same as GET /api/provision/{siteId}, plus ok, siteId and statusUrl. Same 401 and 404 rules.
White-label agency API
For agencies that take site requests from their own clients. Agency keys start with sf_agency_: on the API Keys page, pick Agency key before you click + Create New Key. Agency keys work only on the three routes below, and account keys do not work on them.
Templates
GET /api/agency/v1/templates
Returns templates (the same list as GET /api/templates) and themes (the themeId values you can send).
Create a site request
POST /api/agency/v1/site-requests
Takes every field of POST /api/provision, plus:
| Field | Type | Description |
|---|---|---|
email | string | Required. Your client's email. It is saved as the business email. We do not send it anything. |
autoApprove | boolean | When true, the build starts now and uses 1 site credit, with the same 403 and paused answers as POST /api/provision. Otherwise the request waits under Agency site requests on the API Keys page, and the credit is used when you click Approve. |
themeId | string | Same as look. |
Check a site request
GET /api/agency/v1/site-requests/{requestId}
Any agency key on your account can read your requests. The answer has requestId, approvalStatus (pending, approved or rejected), status (the build status, or awaiting_approval / rejected before a build exists), siteId, siteUrl, previewUrl, adminUrl, progressPct, warnings and error.
Errors
Error responses have "ok": false and an error string. Validation errors also have a details list with one line per problem.
{
"ok": false,
"error": "Invalid provision request",
"details": ["phone: must contain at least 10 digits"]
}
| Status | error | When |
|---|---|---|
| 400 | Invalid provision request | The body is not valid JSON, or a field is missing or invalid. See details. No credit is used. |
| 401 | Missing or invalid bearer API key. | The key is missing, unknown or revoked. |
| 403 | No site credits remain. | Your account has no credits left. |
| 404 | Site not found. | Checking a build: the ID is unknown, or another key created it. |
| 500 | Provisioning hit a transient storage error. No job was created and no credit was used. Please retry. | Creating a site failed on our side. Send the request again. |
| 503 | New site generation is temporarily in maintenance mode. | Site creation is paused for maintenance. |