DEMO: sample company. No real requests or payments.
Summit Peak Plumbing (Demo) · Developers

Developers

This is a demo. Nothing is sent to a business or charged. Test requests are kept in a private demo sandbox for about 3 days so status links work, then deleted. There is no API key and no account. The business is fictional.

1. Embed the request form

Paste this where the form should appear. It renders the full request flow (request, optional deposit, confirmation with a status link) in an iframe that resizes itself and works on phones.

<div id="atlas-request"><a href="https://trades-request-demo.vercel.app/?src=embed-fallback">Request service</a></div>
<script src="https://trades-request-demo.vercel.app/embed.js" data-business="summit-peak" async></script>

The script replaces the link inside the <div> with the form. If the script is ever blocked, visitors still get a working link. The shorter form still works too: an empty <div id="atlas-request"></div>, or no div at all (then the form appears right where the script tag is).

Or show a button that opens the form in an overlay:

<div id="atlas-request"><a href="https://trades-request-demo.vercel.app/?src=embed-fallback">Request service</a></div>
<script src="https://trades-request-demo.vercel.app/embed.js" data-business="summit-peak" data-button-mode="modal" data-accent="#b4532a" async></script>

See both on a pretend business site: embed demo.

Options

AttributeValuesWhat it does
data-businessbusiness id, e.g. summit-peakWhich business the form is for. Each business gets its own id (the demo business is summit-peak). An unknown id logs a console error naming it.
data-accenthex color, e.g. #b4532aBrand color for buttons. Text color flips to dark on light colors.
data-button-modemodalRender a button that opens the form in an overlay (Esc, the × or a click outside closes it).
data-button-texttextButton label in modal mode. Default "Request service".
data-targetCSS selectorMount element. Default #atlas-request.

When a request is submitted, the mount element fires atlas:request-submitted with event.detail.ref (the reference only, no personal details):

document.addEventListener('atlas:request-submitted', function (e) {
  console.log('Request received:', e.detail.ref);
});

How it behaves

Strict security policies (CSP)

If your site sends a Content-Security-Policy header, add our hosts to two directives (keep your existing values, just append):

script-src https://demo.atlasag.co https://trades-request-demo.vercel.app
frame-src https://demo.atlasag.co https://trades-request-demo.vercel.app

Nothing else is needed. The embed uses no inline <style>, no style="" attributes and no eval, so it works without 'unsafe-inline' or 'unsafe-eval'. If your policy uses default-src or child-src instead of frame-src, add the hosts there.

If the policy isn't updated, the embed fails gracefully:

Test pages served with real CSP headers: frames blocked · script blocked · strict policy that allows our hosts.

2. Request API

POST https://trades-request-demo.vercel.app/api/service-request with a JSON body. GET the same URL for a short description. CORS is open. The spec is at openapi.json (OpenAPI 3.1), and a plain summary for AI assistants is at llms.txt.

curl -X POST https://trades-request-demo.vercel.app/api/service-request \
  -H 'Content-Type: application/json' \
  -d '{"name":"Jordan Example","phone":"(555) 555-0123","address":"123 Sample St, Sample City, CO",
       "service":"water_heater","urgency":"today","description":"No hot water since last night."}'

Required: name, phone, address, service, urgency, description. Optional: email, zip, preferred_time. A success returns 201 with request_id, status_url, demo: true and deposit_required: false. Field problems return 400 with an errors object. Requests are rate-limited per IP. Demo API requests go to a shared demo sandbox and are deleted after about 3 days.

Deposits are never taken through the API. If a job needs one, the business texts the customer a separate link, and the customer approves it themselves.