# Waveform Apps Developer API

A small public JSON API and machine-readable resources for agents and integrations.

## Overview

The Waveform Apps API is a small public JSON API for reading what we build, what it costs and what we have shipped, and for sending us a message. It exists so AI agents and integrations can act for a user without scraping the site.

- **Base URL:** `https://www.waveformapps.com/api`
- **Specification:** [/openapi.json](https://www.waveformapps.com/openapi.json) (OpenAPI 3.1 with operationIds and typed request and response schemas)
- **Agent guide:** [/llms.txt](https://www.waveformapps.com/llms.txt)
- **Machine-readable documents:** [/pricing.md](https://www.waveformapps.com/pricing.md), [/llms-full.txt](https://www.waveformapps.com/llms-full.txt), [/.well-known/ard.json](https://www.waveformapps.com/.well-known/ard.json) (also at [/.well-known/ai-catalog.json](https://www.waveformapps.com/.well-known/ai-catalog.json)), [/sitemap.xml](https://www.waveformapps.com/sitemap.xml) and [/.well-known/security.txt](https://www.waveformapps.com/.well-known/security.txt)
- **Markdown pages:** every page returns Markdown when requested with `Accept: text/markdown`, or by appending `.md` to the page URL (for example `https://www.waveformapps.com/about.md`).
- **Cross-origin:** every response carries `Access-Control-Allow-Origin: *`, so browser-based callers can read the API from any origin. `OPTIONS` preflights are free and never use up rate limit.
- **HEAD:** GET endpoints answer `HEAD` with the same status and headers and no body, so you can check availability without downloading anything.
- **Caching:** the catalog GETs carry an `ETag` and `Cache-Control: public, max-age=300`. Send the ETag back in `If-None-Match`; a match answers `304` with no body. The machine documents this site serves itself (`/openapi.json`, `/.well-known/ard.json`, `/pricing.md`) revalidate the same way.

## Authentication

None. Every endpoint is public and anonymous. Rate limits apply per client IP address (IPv6: per /64 prefix), and the contact endpoint sends one email per successful call, so treat it as non-idempotent.

## Endpoints

- `GET /api/services` **List the services Waveform Apps offers** (listServices). Returns every service category with a one-line description. Read-only, takes no parameters and changes only when the site is redeployed.
- `HEAD /api/services` **Check the services list without a response body** (headServices). Identical to listServices (RFC 9110 section 9.3.2): same status and headers, no response content. Useful for availability checks and cache warm-ups.
- `GET /api/pricing` **List fixed-price project options** (listPricingOptions). Returns the published project packages with price, timeline and what is included. Every option carries both the display string exactly as shown on the pricing page (`price`) and structured fields: `currency` + `priceValue` give the numeric figure, and `priceIsFrom` marks a starting point rather than a final price. Every project includes 30 days of free maintenance. After that, a care plan is $99 a month. Cancel any month. Read-only and takes no parameters.
- `HEAD /api/pricing` **Check the pricing list without a response body** (headPricing). Identical to listPricingOptions (RFC 9110 section 9.3.2): same status and headers, no response content.
- `GET /api/work` **List the projects the studio has shipped** (listProjects). Returns shipped projects with a one-paragraph summary, the stack behind each where published and a link to the live site — the same catalog as the work page. Read-only and takes no parameters; it changes only when the site is redeployed.
- `HEAD /api/work` **Check the project list without a response body** (headProjects). Identical to listProjects (RFC 9110 section 9.3.2): same status and headers, no response content.
- `GET /api/faq` **List the frequently asked questions and their published answers** (listFaq). Returns the homepage FAQ verbatim: pricing, timelines, maintenance and how to start. Read-only and takes no parameters; it changes only when the site is redeployed. Prefer this over scraping the page for the same answers.
- `HEAD /api/faq` **Check the FAQ list without a response body** (headFaq). Identical to listFaq (RFC 9110 section 9.3.2): same status and headers, no response content.
- `GET /api/process` **List the steps of a Waveform Apps project** (listProcessSteps). Returns the 4-step engagement process — call, design, build, launch and care — with what happens in each. Read-only and takes no parameters; it changes only when the site is redeployed.
- `HEAD /api/process` **Check the process list without a response body** (headProcessSteps). Identical to listProcessSteps (RFC 9110 section 9.3.2): same status and headers, no response content.
- `POST /api/contact` **Send a project enquiry to Waveform Apps** (sendContactMessage). Delivers a message to the Waveform Apps team by email. Use it when a user wants to hire Waveform Apps, ask for a quote, or start a project conversation. Send the user's real name and a reachable email address; the team replies to that address within one business day. Not idempotent: every successful call sends one message, so do not retry a 200.

## Rate limits

10 requests per 60 seconds per client IP address (IPv6: per /64 prefix) across all /api/ endpoints, using the IETF RateLimit header fields draft. Every API response carries the policy; a 429 response also carries the remaining quota and a Retry-After value in seconds.

```
RateLimit-Policy: "api";q=10;w=60

HTTP/1.1 429 Too Many Requests
RateLimit-Policy: "api";q=10;w=60
RateLimit: "api";r=0;t=60
Retry-After: 60
```

## Errors

Errors use RFC 9457 problem details with the content type application/problem+json. Every error has type, title, status, detail, a stable code, and a hint that says how to recover. Validation errors add an errors array of field and message pairs.

```
{
  "type": "https://www.waveformapps.com/api-docs#errors",
  "title": "Bad Request",
  "status": 400,
  "detail": "One or more fields are invalid.",
  "code": "validation_failed",
  "hint": "Fix the fields listed in `errors` and resend.",
  "errors": [
    {
      "field": "email",
      "message": "Valid email is required"
    }
  ]
}
```

- `not_found`: No endpoint at that path (404).
- `method_not_allowed`: Wrong HTTP method; the Allow header lists the supported ones (405).
- `unsupported_media_type`: The POST body was not sent as application/json (415).
- `payload_too_large`: The POST body is over 16 KiB (413).
- `invalid_json`: The POST body could not be parsed as JSON (400).
- `validation_failed`: A field is missing or invalid; errors lists each field (400).
- `rate_limited`: Over the rate limit; wait Retry-After seconds and retry (429).
- `email_unavailable`: Email delivery failed; retry later or email hello@waveformapps.com (503).
- `internal_error`: The server hit an unexpected fault; retry, and report it if it keeps failing (500).

## Examples

```
curl https://www.waveformapps.com/api/services
curl https://www.waveformapps.com/api/pricing
curl https://www.waveformapps.com/api/work
curl https://www.waveformapps.com/api/faq
curl https://www.waveformapps.com/api/process

curl -X POST https://www.waveformapps.com/api/contact \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Ada Lovelace",
    "email": "ada@example.com",
    "message": "We need a booking website for a two-location clinic."
  }'

curl -H "Accept: text/markdown" https://www.waveformapps.com/about
curl https://www.waveformapps.com/about.md
```

---

Canonical: https://www.waveformapps.com/api-docs
Agent guide: https://www.waveformapps.com/llms.txt