Partner Jobs API
Feed quoted, sold jobs into the Lawnager pro network. You post a job with the bid price, photos, and measurements; opted-in pros in your target market get an instant push + email; the first pro to accept wins; you receive a signed job.acceptedwebhook with the confirmed pro’s contact details. The pro runs the work in their own Lawnager account — your app keeps your sales CRM.
Base URL: https://app.lawnager.com
Authentication
Every request carries the API key issued during partner onboarding (shown once — keep it secret; we store only a hash):
Authorization: Bearer <api_key>Beta constraints: jobs must fall inside your configured target market(s), and lawn & landscaping services only.
POST /api/partner/v1/jobs
Create a job offer.
{
"external_ref": "your-crm-job-123",
"service_name": "Fall Cleanup",
"bid_amount": 450.00,
"description": "Front + back yard, heavy leaf cover, two large oaks.",
"measurements": { "lawn_sqft": 8200, "beds_sqft": 600 },
"materials": [
{ "name": "Hardwood mulch", "quantity": 10, "unit": "yd", "estimated_cost": 350.00 }
],
"materials_provided_by": "pro",
"photo_urls": ["https://your-cdn.example.com/job123-front.jpg"],
"homeowner_first_name": "Dana",
"homeowner_last_name": "Miller",
"homeowner_phone": "+14175551234",
"homeowner_email": "dana@example.com",
"address": "417 Oakwood Dr",
"city": "Springfield",
"state_code": "MO",
"zip": "65804",
"preferred_window": "This week, mornings",
"expires_in_minutes": 240
}Required: service_name, bid_amount (> 0), homeowner_first_name, address, city, state_code, and at least one of homeowner_phone / homeowner_email. photo_urls must be https (max 10). expires_in_minutesdefaults to 240, clamped 30–10080 — quoted homeowners don’t wait, keep it short.
Materials: when the job includes materials, declare them — each line needs a name; quantity, unit, and estimated_cost (line total, your estimate) are optional; max 25 lines. materials_provided_by ("pro" | "partner" | "homeowner") is required whenever materials are given — who buys the mulch changes the pro’s real take as much as the referral fee does, so it’s shown to pros before they accept. A job where the pro supplies expensive materials on a thin bid will simply expire; price accordingly.
Privacy model: pros see the service, price, city/zip, description, measurements, materials, and photos — the street address and homeowner contact are revealed only to the pro who accepts.
Responses:
201 { "id": "<uuid>", "status": "offered", "offered_to": 4,
"expires_at": "...", "lawnager_fee_pct": 8,
"lawnager_fee_amount": 36.00, "pro_net_amount": 414.00 }
400 missing/invalid fields
401 bad API key
422 outside your target markets, or no pros currently cover that market
(treat as "don't sell here yet" and tell us — supply is recruited
market-by-market)GET /api/partner/v1/jobs/{id}
Poll a job (reconciliation; the webhook is the push channel).
{
"id": "<uuid>",
"external_ref": "your-crm-job-123",
"status": "offered | accepted | expired | cancelled",
"service_name": "Fall Cleanup",
"bid_amount": 450,
"market": "Springfield, MO",
"offered_to": 4,
"declined_by": 1,
"accepted_by": { "name": "Joe's Lawn Care", "phone": "+1417...", "email": "joe@..." },
"accepted_at": "...",
"expires_at": "...",
"created_at": "..."
}accepted_by is null until a pro accepts. A job past expires_at with no acceptance reads as expired.
Webhook: job.accepted
POSTed to your configured webhook URL the moment a pro accepts:
{
"event": "job.accepted",
"sent_at": "2026-09-12T15:04:05Z",
"data": {
"id": "<lawnager job offer uuid>",
"external_ref": "your-crm-job-123",
"accepted_at": "...",
"pro": { "name": "Joe's Lawn Care", "phone": "+1417...", "email": "joe@..." },
"bid_amount": 450.00,
"lawnager_fee_pct": 8,
"lawnager_fee_amount": 36.00,
"pro_net_amount": 414.00
}
}Headers: X-Lawnager-Event: job.accepted and X-Lawnager-Signature: sha256=<hmac> — HMAC-SHA256 of the raw request body with your webhook secret. Verify before trusting:
const crypto = require('crypto')
function verify(rawBody, signature, secret) {
const expected = 'sha256=' +
crypto.createHmac('sha256', secret).update(rawBody).digest('hex')
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature))
}Respond 2xx quickly. Delivery is attempted once at accept time; use the status endpoint to reconcile anything missed.
Referral fee & settlement
Lawnager’s referral fee is a fixed percentage of bid_amount, configured per partner and snapshotted onto each job at creation (echoed in the 201 response and the webhook). The pro sees their net amount before accepting — fee transparency is deliberate on both sides. While your app collects from the homeowner, you withhold lawnager_fee_amount and settle monthly against the ledger; if payment later rides Lawnager’s Stripe rails, the fee becomes automatic.
Price your quotes with the full fee stack in mind — a bid whose net is below what pros will take just expires, which helps nobody at the door.
Getting access
The program launches market by market so every job has committed pros behind it. Email rbowers@lawnager.com with where you sell and your expected volume — we’ll set up your market, mint your API key and webhook secret, and agree a price book.