API ReferencePATCH /v1/sites/:id/research-draft

PATCH /v1/sites/:id/research-draft

Save partial edits to a site’s research payload without advancing into generation. Use this to checkpoint operator edits between separate review sessions — every field round-trips, so the next GET /v1/sites/:id/research reflects what was saved. The site stays in research_review until you POST to /v1/sites/:id/approve-research.

Cost: Free.

Request

curl -X PATCH https://api.warpweb.ai/v1/sites/8f3c2a1b/research-draft \
  -H "Authorization: Bearer wwk_<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "services": [
      { "name": "Drain cleaning", "description": "Hydro-jetting and cabling." }
    ],
    "brandColors": { "primary": "#0F4C81" }
  }'

An empty {} is valid — it bumps updated_at and returns 200, useful as a write-side keepalive from a UI.

Body

The same field-level edits as POST /v1/sites/:id/approve-research, minus the two side-effecting fields:

FieldTypeDescription
servicesarrayReplace the services list. { name, description?, price? }.
testimonialsarrayReplace the testimonials list. { quote, author?, rating?, source? }.
faqsarrayReplace the FAQ list. { question, answer }.
hoursobjectWeekday → hour string. Replaces wholesale.
brandColorsobject{ primary?, secondary?, accent?, personality? }. Omitted slots preserve existing values.
existingSiteUrlstringUpdate the recorded existing-site URL.
ownerPromptstringVoice / tone direction.
businessDescriptionstringOne-sentence pitch.
designStylestringOverride the design style. Unknown values are silently ignored.
allowStockPhotosbooleanToggle the stock-photo (Pexels) layer. Default false (set at create time). Set true for generic stock fallback in slots that uploads + Google Places didn’t cover; false keeps those slots as Lucide-icon-over-brand-color sections.
contentPlanobjectPartial overrides to the AI-generated content plan. Shallow-merged.

Not accepted here: excludeImages and uploadedPhotos. Both perform filesystem side effects (deleting from staging, downloading remote URLs) that don’t belong in a non-advancing checkpoint. Pass them on approve-research when you’re ready to build.

Response

{
  "success": true,
  "saved_at": "2026-05-23T18:42:17.314Z"
}

saved_at is the new updated_at on the site row — useful as an idempotency key when a UI wants to dedupe overlapping saves.

Errors

StatusBodyCause
400{ "error": "Site is not in research review phase" }Drafts are only writable while the site is paused in research_review. Once generation starts, edits must go through POST /v1/sites/:id/revisions instead.
400{ "error": "No research data found" }The site exists but research_data is empty. Should not happen for sites that reached research_review.
404{ "error": "Site not found" }No site with that ID belongs to your account.