Build with Clarity Measure
Use the API from your server, or connect an MCP client. Both are on Pro and Pro Plus, create the same saved measurement jobs, and charge each search at your plan’s price.
Authentication
Create an API key in your workspace. Send it as a Bearer token. Store it in a server environment variable and never put it in browser code or a public form.
Authorization: Bearer YOUR_CLARITY_MEASURE_KEY
Every request runs against https://app.claritymeasure.com. A key carries the scopes measurements:read and measurements:write; a full submit-and-poll integration needs both. With lead forms on, a key can also carry forms:read, forms:write, leads:read, leads:write, services:read, services:write and account:read; tick only what the integration needs. Keys belong to one account and cannot read another.
Start a measurement
Submit a complete street address and a unique UUID in the Idempotency-Key header. A successful request returns HTTP 202 and a saved job identifier. Reuse the same idempotency key when retrying the same request.
curl -X POST https://app.claritymeasure.com/api/v1/measurements \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_REQUEST_UUID" \
-d '{"address":"YOUR_FULL_PROPERTY_ADDRESS","requested_zones":"both","curb_strip":true,"measurement_mode":"quick"}'
The address is 8 to 180 characters and must contain its street number. requested_services is optional and accepts turf, driveway, sidewalk and paving (parking and patios), measured in the same fast pass at the same price per search; ["turf"] is the default. Send any non-empty mix: ["turf","driveway","sidewalk"] measures the lawn, the driveway and the walks together, and the lawn is optional, so ["driveway"] measures the driveway alone. An empty list is refused with 422. driveway measures driveways to the curb, sidewalk measures private walkways and the public sidewalk along the street, and paving measures other paving and patios, including parking lots. A public sidewalk is measured and published on its own and is never counted as the customer’s ground, and trees and shrubs are not measured yet. The response carries measurement_id, status, idempotency_key, poll_url and result_url, and repeats poll_url in the Location header.
Three optional settings shape the measurement. requested_zones is both, front or rear, and decides which part of the one property is measured: a zone outside the request is not counted, and normally not traced; any outline still returned for it is listed separately as not requested, so rear measures the back lawn and front measures the front lawn and the strip to the curb. curb_strip defaults to true and traces and counts the frontage strip between the sidewalk and the near curb along with the front; a rear request never reaches it. measurement_mode is quick, the Fast single pass; auto, which measures in that same pass and may take a closer look on a large or complex lot (a review round, or a flag for you to check, depending on the tracer this server runs), at the same price; when the trace shows part of the lawn was hard to see, the result says so, and it recommends Thorough for heavy canopy or a very complex lawn; or thorough, the careful tier for tighter outlines to check before you quote, offered on earlier credit plans only (Pro and Pro Plus refuse it with 400 mode_unavailable). On Pro and Pro Plus every mode is one search at your plan’s price. On an earlier credit plan Fast costs one credit, Auto reserves two credits and settles at one when no review ran, and Thorough costs three credits. get_measurement_options says exactly what each mode runs on this server today and how long it takes. Omit any of them to take the current default.
curl https://app.claritymeasure.com/api/v1/measurement-options -H "Authorization: Bearer $CLARITY_MEASURE_API_KEY"
That read-scope endpoint takes no parameters and starts no work. It returns modes with what each costs on your plan and the current default, the zones choices, the curb_strip switch, the services measured today and short notes. Read the values from it instead of hard-coding them.
Read the result
Poll the job endpoint using the identifier returned by your request. While processing, the status stays queued or running. A completed response includes the saved result. A failed job is never charged.
curl https://app.claritymeasure.com/api/v1/measurements/MEASUREMENT_ID \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY"
curl https://app.claritymeasure.com/api/v1/measurements \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY"
The list accepts limit (1–100, default 20), offset (0–10000, default 0) and search (up to 100 characters), and returns measurements, limit, offset and next_offset. A single measurement returns without source imagery and inline_images_included: false; add ?include_images=true to ask for the original images. Add ?format=geojson to get the traced outlines as GeoJSON instead (application/geo+json): a FeatureCollection in WGS84 longitude and latitude with one feature per measured surface, each with kind, zone, area_sqft (the saved measured area), qualifier and counted. kind is one of lawn, driveway, private_walk (the customer’s own walks), sidewalk (the public sidewalk), parking, covered_paving, patio, landscape_bed, pool, bare_ground, roof_plan, unresolved (ground that could not be classified) and canopy_over_turf (tree canopy over the lawn), limited to what was asked for. counted is true only for the lawn and the customer’s own surfaces that make up the measured totals. It is false for the public sidewalk, unresolved ground, canopy over the lawn (it sits inside the lawn) and context layers such as the roof plan, so add up only the counted features. It is the outline as first measured, not a later correction. Coordinates are rounded to 7 decimal places and every ring is closed and wound by the RFC 7946 right-hand rule. A measurement that has not finished, failed, has no saved outline, or whose saved outline is damaged answers 409 with detail.code no_outline, never an empty collection. Without format the JSON response is unchanged.
The measurement summary’s area_sqft is the lawn alone. When driveway, sidewalk or paving was asked for, a single measurement’s summary also carries surface_totals (square feet per surface, such as driveway, private_walk, parking, patio or sidewalk; null when nothing was measured, never zero), surface_total_labels (a plain label for each) and surface_totals_not_counted (["sidewalk"]: the public sidewalk, measured for reference and never part of the customer’s total). The same fields sit at the top of result. A lawn-only measurement has none of them, and the list returns summaries without them.
curl https://app.claritymeasure.com/api/v1/measurements/MEASUREMENT_ID/image \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY" -o measurement.png
Once a measurement has finished, its read carries image_url: a PNG of the saved overhead image with the measured outlines drawn (the corrected outline when someone corrected it), the total square feet and the imagery source and date. It costs nothing and never measures again. max_side sets the longest side (200–1600 pixels) and view=original draws the outline as first measured. The county lot line is drawn as a thin dashed line and labelled “Lot line (county record)”; show_parcel=false leaves it off. It is display only and never changes a total or a charge. The response is cacheable for five minutes and carries an ETag.
Handle results carefully
- Check status before reading the result. A successful request does not mean the measurement has finished.
- Missing quantities and costs remain null. Do not replace unknown values with zero.
- Geometry uses the calibrated overhead image. Preserve image dimensions, source attribution and capture-date notes.
- Inspect partial results, review notes and failure details before using an area in a quote.
- HTTP 401 means the key is missing or invalid. HTTP 402 means the search could not be paid for. HTTP 403 means access is not allowed, or the account is on Free. HTTP 503 means a required service is unavailable.
- For support, include your measurement ID. Keep your API key out of support messages.
Errors
Errors answer with a JSON detail and a fixed message, so a provider fault never leaks through the API. Read the status before retrying. A plan refusal makes detail an object with code, reason, a plain message and one link, and repeats reason at the top level:
{
"detail": {
"code": "no_funds",
"reason": "no_funds",
"message": "Add funds to keep measuring.",
"add_funds_url": "https://app.claritymeasure.com/app#settings/billing"
},
"reason": "no_funds"
}
| Status | What it means |
|---|---|
400 | Invalid request. mode_unavailable means that mode is not sold on your plan: Pro and Pro Plus measure with quick and auto. |
401 | Use a valid, active Bearer API key. The response carries WWW-Authenticate: Bearer. |
402 | The search could not be paid for. free_limit: this month’s free searches are used, and resets_at says when they return. no_funds: add funds or turn on auto top-up (add_funds_url). own_key_required: the Pro Plus welcome searches are used, so add your OpenAI key (settings_url). On an earlier credit plan it means not enough credits. |
403 | This request is not permitted. plan_required means the account is on Free: the API and MCP are on Pro and Pro Plus (upgrade_url). Otherwise check the key scope, and the Origin header if your client sends one. |
404 | Not found. The measurement belongs to another account, or integrations are disabled on that deployment. |
405 | This transport supports POST requests only. Returned for GET and DELETE on /mcp, with Allow: POST. |
406 | Accept must include application/json and text/event-stream. |
409 | This request conflicts with an existing measurement. The body also carries reason: request_conflict (the address is already being measured) or idempotency_conflict (the UUID was used with a different body). Do not loop with new UUIDs. |
413 | Request body is too large. |
415 | Send UTF-8 application/json without content encoding. |
422 | Invalid measurement parameters. Correct the UUID, the body fields or an unsupported value. An empty requested_services list is refused here too. |
429 | Request limit reached. Retry in 60 seconds. |
503 | The measurement service is temporarily unavailable. When the body carries a measurement_id, poll it instead of resubmitting. |
A dropped connection after a submission is not a cancelled job. Poll the measurement if you have its ID, otherwise resend the same UUID and the identical body.
Rate limits
Limits apply to each account and each API key over a rolling minute, shared by REST and MCP. Creating another key does not increase the account allowance.
| Limit | Value |
|---|---|
| Authenticated requests | 60 per account and per key per minute |
| Measurement submissions or replays | 6 per account and per key per minute, inside the 60 |
| Writes to forms, services and packages, and to leads | 30 per account and per key per minute each, inside the 60 |
| Pictures | 20 per account and per key per minute, inside the 60 |
| JSON request body | 16 KiB, UTF-8 application/json, no compression, no duplicate keys (128 KiB for creating or changing a form) |
Retry hint on 429 | Retry-After: 60 |
Customer webhook subscriptions are not currently supported. Poll the saved job to track completion.
Forms, leads and account
With lead forms on, everything the workspace does with forms, leads, services and packages is on the API too, under the same rules as the screens: /api/v1/forms (list, create, read, change, switch off, and /api/v1/forms/stats), /api/v1/service-areas, /api/v1/services and /api/v1/service-packages (with /order to reorder), /api/v1/leads (read, archive or mark read, add notes, and /measure to measure one now, which is one search) and /api/v1/account for your plan, searches or credits, and usage. A new form comes back with its public link and the embed snippets ready to paste into a website.
curl -X POST https://app.claritymeasure.com/api/v1/forms \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_REQUEST_UUID" \
-d '{"name":"Spring promo","heading":"Get your lawn quote"}'
curl https://app.claritymeasure.com/api/v1/account \
-H "Authorization: Bearer $CLARITY_MEASURE_API_KEY"
Creates accept an optional Idempotency-Key: a retry with the same key returns the first result instead of a duplicate. A refusal the workspace would show comes back with its own sentence and a stable code, such as form_limit, no_funds or no_credits. Every route and field is in the developer guide.
MCP
Use a client that supports remote Streamable HTTP and an Authorization header. The endpoint exposes measure_property, get_measurement_options, get_playbook, get_measurement, get_measurement_image and list_measurements, and with lead forms on the same forms, services, packages, service areas, leads and account tools as the REST routes above. Each tool is limited to the workspace that owns your key, and tools/list shows only the ones your key’s scopes allow.
MCP is on Pro and Pro Plus, and each measure_property call is one search at your plan’s price. On a Free account every MCP request, initialize included, gets HTTP 403 with JSON-RPC error -32000 and plan_required in its data. A tool call that cannot pay for its search returns isError with the same code, reason and link as the REST error.
Call get_measurement_options before the first measurement. It takes no arguments, starts no work, and reports the modes with what each costs on your plan, the front and back zone choices, the strip-to-the-curb switch and the services (turf plus driveway, sidewalk and paving), so an agent offers what this server actually has. measure_property takes the same requested_services as REST, and get_measurement returns the same surface_totals in its summary.
Endpoint: https://app.claritymeasure.com/mcp
Transport: Streamable HTTP
Authorization: Bearer YOUR_CLARITY_MEASURE_KEY
For an API-key connection, enter the key in the client’s protected configuration. For an OAuth-capable client such as Claude’s custom connectors, use https://app.claritymeasure.com/mcp, sign in and approve the permissions shown. The server publishes OAuth discovery metadata; your client must support the advertised flow. A connection keeps the permissions it was approved with; to add the newer ones, remove the connector and add it again.
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer YOUR_CLARITY_MEASURE_KEY
MCP-Protocol-Version: 2025-11-25
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "measure_property",
"arguments": {
"address": "YOUR_FULL_PROPERTY_ADDRESS",
"idempotency_key": "YOUR_REQUEST_UUID",
"requested_services": ["turf", "driveway", "sidewalk"],
"requested_zones": "both",
"curb_strip": true,
"measurement_mode": "quick"
}
}
}
Initialize the MCP session through your client before calling a tool. Your client manages the protocol handshake. Supported protocol versions are 2025-11-25, 2025-06-18 and 2025-03-26; an absent version header defaults to March 2025.
The endpoint is stateless. It creates no session ID, opens no SSE stream and accepts no JSON-RPC batches. A finished measurement’s picture comes back as an image content block a chat can show (turn it off with include_image: false), never the original source imagery, and geometry is opt-in through include_geometry and size-bounded. Full detail lives behind the REST result.
Give an agent a clear spending boundary. Require the account holder’s intent before calling measure_property or measure_lead, or any tool whose description starts with Destructive, and reuse the request UUID for a retry instead of starting a new billable attempt. The full reference lives in the MCP documentation, and keys are created on the API keys page.