Ambiance Artist API Documentation

For developers and AI agents

Ambiance Artist API Documentation

One public JSON API for the catalog, contact messages and orders. No API key required.

Overview

Ambiance Artist designs, delivers and installs luxury seasonal decorations in Park City, Heber City, Kamas and Salt Lake City, Utah. The endpoints below are the same ones the website uses. Base URL: https://ambianceartist.com.

  • OpenAPI 3.1 specification: /openapi.json
  • Briefing for AI agents, including when to use this site: /llms.txt
  • Every page offers a Markdown version: send Accept: text/markdown.

Authentication

None. The endpoints documented here are public. All other routes under /api/ are administrative; they require a signed session cookie and answer 401 with a JSON error to everyone else. Orders are always priced on the server from the catalog: send package ids, quantities and option labels, never prices.

Endpoints

List decor packages and add-ons

GET /api/packages · operationId listPackages

Returns every package that is currently published and inside its availability window, including add-ons (`is_addon: true`). Sold-out packages stay in the list with `availability` set accordingly and cannot be ordered. Prices are in US dollars.

curl -sS "https://ambianceartist.com/api/packages"

Search packages by keyword

GET /api/packages/search · operationId searchPackages

Case-insensitive keyword search over the title, card description and description of active packages. Returns at most 10 results.

curl -sS "https://ambianceartist.com/api/packages/search?q=pumpkin"

Search packages by keyword (alias)

GET /api/search · operationId searchCatalog

Alias of `searchPackages`. Also accepts `query` as the parameter name. Returns at most 10 results.

curl -sS "https://ambianceartist.com/api/search?q=pumpkin"

List delivery and service areas

GET /api/areas · operationId listServiceAreas

The areas Ambiance Artist delivers and installs in, with the delivery fee for each. Use `id` as `delivery_area_id` when placing an order.

curl -sS "https://ambianceartist.com/api/areas"

List order form options

GET /api/options · operationId listFormOptions

The choices offered when ordering: installation weeks, removal options, styling options and custom questions, each with a price adjustment. Option `label` values (and choice labels) are what an order request refers to.

curl -sS "https://ambianceartist.com/api/options"

List color palettes

GET /api/color-palettes · operationId listColorPalettes

Color palettes a customer can choose for a package. A palette with `scope: "global"` applies to every package; `selected_packages` palettes list their `package_ids`.

curl -sS "https://ambianceartist.com/api/color-palettes"

List frequently asked questions

GET /api/faq · operationId listFaqs

Published FAQ entries, ordered by `display_order`.

curl -sS "https://ambianceartist.com/api/faq"

List gallery images

GET /api/portfolio · operationId listPortfolio

Photos of completed installations with a title and category.

curl -sS "https://ambianceartist.com/api/portfolio"

Read editable site copy

GET /api/site-content · operationId getSiteContent

The marketing copy shown on the website. With `page`, returns that page's sections as an object keyed by section key; without it, returns every section as a flat array.

curl -sS "https://ambianceartist.com/api/site-content"

Get recommended add-ons for a cart

POST /api/recommendations · operationId getRecommendedAddons

Given the package ids in a cart, returns the add-ons the business recommends alongside them. Read-only: nothing is written. POST is used only because the cart is the input.

curl -sS -X POST "https://ambianceartist.com/api/recommendations" \
  -H "Content-Type: application/json" \
  -d '{"ids":["b5204a91-eacc-41e5-9174-ebf122e5cffa"]}'

Send a message to the business

POST /api/contact · operationId submitContactMessage

Sends an inquiry (custom design request, booking question, etc.) to the owners, who reply by email or phone. Limited to 5 requests per 1 hour per client IP. The server may require a bot-verification token (`turnstileToken`); an automated client that cannot supply one should send the person to https://ambianceartist.com/contact instead.

curl -sS -X POST "https://ambianceartist.com/api/contact" \
  -H "Content-Type: application/json" \
  -d '{}'

Place an order

POST /api/orders · operationId createOrder

Creates an order (payment status `Unpaid`, order status `New`) from package ids, quantities and option labels. The server prices the order itself from the catalog, delivery area and options; any price in the request is ignored, and `expected_total` is only compared with the computed total as a safety check (409 `PRICE_CHANGED` if they differ). Limited to 8 requests per 1 hour per client IP.

curl -sS -X POST "https://ambianceartist.com/api/orders" \
  -H "Content-Type: application/json" \
  -d '{}'

Start a card payment (Stripe embedded checkout)

POST /api/checkout · operationId createCheckoutSession

Prices the cart server-side and creates a Stripe Checkout Session. The caller completes payment in the browser with the returned `clientSecret`; an agent cannot finish this step on its own and should hand the person the site URL instead. `terms_accepted` must be `true`. Limited to 8 requests per 1 hour per client IP.

curl -sS -X POST "https://ambianceartist.com/api/checkout" \
  -H "Content-Type: application/json" \
  -d '{}'

Errors

Failures are JSON, never an HTML page. Branch on code; show error to a person; follow hint.

HTTP/1.1 400 Bad Request
Content-Type: application/json

{
  "error": "email: Invalid email address",
  "code": "validation_failed",
  "hint": "Fix the named field and resubmit; see the request schema in /openapi.json.",
  "docs": "https://ambianceartist.com/docs#errors",
  "field": "email"
}
StatuscodeMeaning
400invalid_json, validation_failed, pricing_errorThe body is not valid JSON, a field failed validation, or an id/label is not in the catalog.
401unauthorizedNot a public endpoint, or an admin session is required.
404not_foundNo endpoint at that path.
409price_changedThe computed total differs from expected_total; resubmit with the returned total.
429rate_limitedToo many requests. Wait Retry-After seconds.
500ERR-XXXXXXXXServer failure. The code is a reference to quote to support.

Rate limits

The read-only catalog endpoints have no application-level limit. Endpoints that write data are limited per client IP address:

  • 5 requests per 1 hour — contact_message
  • 15 requests per 1 hour — contact_upload
  • 5 requests per 1 hour — waitlist_signup
  • 5 requests per 1 hour — invoice_send
  • 8 requests per 1 hour — order_submission
  • 8 requests per 1 hour — checkout_attempt
  • 5 requests per 1 hour — review_submission
  • 15 requests per 1 hour — review_upload
  • 30 requests per 1 hour — crm_reply

A rejected request returns 429 with Retry-After (seconds) and the IETF RateLimit-Policy, RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset headers.

HTTP/1.1 429 Too Many Requests
Retry-After: 1800
RateLimit-Policy: 5;w=3600
RateLimit-Limit: 5
RateLimit-Remaining: 0
RateLimit-Reset: 1800

Markdown pages

The home, about, contact, how-it-works, collection, package, privacy and terms pages can be read as Markdown at their normal URL:

curl -sS -H "Accept: text/markdown" https://ambianceartist.com/

The response has Content-Type: text/markdown and Vary: Accept; requests that prefer HTML still get HTML. The same content is available at /markdown/<path> (for example /markdown/about) for clients that cannot set headers.

Support

Questions about the API or the business: contact page.