1<!DOCTYPE html><html lang="en" class="font-sans __variable_geist_1th67zq"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/assets/index-DxmyaP73.css" data-rsc-css-href="/assets/index-DxmyaP73.css" data-precedence="vite-rsc/importer-resources"/><link rel="stylesheet" href="/assets/founder-contact-D5iYgzFq.css" data-precedence="vite-rsc/client-reference"/><link rel="stylesheet" href="/assets/marketing-header-BjOJSlOW.css" data-precedence="vite-rsc/client-reference"/><link rel="stylesheet" href="/assets/api-playground-CBS1I3bZ.css" data-precedence="vite-rsc/client-reference"/><link rel="modulepreload" href="/assets/layout-segment-context-JnofITsR.js" crossorigin=""/><link rel="modulepreload" href="/assets/rolldown-runtime-DWdDZTNf.js" crossorigin=""/><link rel="modulepreload" href="/assets/index-CuK3ZBoT.js" crossorigin=""/><link rel="modulepreload" href="/assets/framework-Dykh5YIU.js" crossorigin=""/><link rel="modulepreload" href="/assets/public-session-recorder--xQxZHnF.js" crossorigin=""/><link rel="modulepreload" href="/assets/support-view-banner-CTcUDaCp.js" crossorigin=""/><link rel="modulepreload" href="/assets/founder-contact-pPWEOVsK.js" crossorigin=""/><link rel="modulepreload" href="/assets/marketing-header-t07t9qqS.js" crossorigin=""/><link rel="modulepreload" href="/assets/link-ienGDWMw.js" crossorigin=""/><link rel="modulepreload" href="/assets/api-playground-BYrAn6YY.js" crossorigin=""/><link rel="modulepreload" href="/assets/homepage-examples-BGqPCWRy.js" crossorigin=""/><link rel="modulepreload" href="/assets/public-api-contract-Dau-AOBP.js" crossorigin=""/><title>OpenLawn API Documentation â Lawn Measurement API</title><meta name="description" content="Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks."/><meta name="application-name" content="OpenLawn"/><meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1"/><meta property="og:title" content="OpenLawn API Documentation â Lawn Measurement API"/><meta property="og:description" content="Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks."/><meta property="og:url" content="https://openlawn.ai/docs"/><meta property="og:site_name" content="OpenLawn"/><meta property="og:type" content="website"/><meta property="og:locale" content="en_US"/><meta property="og:image" content="https://openlawn.ai/og.png?v=2026-09-homepage-neighborhood"/><meta property="og:image:width" content="1200"/><meta property="og:image:height" content="630"/><meta property="og:image:type" content="image/png"/><meta property="og:image:alt" content="OpenLawn â Measure the property. Prepare the quote. An illustrative neighborhood aerial with green lawn outlines, matching the homepage. AI lawn measurement for lawn care and pest control. Powered by OpenAI GPT-6 Astra. Works with Codex, Claude Code, and Gemini CLI."/><meta name="twitter:card" content="summary_large_image"/><meta name="twitter:title" content="OpenLawn API Documentation â Lawn Measurement API"/><meta name="twitter:description" content="Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks."/><meta name="twitter:image" content="https://openlawn.ai/og.png?v=2026-09-homepage-neighborhood"/><meta name="twitter:image:alt" content="OpenLawn â Measure the property. Prepare the quote. An illustrative neighborhood aerial with green lawn outlines, matching the homepage. AI lawn measurement for lawn care and pest control. Powered by OpenAI GPT-6 Astra. Works with Codex, Claude Code, and Gemini CLI."/><link rel="shortcut icon" href="https://openlawn.ai/openlawn-mark.png"/><link rel="icon" href="https://openlawn.ai/openlawn-mark.png"/><link rel="apple-touch-icon" href="https://openlawn.ai/icons/apple-touch-icon.png"/><link rel="manifest" href="https://openlawn.ai/manifest.webmanifest"/><link rel="canonical" href="https://openlawn.ai/docs"/><link rel="alternate" type="text/markdown" href="https://openlawn.ai/docs.md"/><meta name="mobile-web-app-capable" content="yes"/><meta name="apple-mobile-web-app-title" content="OpenLawn"/><meta name="apple-mobile-web-app-status-bar-style" content="default"/><meta name="theme-color" content="#ffffff"/>
1<script>self.__VINEXT_RSC_PARAMS__={}</script>
1<script>self.__VINEXT_RSC_NAV__={"pathname":"/docs","searchParams":[]}</script>
1<link rel="modulepreload" href="/assets/index-CuK3ZBoT.js" /> 2<link rel="preload" href="/assets/_vinext_fonts/geist-8ac0455e797f/geist-ff2310f5.woff2" as="font" type="font/woff2" crossorigin /> 3<link rel="preload" href="/assets/_vinext_fonts/geist-8ac0455e797f/geist-875ccdd4.woff2" as="font" type="font/woff2" crossorigin /> 4<link rel="preload" href="/assets/_vinext_fonts/geist-8ac0455e797f/geist-52306abf.woff2" as="font" type="font/woff2" crossorigin /> 5<link rel="preload" href="/assets/_vinext_fonts/geist-8ac0455e797f/geist-001175b1.woff2" as="font" type="font/woff2" crossorigin /> 6<link rel="preload" href="/assets/_vinext_fonts/geist-8ac0455e797f/geist-98bbbccb.woff2" as="font" type="font/woff2" crossorigin /> 7<style data-vinext-fonts>/* cyrillic-ext */ 8@font-face { 9 font-family: 'Geist'; 10 font-style: normal; 11 font-weight: 100 900; 12 font-display: swap; 13 src: url(/assets/_vinext_fonts/geist-8ac0455e797f/geist-ff2310f5.woff2) format('woff2'); 14 unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F; 15} 16/* cyrillic */ 17@font-face { 18 font-family: 'Geist'; 19 font-style: normal; 20 font-weight: 100 900; 21 font-display: swap; 22 src: url(/assets/_vinext_fonts/geist-8ac0455e797f/geist-875ccdd4.woff2) format('woff2'); 23 unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; 24} 25/* vietnamese */ 26@font-face { 27 font-family: 'Geist'; 28 font-style: normal; 29 font-weight: 100 900; 30 font-display: swap; 31 src: url(/assets/_vinext_fonts/geist-8ac0455e797f/geist-52306abf.woff2) format('woff2'); 32 unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB; 33} 34/* latin-ext */ 35@font-face { 36 font-family: 'Geist'; 37 font-style: normal; 38 font-weight: 100 900; 39 font-display: swap; 40 src: url(/assets/_vinext_fonts/geist-8ac0455e797f/geist-001175b1.woff2) format('woff2'); 41 unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF; 42} 43/* latin */ 44@font-face { 45 font-family: 'Geist'; 46 font-style: normal; 47 font-weight: 100 900; 48 font-display: swap; 49 src: url(/assets/_vinext_fonts/geist-8ac0455e797f/geist-98bbbccb.woff2) format('woff2'); 50 unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD; 51} 52 53.__font_geist_1th67zq { font-family: 'Geist', sans-serif; } 54 55.__variable_geist_1th67zq { --font-sans: 'Geist', sans-serif; } 56</style> 57</head><body><main class="_page_wcsq3_1" id="top">
57<script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://openlawn.ai/#organization","name":"OpenLawn","url":"https://openlawn.ai","logo":"https://openlawn.ai/openlawn-mark.png"},{"@type":"TechArticle","@id":"https://openlawn.ai/docs#reference","url":"https://openlawn.ai/docs","headline":"OpenLawn API documentation","description":"Public REST API documentation for asynchronous lawn measurements, normalized polygon results, and signed webhooks.","inLanguage":"en","isAccessibleForFree":true,"publisher":{"@id":"https://openlawn.ai/#organization"},"about":{"@id":"https://api.openlawn.ai/#api"},"hasPart":[{"@type":"TechArticle","name":"Agent API quickstart","url":"https://openlawn.ai/docs/agent-quickstart.md"}]},{"@type":"WebAPI","@id":"https://api.openlawn.ai/#api","name":"OpenLawn lawn measurement API","url":"https://api.openlawn.ai/v1","description":"Workspace-scoped U.S. and Canadian lawn measurement jobs, saved estimates, property history, and signed webhooks. API operations require a key and completed measurements consume credits.","documentation":"https://openlawn.ai/docs","provider":{"@id":"https://openlawn.ai/#organization"}}]}</script>
57<header class="_header_mel4u_1"><div class="_inner_mel4u_2"><a href="/" class="_brand_mel4u_3"><span class="brand-logo" aria-hidden="true"></span>OpenLawn</a><nav id="marketing-navigation" aria-label="Main navigation" class="_navigation_mel4u_5 "><a href="/#how-it-works">How it works</a><a href="/#pricing">Pricing</a><a href="/compare">Compare</a><a href="/developers">For agents</a><a href="/docs">API docs</a><a href="/auth/sign-in?next=%2Fagent" class="_mobileSignIn_mel4u_11">Sign in</a></nav><div class="_actions_mel4u_5"><a href="/auth/sign-in?next=%2Fagent" class="_signIn_mel4u_6">Sign in</a><a href="/auth/sign-up?next=%2Fagent" class="_signup_mel4u_8">Get started free <span aria-hidden="true">â</span></a><button type="button" class="_toggle_mel4u_10" aria-label="Open menu" aria-expanded="false" aria-controls="marketing-navigation"><span aria-hidden="true">â°</span></button></div></div></header><header class="_hero_wcsq3_1"><span>OPENLAWN / DEVELOPERS</span><h1>Lawn measurements.<br/><em>Built into your workflow.</em></h1><p>Explore the API, test a sample residential measurement, then connect your own account when youâre ready.</p><div><a href="/settings/api">Create an API key â</a><a href="/openapi.json">OpenAPI specification â</a><a href="#guides">Guides & quickstart â</a></div><code>https://api.openlawn.ai/v1</code></header><section class="_portal_17uwm_1" id="playground" aria-label="Interactive API playground"><div class="_toolbar_17uwm_1"><div><span class="_eyebrow_17uwm_1">INTERACTIVE API CONSOLE</span><h2>Try it. See the response.</h2></div><div class="_controls_17uwm_1"><div class="_switcher_17uwm_1" role="group" aria-label="API environment"><button type="button" aria-pressed="true">Demo</button><button type="button" aria-pressed="false">Live API</button></div><button type="button" class="_reset_17uwm_1">Reset console</button></div></div><p class="_notice_17uwm_1" role="status">Demo environment · Sample responses only. No key, network requests, or credits. Not a hosted sandbox.</p><div class="_walkthrough_17uwm_1"><div class="_exampleMap_17uwm_1"><img src="/measurement-examples/residential-1.jpg" alt="Anonymized residential lawn measurement example" width="1000" height="1000" loading="lazy"/><span>Sample imagery · not a live measurement</span></div><div class="_demoFlow_17uwm_1"><span class="_eyebrow_17uwm_1">ONE RESIDENTIAL EXAMPLE</span><h3>From queued job to mapped lawn.</h3><p>Walk through the response shapes with an anonymized example. Any address entered in the demo returns sample data, not a measurement of that address. Coordinates and timing are placeholders.</p><ol><li class=""><span>1</span>Submit address</li><li class=""><span>2</span>Poll: running</li><li class=""><span>3</span>Poll: completed</li><li class=""><span>4</span>Read measurement</li></ol><button type="button" class="_primary_17uwm_1" disabled="">Submit sample address â</button></div></div><div class="_referenceHeading_17uwm_1"><h3>Endpoint explorer</h3><p>Use âTest Requestâ on any endpoint. All responses stay in this browser.</p><a href="#guides">Read the integration guides â</a></div><div class="_loading_17uwm_1" role="status">Loading the interactive referenceâ¦</div></section><details class="_guideWrapper_wcsq3_2" id="guides"><summary>Integration guides & operational details</summary><div class="_layout_wcsq3_1"><nav aria-label="Documentation sections"><a href="#agents">For AI agents</a><a href="#quickstart">Quickstart</a><a href="#authentication">Authentication</a><a href="#jobs">Jobs & credits</a><a href="#endpoints">Endpoints</a><a href="#results">Results & pagination</a><a href="#webhooks">Webhooks</a><a href="#errors">Errors & limits</a><a href="/docs.md">Markdown version â</a></nav><div class="_content_wcsq3_1"><section id="agents"><span>FOR DEVELOPERS & AI AGENTS</span><h2>Public docs. A direct path to the API.</h2><p>No login is needed to read or fetch this documentation. For a server-side agent or CRM connection, start with the <a href="/docs/agent-quickstart.md">agent API quickstart</a>, then load the <a href="/openapi.json">OpenAPI 3.1 contract</a>. Prefer plain text? Use the <a href="/docs.md">Markdown reference</a> or <a href="/docs/llms.txt">API documentation index</a>.</p><p>Keep API keys in your backend secret manager, not in prompts. Submit each intended measurement once with a stable idempotency key, wait for its terminal status, then retrieve the estimated square feet and polygons. Reading existing results does not use a measurement credit.</p><p>Want an agent to operate the website instead? Use the <a href="/developers">browser skill</a>. The browser skill and REST API are separate integration paths; neither is a public MCP server.</p></section><section id="quickstart"><span>01 / GET CONNECTED</span><h2>One address. One job.</h2><p>Create an account, then open <a href="/settings/api">Settings â API connections</a> as a workspace owner or admin. Create a key with <code>measurements:write</code> and <code>measurements:read</code>. Copy it once into your serverâs secret manager as <code>OPENLAWN_API_KEY</code>.</p><pre><code>curl https://api.openlawn.ai/v1/measurement-jobs \ 58 -H "Authorization: Bearer $OPENLAWN_API_KEY" \ 59 -H 'Content-Type: application/json' \ 60 -H 'Idempotency-Key: crm-property-1042-v1' \ 61 -d '{"address":"5915 Castle Brook Avenue Southeast, Kentwood, MI 49508"}'</code></pre><p>A successful request returns HTTP <strong>
61202</strong> with <code>data.id</code>. This is acceptance into the queue, not a completed measurement. Poll the job every 5â10 seconds, or register a webhook.</p><pre><code>curl https://api.openlawn.ai/v1/measurement-jobs/JOB_ID \ 62 -H "Authorization: Bearer $OPENLAWN_API_KEY" 63 64# Once status is completed, use the returned measurement_id: 65curl https://api.openlawn.ai/v1/measurements/MEASUREMENT_ID \ 66 -H "Authorization: Bearer $OPENLAWN_API_KEY"</code></pre><p>The same routes are available at <code>https://openlawn.ai/v1</code>. Examples use shell environment variables; never paste your real key into a public client or repository.</p></section><section id="authentication"><span>02 / ACCESS</span><h2>Small permissions. Clear boundaries.</h2><p>Send <code>Authorization: Bearer YOUR_KEY</code>. Each key is bound to one workspace and its creator. Keys expire after 30, 90, or 365 days, can be revoked immediately, and are stored as hashes. The full key is returned only at creation.</p><div class="_scopeGrid_wcsq3_1"><code>account:read</code><code>measurements:read</code><code>measurements:write</code><code>properties:read</code><code>webhooks:read</code><code>webhooks:write</code></div><p>Read scopes can access that workspaceâs saved records, including records created by teammates. Write scope queues measurements billed to the <strong>key creatorâs account</strong>. A key stops working if its creator is removed, demoted below admin, or banned. Revocation does not cancel jobs already accepted.</p><p>API keys are for server-to-server connections. Browser cookies are not accepted by v1 endpoints, and cross-origin browser access is not enabled. API keys cannot administer team members, buy credits, or manage other API keys.</p></section><section id="jobs"><span>03 / ASYNC MEASUREMENTS</span><h2>Built for queues, not long requests.</h2><p>Jobs move from <code>queued</code> to <code>running</code>, then <code>completed</code>, <code>failed</code>, or <code>canceled</code>. A completed job includes a measurement ID. Polling and reopening results do not cost measurement credits.</p><p>One credit is reserved when execution begins and used when a result completes. Failed or canceled work releases its reservation. Queue acceptance does not guarantee credit availability later. The queue currently allows up to 100 pending/running jobs per creator; execution concurrency is bounded by the shared worker.</p><h3>Safe retries</h3><p>For a single job, supply an <code>Idempotency-Key</code> header containing 8â128 letters, digits, hyphens, or underscores. Repeating the same key and address under the same creator/workspace returns the existing job. Using it for a different address returns 409. A different key creates a new job and can consume another credit.</p><h3>Batch submission</h3><p>Submit 1â25 addresses with a separate <code>idempotency_key</code> for each. Validate every item in the 202 response: the array may contain both accepted jobs and per-item errors. Retry unsuccessful items with their original keys.</p><pre><code>curl https://api.openlawn.ai/v1/measurement-jobs/batch \ 67 -H "Authorization: Bearer $OPENLAWN_API_KEY" \ 68 -H 'Content-Type: application/json' \ 69 -d '{"jobs":[ 70 {"address":"5915 Castle Brook Avenue Southeast, Kentwood, MI 49508", "idempotency_key":"crm-1042-v1"}, 71 {"address":"5920 Castle Brook Avenue Southeast, Kentwood, MI 49508", "idempotency_key":"crm-1043-v1"} 72 ]}'</code></pre><p>Cancellation requires the same creator as the original job and a non-terminal status. Completed results remain in measurement history.</p></section><section id="endpoints"><span>04 / REFERENCE</span><h2>The v1 surface.</h2><div class="_endpoints_wcsq3_1"><article><div><b>GET</b><code>/account</code></div><p>Workspace identity and the key creatorâs credit balance.</p><small>account:read</small></article><article><div><b>GET</b><code>/measurement-jobs</code></div><p>List background measurement jobs.</p><small>measurements:read</small></article><article><div><b>POST</b><code>/measurement-jobs</code></div><p>Queue one address. Requires an Idempotency-Key header.</p><small>measurements:write</small></article><article><div><b>POST</b><code>/measurement-jobs/batch</code></div><p>Queue up to 25 addresses with an idempotency_key per item.</p><small>measurements:write</small></article><article><div><b>GET</b><code>/measurement-jobs/{id}</code></div><p>Read a jobâs phase, status, and resulting measurement ID.</p><small>measurements:read</small></article><article><div><b>DELETE</b><code>/measurement-jobs/{id}</code></div><p>Cancel a non-terminal job created by this keyâs user.</p><small>measurements:write</small></article><article><div><b>GET</b><code>/measurements</code></div><p>List saved lawn estimates in this workspace.</p><small>measurements:read</small></article><article><div><b>GET</b><code>/measurements/{id}</code></div><p>Get geometry, area totals, and a five-minute signed snapshot URL.</p><small>measurements:read</small></article><article><div><b>GET</b><code>/properties</code></div><p>List properties grouped by normalized saved address.</p><small>properties:read</small></article><article><div><b>GET</b><code>/properties/{id}</code></div><p>Get a property and its latest measurement ID.</p><small>properties:read</small></article><article><div><b>GET</b><code>/webhooks</code></div><p>
72List webhook receivers without their signing secrets.</p><small>webhooks:read</small></article><article><div><b>POST</b><code>/webhooks</code></div><p>Register a receiver; the signing secret is returned only once.</p><small>webhooks:write</small></article><article><div><b>DELETE</b><code>/webhooks/{id}</code></div><p>Disable a receiver and stop future delivery attempts.</p><small>webhooks:write</small></article><article><div><b>POST</b><code>/webhooks/{id}/test</code></div><p>Queue a webhook.test event without running a measurement.</p><small>webhooks:write</small></article><article><div><b>GET</b><code>/webhooks/{id}/deliveries</code></div><p>List delivery status and attempts for this receiver.</p><small>webhooks:read</small></article></div><p><a href="/openapi.json">Download the machine-readable OpenAPI specification</a> for request schemas and response fields.</p></section><section id="results"><span>05 / READING RESULTS</span><h2>Numbers with their context.</h2><p>Measurement details include estimated square feet, parcel lawn and verge totals, available confidence and timing, model identity, and normalized polygon actions. Snapshot links expire after five minutes: request the detail endpoint again for a fresh link. Storage objects are not public.</p><p><code>geometry.coordinate_system</code> is <code>normalized_image</code>: x/y values run from 0 to 1 across the measurement image, with (0,0) at the top left. These are <strong>not longitude/latitude GeoJSON coordinates</strong>. Preserve the complete image frame when drawing overlays. Polygon actions may include paint and erase operations.</p><p>Estimates are not legal surveys. Review imagery, tree cover, maintained extensions, and the intended service area before using a result in a quote.</p><h3>Pagination</h3><p>List endpoints accept <code>limit</code> (1â100, default 25) and an opaque <code>cursor</code>. Continue using <code>next_cursor</code> until it is null. Records are ordered newest first. Properties are grouped by normalized saved address and can move when new measurements arrive; use their stable IDs to deduplicate or upsert during synchronization.</p></section><section id="webhooks"><span>06 / EVENTS</span><h2>Know when the work is ready.</h2><p>Register an HTTPS receiver in <a href="/settings/api">API connections</a> or with <code>POST /webhooks</code>. Save the returned <code>signing_secret</code> immediately; it is not shown again. Receivers get all terminal measurement events in their workspace, including jobs started in the app.</p><div class="_scopeGrid_wcsq3_1"><code>measurement.completed</code><code>measurement.failed</code><code>measurement.canceled</code><code>webhook.test</code></div><pre><code>{ 73 "id": "evt_JOB_UUID_completed", 74 "type": "measurement.completed", 75 "created_at": "2026-09-06T16:00:00Z", 76 "data": { 77 "job_id": "JOB_UUID", 78 "measurement_id": "MEASUREMENT_UUID", 79 "status": "completed" 80 } 81}</code></pre><p>This is an illustrative payload. Events contain IDs and status, not the address or full imagery. Fetch the measurement using your own API key. A <code>webhook.test</code> event is available without spending credits.</p><h3>Delivery behavior</h3><p>The dispatcher checks for work every minute. Delivery is at least once while retries remain; ordering is not guaranteed. OpenLawn retries unsuccessful requests up to five total attempts, with increasing delays. Return a 2xx response within 10 seconds after durably accepting the event. Redirects are not followed. Delivery logs show status, attempts, and the last HTTP status. Disabling a receiver stops future attempts; an in-flight request may finish.</p><h3>Verify the signature</h3><p>Read the <code>OpenLawn-Signature</code> header. Verify HMAC-SHA256 over <code>timestamp + "." + rawBody</code> using the signing secret. Reject timestamps older than five minutes, compare signatures safely, and deduplicate by event ID.</p><pre><code>import { createHmac, timingSafeEqual } from 'node:crypto'; 82 83// rawBody must be the exact bytes received, BEFORE JSON parsing. 84export function verifyWebhook(rawBody, signature, secret) { 85 const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(signature || ''); 86 if (!match) return false;
87 const timestamp = Number(match[1]); 88 if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false; 89 const expected = createHmac('sha256', secret) 90 .update(match[1] + '.').update(rawBody).digest(); 91 return timingSafeEqual(expected, Buffer.from(match[2], 'hex')); 92} 93// Reject invalid signatures. Persist valid events before returning 2xx. 94// Deduplicate by event.id; events can be repeated or arrive out of order.</code></pre><h3>Receiver safety</h3><p>This first release supports these approved domains:</p><ul><li><code>hooks.zapier.com</code></li><li><code>hook.us1.make.com</code></li><li><code>hook.us2.make.com</code></li><li><code>hook.eu1.make.com</code></li><li><code>hook.eu2.make.com</code></li><li><code>hook.integromat.com</code></li></ul><p>For your own server, contact <a href="mailto:[email protected]">[email protected]</a> to approve its public HTTPS hostname. Private IPs, arbitrary domains, custom ports, and redirects are not accepted. Receiver creation alone does not make an unapproved domain eligible.</p></section><section id="errors"><span>07 / OPERATIONS</span><h2>Predictable limits and errors.</h2><p>The API allows 120 authenticated requests per workspace per minute, shared by all its keys. A 429 includes <code>Retry-After: 60</code>. Successful responses include <code>X-RateLimit-Limit</code>, <code>X-RateLimit-Remaining</code>, and <code>X-Request-Id</code>. Workspaces can have 20 active keys and five active receivers; test events are limited to five per receiver per minute.</p><pre><code>{"error":{"code":"insufficient_scope","message":"This endpoint requires measurements:read."},"request_id":"â¦"}</code></pre><p>400: invalid input. 401: invalid, expired, or revoked key. 403: insufficient scope. 404: unavailable record. 409: idempotency conflict or invalid job state. 413: oversized body. 422: unapproved receiver. 429: rate limit. 503: temporary service failure. Keep request IDs when contacting support; never send your key or webhook secret.</p><p>Retry 429 and transient 503 responses with exponential backoff and jitter, retaining the same idempotency key for job submission. Do not automatically repeat successful measurements with a new key.</p></section></div></div></details><footer class="_footer_yjmsp_1" id="footer" aria-label="OpenLawn footer"><div class="_inner_yjmsp_2"><div class="_top_yjmsp_2"><div class="_intro_yjmsp_2"><a href="/" class="_brand_yjmsp_2"><span class="brand-logo" aria-hidden="true"></span>OpenLawn</a><p>A clearer view of<br/>your next job.</p><span>Lawn measurement for the teams<br/>that take care of the outdoors.</span></div><nav class="_columns_yjmsp_2" aria-label="Footer navigation"><div><h2>Product</h2><ul><li><a href="/agent">Agent View</a></li><li><a href="/#how-it-works">How it works</a></li><li><a href="/#pricing">Pricing</a></li><li><a href="/billing">Billing & credits</a></li><li><a href="/auth/sign-up?next=%2Fagent">Create an account</a></li></ul></div><div><h2>Explore</h2><ul><li><a href="/lawn-measurement-guide">Measurement guide</a></li><li><a href="/benchmarks/2026-09-29">GPT-6.1 Sol case study</a></li><li><a href="/benchmarks/2026-09-22">Model benchmark</a></li><li><a href="/developers">For AI agents</a></li><li><a href="/#questions">Questions, answered</a></li></ul></div><div><h2>Compare</h2><ul><li><a href="/compare">All comparisons</a></li><li><a href="/compare/deep-lawn">OpenLawn vs. Deep Lawn</a></li><li><a href="/compare/find-lot-size">OpenLawn vs. FindLotSize</a></li><li><a href="/compare/local-gis">OpenLawn vs. local GIS</a></li></ul></div><div><h2>Connect</h2><ul><li><a href="/docs">API documentation</a></li><li><a href="/settings/api">API keys & webhooks</a></li><li><a href="mailto:[email protected]">Contact support â</a></li><li><a href="/privacy">Privacy policy</a></li><li><a href="/developers#install">Agent documentation</a></li><li><a href="/llms.txt">AI-readable overview</a></li><li><a href="/sitemap.xml">Sitemap</a></li></ul></div></nav></div><a href="/" class="_wordmark_yjmsp_2" aria-label="OpenLawn home">OpenLawn</a><div class="_bottom_yjmsp_2"><span>© <!-- -->2026<!-- --> Clicki, Inc.</span><span>Aerial estimates. Human judgment.</span><a href="#top">Back to top <span aria-hidden="true">â</span></a></div><p class="_note_yjmsp_2">Review every measurement before quoting. Aerial estimates and parcel overlays are not legal surveys.</p><p class="_note_yjmsp_2"><button type="button" style="font:inherit;color:inherit;background:none;border:0;padding:0;text-decoration:underline;cursor:pointer" aria-label="Turn off public website session recording">Session recording: <!-- -->on</button> · <a href="/privacy#session-recording">Privacy choices</a></p></div></footer></main>
94<script id="_R_">import("/assets/index-CuK3ZBoT.js")</script>
94<script>(function(){function c(){var b=a.contentDocument||(a.contentWindow&&a.contentWindow.document);if(b){var d=b.createElement('script');d.innerHTML="window.__CF$cv$params={r:'a45cf48eead917dd',t:'MTc5MTIwODg1NA=='};var a=document.createElement('script');a.src='/cdn-cgi/challenge-platform/scripts/jsd/main.js';document.getElementsByTagName('head')[0].appendChild(a);";b.getElementsByTagName('head')[0].appendChild(d)}}if(document.body){var a=document.createElement('iframe');a.height=1;a.width=1;a.style.position='absolute';a.style.top=0;a.style.left=0;a.style.border='none';a.style.visibility='hidden';document.body.appendChild(a);if('loading'!==document.readyState)c();else if(window.addEventListener)document.addEventListener('DOMContentLoaded',c);else{var e=document.onreadystatechange||function(){};document.onreadystatechange=function(b){e(b);'loading'!==document.readyState&&(document.onreadystatechange=e,c())}}}})();</script>
94</body></html>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("2:I[\"5eae192f4b46\",[],\"PublicSessionRecorder\",1]\n3:I[\"416cfbe3db71\",[],\"SupportViewBanner\",1]\n4:I[\"8c0f216c4604\",[],\"Children\",1]\n5:I[\"f2ed27736b10\",[],\"FounderContact\",1]\n6:I[\"15c18cfaeeff\",[],\"LayoutSegmentProvider\",1]\n7:I[\"8c0f216c4604\",[],\"Slot\",1]\n:HL[\"/assets/index-DxmyaP73.css\",\"style\"]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("0:{\"__route\":\"route:/docs\",\"__interceptionContext\":null,\"__layoutIds\":[\"layout:/\"],\"__rootLayout\":\"/\",\"page:/docs\":\"$L1\",\"layout:/\":[[[[\"$\",\"link\",\"css:/assets/index-DxmyaP73.css\",{\"rel\":\"stylesheet\",\"precedence\":\"vite-rsc/importer-resources\",\"href\":\"/assets/index-DxmyaP73.css\",\"data-rsc-css-href\":\"/assets/index-DxmyaP73.css\"}],\"$undefined\"],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"font-sans __variable_geist_1th67zq\",\"children\":[\"$\",\"body\",null,{\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"$L3\",null,{}],[\"$\",\"$L4\",null,{}],[\"$\",\"$L5\",null,{}]]}]}]],null],\"route:/docs\":[[[\"$\",\"meta\",null,{\"charSet\":\"utf-8\"}],[[\"$\",\"title\",\"0\",{\"children\":\"OpenLawn API Documentation â Lawn Measurement API\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks.\"}],[\"$\",\"meta\",\"2\",{\"name\":\"application-name\",\"content\":\"OpenLawn\"}],[\"$\",\"meta\",\"3\",{\"name\":\"robots\",\"content\":\"index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1\"}],[\"$\",\"meta\",\"4\",{\"property\":\"og:title\",\"content\":\"OpenLawn API Documentation â Lawn Measurement API\"}],[\"$\",\"meta\",\"5\",{\"property\":\"og:description\",\"content\":\"Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks.\"}],[\"$\",\"meta\",\"6\",{\"property\":\"og:url\",\"content\":\"https://openlawn.ai/docs\"}],[\"$\",\"meta\",\"7\",{\"property\":\"og:site_name\",\"content\":\"OpenLawn\"}],[\"$\",\"meta\",\"8\",{\"property\":\"og:type\",\"content\":\"website\"}],[\"$\",\"meta\",\"9\",{\"property\":\"og:locale\",\"content\":\"en_US\"}],[\"$\",\"meta\",\"10\",{\"property\":\"og:image\",\"content\":\"https://openlawn.ai/og.png?v=2026-09-homepage-neighborhood\"}],[\"$\",\"meta\",\"11\",{\"property\":\"og:image:width\",\"content\":\"1200\"}],[\"$\",\"meta\",\"12\",{\"property\":\"og:image:height\",\"content\":\"630\"}],[\"$\",\"meta\",\"13\",{\"property\":\"og:image:type\",\"content\":\"image/png\"}],[\"$\",\"meta\",\"14\",{\"property\":\"og:image:alt\",\"content\":\"OpenLawn â Measure the property. Prepare the quote. An illustrative neighborhood aerial with green lawn outlines, matching the homepage. AI lawn measurement for lawn care and pest control. Powered by OpenAI GPT-6 Astra. Works with Codex, Claude Code, and Gemini CLI.\"}],[\"$\",\"meta\",\"15\",{\"name\":\"twitter:card\",\"content\":\"summary_large_image\"}],[\"$\",\"meta\",\"16\",{\"name\":\"twitter:title\",\"content\":\"OpenLawn API Documentation â Lawn Measurement API\"}],[\"$\",\"meta\",\"17\",{\"name\":\"twitter:description\",\"content\":\"Connect your CRM to OpenLawn with scoped API keys, asynchronous lawn measurements, batch jobs, saved property results, and signed webhooks.\"}],[\"$\",\"meta\",\"18\",{\"name\":\"twitter:image\",\"content\":\"https://openlawn.ai/og.png?v=2026-09-homepage-neighborhood\"}],[\"$\",\"meta\",\"19\",{\"name\":\"twitter:image:alt\",\"content\":\"OpenLawn â Measure the property. Prepare the quote. An illustrative neighborhood aerial with green lawn outlines, matching the homepage. AI lawn measurement for lawn care and pest control. Powered by OpenAI GPT-6 Astra. Works with Codex, Claude Code, and Gemini CLI.\"}],[\"$\",\"link\",\"20\",{\"rel\":\"shortcut icon\",\"href\":\"https://openlawn.ai/openlawn-mark.png\"}],[\"$\",\"link\",\"21\",{\"rel\":\"icon\",\"href\":\"https://openlawn.ai/openlawn-mark.png\"}],[\"$\",\"link\",\"22\",{\"rel\":\"apple-touch-icon\",\"href\":\"https://openlawn.ai/icons/apple-touch-icon.png\"}],[\"$\",\"link\",\"23\",{\"rel\":\"manifest\",\"href\":\"https://openlawn.ai/manifest.webmanifest\"}],[\"$\",\"link\",\"24\",{\"rel\":\"canonical\",\"href\":\"https://openlawn.ai/docs\"}],[\"$\",\"link\",\"25\",{\"rel\":\"alternate\",\"type\":\"text/markdown\",\"href\":\"https://openlawn.ai/docs.md\"}],[\"$\",\"meta\",\"26\",{\"name\":\"mobile-web-app-capable\",\"content\":\"yes\"}],[\"$\",\"meta\",\"27\",{\"name\":\"apple-mobile-web-app-title\",\"content\":\"OpenLawn\"}],[\"$\",\"meta\",\"28\",{\"name\":\"apple-mobile-web-app-status-bar-style\",\"content\":\"default\"}]],[[\"$\",\"meta\",\"0\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}],[\"$\",\"meta\",\"1\",{\"name\":\"theme-color\",\"content\":\"#ffffff\"}]]],[\"$\",\"$L6\",null,{\"segmentMap\":{\"children\":[\"docs\"]},\"children\":[\"$\",\"$L7\",null,{\"id\":\"layout:/\",\"parallelSlots\":\"$undefined\",\"children\":\"$L8\"}]}]],\"__layoutFlags\":{\"layout:/\":\"s\"},\"__artifactCompatibility\":{\"schemaVersion\":1,\"graphVersion\":\"app-route-graph:1q4l5q81akpobl\",\"deploymentVersion\":\"0e2e94e4-cc46-4245-8ba4-f1d792785de9\",\"appElementsSchemaVersion\":1,\"rscPayloadSchemaVersion\":1,\"rootBoundaryId\":\"/\",\"renderEpoch\":null}}\n9:I[\"593f344dc510\",[],\"RedirectBoundary\",1]\n8:[\"$\",\"$L9\",null,{\"children\":[\"$\",\"$L6\",null,{\"segmentMap\":{\"children\":[]},\"children\":[\"$\",\"$L7\",null,{\"id\":\"page:/docs\"}]}]}]\nb:I[\"c809634099f9\",[],\"default\",1]\nc:I[\"f1d1f800e523\",[],\"default\",1]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("a:T495,{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://openlawn.ai/#organization\",\"name\":\"OpenLawn\",\"url\":\"https://openlawn.ai\",\"logo\":\"https://openlawn.ai/openlawn-mark.png\"},{\"@type\":\"TechArticle\",\"@id\":\"https://openlawn.ai/docs#reference\",\"url\":\"https://openlawn.ai/docs\",\"headline\":\"OpenLawn API documentation\",\"description\":\"Public REST API documentation for asynchronous lawn measurements, normalized polygon results, and signed webhooks.\",\"inLanguage\":\"en\",\"isAccessibleForFree\":true,\"publisher\":{\"@id\":\"https://openlawn.ai/#organization\"},\"about\":{\"@id\":\"https://api.openlawn.ai/#api\"},\"hasPart\":[{\"@type\":\"TechArticle\",\"name\":\"Agent API quickstart\",\"url\":\"https://openlawn.ai/docs/agent-quickstart.md\"}]},{\"@type\":\"WebAPI\",\"@id\":\"https://api.openlawn.ai/#api\",\"name\":\"OpenLawn lawn measurement API\",\"url\":\"https://api.openlawn.ai/v1\",\"description\":\"Workspace-scoped U.S. and Canadian lawn measurement jobs, saved estimates, property history, and signed webhooks. API operations require a key and completed measurements consume credits.\",\"documentation\":\"https://openlawn.ai/docs\",\"provider\":{\"@id\":\"https://openlawn.ai/#organization\"}}]}1:[[[\"$\",\"link\",\"css:/assets/index-DxmyaP73.css\",{\"rel\":\"stylesheet\",\"precedence\":\"vite-rsc/importer-resources\",\"href\":\"/assets/index-DxmyaP73.css\",\"data-rsc-css-href\":\"/assets/index-DxmyaP73.css\"}],\"$undefined\"],[\"$\",\"main\",null,{\"className\":\"_page_wcsq3_1\",\"id\":\"top\",\"children\":[[\"$\",\"script\",null,{\"type\":\"application/ld+json\",\"dangerouslySetInnerHTML\":{\"__html\":\"$a\"}}],[\"$\",\"$Lb\",null,{}],[\"$\",\"header\",null,{\"className\":\"_hero_wcsq3_1\",\"children\":[[\"$\",\"span\",null,{\"children\":\"OPENLAWN / DEVELOPERS\"}],[\"$\",\"h1\",null,{\"children\":[\"Lawn measurements.\",[\"$\",\"br\",null,{}],[\"$\",\"em\",null,{\"children\":\"Built into your workflow.\"}]]}],[\"$\",\"p\",null,{\"children\":\"Explore the API, test a sample residential measurement, then connect your own account when youâre ready.\"}],[\"$\",\"div\",null,{\"children\":[[\"$\",\"a\",null,{\"href\":\"/settings/api\",\"children\":\"Create an API key â\"}],[\"$\",\"a\",null,{\"href\":\"/openapi.json\",\"children\":\"OpenAPI specification â\"}],[\"$\",\"a\",null,{\"href\":\"#guides\",\"children\":\"Guides \u0026 quickstart â\"}]]}],[\"$\",\"code\",null,{\"children\":\"https://api.openlawn.ai/v1\"}]]}],[\"$\",\"$Lc\",null,{}],[\"$\",\"details\",null,{\"className\":\"_guideWrapper_wcsq3_2\",\"id\":\"guides\",\"children\":[[\"$\",\"summary\",null,{\"children\":\"Integration guides \u0026 operational details\"}],[\"$\",\"div\",null,{\"className\":\"_layout_wcsq3_1\",\"children\":[[\"$\",\"nav\",null,{\"aria-label\":\"Documentation sections\",\"children\":[[[\"$\",\"a\",\"agents\",{\"href\":\"#agents\",\"children\":\"For AI agents\"}],[\"$\",\"a\",\"quickstart\",{\"href\":\"#quickstart\",\"children\":\"Quickstart\"}],[\"$\",\"a\",\"authentication\",{\"href\":\"#authentication\",\"children\":\"Authentication\"}],[\"$\",\"a\",\"jobs\",{\"href\":\"#jobs\",\"children\":\"Jobs \u0026 credits\"}],[\"$\",\"a\",\"endpoints\",{\"href\":\"#endpoints\",\"children\":\"Endpoints\"}],[\"$\",\"a\",\"results\",{\"href\":\"#results\",\"children\":\"Results \u0026 pagination\"}],[\"$\",\"a\",\"webhooks\",{\"href\":\"#webhooks\",\"children\":\"Webhooks\"}],[\"$\",\"a\",\"errors\",{\"href\":\"#errors\",\"children\":\"Errors \u0026 limits\"}]],[\"$\",\"a\",null,{\"href\":\"/docs.md\",\"children\":\"Markdown version â\"}]]}],[\"$\",\"div\",null,{\"className\":\"_content_wcsq3_1\",\"children\":[[\"$\",\"section\",null,{\"id\":\"agents\",\"children\":[[\"$\",\"span\",null,{\"children\":\"FOR DEVELOPERS \u0026 AI AGENTS\"}],[\"$\",\"h2\",null,{\"children\":\"Public docs. A direct path to the API.\"}],[\"$\",\"p\",null,{\"children\":[\"No login is needed to read or fetch this documentation. For a server-side agent or CRM connection, start with the \",[\"$\",\"a\",null,{\"href\":\"/docs/agent-quickstart.md\",\"children\":\"agent API quickstart\"}],\", then load the \",[\"$\",\"a\",null,{\"href\":\"/openapi.json\",\"children\":\"OpenAPI 3.1 contract\"}],\". Prefer plain text? Use the \",[\"$\",\"a\",null,{\"href\":\"/docs.md\",\"children\":\"Markdown reference\"}],\" or \",[\"$\",\"a\",null,{\"href\":\"/docs/llms.txt\",\"children\":\"API documentation index\"}],\".\"]}],[\"$\",\"p\",null,{\"children\":\"Keep API keys in your backend secret manager, not in prompts. Submit each intended measurement once with a stable idempotency key, wait for its terminal status, then retrieve the estimated square feet and polygons. Reading existing results does not use a measurement credit.\"}],\"$Ld\"]}],\"$Le\",\"$Lf\",\"$L10\",\"$L11\",\"$L12\",\"$L13\",\"$L14\"]}]]}]]}],\"$L15\"]}]]\n19:I[\"c2747888630f\",[],\"default\",1]\n1a:I[\"5eae192f4b46\",[],\"SessionRecordingPreference\",1]\nd:[\"$\",\"p\",null,{\"children\":[\"Want an agent to operate the website instead? Use the \",[\"$\",\"a\",null,{\"href\":\"/developers\",\"children\":\"browser skill\"}],\". The browser skill and REST API are separate integration paths; neither is a public MCP server.\"]}]\ne:[\"$\",\"section\",null,{\"id\":\"quickstart\",\"children\":[[\"$\",\"span\",null,{\"children\":\"01 / GET CONNECTED\"}],[\"$\",\"h2\",null,{\"children\":\"One address. One job.\"}],[\"$\",\"p\",null,{\"children\":[\"Create an account, then open \",[\"$\",\"a\",null,{\"href\":\"/settings/api\",\"children\":\"Settings â API connections\"}],\" as a workspace owner or admin. Create a key with \",[\"$\",\"code\",null,{\"children\":\"measurements:write\"}],\" and \",[\"$\",\"code\",null,{\"children\":\"measurements:read\"}],\". Copy it once into your serverâs secret manager as \",[\"$\",\"code\",null,{\"children\":\"OPENLAWN_API_KEY\"}],\".\"]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"curl https://api.openlawn.ai/v1/measurement-jobs \\\\\\n -H \\\"Authorization: Bearer $OPENLAWN_API_KEY\\\" \\\\\\n -H 'Content-Type: application/json' \\\\\\n -H 'Idempotency-Key: crm-property-1042-v1' \\\\\\n -d '{\\\"address\\\":\\\"5915 Castle Brook Avenue Southeast, Kentwood, MI 49508\\\"}'\"}]}],[\"$\",\"p\",null,{\"children\":[\"A successful request returns HTTP \",[\"$\",\"strong\",null,{\"children\":\"202\"}],\" with \",[\"$\",\"code\",null,{\"children\":\"data.id\"}],\". This is acceptance into the queue, not a completed measurement. Poll the job every 5â10 seconds, or register a webhook.\"]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"curl https://api.openlawn.ai/v1/measurement-jobs/JOB_ID \\\\\\n -H \\\"Authorization: Bearer $OPENLAWN_API_KEY\\\"\\n\\n# Once status is completed, use the returned measurement_id:\\ncurl https://api.openlawn.ai/v1/measurements/MEASUREMENT_ID \\\\\\n -H \\\"Authorization: Bearer $OPENLAWN_API_KEY\\\"\"}]}],[\"$\",\"p\",null,{\"children\":[\"The same routes are available at \",[\"$\",\"code\",null,{\"children\":\"https://openlawn.ai/v1\"}],\". Examples use shell environment variables; never paste your real key into a public client or repository.\"]}]]}]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("f:[\"$\",\"section\",null,{\"id\":\"authentication\",\"children\":[[\"$\",\"span\",null,{\"children\":\"02 / ACCESS\"}],[\"$\",\"h2\",null,{\"children\":\"Small permissions. Clear boundaries.\"}],[\"$\",\"p\",null,{\"children\":[\"Send \",[\"$\",\"code\",null,{\"children\":\"Authorization: Bearer YOUR_KEY\"}],\". Each key is bound to one workspace and its creator. Keys expire after 30, 90, or 365 days, can be revoked immediately, and are stored as hashes. The full key is returned only at creation.\"]}],[\"$\",\"div\",null,{\"className\":\"_scopeGrid_wcsq3_1\",\"children\":[[\"$\",\"code\",\"account:read\",{\"children\":\"account:read\"}],[\"$\",\"code\",\"measurements:read\",{\"children\":\"measurements:read\"}],[\"$\",\"code\",\"measurements:write\",{\"children\":\"measurements:write\"}],[\"$\",\"code\",\"properties:read\",{\"children\":\"properties:read\"}],[\"$\",\"code\",\"webhooks:read\",{\"children\":\"webhooks:read\"}],[\"$\",\"code\",\"webhooks:write\",{\"children\":\"webhooks:write\"}]]}],[\"$\",\"p\",null,{\"children\":[\"Read scopes can access that workspaceâs saved records, including records created by teammates. Write scope queues measurements billed to the \",[\"$\",\"strong\",null,{\"children\":\"key creatorâs account\"}],\". A key stops working if its creator is removed, demoted below admin, or banned. Revocation does not cancel jobs already accepted.\"]}],[\"$\",\"p\",null,{\"children\":\"API keys are for server-to-server connections. Browser cookies are not accepted by v1 endpoints, and cross-origin browser access is not enabled. API keys cannot administer team members, buy credits, or manage other API keys.\"}]]}]\n10:[\"$\",\"section\",null,{\"id\":\"jobs\",\"children\":[[\"$\",\"span\",null,{\"children\":\"03 / ASYNC MEASUREMENTS\"}],[\"$\",\"h2\",null,{\"children\":\"Built for queues, not long requests.\"}],[\"$\",\"p\",null,{\"children\":[\"Jobs move from \",[\"$\",\"code\",null,{\"children\":\"queued\"}],\" to \",[\"$\",\"code\",null,{\"children\":\"running\"}],\", then \",[\"$\",\"code\",null,{\"children\":\"completed\"}],\", \",[\"$\",\"code\",null,{\"children\":\"failed\"}],\", or \",[\"$\",\"code\",null,{\"children\":\"canceled\"}],\". A completed job includes a measurement ID. Polling and reopening results do not cost measurement credits.\"]}],[\"$\",\"p\",null,{\"children\":\"One credit is reserved when execution begins and used when a result completes. Failed or canceled work releases its reservation. Queue acceptance does not guarantee credit availability later. The queue currently allows up to 100 pending/running jobs per creator; execution concurrency is bounded by the shared worker.\"}],[\"$\",\"h3\",null,{\"children\":\"Safe retries\"}],[\"$\",\"p\",null,{\"children\":[\"For a single job, supply an \",[\"$\",\"code\",null,{\"children\":\"Idempotency-Key\"}],\" header containing 8â128 letters, digits, hyphens, or underscores. Repeating the same key and address under the same creator/workspace returns the existing job. Using it for a different address returns 409. A different key creates a new job and can consume another credit.\"]}],[\"$\",\"h3\",null,{\"children\":\"Batch submission\"}],[\"$\",\"p\",null,{\"children\":[\"Submit 1â25 addresses with a separate \",[\"$\",\"code\",null,{\"children\":\"idempotency_key\"}],\" for each. Validate every item in the 202 response: the array may contain both accepted jobs and per-item errors. Retry unsuccessful items with their original keys.\"]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"curl https://api.openlawn.ai/v1/measurement-jobs/batch \\\\\\n -H \\\"Authorization: Bearer $OPENLAWN_API_KEY\\\" \\\\\\n -H 'Content-Type: application/json' \\\\\\n -d '{\\\"jobs\\\":[\\n {\\\"address\\\":\\\"5915 Castle Brook Avenue Southeast, Kentwood, MI 49508\\\", \\\"idempotency_key\\\":\\\"crm-1042-v1\\\"},\\n {\\\"address\\\":\\\"5920 Castle Brook Avenue Southeast, Kentwood, MI 49508\\\", \\\"idempotency_key\\\":\\\"crm-1043-v1\\\"}\\n ]}'\"}]}],[\"$\",\"p\",null,{\"children\":\"Cancellation requires the same creator as the original job and a non-terminal status. Completed results remain in measurement history.\"}]]}]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("11:[\"$\",\"section\",null,{\"id\":\"endpoints\",\"children\":[[\"$\",\"span\",null,{\"children\":\"04 / REFERENCE\"}],[\"$\",\"h2\",null,{\"children\":\"The v1 surface.\"}],[\"$\",\"div\",null,{\"className\":\"_endpoints_wcsq3_1\",\"children\":[[\"$\",\"article\",\"GET/account\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/account\"}]]}],[\"$\",\"p\",null,{\"children\":\"Workspace identity and the key creatorâs credit balance.\"}],[\"$\",\"small\",null,{\"children\":\"account:read\"}]]}],[\"$\",\"article\",\"GET/measurement-jobs\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/measurement-jobs\"}]]}],[\"$\",\"p\",null,{\"children\":\"List background measurement jobs.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:read\"}]]}],[\"$\",\"article\",\"POST/measurement-jobs\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"POST\"}],[\"$\",\"code\",null,{\"children\":\"/measurement-jobs\"}]]}],[\"$\",\"p\",null,{\"children\":\"Queue one address. Requires an Idempotency-Key header.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:write\"}]]}],[\"$\",\"article\",\"POST/measurement-jobs/batch\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"POST\"}],[\"$\",\"code\",null,{\"children\":\"/measurement-jobs/batch\"}]]}],[\"$\",\"p\",null,{\"children\":\"Queue up to 25 addresses with an idempotency_key per item.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:write\"}]]}],[\"$\",\"article\",\"GET/measurement-jobs/{id}\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/measurement-jobs/{id}\"}]]}],[\"$\",\"p\",null,{\"children\":\"Read a jobâs phase, status, and resulting measurement ID.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:read\"}]]}],[\"$\",\"article\",\"DELETE/measurement-jobs/{id}\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"DELETE\"}],[\"$\",\"code\",null,{\"children\":\"/measurement-jobs/{id}\"}]]}],[\"$\",\"p\",null,{\"children\":\"Cancel a non-terminal job created by this keyâs user.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:write\"}]]}],[\"$\",\"article\",\"GET/measurements\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/measurements\"}]]}],[\"$\",\"p\",null,{\"children\":\"List saved lawn estimates in this workspace.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:read\"}]]}],[\"$\",\"article\",\"GET/measurements/{id}\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/measurements/{id}\"}]]}],[\"$\",\"p\",null,{\"children\":\"Get geometry, area totals, and a five-minute signed snapshot URL.\"}],[\"$\",\"small\",null,{\"children\":\"measurements:read\"}]]}],[\"$\",\"article\",\"GET/properties\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/properties\"}]]}],[\"$\",\"p\",null,{\"children\":\"List properties grouped by normalized saved address.\"}],[\"$\",\"small\",null,{\"children\":\"properties:read\"}]]}],[\"$\",\"article\",\"GET/properties/{id}\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/properties/{id}\"}]]}],[\"$\",\"p\",null,{\"children\":\"Get a property and its latest measurement ID.\"}],[\"$\",\"small\",null,{\"children\":\"properties:read\"}]]}],[\"$\",\"article\",\"GET/webhooks\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/webhooks\"}]]}
94],[\"$\",\"p\",null,{\"children\":\"List webhook receivers without their signing secrets.\"}],[\"$\",\"small\",null,{\"children\":\"webhooks:read\"}]]}],[\"$\",\"article\",\"POST/webhooks\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"POST\"}],[\"$\",\"code\",null,{\"children\":\"/webhooks\"}]]}],[\"$\",\"p\",null,{\"children\":\"Register a receiver; the signing secret is returned only once.\"}],[\"$\",\"small\",null,{\"children\":\"webhooks:write\"}]]}],[\"$\",\"article\",\"DELETE/webhooks/{id}\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"DELETE\"}],[\"$\",\"code\",null,{\"children\":\"/webhooks/{id}\"}]]}],[\"$\",\"p\",null,{\"children\":\"Disable a receiver and stop future delivery attempts.\"}],[\"$\",\"small\",null,{\"children\":\"webhooks:write\"}]]}],[\"$\",\"article\",\"POST/webhooks/{id}/test\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"POST\"}],[\"$\",\"code\",null,{\"children\":\"/webhooks/{id}/test\"}]]}],[\"$\",\"p\",null,{\"children\":\"Queue a webhook.test event without running a measurement.\"}],[\"$\",\"small\",null,{\"children\":\"webhooks:write\"}]]}],[\"$\",\"article\",\"GET/webhooks/{id}/deliveries\",{\"children\":[[\"$\",\"div\",null,{\"children\":[[\"$\",\"b\",null,{\"children\":\"GET\"}],[\"$\",\"code\",null,{\"children\":\"/webhooks/{id}/deliveries\"}]]}],[\"$\",\"p\",null,{\"children\":\"List delivery status and attempts for this receiver.\"}],\"$L16\"]}]]}],\"$L17\"]}]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("12:[\"$\",\"section\",null,{\"id\":\"results\",\"children\":[[\"$\",\"span\",null,{\"children\":\"05 / READING RESULTS\"}],[\"$\",\"h2\",null,{\"children\":\"Numbers with their context.\"}],[\"$\",\"p\",null,{\"children\":\"Measurement details include estimated square feet, parcel lawn and verge totals, available confidence and timing, model identity, and normalized polygon actions. Snapshot links expire after five minutes: request the detail endpoint again for a fresh link. Storage objects are not public.\"}],[\"$\",\"p\",null,{\"children\":[[\"$\",\"code\",null,{\"children\":\"geometry.coordinate_system\"}],\" is \",[\"$\",\"code\",null,{\"children\":\"normalized_image\"}],\": x/y values run from 0 to 1 across the measurement image, with (0,0) at the top left. These are \",[\"$\",\"strong\",null,{\"children\":\"not longitude/latitude GeoJSON coordinates\"}],\". Preserve the complete image frame when drawing overlays. Polygon actions may include paint and erase operations.\"]}],[\"$\",\"p\",null,{\"children\":\"Estimates are not legal surveys. Review imagery, tree cover, maintained extensions, and the intended service area before using a result in a quote.\"}],[\"$\",\"h3\",null,{\"children\":\"Pagination\"}],[\"$\",\"p\",null,{\"children\":[\"List endpoints accept \",[\"$\",\"code\",null,{\"children\":\"limit\"}],\" (1â100, default 25) and an opaque \",[\"$\",\"code\",null,{\"children\":\"cursor\"}],\". Continue using \",[\"$\",\"code\",null,{\"children\":\"next_cursor\"}],\" until it is null. Records are ordered newest first. Properties are grouped by normalized saved address and can move when new measurements arrive; use their stable IDs to deduplicate or upsert during synchronization.\"]}]]}]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("13:[\"$\",\"section\",null,{\"id\":\"webhooks\",\"children\":[[\"$\",\"span\",null,{\"children\":\"06 / EVENTS\"}],[\"$\",\"h2\",null,{\"children\":\"Know when the work is ready.\"}],[\"$\",\"p\",null,{\"children\":[\"Register an HTTPS receiver in \",[\"$\",\"a\",null,{\"href\":\"/settings/api\",\"children\":\"API connections\"}],\" or with \",[\"$\",\"code\",null,{\"children\":\"POST /webhooks\"}],\". Save the returned \",[\"$\",\"code\",null,{\"children\":\"signing_secret\"}],\" immediately; it is not shown again. Receivers get all terminal measurement events in their workspace, including jobs started in the app.\"]}],[\"$\",\"div\",null,{\"className\":\"_scopeGrid_wcsq3_1\",\"children\":[[\"$\",\"code\",\"measurement.completed\",{\"children\":\"measurement.completed\"}],[\"$\",\"code\",\"measurement.failed\",{\"children\":\"measurement.failed\"}],[\"$\",\"code\",\"measurement.canceled\",{\"children\":\"measurement.canceled\"}],[\"$\",\"code\",\"webhook.test\",{\"children\":\"webhook.test\"}]]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"{\\n \\\"id\\\": \\\"evt_JOB_UUID_completed\\\",\\n \\\"type\\\": \\\"measurement.completed\\\",\\n \\\"created_at\\\": \\\"2026-09-06T16:00:00Z\\\",\\n \\\"data\\\": {\\n \\\"job_id\\\": \\\"JOB_UUID\\\",\\n \\\"measurement_id\\\": \\\"MEASUREMENT_UUID\\\",\\n \\\"status\\\": \\\"completed\\\"\\n }\\n}\"}]}],[\"$\",\"p\",null,{\"children\":[\"This is an illustrative payload. Events contain IDs and status, not the address or full imagery. Fetch the measurement using your own API key. A \",[\"$\",\"code\",null,{\"children\":\"webhook.test\"}],\" event is available without spending credits.\"]}],[\"$\",\"h3\",null,{\"children\":\"Delivery behavior\"}],[\"$\",\"p\",null,{\"children\":\"The dispatcher checks for work every minute. Delivery is at least once while retries remain; ordering is not guaranteed. OpenLawn retries unsuccessful requests up to five total attempts, with increasing delays. Return a 2xx response within 10 seconds after durably accepting the event. Redirects are not followed. Delivery logs show status, attempts, and the last HTTP status. Disabling a receiver stops future attempts; an in-flight request may finish.\"}],[\"$\",\"h3\",null,{\"children\":\"Verify the signature\"}],[\"$\",\"p\",null,{\"children\":[\"Read the \",[\"$\",\"code\",null,{\"children\":\"OpenLawn-Signature\"}],\" header. Verify HMAC-SHA256 over \",[\"$\",\"code\",null,{\"children\":\"timestamp + \\\".\\\" + rawBody\"}],\" using the signing secret. Reject timestamps older than five minutes, compare signatures safely, and deduplicate by event ID.\"]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"import { createHmac, timingSafeEqual } from 'node:crypto';\\n\\n// rawBody must be the exact bytes received, BEFORE JSON parsing.\\nexport function verifyWebhook(rawBody, signature, secret) {\\n const match = /^t=(\\\\d+),v1=([a-f0-9]{64})$/.exec(signature || '');\\n if (!match) return false;\\n const timestamp = Number(match[1]);\\n if (Math.abs(Date.now() / 1000 - timestamp) \u003e 300) return false;\\n const expected = createHmac('sha256', secret)\\n .update(match[1] + '.').update(rawBody).digest();\\n return timingSafeEqual(expected, Buffer.from(match[2], 'hex'));\\n}\\n// Reject invalid signatures. Persist valid events before returning 2xx.\\n// Deduplicate by event.id; events can be repeated or arrive out of order.\"}]}],[\"$\",\"h3\",null,{\"children\":\"Receiver safety\"}],[\"$\",\"p\",null,{\"children\":\"This first release supports these approved domains:\"}],[\"$\",\"ul\",null,{\"children\":[[\"$\",\"li\",\"hooks.zapier.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hooks.zapier.com\"}]}],[\"$\",\"li\",\"hook.us1.make.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hook.us1.make.com\"}]}],[\"$\",\"li\",\"hook.us2.make.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hook.us2.make.com\"}]}],[\"$\",\"li\",\"hook.eu1.make.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hook.eu1.make.com\"}]}],[\"$\",\"li\",\"hook.eu2.make.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hook.eu2.make.com\"}]}],[\"$\",\"li\",\"hook.integromat.com\",{\"children\":[\"$\",\"code\",null,{\"children\":\"hook.integromat.com\"}]}]]}],\"$L18\"]}]\n14:[\"$\",\"section\",null,{\"id\":\"errors\",\"children\":[[\"$\",\"span\",null,{\"children\":\"07 / OPERATIONS\"}],[\"$\",\"h2\",null,{\"children\":\"Predictable limits and errors.\"}],[\"$\",\"p\",null,{\"children\":[\"The API allows 120 authenticated requests per workspace per minute, shared by all its keys. A 429 includes \",[\"$\",\"code\",null,{\"children\":\"Retry-After: 60\"}],\". Successful responses include \",[\"$\",\"code\",null,{\"children\":\"X-RateLimit-Limit\"}],\", \",[\"$\",\"code\",null,{\"children\":\"X-RateLimit-Remaining\"}],\", and \",[\"$\",\"code\",null,{\"children\":\"X-Request-Id\"}],\". Workspaces can have 20 active keys and five active receivers; test events are limited to five per receiver per minute.\"]}],[\"$\",\"pre\",null,{\"children\":[\"$\",\"code\",null,{\"children\":\"{\\\"error\\\":{\\\"code\\\":\\\"insufficient_scope\\\",\\\"message\\\":\\\"This endpoint requires measurements:read.\\\"},\\\"request_id\\\":\\\"â¦\\\"}\"}]}
94],[\"$\",\"p\",null,{\"children\":\"400: invalid input. 401: invalid, expired, or revoked key. 403: insufficient scope. 404: unavailable record. 409: idempotency conflict or invalid job state. 413: oversized body. 422: unapproved receiver. 429: rate limit. 503: temporary service failure. Keep request IDs when contacting support; never send your key or webhook secret.\"}],[\"$\",\"p\",null,{\"children\":\"Retry 429 and transient 503 responses with exponential backoff and jitter, retaining the same idempotency key for job submission. Do not automatically repeat successful measurements with a new key.\"}]]}]\n")</script>
94<script>self.__VINEXT_RSC_CHUNKS__=self.__VINEXT_RSC_CHUNKS__||[];self.__VINEXT_RSC_CHUNKS__.push("15:[[[\"$\",\"link\",\"css:/assets/index-DxmyaP73.css\",{\"rel\":\"stylesheet\",\"precedence\":\"vite-rsc/importer-resources\",\"href\":\"/assets/index-DxmyaP73.css\",\"data-rsc-css-href\":\"/assets/index-DxmyaP73.css\"}],\"$undefined\"],[\"$\",\"footer\",null,{\"className\":\"_footer_yjmsp_1\",\"id\":\"footer\",\"aria-label\":\"OpenLawn footer\",\"children\":[\"$\",\"div\",null,{\"className\":\"_inner_yjmsp_2\",\"children\":[[\"$\",\"div\",null,{\"className\":\"_top_yjmsp_2\",\"children\":[[\"$\",\"div\",null,{\"className\":\"_intro_yjmsp_2\",\"children\":[[\"$\",\"$L19\",null,{\"href\":\"/\",\"className\":\"_brand_yjmsp_2\",\"children\":[[\"$\",\"span\",null,{\"className\":\"brand-logo\",\"aria-hidden\":\"true\"}],\"OpenLawn\"]}],[\"$\",\"p\",null,{\"children\":[\"A clearer view of\",[\"$\",\"br\",null,{}],\"your next job.\"]}],[\"$\",\"span\",null,{\"children\":[\"Lawn measurement for the teams\",[\"$\",\"br\",null,{}],\"that take care of the outdoors.\"]}]]}],[\"$\",\"nav\",null,{\"className\":\"_columns_yjmsp_2\",\"aria-label\":\"Footer navigation\",\"children\":[[\"$\",\"div\",\"Product\",{\"children\":[[\"$\",\"h2\",null,{\"children\":\"Product\"}],[\"$\",\"ul\",null,{\"children\":[[\"$\",\"li\",\"/agent\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/agent\",\"children\":\"Agent View\"}]}],[\"$\",\"li\",\"/#how-it-works\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/#how-it-works\",\"children\":\"How it works\"}]}],[\"$\",\"li\",\"/#pricing\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/#pricing\",\"children\":\"Pricing\"}]}],[\"$\",\"li\",\"/billing\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/billing\",\"children\":\"Billing \u0026 credits\"}]}],[\"$\",\"li\",\"/auth/sign-up?next=%2Fagent\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/auth/sign-up?next=%2Fagent\",\"children\":\"Create an account\"}]}]]}]]}],[\"$\",\"div\",\"Explore\",{\"children\":[[\"$\",\"h2\",null,{\"children\":\"Explore\"}],[\"$\",\"ul\",null,{\"children\":[[\"$\",\"li\",\"/lawn-measurement-guide\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/lawn-measurement-guide\",\"children\":\"Measurement guide\"}]}],[\"$\",\"li\",\"/benchmarks/2026-09-29\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/benchmarks/2026-09-29\",\"children\":\"GPT-6.1 Sol case study\"}]}],[\"$\",\"li\",\"/benchmarks/2026-09-22\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/benchmarks/2026-09-22\",\"children\":\"Model benchmark\"}]}],[\"$\",\"li\",\"/developers\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/developers\",\"children\":\"For AI agents\"}]}],[\"$\",\"li\",\"/#questions\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/#questions\",\"children\":\"Questions, answered\"}]}]]}]]}],[\"$\",\"div\",\"Compare\",{\"children\":[[\"$\",\"h2\",null,{\"children\":\"Compare\"}],[\"$\",\"ul\",null,{\"children\":[[\"$\",\"li\",\"/compare\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/compare\",\"children\":\"All comparisons\"}]}],[\"$\",\"li\",\"/compare/deep-lawn\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/compare/deep-lawn\",\"children\":\"OpenLawn vs. Deep Lawn\"}]}],[\"$\",\"li\",\"/compare/find-lot-size\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/compare/find-lot-size\",\"children\":\"OpenLawn vs. FindLotSize\"}]}],[\"$\",\"li\",\"/compare/local-gis\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/compare/local-gis\",\"children\":\"OpenLawn vs. local GIS\"}]}]]}]]}],[\"$\",\"div\",\"Connect\",{\"children\":[[\"$\",\"h2\",null,{\"children\":\"Connect\"}],[\"$\",\"ul\",null,{\"children\":[[\"$\",\"li\",\"/docs\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/docs\",\"children\":\"API documentation\"}]}],[\"$\",\"li\",\"/settings/api\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/settings/api\",\"children\":\"API keys \u0026 webhooks\"}]}],[\"$\",\"li\",\"mailto:[email protected]\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"mailto:[email protected]\",\"children\":\"Contact support â\"}]}],[\"$\",\"li\",\"/privacy\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/privacy\",\"children\":\"Privacy policy\"}]}],[\"$\",\"li\",\"/developers#install\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/developers#install\",\"children\":\"Agent documentation\"}]}],[\"$\",\"li\",\"/llms.txt\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/llms.txt\",\"children\":\"AI-readable overview\"}]}],[\"$\",\"li\",\"/sitemap.xml\",{\"children\":[\"$\",\"$L19\",null,{\"href\":\"/sitemap.xml\",\"children\":\"Sitemap\"}]}]]}]]}]]}]]}],[\"$\",\"$L19\",null,{\"href\":\"/\",\"className\":\"_wordmark_yjmsp_2\",\"aria-label\":\"OpenLawn home\",\"children\":\"OpenLawn\"}],[\"$\",\"div\",null,{\"className\":\"_bottom_yjmsp_2\",\"children\":[[\"$\",\"span\",null,{\"children\":[\"© \",2026,\" Clicki, Inc.\"]}],[\"$\",\"span\",null,{\"children\":\"Aerial estimates. Human judgment.\"}],[\"$\",\"a\",null,{\"href\":\"#top\",\"children\":[\"Back to top \",[\"$\",\"span\",null,{\"aria-hidden\":\"true\",\"children\":\"â\"}]]}]]}],[\"$\",\"p\",null,{\"className\":\"_note_yjmsp_2\",\"children\":\"Review every measurement before quoting. Aerial estimates and parcel overlays are not legal surveys.\"}],[\"$\",\"p\",null,{\"className\":\"_note_yjmsp_2\",\"children\":[[\"$\",\"$L1a\",null,{}],\" · \",[\"$\",\"$L19\",null,{\"href\":\"/privacy#session-recording\",\"children\":\"Privacy choices\"}]]}]]}]}]]\n16:[\"$\",\"small\",null,{\"children\":\"webhooks:read\"}]\n17:[\"$\",\"p\",null,{\"children\":[[\"$\",\"a\",null,{\"href\":\"/openapi.json\",\"children\":\"Download the machine-readable OpenAPI specification\"}],\" for request schemas and response fields.\"]}]\n18:[\"$\",\"p\",null,{\"children\":[\"For your own server, contact \",[\"$\",\"a\",null,{\"href\":\"mailto:[email protected]\",\"children\":\"[email protected]\"}],\" to approve its public HTTPS hostname. Private IPs, arbitrary domains, custom ports, and redirects are not accepted. Receiver creation alone does not make an unapproved domain eligible.\"]}]\n")</script>
94<script>self.__VINEXT_RSC_DONE__=true</script>
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.