---
canonical_url: "https://buildwithwave.com/docs/developers/api-examples"
title: "API examples"
description: "curl examples for Wave's HTTP API: check the connection, read the guide, find a job, catch up on changes, open a job, add a note, build an estimate, record drying readings, work with photos and documents, and download a PDF."
group: "developers"
lane: "how-to"
status: "published"
publishedAt: 2026-10-03
updatedAt: 2026-10-09
sidebarOrder: 90
tags: ["developer", "api", "curl"]
relatedSlugs:
  - "developers/tool-reference"
  - "developers/errors-and-limits"
  - "developers/quick-start"
  - "developers/for-assistants"
sidebarLabel: "API examples"
---

An AI assistant connects to Wave over MCP at `https://wave-mcp.prod.buildwithwave.com/mcp`. Scripts and integrations call the same tools over HTTP at `https://api.go.buildwithwave.com/api/v1`, with the same key and the same `Authorization: Bearer` header. Both are covered in [Where to send the key](/docs/developers/errors-and-limits#where-to-send-the-key).

These examples keep the address and the key in two shell variables. `WAVE_KEY` holds a stand-in key, so swap in your own.

```bash
WAVE_API="https://api.go.buildwithwave.com/api/v1"
WAVE_KEY="wave_live_EXAMPLE_NOT_A_REAL_KEY"
```

## Check the connection

`GET /api/v1/context` returns the person the key works for, the company, its timezone, whether Slack is connected, whether the key is `read` or `write`, and the company's credits.

```bash
curl "$WAVE_API/context" \
  -H "Authorization: Bearer $WAVE_KEY"
```

## Read the guide

`GET /api/v1/guide` returns how Wave names jobs, dates, and amounts, every tool with what it does, and recipes for common asks. It is the same guide an assistant reads with `get_guide`.

```bash
curl "$WAVE_API/guide" \
  -H "Authorization: Bearer $WAVE_KEY"
```

## Find a job

`GET /api/v1/jobs` takes `q` (a customer, street, title, job number, claim number, carrier, adjuster, or phone), `status`, `drying`, `photos` (`with` or `without`), `created_from`, `created_to`, `limit`, and `cursor`. A match includes `id`, `job_number`, `title`, `customer_name`, `address`, `status`, and `photo_count`.

```bash
curl "$WAVE_API/jobs?q=Elm%20Street&limit=5" \
  -H "Authorization: Bearer $WAVE_KEY"
```

```bash
curl "$WAVE_API/jobs?drying=active" \
  -H "Authorization: Bearer $WAVE_KEY"
```

Open one job with `GET /api/v1/jobs/job_id`, by its id or its number, such as `16`. Look up a person with `GET /api/v1/customers?q=Hernandez`. Search Wave's catalog with `GET /api/v1/price-list?q=drywall`.

```bash
curl "$WAVE_API/jobs/16" \
  -H "Authorization: Bearer $WAVE_KEY"
```

## Catch up on changes

`GET /api/v1/changes` lists what changed across the company's jobs, oldest first: notes, status moves, assignments, files added, and schedule and estimate activity. Send the reply's `next_cursor` back as `cursor` next time to get only newer changes. `kind` narrows the list to `notes`, `visits`, `files`, `schedule`, `changes`, or `estimates`.

```bash
curl "$WAVE_API/changes?kind=notes" \
  -H "Authorization: Bearer $WAVE_KEY"
```

## Create a job

`POST /api/v1/jobs` creates the job and fills it in with one request. Only `operation_id` is required. Send whatever you have. This one opens a roof claim.

```bash
curl "$WAVE_API/jobs" \
  -H "Authorization: Bearer $WAVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_id":"job-alder-001","customer_name":"Maria Hernandez","customer_phone":"555-0142","customer_email":"maria@example.com","address_line1":"412 Alder Street","city":"Springfield","region":"OR","postal_code":"97477","loss_type":"storm","carrier":"Northline Mutual","claim_number":"88-1234","policy_number":"HO-55120","assignee":"Luis"}'
```

## Add a note

`POST /api/v1/jobs/job_id/notes` takes `operation_id` and `text`. The note posts as the person who owns the key. It also goes to Slack when an admin has turned on **New note** in Slack notifications, a switch that starts off.

```bash
curl "$WAVE_API/jobs/16/notes" \
  -H "Authorization: Bearer $WAVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_id":"note-alder-001","text":"Adjuster inspected the roof and asked for photos of the south slope."}'
```

## Create an estimate

`POST /api/v1/jobs/job_id/estimates` takes `operation_id`, and can include `scope_summary`, `rooms`, and `line_items`. A catalog line sends `code` with `quantity`, or `units_per_day` for items billed by the day, and Wave sets the price. Your own line sends `description`, `unit`, `quantity`, and `unit_price`. The reply includes `credits`, the credits it used. This one is a kitchen fire.

```bash
curl "$WAVE_API/jobs/21/estimates" \
  -H "Authorization: Bearer $WAVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_id":"est-birch-001","scope_summary":"Kitchen fire, smoke and soot","rooms":[{"name":"Kitchen","length":12,"width":14,"height":8}],"line_items":[{"code":"SEAL-WALL","quantity":416,"room_id":"Kitchen"},{"description":"Electrician invoice, range circuit repair","unit":"EA","quantity":1,"unit_price":450,"room_id":"Kitchen"}]}'
```

`SEAL-WALL` is a stand-in. Search `GET /api/v1/price-list` and send a code from the results. Add more lines later with `POST /api/v1/estimates/estimate_id/line-items`.

## Record drying readings

`POST /api/v1/jobs/job_id/drying-log/readings` takes `operation_id`, `source_of_values` (`dictated_by_user` or `read_from_log`), and a `day`, an `area`, and `readings`. Send `rows` to record several days or areas at once. Wave starts the log and adds the area when it needs to.

```bash
curl "$WAVE_API/jobs/12/drying-log/readings" \
  -H "Authorization: Bearer $WAVE_KEY" \
  -H "Content-Type: application/json" \
  -d '{"operation_id":"dry-elm-day2","source_of_values":"dictated_by_user","day":2,"area":"Kitchen","readings":[{"metric":"temp_f","value":72},{"metric":"rh_pct","value":45},{"metric":"drywall","value":18}]}'
```

## Photos and documents

`GET /api/v1/jobs/job_id/photos` lists a job's photos with their rooms and captions, and `room` narrows it to one room or `Unsorted`. `POST /api/v1/jobs/job_id/photos/rooms` files photos into rooms, and `PATCH /api/v1/jobs/job_id/photos` writes captions. To add photos from a script, send them to `POST /api/v1/jobs/job_id/photos` as a multipart upload: a part named `photo` for each photo, and a part named `meta` with JSON that holds the `operation_id` and, when you want one, the `room`. See [upload_job_photos](/docs/developers/tool-reference#upload_job_photos).

```bash
curl "$WAVE_API/jobs/16/photos?room=Unsorted" \
  -H "Authorization: Bearer $WAVE_KEY"
```

`GET /api/v1/jobs/job_id/documents` lists the files on a job's Files tab, and `GET /api/v1/documents/document_id` reads a PDF from that list, page by page.

```bash
curl "$WAVE_API/jobs/21/documents" \
  -H "Authorization: Bearer $WAVE_KEY"
```

## Download a PDF

`GET /api/v1/jobs/job_id/export-pdf` takes `documents`, what the PDF holds, such as `estimate`, `drying_log`, or `photos`. Repeat it to build one packet. The reply carries `url`, a page whose **Download** button builds the PDF the Export dialog builds. Opening the page changes nothing. Downloading a PDF that holds the estimate marks the estimate final in Wave.

```bash
curl "$WAVE_API/jobs/21/export-pdf?documents=estimate&documents=photos" \
  -H "Authorization: Bearer $WAVE_KEY"
```

`GET /api/v1/jobs/job_id/photos/export` returns a link to a ZIP of the job's photos, or of one room's with `room`.

## Retry a write

Send the same `operation_id` with the same details, and Wave returns the first result without saving twice. A new action uses a new `operation_id`. If that id was already used with different details, Wave says so, and you resend the original request unchanged or start the new one with a new id.

## Related

- [Tool reference](/docs/developers/tool-reference): the tools and their HTTP requests
- [Errors and retries](/docs/developers/errors-and-limits): messages and the next step
- [Quick start](/docs/developers/quick-start): connect an assistant over MCP
- [For assistants](/docs/developers/for-assistants): where an assistant reads first
