Skip to Content
DocumentationAPI ReferenceOverview

API Overview

The LawnLedger CRM API is a RESTful JSON API that allows you to integrate with your LawnLedger data programmatically. All endpoints are prefixed with /api/ and return JSON responses.

Base URL

https://api.lawnledgercrm.com

For local development:

http://localhost:3000

Authentication

Most API requests use cookie-based session authentication - the same session your browser holds after signing in.

There is a second path: API keys, for server-to-server integrations that have no browser session. API keys require the apiAccess feature (Business plan). New API keys are coming soon: for now no one can create one, and keys that already exist keep working. The Zapier integration is coming soon too: it opens once Zapier has its own set of key permissions. The mobile app and the customer portal each authenticate differently again, with their own tokens.

API keys

Creating new API keys is paused for now. If your business already has keys, they keep working, and you can see and revoke them under Settings → Integrations → API keys. The rest of this section describes how a key behaves.

Each key carries its own permissions, picked when it was created - Read-only, or Custom from the permissions its creator holds - and the key is shown once. Send it as a bearer token:

curl https://api.lawnledgercrm.com/api/customers \ -H "Authorization: Bearer llk_live_..."

A key reaches these endpoints, each with the permission named:

EndpointPermission
GET /api/customers, GET /api/customers/:idcustomers.view
POST /api/customers · PATCH /api/customers/:id · DELETE /api/customers/:idcustomers.create · customers.edit · customers.delete
GET /api/properties, GET /api/properties/:idproperties.view
POST /api/properties · PUT/PATCH /api/properties/:id · DELETE /api/properties/:idproperties.create · properties.edit · properties.delete
GET /api/jobs, GET /api/jobs/:idjobs.view
POST /api/jobs · PUT /api/jobs/:id · DELETE /api/jobs/:idjobs.create · jobs.edit · jobs.delete
GET /api/estimates, GET /api/estimates/:idestimates.view
POST /api/estimates · PUT /api/estimates/:id · DELETE /api/estimates/:idestimates.create · estimates.edit · estimates.delete
GET /api/invoices, GET /api/invoices/:id, GET /api/invoices/:id/paymentsinvoices.view
POST /api/invoices · PUT /api/invoices/:id · DELETE /api/invoices/:idinvoices.create · invoices.edit · invoices.delete
POST /api/invoices/:id/paymentsinvoices.record_payment
GET /api/expenses, GET /api/expenses/:id · POST /api/expensesexpenses.view · expenses.create

Anything else answers 403 with API_KEY_ROUTE_NOT_ALLOWED, and a listed endpoint without its permission answers 403 with API_KEY_SCOPE_MISSING (the required field names the permission). A key never does more than the person who created it can do today, and never anything an admin does - settings, your team, billing, integrations, or moving money.

Keys created before key permissions existed show as Legacy on the keys page. While new keys are paused, legacy keys keep working with no end date, because there is no way to create a replacement. When new keys open again, the creator of each legacy key is emailed before anything changes, with what the key has been calling and a link to a replacement.

Logging In

To authenticate, send a POST request to the auth endpoint:

curl -X POST https://api.lawnledgercrm.com/api/auth/sign-in/email \ -H "Content-Type: application/json" \ -c cookies.txt \ -d '{ "email": "you@example.com", "password": "your-password" }'

The -c cookies.txt flag saves the session cookie to a file. Use -b cookies.txt on subsequent requests to include it.

Authenticated Requests

curl https://api.lawnledgercrm.com/api/customers \ -b cookies.txt

All API requests (except auth endpoints) require authentication. Unauthenticated requests return a 401 Unauthorized response.

Response Format

All successful responses follow a consistent envelope format:

{ "data": { ... } }

The data field contains the response payload (an object, array, or primitive).

Error Responses

Errors return an error object with a message and code:

{ "error": { "message": "Customer not found", "code": "NOT_FOUND" } }

HTTP status codes:

CodeMeaning
200Success
201Created
204No Content (empty body)
400Bad Request (validation error)
401Unauthorized (not logged in)
403Forbidden (insufficient permissions)
404Not Found
429Too Many Requests (rate limited)
500Internal Server Error

Multi-Tenancy

LawnLedger is a multi-tenant application. All data is scoped to your organization automatically based on your session. You do not need to pass an organization ID in most requests.

Rate Limiting

API requests are rate-limited to prevent abuse. If you exceed the rate limit, you will receive a 429 response. Wait and retry after the indicated period.

The API is designed for integration purposes. For high-volume data access, consider using the bulk export features available in the app settings.

Available Endpoints

ResourceBase Path
Customers/api/customers
Invoices/api/invoices
Estimates/api/estimates
Contracts/api/contracts
Jobs/api/jobs
Webhooks/api/webhooks
Properties/api/properties
Services/api/services
Payments (Stripe intents, refunds, reconciliation)/api/payments
Equipment/api/equipment
Time Tracking/api/crew-tracking
Winter Routes/api/winter-routes
Dashboard/api/dashboard
Settings/api/settings
Last updated on