Jump to an endpoint

Reference

HailMate API reference

Jobs, contacts, tasks, money, photos, door knocks and hail history for your HailMate workspace. Requests and responses are JSON. Lists are newest first and paged with a cursor. New to the API? Start with the overview and quickstart.

Base URL
https://app.hailmate.ai/api/v1
Authentication
Authorization: Bearer hm_live_… on every request. Keys
OpenAPI 3.1
openapi.yaml · openapi.json

Endpoints

Connection

Check a key and see which workspace it belongs to.

Check a key

GET/ping

The cheapest authenticated call. Returns the workspace the key belongs to and what the key may do. /me is the same endpoint.

Returns

200The key is valid. A Ping object.

  • 401unauthorizedThe key is missing, wrong or revoked.
  • 402plan_requiredThe workspace has no active subscription.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/ping \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "ok": true,
  "object": "workspace",
  "workspace_id": "5f0c2a8e-1b3d-4c7a-9e21-7a3b8d4c6e10",
  "workspace": "Ridgeline Roofing",
  "api_version": "v1",
  "key": {
    "name": "Zapier",
    "access": "write"
  }
}

Endpoints

Jobs

The storm-restoration jobs on your pipeline boards.

List jobs

GET/jobs

Newest first. Archived jobs are left out unless you ask for them.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • stagestring

    A stage key from /stages.

  • pipeline_idstringuuid
  • job_typestring
    insuranceretail
  • assigned_tostringuuid

    A user id. Matches the primary assignee OR any co-assignee.

  • contact_idstringuuid

    Jobs where this contact is the homeowner, the adjuster, or a secondary contact.

  • archivedstring

    Omitted, only live jobs. true returns archived jobs, any returns both.

    trueany

Returns

200A page of jobs. A page of Job objects in data, with has_more and next_cursor.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs?stage=claim_approved&limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "object": "job",
      "job_number": "JOB-00142",
      "name": "1804 Cedar Ridge Dr",
      "job_type": "insurance",
      "stage": "inspection_scheduled",
      "stage_label": "Inspection Scheduled",
      "stage_is_completed": false,
      "stage_is_lost": false,
      "stage_entered_at": "2026-09-16T14:02:00.000Z",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "pipeline_name": "Insurance",
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "county": "Collin",
      "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "homeowner": {
        "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
        "name": "Dana Reed",
        "email": "dana@example.com",
        "phone": "(972) 555-0148"
      },
      "adjuster_id": null,
      "adjuster": null,
      "secondary_contact_ids": [],
      "secondary_adjuster_ids": [],
      "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "assigned_to_name": "Sam Carter",
      "assignee_ids": [
        "5d0e1c2b-7777-4000-8000-0000000000ab"
      ],
      "assignee_names": [
        "Sam Carter"
      ],
      "insurance_company": "Example Mutual",
      "claim_number": "CLM-88213",
      "policy_number": null,
      "date_of_loss": "2026-09-12",
      "damage_types": [
        "hail"
      ],
      "tags": [],
      "lead_source": "Website",
      "priority": "normal",
      "mortgage_company": null,
      "financing_method": null,
      "rcv_amount": 24380.5,
      "acv_amount": 19240,
      "deductible": 2500,
      "supplements_amount": null,
      "estimated_amount": null,
      "final_amount": null,
      "total_job_value": 24380.5,
      "amount_received": 0,
      "balance_due": 24380.5,
      "contract_date": null,
      "installation_date": null,
      "archived": false,
      "completed_at": null,
      "lost_at": null,
      "lost_reason": null,
      "created_at": "2026-09-16T14:02:00.000Z",
      "updated_at": "2026-09-16T14:02:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
      "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
    }
  ]
}

Create a job

POST/jobs

Only name and address are required. With no stage the job lands on the first column of your default pipeline. stage may be a stage key or its label as your board shows it ("Claim Approved"). notes, when sent, becomes the first note on the job's timeline.

A homeowner, adjuster or assignee named by id must belong to this workspace. The new job fires job.created.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • namestringRequired

    job_name works too.

    Up to 200 characters

  • addressstringRequired

    property_address works too.

    Up to 300 characters

  • citystring
  • statestring

    A code or a name — "TX" or "Texas".

  • postal_codestring

    zip works too.

  • countystring
  • job_typestring
    insuranceretail

    Default insurance

  • stagestring

    A stage key or label. Defaults to the first stage of the default pipeline.

  • pipeline_idstringuuid
  • homeowner_idstringuuid
  • adjuster_idstringuuid
  • assigned_tostringuuid

    A teammate's user id from /users.

  • lead_sourcestring
  • prioritystring
    lownormalhighurgent
  • insurance_companystring
  • claim_numberstring
  • policy_numberstring
  • date_of_lossstringdate
  • mortgage_companystring
  • financing_methodstring
    cashcheckcredit_cardfinancingother
  • rcv_amountnumber
  • acv_amountnumber
  • deductiblenumber
  • supplements_amountnumber
  • estimated_amountnumber
  • final_amountnumber
  • contract_datestringdate
  • installation_datestringdate
  • damage_typesarray of string

    Or a comma-separated string.

  • tagsarray of string

    Or a comma-separated string.

  • notesstring

    Becomes the first note on the job.

Returns

201Created. A Job object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 403forbiddenA read-only key tried to change something.
  • 409conflictAn Idempotency-Key clash — reused for a different request, or the first is still running.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/jobs \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "name": "1804 Cedar Ridge Dr",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "job_type": "insurance",
  "stage": "Inspection Scheduled",
  "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "lead_source": "Website",
  "insurance_company": "Example Mutual",
  "claim_number": "CLM-88213",
  "notes": "Homeowner reports hail on the back slope."
}'
Response · 201
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "job_number": "JOB-00142",
  "name": "1804 Cedar Ridge Dr",
  "job_type": "insurance",
  "stage": "inspection_scheduled",
  "stage_label": "Inspection Scheduled",
  "stage_is_completed": false,
  "stage_is_lost": false,
  "stage_entered_at": "2026-09-16T14:02:00.000Z",
  "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "pipeline_name": "Insurance",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "county": "Collin",
  "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "homeowner": {
    "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
    "name": "Dana Reed",
    "email": "dana@example.com",
    "phone": "(972) 555-0148"
  },
  "adjuster_id": null,
  "adjuster": null,
  "secondary_contact_ids": [],
  "secondary_adjuster_ids": [],
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "assignee_ids": [
    "5d0e1c2b-7777-4000-8000-0000000000ab"
  ],
  "assignee_names": [
    "Sam Carter"
  ],
  "insurance_company": "Example Mutual",
  "claim_number": "CLM-88213",
  "policy_number": null,
  "date_of_loss": "2026-09-12",
  "damage_types": [
    "hail"
  ],
  "tags": [],
  "lead_source": "Website",
  "priority": "normal",
  "mortgage_company": null,
  "financing_method": null,
  "rcv_amount": 24380.5,
  "acv_amount": 19240,
  "deductible": 2500,
  "supplements_amount": null,
  "estimated_amount": null,
  "final_amount": null,
  "total_job_value": 24380.5,
  "amount_received": 0,
  "balance_due": 24380.5,
  "contract_date": null,
  "installation_date": null,
  "archived": false,
  "completed_at": null,
  "lost_at": null,
  "lost_reason": null,
  "created_at": "2026-09-16T14:02:00.000Z",
  "updated_at": "2026-09-16T14:02:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
  "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
}

Find jobs

GET/jobs/search

address and name match part of the value ("1804 Cedar" finds "1804 Cedar Ridge Dr"); job_number and claim_number must match whole (case-insensitive). With no criteria the result is EMPTY — never "the newest jobs", which is how a blank search step writes to the wrong job.

Query parameters

  • addressstring
  • job_numberstring
  • claim_numberstring
  • namestring
  • contact_idstringuuid
  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

Returns

200Matching jobs, newest first. Not paged. A page of Job objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/search?address=1804%20Cedar" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "object": "job",
      "job_number": "JOB-00142",
      "name": "1804 Cedar Ridge Dr",
      "job_type": "insurance",
      "stage": "inspection_scheduled",
      "stage_label": "Inspection Scheduled",
      "stage_is_completed": false,
      "stage_is_lost": false,
      "stage_entered_at": "2026-09-16T14:02:00.000Z",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "pipeline_name": "Insurance",
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "county": "Collin",
      "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "homeowner": {
        "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
        "name": "Dana Reed",
        "email": "dana@example.com",
        "phone": "(972) 555-0148"
      },
      "adjuster_id": null,
      "adjuster": null,
      "secondary_contact_ids": [],
      "secondary_adjuster_ids": [],
      "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "assigned_to_name": "Sam Carter",
      "assignee_ids": [
        "5d0e1c2b-7777-4000-8000-0000000000ab"
      ],
      "assignee_names": [
        "Sam Carter"
      ],
      "insurance_company": "Example Mutual",
      "claim_number": "CLM-88213",
      "policy_number": null,
      "date_of_loss": "2026-09-12",
      "damage_types": [
        "hail"
      ],
      "tags": [],
      "lead_source": "Website",
      "priority": "normal",
      "mortgage_company": null,
      "financing_method": null,
      "rcv_amount": 24380.5,
      "acv_amount": 19240,
      "deductible": 2500,
      "supplements_amount": null,
      "estimated_amount": null,
      "final_amount": null,
      "total_job_value": 24380.5,
      "amount_received": 0,
      "balance_due": 24380.5,
      "contract_date": null,
      "installation_date": null,
      "archived": false,
      "completed_at": null,
      "lost_at": null,
      "lost_reason": null,
      "created_at": "2026-09-16T14:02:00.000Z",
      "updated_at": "2026-09-16T14:02:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
      "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
    }
  ]
}

Get a job

GET/jobs/{id}

Path parameters

  • idstringuuidRequired

Returns

200The job. A Job object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "job_number": "JOB-00142",
  "name": "1804 Cedar Ridge Dr",
  "job_type": "insurance",
  "stage": "inspection_scheduled",
  "stage_label": "Inspection Scheduled",
  "stage_is_completed": false,
  "stage_is_lost": false,
  "stage_entered_at": "2026-09-16T14:02:00.000Z",
  "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "pipeline_name": "Insurance",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "county": "Collin",
  "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "homeowner": {
    "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
    "name": "Dana Reed",
    "email": "dana@example.com",
    "phone": "(972) 555-0148"
  },
  "adjuster_id": null,
  "adjuster": null,
  "secondary_contact_ids": [],
  "secondary_adjuster_ids": [],
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "assignee_ids": [
    "5d0e1c2b-7777-4000-8000-0000000000ab"
  ],
  "assignee_names": [
    "Sam Carter"
  ],
  "insurance_company": "Example Mutual",
  "claim_number": "CLM-88213",
  "policy_number": null,
  "date_of_loss": "2026-09-12",
  "damage_types": [
    "hail"
  ],
  "tags": [],
  "lead_source": "Website",
  "priority": "normal",
  "mortgage_company": null,
  "financing_method": null,
  "rcv_amount": 24380.5,
  "acv_amount": 19240,
  "deductible": 2500,
  "supplements_amount": null,
  "estimated_amount": null,
  "final_amount": null,
  "total_job_value": 24380.5,
  "amount_received": 0,
  "balance_due": 24380.5,
  "contract_date": null,
  "installation_date": null,
  "archived": false,
  "completed_at": null,
  "lost_at": null,
  "lost_reason": null,
  "created_at": "2026-09-16T14:02:00.000Z",
  "updated_at": "2026-09-16T14:02:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
  "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
}

Update a job

PATCH/jobs/{id}

Send only the fields to change. A field sent as null (or "") is cleared; a field left out is untouched. name and address cannot be cleared.

Moving a job is {"stage": "Claim Approved"} — a key or a label. It runs every stage automation, writes the timeline entry and fires job.stage_changed, exactly as dragging the card does. Setting assigned_to makes that teammate the primary assignee.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • namestring
  • addressstring
  • citystring | null
  • statestring | null
  • postal_codestring | null
  • countystring | null
  • job_typestring
    insuranceretail
  • stagestring
  • pipeline_idstringuuid
  • homeowner_idstring | nulluuid
  • adjuster_idstring | nulluuid
  • assigned_tostring | nulluuid
  • lead_sourcestring | null
  • prioritystring | null
    lownormalhighurgent
  • insurance_companystring | null
  • claim_numberstring | null
  • policy_numberstring | null
  • date_of_lossstring | nulldate
  • mortgage_companystring | null
  • financing_methodstring | null
  • rcv_amountnumber | null
  • acv_amountnumber | null
  • deductiblenumber | null
  • supplements_amountnumber | null
  • estimated_amountnumber | null
  • final_amountnumber | null
  • contract_datestring | nulldate
  • installation_datestring | nulldate
  • damage_typesarray of string | null
  • tagsarray of string | null
  • archivedboolean
  • lost_reasonstring | null

Returns

200The job, as it is now. A Job object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 403forbiddenA read-only key tried to change something.
  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "stage": "claim_approved",
  "rcv_amount": 24380.5,
  "assigned_to": "5d0e1c2b-7777-4000-8000-0000000000ab"
}'
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "job_number": "JOB-00142",
  "name": "1804 Cedar Ridge Dr",
  "job_type": "insurance",
  "stage": "inspection_scheduled",
  "stage_label": "Inspection Scheduled",
  "stage_is_completed": false,
  "stage_is_lost": false,
  "stage_entered_at": "2026-09-16T14:02:00.000Z",
  "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "pipeline_name": "Insurance",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "county": "Collin",
  "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "homeowner": {
    "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
    "name": "Dana Reed",
    "email": "dana@example.com",
    "phone": "(972) 555-0148"
  },
  "adjuster_id": null,
  "adjuster": null,
  "secondary_contact_ids": [],
  "secondary_adjuster_ids": [],
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "assignee_ids": [
    "5d0e1c2b-7777-4000-8000-0000000000ab"
  ],
  "assignee_names": [
    "Sam Carter"
  ],
  "insurance_company": "Example Mutual",
  "claim_number": "CLM-88213",
  "policy_number": null,
  "date_of_loss": "2026-09-12",
  "damage_types": [
    "hail"
  ],
  "tags": [],
  "lead_source": "Website",
  "priority": "normal",
  "mortgage_company": null,
  "financing_method": null,
  "rcv_amount": 24380.5,
  "acv_amount": 19240,
  "deductible": 2500,
  "supplements_amount": null,
  "estimated_amount": null,
  "final_amount": null,
  "total_job_value": 24380.5,
  "amount_received": 0,
  "balance_due": 24380.5,
  "contract_date": null,
  "installation_date": null,
  "archived": false,
  "completed_at": null,
  "lost_at": null,
  "lost_reason": null,
  "created_at": "2026-09-16T14:02:00.000Z",
  "updated_at": "2026-09-16T14:02:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
  "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
}

Delete a job

DELETE/jobs/{id}

The job goes to Settings → Recently Deleted for 30 days with everything on it, and can be restored from there. Fires job.deleted.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Returns

200Deleted. A Deleted object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true
}

List a job's notes

GET/jobs/{id}/notes

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of notes. A page of Note objects in data, with has_more and next_cursor.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/notes?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "3c8b1a07-6666-4000-8000-0000000000b4",
      "object": "note",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "content": "Adjuster meeting moved to Thursday 10am. Homeowner will be home.",
      "author_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "author_name": "Sam Carter",
      "created_at": "2026-09-27T14:20:00.000Z",
      "updated_at": "2026-09-27T14:20:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

List a job's photos and documents

GET/jobs/{id}/files

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • categorystring
    photodocumentscopeestimatecontractother

Returns

200A page of files. A page of File objects in data, with has_more and next_cursor.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/files?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "7e2d9c40-8888-4000-8000-0000000000a5",
      "object": "file",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "name": "north-slope-hits.jpg",
      "category": "photo",
      "mime_type": "image/jpeg",
      "is_photo": true,
      "is_video": false,
      "size_bytes": 1532410,
      "description": "Hail hits on the north slope, chalked",
      "tags": [
        "damage",
        "north slope"
      ],
      "latitude": 33.0726,
      "longitude": -96.7512,
      "taken_at": "2026-09-16T15:12:08.000Z",
      "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "uploaded_by_name": "Sam Carter",
      "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
      "created_at": "2026-09-16T15:12:40.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

List a job's photos

GET/jobs/{id}/photos

/jobs/{id}/files?category=photo, as its own path.

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of photos. A page of File objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/photos?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "7e2d9c40-8888-4000-8000-0000000000a5",
      "object": "file",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "name": "north-slope-hits.jpg",
      "category": "photo",
      "mime_type": "image/jpeg",
      "is_photo": true,
      "is_video": false,
      "size_bytes": 1532410,
      "description": "Hail hits on the north slope, chalked",
      "tags": [
        "damage",
        "north slope"
      ],
      "latitude": 33.0726,
      "longitude": -96.7512,
      "taken_at": "2026-09-16T15:12:08.000Z",
      "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "uploaded_by_name": "Sam Carter",
      "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
      "created_at": "2026-09-16T15:12:40.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

List a job's tasks and appointments

GET/jobs/{id}/tasks

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of tasks. A page of Task objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/tasks?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
      "object": "task",
      "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
      "description": null,
      "due_date": "2026-10-02T15:00:00",
      "end_date": null,
      "duration_minutes": 60,
      "priority": "normal",
      "completed": false,
      "completed_at": null,
      "is_appointment": true,
      "appointment_type": "adjuster_meeting",
      "outcome": null,
      "customer_reminder": "sms",
      "reminder_minutes": 60,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "assigned_to_name": "Sam Carter",
      "created_at": "2026-09-16T14:10:00.000Z",
      "updated_at": "2026-09-16T14:10:00.000Z",
      "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
    }
  ]
}

List a job's estimates

GET/jobs/{id}/estimates

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of estimates. A page of Estimate objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/estimates?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "a41c9e20-2222-4000-8000-0000000000e1",
      "object": "estimate",
      "estimate_number": "EST-0214",
      "title": "Roof replacement — 1804 Cedar Ridge Dr",
      "document_type": "proposal",
      "status": "sent",
      "signature_status": "pending",
      "total": 21900,
      "package_totals": {
        "good": 18450,
        "better": 21900,
        "best": 26400
      },
      "upgrades_total": 1250,
      "selected_tier": null,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "valid_until": "2026-10-28T00:00:00.000Z",
      "sent_at": "2026-09-28T15:10:00.000Z",
      "first_viewed_at": "2026-09-28T18:42:00.000Z",
      "last_viewed_at": "2026-09-28T19:05:00.000Z",
      "view_count": 3,
      "signed_at": null,
      "signer_name": null,
      "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
      "signed_pdf_url": null,
      "created_at": "2026-09-27T21:30:00.000Z",
      "updated_at": "2026-09-28T19:05:00.000Z",
      "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
      "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
    }
  ]
}

List a job's invoices

GET/jobs/{id}/invoices

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of invoices. A page of Invoice objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/invoices?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "c90d7b31-3333-4000-8000-0000000000f2",
      "object": "invoice",
      "invoice_number": "INV-0311",
      "title": "Deductible",
      "status": "sent",
      "purpose": "deductible",
      "subtotal": 2500,
      "discount_amount": 0,
      "tax_amount": 0,
      "late_fee_amount": 0,
      "total_amount": 2500,
      "amount_paid": 0,
      "balance_due": 2500,
      "part_number": null,
      "part_count": null,
      "issue_date": "2026-09-28",
      "due_date": "2026-10-12",
      "sent_at": "2026-09-28T16:00:00.000Z",
      "first_viewed_at": null,
      "paid_at": null,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "estimate_id": null,
      "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
      "created_at": "2026-09-28T15:55:00.000Z",
      "updated_at": "2026-09-28T16:00:00.000Z",
      "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
      "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
    }
  ]
}

List a job's payments

GET/jobs/{id}/payments

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of payments. A page of Payment objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/jobs/f2b1a0c4-1111-4000-8000-0000000000aa/payments?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "9fa3e1d2-5555-4000-8000-0000000000c3",
      "object": "payment",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "invoice_id": null,
      "amount": 13164,
      "payment_type": "acv",
      "payer_type": "insurance",
      "payment_method": "check",
      "status": "received",
      "check_number": "4471",
      "date_received": "2026-09-26",
      "date_deposited": null,
      "notes": "First ACV check from Example Mutual",
      "is_refund": false,
      "refund_of_payment_id": null,
      "online": false,
      "created_at": "2026-09-26T20:14:00.000Z",
      "updated_at": "2026-09-26T20:14:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

Endpoints

Contacts

Homeowners, adjusters, subcontractors and everyone else in your book.

List contacts

GET/contacts

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • typestring
    homeownercommercialadjustercontractorsubcontractorinstall_crewinspectormortgage_companyother
  • assigned_tostringuuid

Returns

200A page of contacts. A page of Contact objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/contacts?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "object": "contact",
      "first_name": "Dana",
      "last_name": "Reed",
      "full_name": "Dana Reed",
      "email": "dana@example.com",
      "phone": "(972) 555-0148",
      "company": null,
      "type": "homeowner",
      "trades": [],
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "notes": null,
      "claim_number": null,
      "adjuster_type": null,
      "adjuster_extension": null,
      "assigned_to_id": null,
      "assigned_to_name": null,
      "created_at": "2026-09-16T13:40:00.000Z",
      "updated_at": "2026-09-16T13:40:00.000Z",
      "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
    }
  ]
}

Create a contact

POST/contacts

At least one of a name, email, phone or company is required — a contact with none of them is refused rather than filling your CRM with blank rows. Send name alone and it is split into first and last.

US phone numbers are stored as (615) 555-0148, the way your team types them. sms_consent cannot be set: no integration can establish that a homeowner agreed to be texted.

To avoid duplicates, search first — GET /contacts/search matches a phone number however it was typed.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • namestring

    A full name, split into first and last when those are not sent.

  • first_namestring
  • last_namestring
  • emailstringemail
  • phonestring

    Any format.

  • companystring
  • typestring
    homeownercommercialadjustercontractorsubcontractorinstall_crewinspectormortgage_companyother
  • tradesarray of string
  • addressstring
  • citystring
  • statestring
  • postal_codestring
  • notesstring
  • claim_numberstring
  • adjuster_typestring
  • adjuster_extensionstring
  • assigned_tostringuuid

Returns

201Created. A Contact object.

  • 400invalid_requestSomething in the request was wrong; field names what.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/contacts \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "first_name": "Dana",
  "last_name": "Reed",
  "email": "dana@example.com",
  "phone": "+19725550148",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024"
}'
Response · 201
{
  "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "object": "contact",
  "first_name": "Dana",
  "last_name": "Reed",
  "full_name": "Dana Reed",
  "email": "dana@example.com",
  "phone": "(972) 555-0148",
  "company": null,
  "type": "homeowner",
  "trades": [],
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "notes": null,
  "claim_number": null,
  "adjuster_type": null,
  "adjuster_extension": null,
  "assigned_to_id": null,
  "assigned_to_name": null,
  "created_at": "2026-09-16T13:40:00.000Z",
  "updated_at": "2026-09-16T13:40:00.000Z",
  "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
}

Find contacts

GET/contacts/search

Tries email first, then phone, then name, and returns the first that matches. A phone number matches however it was typed into HailMate — +16155550148, 615-555-0148 and (615) 555-0148 are the same number. name matches a first name, last name, "first last" or a company. With no criteria the result is empty.

Query parameters

  • emailstring
  • phonestring
  • namestring
  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

Returns

200Matching contacts. Not paged. A page of Contact objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/contacts/search?phone=972-555-0148" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "object": "contact",
      "first_name": "Dana",
      "last_name": "Reed",
      "full_name": "Dana Reed",
      "email": "dana@example.com",
      "phone": "(972) 555-0148",
      "company": null,
      "type": "homeowner",
      "trades": [],
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "notes": null,
      "claim_number": null,
      "adjuster_type": null,
      "adjuster_extension": null,
      "assigned_to_id": null,
      "assigned_to_name": null,
      "created_at": "2026-09-16T13:40:00.000Z",
      "updated_at": "2026-09-16T13:40:00.000Z",
      "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
    }
  ]
}

Get a contact

GET/contacts/{id}

Path parameters

  • idstringuuidRequired

Returns

200The contact. A Contact object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/contacts/b7c2d3e4-4444-4000-8000-0000000000dd \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "object": "contact",
  "first_name": "Dana",
  "last_name": "Reed",
  "full_name": "Dana Reed",
  "email": "dana@example.com",
  "phone": "(972) 555-0148",
  "company": null,
  "type": "homeowner",
  "trades": [],
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "notes": null,
  "claim_number": null,
  "adjuster_type": null,
  "adjuster_extension": null,
  "assigned_to_id": null,
  "assigned_to_name": null,
  "created_at": "2026-09-16T13:40:00.000Z",
  "updated_at": "2026-09-16T13:40:00.000Z",
  "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
}

Update a contact

PATCH/contacts/{id}

Send only the fields to change; null clears a field.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • first_namestring | null
  • last_namestring | null
  • emailstring | null
  • phonestring | null
  • companystring | null
  • typestring
    homeownercommercialadjustercontractorsubcontractorinstall_crewinspectormortgage_companyother
  • tradesarray of string | null
  • addressstring | null
  • citystring | null
  • statestring | null
  • postal_codestring | null
  • notesstring | null
  • claim_numberstring | null
  • adjuster_typestring | null
  • adjuster_extensionstring | null
  • assigned_tostring | nulluuid

Returns

200The contact, as it is now. A Contact object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/contacts/b7c2d3e4-4444-4000-8000-0000000000dd \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "dana.reed@example.com",
  "notes": "Prefers texts after 5pm."
}'
Response · 200
{
  "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "object": "contact",
  "first_name": "Dana",
  "last_name": "Reed",
  "full_name": "Dana Reed",
  "email": "dana@example.com",
  "phone": "(972) 555-0148",
  "company": null,
  "type": "homeowner",
  "trades": [],
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "notes": null,
  "claim_number": null,
  "adjuster_type": null,
  "adjuster_extension": null,
  "assigned_to_id": null,
  "assigned_to_name": null,
  "created_at": "2026-09-16T13:40:00.000Z",
  "updated_at": "2026-09-16T13:40:00.000Z",
  "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
}

Delete a contact

DELETE/contacts/{id}

Kept for 30 days under Settings → Recently Deleted. Fires contact.deleted.

Path parameters

  • idstringuuidRequired

Returns

200Deleted. A Deleted object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/contacts/b7c2d3e4-4444-4000-8000-0000000000dd \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true
}

List a contact's jobs

GET/contacts/{id}/jobs

Every job this person is on — as homeowner, adjuster or secondary contact — archived included.

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

Returns

200A page of jobs. A page of Job objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/contacts/b7c2d3e4-4444-4000-8000-0000000000dd/jobs?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "object": "job",
      "job_number": "JOB-00142",
      "name": "1804 Cedar Ridge Dr",
      "job_type": "insurance",
      "stage": "inspection_scheduled",
      "stage_label": "Inspection Scheduled",
      "stage_is_completed": false,
      "stage_is_lost": false,
      "stage_entered_at": "2026-09-16T14:02:00.000Z",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "pipeline_name": "Insurance",
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "county": "Collin",
      "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "homeowner": {
        "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
        "name": "Dana Reed",
        "email": "dana@example.com",
        "phone": "(972) 555-0148"
      },
      "adjuster_id": null,
      "adjuster": null,
      "secondary_contact_ids": [],
      "secondary_adjuster_ids": [],
      "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "assigned_to_name": "Sam Carter",
      "assignee_ids": [
        "5d0e1c2b-7777-4000-8000-0000000000ab"
      ],
      "assignee_names": [
        "Sam Carter"
      ],
      "insurance_company": "Example Mutual",
      "claim_number": "CLM-88213",
      "policy_number": null,
      "date_of_loss": "2026-09-12",
      "damage_types": [
        "hail"
      ],
      "tags": [],
      "lead_source": "Website",
      "priority": "normal",
      "mortgage_company": null,
      "financing_method": null,
      "rcv_amount": 24380.5,
      "acv_amount": 19240,
      "deductible": 2500,
      "supplements_amount": null,
      "estimated_amount": null,
      "final_amount": null,
      "total_job_value": 24380.5,
      "amount_received": 0,
      "balance_due": 24380.5,
      "contract_date": null,
      "installation_date": null,
      "archived": false,
      "completed_at": null,
      "lost_at": null,
      "lost_reason": null,
      "created_at": "2026-09-16T14:02:00.000Z",
      "updated_at": "2026-09-16T14:02:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
      "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
    }
  ]
}

Endpoints

Tasks

Tasks and appointments. An appointment is a task with an appointment_type.

List tasks and appointments

GET/tasks

/appointments is the same list narrowed to appointments.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • completedstring
    truefalse
  • appointmentsstring

    true returns appointments only.

    true
  • job_idstringuuid
  • contact_idstringuuid
  • assigned_tostringuuid
  • due_afterstring

    Wall-clock, e.g. 2026-10-01 or 2026-10-01T08:00:00.

  • due_beforestring

Returns

200A page of tasks. A page of Task objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/tasks?appointments=true&due_after=2026-10-01" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
      "object": "task",
      "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
      "description": null,
      "due_date": "2026-10-02T15:00:00",
      "end_date": null,
      "duration_minutes": 60,
      "priority": "normal",
      "completed": false,
      "completed_at": null,
      "is_appointment": true,
      "appointment_type": "adjuster_meeting",
      "outcome": null,
      "customer_reminder": "sms",
      "reminder_minutes": 60,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "assigned_to_name": "Sam Carter",
      "created_at": "2026-09-16T14:10:00.000Z",
      "updated_at": "2026-09-16T14:10:00.000Z",
      "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
    }
  ]
}

Create a task or an appointment

POST/tasks

Set appointment_type (inspection, adjuster_meeting, build_day) to make it an appointment; POST /appointments requires one.

Times are wall-clock. due_date is the local time your crew will read. If you send an offset (2026-10-02T15:00:00-05:00, which is what Zapier sends) the offset is dropped and 3:00 PM is kept — HailMate never shifts an appointment by a time zone.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • titlestringRequired

    Up to 200 characters

  • descriptionstring
  • due_datestring

    A date or date-time. Any offset is dropped; the digits are kept.

  • end_datestringdate
  • duration_minutesinteger

    15 to 480

  • prioritystring
    lownormalhigh
  • appointment_typestring
    inspectionadjuster_meetingbuild_day
  • customer_reminderstring

    Remind the homeowner the day before.

    nonesmsemailboth
  • reminder_minutesinteger
    -105101530601201440
  • job_idstringuuid
  • contact_idstringuuid
  • assigned_tostringuuid
  • completedboolean

Returns

201Created. A Task object.

  • 400invalid_requestSomething in the request was wrong; field names what.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/tasks \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
  "due_date": "2026-10-02T15:00:00",
  "duration_minutes": 60,
  "appointment_type": "adjuster_meeting",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "assigned_to": "5d0e1c2b-7777-4000-8000-0000000000ab"
}'
Response · 201
{
  "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
  "object": "task",
  "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
  "description": null,
  "due_date": "2026-10-02T15:00:00",
  "end_date": null,
  "duration_minutes": 60,
  "priority": "normal",
  "completed": false,
  "completed_at": null,
  "is_appointment": true,
  "appointment_type": "adjuster_meeting",
  "outcome": null,
  "customer_reminder": "sms",
  "reminder_minutes": 60,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "created_at": "2026-09-16T14:10:00.000Z",
  "updated_at": "2026-09-16T14:10:00.000Z",
  "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
}

Get a task

GET/tasks/{id}

Path parameters

  • idstringuuidRequired

Returns

200The task. A Task object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/tasks/d4e5f6a7-5555-4000-8000-0000000000ee \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
  "object": "task",
  "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
  "description": null,
  "due_date": "2026-10-02T15:00:00",
  "end_date": null,
  "duration_minutes": 60,
  "priority": "normal",
  "completed": false,
  "completed_at": null,
  "is_appointment": true,
  "appointment_type": "adjuster_meeting",
  "outcome": null,
  "customer_reminder": "sms",
  "reminder_minutes": 60,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "created_at": "2026-09-16T14:10:00.000Z",
  "updated_at": "2026-09-16T14:10:00.000Z",
  "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
}

Update a task

PATCH/tasks/{id}

Reschedule it, reassign it, or finish it with {"completed": true} (fires task.completed). null clears a field.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • titlestring
  • descriptionstring | null
  • due_datestring | null
  • end_datestring | nulldate
  • duration_minutesinteger | null
  • prioritystring | null
  • appointment_typestring | null
  • outcomestring | null
    completedno_showrescheduledcanceled
  • customer_reminderstring
  • reminder_minutesinteger | null
  • job_idstring | nulluuid
  • contact_idstring | nulluuid
  • assigned_tostring | nulluuid
  • completedboolean

Returns

200The task, as it is now. A Task object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/tasks/d4e5f6a7-5555-4000-8000-0000000000ee \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "completed": true,
  "outcome": "completed"
}'
Response · 200
{
  "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
  "object": "task",
  "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
  "description": null,
  "due_date": "2026-10-02T15:00:00",
  "end_date": null,
  "duration_minutes": 60,
  "priority": "normal",
  "completed": false,
  "completed_at": null,
  "is_appointment": true,
  "appointment_type": "adjuster_meeting",
  "outcome": null,
  "customer_reminder": "sms",
  "reminder_minutes": 60,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "created_at": "2026-09-16T14:10:00.000Z",
  "updated_at": "2026-09-16T14:10:00.000Z",
  "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
}

Delete a task

DELETE/tasks/{id}

Permanent. Fires task.deleted.

Path parameters

  • idstringuuidRequired

Returns

200Deleted. A Deleted object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/tasks/d4e5f6a7-5555-4000-8000-0000000000ee \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true
}

Endpoints

Estimates

Estimates and proposals — made from one of your templates or as your standard proposal, then finished and sent in HailMate.

List estimates

GET/estimates

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • statusstring
    draftsentviewedsignedexpireddeclined
  • job_idstringuuid
  • estimate_numberstring

Returns

200A page of estimates. A page of Estimate objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/estimates?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "a41c9e20-2222-4000-8000-0000000000e1",
      "object": "estimate",
      "estimate_number": "EST-0214",
      "title": "Roof replacement — 1804 Cedar Ridge Dr",
      "document_type": "proposal",
      "status": "sent",
      "signature_status": "pending",
      "total": 21900,
      "package_totals": {
        "good": 18450,
        "better": 21900,
        "best": 26400
      },
      "upgrades_total": 1250,
      "selected_tier": null,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "valid_until": "2026-10-28T00:00:00.000Z",
      "sent_at": "2026-09-28T15:10:00.000Z",
      "first_viewed_at": "2026-09-28T18:42:00.000Z",
      "last_viewed_at": "2026-09-28T19:05:00.000Z",
      "view_count": 3,
      "signed_at": null,
      "signer_name": null,
      "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
      "signed_pdf_url": null,
      "created_at": "2026-09-27T21:30:00.000Z",
      "updated_at": "2026-09-28T19:05:00.000Z",
      "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
      "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
    }
  ]
}

Create an estimate

POST/estimates

Makes a draft estimate on a job, one of two ways — the same two the app offers:

  • From one of your templates (template_id, from GET /estimate_templates): an exact copy, with its smart fields ({{customer_name}}, {{property_address}}…) filled in from the job.
  • Your standard proposal: cover, introduction, Scope of Work, warranty, terms and signature. The Scope of Work is the lines you send, or HailMate's standard checklist when you send none.

price states one price for the whole job, which is what the homeowner sees as the total. The estimate is not sent — a person finishes and sends it in HailMate. Fires estimate.created.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • job_idstringuuidRequired
  • template_idstringuuid

    One of your templates. Leave out for your standard proposal.

  • titlestring
  • pricenumber

    One price for the whole job.

    More than 0

  • valid_untilstringdate

    Defaults to your workspace's setting.

  • line_itemsarray of LineItemInput

    The Scope of Work, without a template. Leave out for the standard checklist.

Returns

201Created, as a draft. An Estimate object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 403forbiddenA read-only key tried to change something.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/estimates \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "template_id": "7a1c9e02-2222-4000-8000-0000000000c3",
  "price": 14500
}'
Response · 201
{
  "id": "a41c9e20-2222-4000-8000-0000000000e1",
  "object": "estimate",
  "estimate_number": "EST-0214",
  "title": "Roof replacement — 1804 Cedar Ridge Dr",
  "document_type": "proposal",
  "status": "sent",
  "signature_status": "pending",
  "total": 21900,
  "package_totals": {
    "good": 18450,
    "better": 21900,
    "best": 26400
  },
  "upgrades_total": 1250,
  "selected_tier": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "valid_until": "2026-10-28T00:00:00.000Z",
  "sent_at": "2026-09-28T15:10:00.000Z",
  "first_viewed_at": "2026-09-28T18:42:00.000Z",
  "last_viewed_at": "2026-09-28T19:05:00.000Z",
  "view_count": 3,
  "signed_at": null,
  "signer_name": null,
  "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
  "signed_pdf_url": null,
  "created_at": "2026-09-27T21:30:00.000Z",
  "updated_at": "2026-09-28T19:05:00.000Z",
  "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
  "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
}

Get an estimate

GET/estimates/{id}

Path parameters

  • idstringuuidRequired

Returns

200The estimate. An Estimate object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/estimates/a41c9e20-2222-4000-8000-0000000000e1 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "a41c9e20-2222-4000-8000-0000000000e1",
  "object": "estimate",
  "estimate_number": "EST-0214",
  "title": "Roof replacement — 1804 Cedar Ridge Dr",
  "document_type": "proposal",
  "status": "sent",
  "signature_status": "pending",
  "total": 21900,
  "package_totals": {
    "good": 18450,
    "better": 21900,
    "best": 26400
  },
  "upgrades_total": 1250,
  "selected_tier": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "valid_until": "2026-10-28T00:00:00.000Z",
  "sent_at": "2026-09-28T15:10:00.000Z",
  "first_viewed_at": "2026-09-28T18:42:00.000Z",
  "last_viewed_at": "2026-09-28T19:05:00.000Z",
  "view_count": 3,
  "signed_at": null,
  "signer_name": null,
  "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
  "signed_pdf_url": null,
  "created_at": "2026-09-27T21:30:00.000Z",
  "updated_at": "2026-09-28T19:05:00.000Z",
  "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
  "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
}

Update an estimate

PATCH/estimates/{id}

Changes what sits outside the document: its title, how long it is valid, and one stated price (null takes the price off). The sections and lines are edited in HailMate. Refused with 409 once the estimate is out for signature or signed.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • titlestring | null
  • pricenumber | null

    null takes the stated price off.

    More than 0

  • valid_untilstring | nulldate

Returns

200The estimate, as it is now. An Estimate object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 404not_foundNo such record in this workspace.
  • 409conflictAn Idempotency-Key clash — reused for a different request, or the first is still running.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/estimates/a41c9e20-2222-4000-8000-0000000000e1 \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "price": 15250,
  "valid_until": "2026-12-01"
}'
Response · 200
{
  "id": "a41c9e20-2222-4000-8000-0000000000e1",
  "object": "estimate",
  "estimate_number": "EST-0214",
  "title": "Roof replacement — 1804 Cedar Ridge Dr",
  "document_type": "proposal",
  "status": "sent",
  "signature_status": "pending",
  "total": 21900,
  "package_totals": {
    "good": 18450,
    "better": 21900,
    "best": 26400
  },
  "upgrades_total": 1250,
  "selected_tier": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "valid_until": "2026-10-28T00:00:00.000Z",
  "sent_at": "2026-09-28T15:10:00.000Z",
  "first_viewed_at": "2026-09-28T18:42:00.000Z",
  "last_viewed_at": "2026-09-28T19:05:00.000Z",
  "view_count": 3,
  "signed_at": null,
  "signer_name": null,
  "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
  "signed_pdf_url": null,
  "created_at": "2026-09-27T21:30:00.000Z",
  "updated_at": "2026-09-28T19:05:00.000Z",
  "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
  "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
}

List estimate templates

GET/estimate_templates

The workspace's own templates, most recently changed first — what a "which template?" dropdown lists.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

Returns

200The templates. A list of EstimateTemplate objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/estimate_templates?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "id": "7a1c9e02-2222-4000-8000-0000000000c3",
      "object": "estimate_template",
      "name": "Insurance roof replacement",
      "template_number": "TPL-0003",
      "created_at": "2026-08-30T15:00:00.000Z",
      "updated_at": "2026-09-20T18:30:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Endpoints

Invoices

Draft invoices, totalled exactly as HailMate totals them; mark them sent, or void them.

List invoices

GET/invoices

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • statusstring
    draftsentviewedpartially_paidpaidoverduevoidbad_debt
  • job_idstringuuid
  • contact_idstringuuid
  • invoice_numberstring

Returns

200A page of invoices. A page of Invoice objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/invoices?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "c90d7b31-3333-4000-8000-0000000000f2",
      "object": "invoice",
      "invoice_number": "INV-0311",
      "title": "Deductible",
      "status": "sent",
      "purpose": "deductible",
      "subtotal": 2500,
      "discount_amount": 0,
      "tax_amount": 0,
      "late_fee_amount": 0,
      "total_amount": 2500,
      "amount_paid": 0,
      "balance_due": 2500,
      "part_number": null,
      "part_count": null,
      "issue_date": "2026-09-28",
      "due_date": "2026-10-12",
      "sent_at": "2026-09-28T16:00:00.000Z",
      "first_viewed_at": null,
      "paid_at": null,
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
      "estimate_id": null,
      "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
      "created_at": "2026-09-28T15:55:00.000Z",
      "updated_at": "2026-09-28T16:00:00.000Z",
      "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
      "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
    }
  ]
}

Create an invoice

POST/invoices

Makes a draft invoice for a job (job_id) or a contact (contact_id), with at least one line. HailMate numbers it (INV-0312) and totals it with the same calculator the app uses: lines, minus any discount, plus tax on the taxable lines. A negative price is a credit. purpose fills the matching figure on the job — a deductible invoice sets the job's deductible — exactly as in the app.

A draft is not sent. Send it from HailMate, or call mark_sent when it went out another way. Fires invoice.created.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • job_idstringuuid
  • contact_idstringuuid

    Who it bills.

  • estimate_idstringuuid
  • titlestring
  • purposestring
    claim_scopedeductiblesupplementdepreciationcontractother
  • issue_datestringdate

    Defaults to today.

  • due_datestringdate
  • line_itemsarray of LineItemInputRequired
  • tax_ratenumber

    A percent

    0 to 100

  • discount_typestring
    amountpercent
  • discount_valuenumber

    At least 0

  • notesstring
  • termsstring
  • allow_partial_paymentsboolean

Returns

201Created, as a draft. An Invoice object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 403forbiddenA read-only key tried to change something.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/invoices \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "title": "Deductible",
  "purpose": "deductible",
  "due_date": "2026-10-12",
  "line_items": [
    {
      "name": "Insurance deductible",
      "quantity": 1,
      "unit_price": 2500
    }
  ]
}'
Response · 201
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

Get an invoice

GET/invoices/{id}

Path parameters

  • idstringuuidRequired

Returns

200The invoice. An Invoice object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/invoices/c90d7b31-3333-4000-8000-0000000000f2 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

Update a draft invoice

PATCH/invoices/{id}

Only a draft can change — once an invoice is sent the homeowner holds a copy, so a sent one is voided and replaced instead (409). line_items, when sent, replace every line; the totals are worked out again either way.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • contact_idstring | nulluuid
  • estimate_idstring | nulluuid
  • titlestring | null
  • purposestring | null
    claim_scopedeductiblesupplementdepreciationcontractother
  • issue_datestring | nulldate
  • due_datestring | nulldate
  • line_itemsarray of LineItemInput

    Replaces every line.

  • tax_ratenumber

    0 to 100

  • discount_typestring
    amountpercent
  • discount_valuenumber | null

    0 or null takes the discount off.

    At least 0

  • notesstring | null
  • termsstring | null
  • allow_partial_paymentsboolean

Returns

200The invoice, as it is now. An Invoice object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 404not_foundNo such record in this workspace.
  • 409conflictAn Idempotency-Key clash — reused for a different request, or the first is still running.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/invoices/c90d7b31-3333-4000-8000-0000000000f2 \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "due_date": "2026-10-20",
  "tax_rate": 8.25
}'
Response · 200
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

Delete a draft invoice

DELETE/invoices/{id}

Only a draft. A sent invoice is voided instead, so its history stays on the job.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Returns

200Deleted. A Deleted object.

  • 404not_foundNo such record in this workspace.
  • 409conflictAn Idempotency-Key clash — reused for a different request, or the first is still running.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/invoices/c90d7b31-3333-4000-8000-0000000000f2 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "deleted": true
}

Mark an invoice sent

POST/invoices/{id}/mark_sent

Records that the invoice went out some other way. A draft becomes sent, which turns on the homeowner's pay page (payment_url); an invoice already out keeps its status. Refused for a void invoice.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Returns

200The invoice, as it is now. An Invoice object.

  • 404not_foundNo such record in this workspace.
  • 409conflictAn Idempotency-Key clash — reused for a different request, or the first is still running.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/invoices/c90d7b31-3333-4000-8000-0000000000f2/mark_sent \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
Response · 200
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

Void an invoice

POST/invoices/{id}/void

Voids the invoice. Voiding one that is already void answers with it, unchanged.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Returns

200The invoice, now void. An Invoice object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/invoices/c90d7b31-3333-4000-8000-0000000000f2/void \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
Response · 200
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

Endpoints

Payments

Money received against a job — carrier cheques, deductibles, card payments.

List payments

GET/payments

A refund is its own row with a negative amount, so summing amount gives the net.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • job_idstringuuid
  • invoice_idstringuuid
  • payment_typestring
    acvdeductiblesupplementdepreciationretailother

Returns

200A page of payments. A page of Payment objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/payments?job_id=f2b1a0c4-1111-4000-8000-0000000000aa" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "9fa3e1d2-5555-4000-8000-0000000000c3",
      "object": "payment",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "invoice_id": null,
      "amount": 13164,
      "payment_type": "acv",
      "payer_type": "insurance",
      "payment_method": "check",
      "status": "received",
      "check_number": "4471",
      "date_received": "2026-09-26",
      "date_deposited": null,
      "notes": "First ACV check from Example Mutual",
      "is_refund": false,
      "refund_of_payment_id": null,
      "online": false,
      "created_at": "2026-09-26T20:14:00.000Z",
      "updated_at": "2026-09-26T20:14:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

Record a payment

POST/payments

Records money that arrived — a cheque logged in your accounting app, a deposit from a bank feed. The job's money and, when you name one, the invoice's balance and status update exactly as they do for a payment logged in HailMate.

The invoice it pays is never guessed. Send invoice_id to apply it to an invoice on the same job; leave it out and the payment sits on the job. Fires payment.received.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • job_idstringuuidRequired
  • amountnumberRequired

    More than 0

  • invoice_idstringuuid

    An invoice ON THIS JOB to apply it to. Never guessed.

  • payment_typestring
    acvdeductiblesupplementdepreciationretailother

    Default other

  • payer_typestring
    insurancehomeownermortgage_companyother

    Default homeowner

  • payment_methodstring
    checkcashcardachfinancingother

    Default check

  • statusstring
    expectedreceivedsent_to_mortgageendorseddeposited

    Default received

  • check_numberstring
  • date_receivedstringdate

    Defaults to today (US Central).

  • date_depositedstringdate
  • notesstring

Returns

201Recorded. A Payment object.

  • 400invalid_requestSomething in the request was wrong; field names what.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/payments \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "amount": 13164.2,
  "payment_type": "acv",
  "payer_type": "insurance",
  "payment_method": "check",
  "check_number": "004471",
  "date_received": "2026-09-28"
}'
Response · 201
{
  "id": "9fa3e1d2-5555-4000-8000-0000000000c3",
  "object": "payment",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "invoice_id": null,
  "amount": 13164,
  "payment_type": "acv",
  "payer_type": "insurance",
  "payment_method": "check",
  "status": "received",
  "check_number": "4471",
  "date_received": "2026-09-26",
  "date_deposited": null,
  "notes": "First ACV check from Example Mutual",
  "is_refund": false,
  "refund_of_payment_id": null,
  "online": false,
  "created_at": "2026-09-26T20:14:00.000Z",
  "updated_at": "2026-09-26T20:14:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Get a payment

GET/payments/{id}

Path parameters

  • idstringuuidRequired

Returns

200The payment. A Payment object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/payments/9fa3e1d2-5555-4000-8000-0000000000c3 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "9fa3e1d2-5555-4000-8000-0000000000c3",
  "object": "payment",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "invoice_id": null,
  "amount": 13164,
  "payment_type": "acv",
  "payer_type": "insurance",
  "payment_method": "check",
  "status": "received",
  "check_number": "4471",
  "date_received": "2026-09-26",
  "date_deposited": null,
  "notes": "First ACV check from Example Mutual",
  "is_refund": false,
  "refund_of_payment_id": null,
  "online": false,
  "created_at": "2026-09-26T20:14:00.000Z",
  "updated_at": "2026-09-26T20:14:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Endpoints

Notes

Notes on a job's timeline.

List notes

GET/notes

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • job_idstringuuid

Returns

200A page of notes. A page of Note objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/notes?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "3c8b1a07-6666-4000-8000-0000000000b4",
      "object": "note",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "content": "Adjuster meeting moved to Thursday 10am. Homeowner will be home.",
      "author_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "author_name": "Sam Carter",
      "created_at": "2026-09-27T14:20:00.000Z",
      "updated_at": "2026-09-27T14:20:00.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

Add a note to a job

POST/notes

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • job_idstringuuidRequired
  • contentstringRequired

    Up to 10000 characters

Returns

201Created. A Note object.

  • 400invalid_requestSomething in the request was wrong; field names what.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/notes \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "content": "Adjuster confirmed for Thursday at 3."
}'
Response · 201
{
  "id": "3c8b1a07-6666-4000-8000-0000000000b4",
  "object": "note",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "content": "Adjuster meeting moved to Thursday 10am. Homeowner will be home.",
  "author_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "author_name": "Sam Carter",
  "created_at": "2026-09-27T14:20:00.000Z",
  "updated_at": "2026-09-27T14:20:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Get a note

GET/notes/{id}

Path parameters

  • idstringuuidRequired

Returns

200The note. A Note object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/notes/3c8b1a07-6666-4000-8000-0000000000b4 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "3c8b1a07-6666-4000-8000-0000000000b4",
  "object": "note",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "content": "Adjuster meeting moved to Thursday 10am. Homeowner will be home.",
  "author_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "author_name": "Sam Carter",
  "created_at": "2026-09-27T14:20:00.000Z",
  "updated_at": "2026-09-27T14:20:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Endpoints

Files

Photos and documents on a job.

List photos and documents

GET/files

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • job_idstringuuid
  • categorystring
    photodocumentscopeestimatecontractother

Returns

200A page of files. A page of File objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/files?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "7e2d9c40-8888-4000-8000-0000000000a5",
      "object": "file",
      "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
      "name": "north-slope-hits.jpg",
      "category": "photo",
      "mime_type": "image/jpeg",
      "is_photo": true,
      "is_video": false,
      "size_bytes": 1532410,
      "description": "Hail hits on the north slope, chalked",
      "tags": [
        "damage",
        "north slope"
      ],
      "latitude": 33.0726,
      "longitude": -96.7512,
      "taken_at": "2026-09-16T15:12:08.000Z",
      "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "uploaded_by_name": "Sam Carter",
      "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
      "created_at": "2026-09-16T15:12:40.000Z",
      "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
    }
  ]
}

Upload a photo or document to a job

POST/files

Two ways in:

  • multipart/form-data with a file field and a job_id field (plus optional category, description, file_name).
  • JSON with a public file_url HailMate downloads for you.

Up to 25 MB. A JPEG, PNG, WebP, GIF or MP4 is filed as a photo; anything else (a PDF, a HEIC, a spreadsheet) as a document, so it never shows as a broken tile. Fires file.created.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • job_idstringuuidRequired
  • file_urlstringuriRequired

    A public https address. Redirects are followed (up to 3).

  • categorystring
    photodocumentscopeestimatecontractother
  • descriptionstring
  • file_namestring

Request bodymultipart/form-data

Or send the file itself as a form upload:

  • filestringbinaryRequired
  • job_idstringuuidRequired
  • categorystring
    photodocumentscopeestimatecontractother
  • descriptionstring
  • file_namestring

Returns

201Stored. A File object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 413payload_too_largeThe file is larger than 25 MB.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/files \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "file_url": "https://example.com/claim/scope-of-loss.pdf",
  "category": "scope"
}'
Upload a file (multipart/form-data)
curl -X POST https://app.hailmate.ai/api/v1/files \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -F "file=@roof-front.jpg" \
  -F "job_id=f2b1a0c4-1111-4000-8000-0000000000aa" \
  -F "description=Front slope, hail hits circled"
Response · 201
{
  "id": "7e2d9c40-8888-4000-8000-0000000000a5",
  "object": "file",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "name": "north-slope-hits.jpg",
  "category": "photo",
  "mime_type": "image/jpeg",
  "is_photo": true,
  "is_video": false,
  "size_bytes": 1532410,
  "description": "Hail hits on the north slope, chalked",
  "tags": [
    "damage",
    "north slope"
  ],
  "latitude": 33.0726,
  "longitude": -96.7512,
  "taken_at": "2026-09-16T15:12:08.000Z",
  "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "uploaded_by_name": "Sam Carter",
  "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
  "created_at": "2026-09-16T15:12:40.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Get a file

GET/files/{id}

Path parameters

  • idstringuuidRequired

Returns

200The file. A File object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/files/7e2d9c40-8888-4000-8000-0000000000a5 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "7e2d9c40-8888-4000-8000-0000000000a5",
  "object": "file",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "name": "north-slope-hits.jpg",
  "category": "photo",
  "mime_type": "image/jpeg",
  "is_photo": true,
  "is_video": false,
  "size_bytes": 1532410,
  "description": "Hail hits on the north slope, chalked",
  "tags": [
    "damage",
    "north slope"
  ],
  "latitude": 33.0726,
  "longitude": -96.7512,
  "taken_at": "2026-09-16T15:12:08.000Z",
  "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "uploaded_by_name": "Sam Carter",
  "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
  "created_at": "2026-09-16T15:12:40.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Endpoints

Canvassing

Door knocks — pins on the canvassing map with a knock result.

List canvassing pins

GET/pins

Every door a rep dropped a pin on, newest first.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • created_afterstringdate-time

    Only records created at or after this ISO date or date-time.

  • created_beforestringdate-time

    Only records created before this ISO date or date-time.

  • knock_resultstring
    interestednot_interestedcontactedno_answerdoor_hangerfollow_upappointment_scheduleddont_knockrenterno_damagecash_quotelost
  • pin_typestring
    knockinspectionjob
  • job_idstringuuid
  • created_bystringuuid

    The rep who dropped the pin.

Returns

200A page of pins. A page of Pin objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/pins?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "2b6f4e18-9999-4000-8000-0000000000d6",
      "object": "pin",
      "pin_type": "knock",
      "knock_result": "interested",
      "address": "1812 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "postal_code": "75024",
      "latitude": 33.0731,
      "longitude": -96.7519,
      "homeowner_name": "Chris Lane",
      "homeowner_first_name": "Chris",
      "homeowner_last_name": "Lane",
      "phone": "(972) 555-0193",
      "email": null,
      "notes": "Wants an inspection Saturday morning",
      "job_id": null,
      "created_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "created_by_name": "Sam Carter",
      "created_at": "2026-09-27T17:45:00.000Z",
      "updated_at": "2026-09-27T17:45:00.000Z",
      "map_url": "https://www.google.com/maps?q=33.0731,-96.7519",
      "url": "https://app.hailmate.ai/canvassing"
    }
  ]
}

Log a door knock

POST/pins

Drops a pin on the canvassing map. Send latitude and longitude, or an address and HailMate places it. It is credited to the teammate in created_by_id, else to whoever connected the integration. Fires pin.created.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • latitudenumber

    -90 to 90

  • longitudenumber

    -180 to 180

  • addressstring
  • citystring
  • statestring

    A code or a name — "TX" or "Texas".

  • postal_codestring
  • knock_resultstring
    interestednot_interestedcontactedno_answerdoor_hangerfollow_upappointment_scheduleddont_knockrenterno_damagecash_quotelost
  • pin_typestring
    knockinspection

    Default knock

  • homeowner_namestring

    Split into first and last for you.

  • homeowner_first_namestring
  • homeowner_last_namestring
  • phonestring
  • emailstringemail
  • notesstring
  • created_by_idstringuuid

    The teammate who knocked. Defaults to whoever connected the integration.

Returns

201Logged. A Pin object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 403forbiddenA read-only key tried to change something.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/pins \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "knock_result": "interested",
  "homeowner_name": "Dana Reed"
}'
Response · 201
{
  "id": "2b6f4e18-9999-4000-8000-0000000000d6",
  "object": "pin",
  "pin_type": "knock",
  "knock_result": "interested",
  "address": "1812 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "latitude": 33.0731,
  "longitude": -96.7519,
  "homeowner_name": "Chris Lane",
  "homeowner_first_name": "Chris",
  "homeowner_last_name": "Lane",
  "phone": "(972) 555-0193",
  "email": null,
  "notes": "Wants an inspection Saturday morning",
  "job_id": null,
  "created_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "created_by_name": "Sam Carter",
  "created_at": "2026-09-27T17:45:00.000Z",
  "updated_at": "2026-09-27T17:45:00.000Z",
  "map_url": "https://www.google.com/maps?q=33.0731,-96.7519",
  "url": "https://app.hailmate.ai/canvassing"
}

Get a pin

GET/pins/{id}

Path parameters

  • idstringuuidRequired

Returns

200The pin. A Pin object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/pins/2b6f4e18-9999-4000-8000-0000000000d6 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "2b6f4e18-9999-4000-8000-0000000000d6",
  "object": "pin",
  "pin_type": "knock",
  "knock_result": "interested",
  "address": "1812 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "latitude": 33.0731,
  "longitude": -96.7519,
  "homeowner_name": "Chris Lane",
  "homeowner_first_name": "Chris",
  "homeowner_last_name": "Lane",
  "phone": "(972) 555-0193",
  "email": null,
  "notes": "Wants an inspection Saturday morning",
  "job_id": null,
  "created_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "created_by_name": "Sam Carter",
  "created_at": "2026-09-27T17:45:00.000Z",
  "updated_at": "2026-09-27T17:45:00.000Z",
  "map_url": "https://www.google.com/maps?q=33.0731,-96.7519",
  "url": "https://app.hailmate.ai/canvassing"
}

Update a door knock

PATCH/pins/{id}

Most often its knock result. The rep who logged it never changes. Fires pin.result_changed when the result moves.

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • knock_resultstring | null
    interestednot_interestedcontactedno_answerdoor_hangerfollow_upappointment_scheduleddont_knockrenterno_damagecash_quotelost
  • pin_typestring
    knockinspection
  • latitudenumber
  • longitudenumber
  • addressstring | null
  • citystring | null
  • statestring | null
  • postal_codestring | null
  • homeowner_namestring
  • homeowner_first_namestring | null
  • homeowner_last_namestring | null
  • phonestring | null
  • emailstring | nullemail
  • notesstring | null

Returns

200The pin, as it is now. A Pin object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X PATCH https://app.hailmate.ai/api/v1/pins/2b6f4e18-9999-4000-8000-0000000000d6 \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "knock_result": "appointment_scheduled"
}'
Response · 200
{
  "id": "2b6f4e18-9999-4000-8000-0000000000d6",
  "object": "pin",
  "pin_type": "knock",
  "knock_result": "interested",
  "address": "1812 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "latitude": 33.0731,
  "longitude": -96.7519,
  "homeowner_name": "Chris Lane",
  "homeowner_first_name": "Chris",
  "homeowner_last_name": "Lane",
  "phone": "(972) 555-0193",
  "email": null,
  "notes": "Wants an inspection Saturday morning",
  "job_id": null,
  "created_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "created_by_name": "Sam Carter",
  "created_at": "2026-09-27T17:45:00.000Z",
  "updated_at": "2026-09-27T17:45:00.000Z",
  "map_url": "https://www.google.com/maps?q=33.0731,-96.7519",
  "url": "https://app.hailmate.ai/canvassing"
}

Delete a door knock

DELETE/pins/{id}

Path parameters

  • idstringuuidRequired

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Returns

200Deleted. A Deleted object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/pins/2b6f4e18-9999-4000-8000-0000000000d6 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "0e4c2a19-8888-4000-8000-0000000000c1",
  "object": "pin",
  "deleted": true
}

Endpoints

Storm Lists

Every property under hail of a chosen size, with the owner of record (read only).

List storm lists

GET/storm_lists

Read only — building a list spends data credits and happens in HailMate. source: auto is a nightly build off the hail data; manual is one somebody made.

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • updated_sincestringdate-time

    Only records changed at or after this ISO date or date-time. The way to sync only what moved.

  • statusstring
    buildingreadypartialfailed

Returns

200A page of storm lists. A page of StormList objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/storm_lists?limit=25" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "e5a1c7d9-aaaa-4000-8000-0000000000e7",
      "object": "storm_list",
      "name": "Plano 1.25″+ — Sep 12",
      "status": "ready",
      "source": "manual",
      "window_from": "2026-09-12",
      "window_to": "2026-09-12",
      "min_size_in": 1.25,
      "area_kind": "drawn",
      "territory_id": null,
      "clipped_area_sq_mi": 4.2,
      "property_cap": 1000,
      "property_count": 412,
      "skipped_duplicates": 18,
      "dedupe_days": 90,
      "credits_spent": 412,
      "total_available": 430,
      "storm_date": "2026-09-12",
      "built_at": "2026-09-13T13:04:00.000Z",
      "created_at": "2026-09-13T13:02:00.000Z",
      "updated_at": "2026-09-13T13:04:00.000Z",
      "url": "https://app.hailmate.ai/canvassing/lists/e5a1c7d9-aaaa-4000-8000-0000000000e7"
    }
  ]
}

Get a storm list

GET/storm_lists/{id}

Path parameters

  • idstringuuidRequired

Returns

200The storm list. A StormList object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/storm_lists/e5a1c7d9-aaaa-4000-8000-0000000000e7 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "e5a1c7d9-aaaa-4000-8000-0000000000e7",
  "object": "storm_list",
  "name": "Plano 1.25″+ — Sep 12",
  "status": "ready",
  "source": "manual",
  "window_from": "2026-09-12",
  "window_to": "2026-09-12",
  "min_size_in": 1.25,
  "area_kind": "drawn",
  "territory_id": null,
  "clipped_area_sq_mi": 4.2,
  "property_cap": 1000,
  "property_count": 412,
  "skipped_duplicates": 18,
  "dedupe_days": 90,
  "credits_spent": 412,
  "total_available": 430,
  "storm_date": "2026-09-12",
  "built_at": "2026-09-13T13:04:00.000Z",
  "created_at": "2026-09-13T13:02:00.000Z",
  "updated_at": "2026-09-13T13:04:00.000Z",
  "url": "https://app.hailmate.ai/canvassing/lists/e5a1c7d9-aaaa-4000-8000-0000000000e7"
}

List the properties on a storm list

GET/storm_lists/{id}/properties

The rows a mail house wants. mail_deliverable is our own judgement from the address we hold — it is NOT a CASS or NCOA result; run your own validation before you spend postage.

Path parameters

  • idstringuuidRequired

Query parameters

  • limitinteger

    Page size. Out-of-range values fall back to the default.

    1 to 200 · Default 50

  • cursorstring

    The next_cursor from the previous page, exactly as received. A cursor we did not issue is a 400.

  • mailablestring

    true drops properties with no usable mailing address or owner name.

    true
  • residentialstring
    true

Returns

200A page of properties. A page of StormListProperty objects in data, with has_more and next_cursor.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/storm_lists/e5a1c7d9-aaaa-4000-8000-0000000000e7/properties?mailable=true&limit=100" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0wOS0yOFQxNDowMjowMFoiLCJpIjoiZjJiMWEwYzQifQ",
  "data": [
    {
      "id": "d4b3a2c1-bbbb-4000-8000-0000000000f8",
      "object": "storm_list_property",
      "storm_list_id": "e5a1c7d9-aaaa-4000-8000-0000000000e7",
      "address": "1804 Cedar Ridge Dr",
      "city": "Plano",
      "state": "TX",
      "zip": "75024",
      "owner_name": "Dana Reed",
      "owner_occupied": true,
      "mailing_address": "1804 Cedar Ridge Dr",
      "mailing_city": "Plano",
      "mailing_state": "TX",
      "mailing_zip": "75024",
      "mail_deliverable": true,
      "mail_exclude_reason": null,
      "hail_size_in": 1.5,
      "hail_event_date": "2026-09-12",
      "nearest_report_mi": 1.8,
      "nearest_report_size_in": 1.75,
      "year_built": 2004,
      "property_use": "Single family",
      "is_residential": true,
      "latitude": 33.0726,
      "longitude": -96.7512,
      "created_at": "2026-09-13T13:04:00.000Z"
    }
  ]
}

Endpoints

Hail

Hail and damaging-wind history at an address.

Hail and wind history at an address

GET/hail_history

Every hail day and damaging-wind day at an address (or a latitude and longitude) since since — the same Evidence Grade™ ruling HailMate shows on its maps and storm reports, combining radar-estimated hail size, severe-hail probability and verified ground reports.

confidence is confirmed (a ground report backs the size), likely or radar (radar only). Default window: the last five years. United States only. Limited to 20 lookups a minute per key, inside the general limit.

Query parameters

  • addressstring

    A US street address. Or send latitude and longitude.

  • latitudenumber
  • longitudenumber
  • sincestringdate

    YYYY-MM-DD. Defaults to five years ago.

Returns

200The history. A HailReport object.

  • 400invalid_requestSomething in the request was wrong; field names what.
  • 429rate_limitedOver 120 requests a minute (or 20 hail lookups a minute). Wait Retry-After seconds.

Any request can also answer 401, 402, 429 or 500 — errors.

curl "https://app.hailmate.ai/api/v1/hail_history?address=1804%20Cedar%20Ridge%20Dr%2C%20Plano%2C%20TX%2075024" \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "hail_report",
  "address": "1804 Cedar Ridge Dr, Plano, TX 75024, USA",
  "latitude": 33.0198,
  "longitude": -96.6989,
  "since": "2021-09-28",
  "hail_day_count": 2,
  "largest_hail_in": 1.5,
  "last_hail_date": "2025-03-25",
  "hail_events": [
    {
      "date": "2025-03-25",
      "size_in": 1.5,
      "confidence": "confirmed",
      "confirmed_by_ground_report": true,
      "radar_estimated_size_in": null,
      "severe_hail_probability": null,
      "ground_report_size_in": 1.5,
      "ground_report_distance_mi": 1.4,
      "ground_report_count": 11
    },
    {
      "date": "2024-05-28",
      "size_in": 1.5,
      "confidence": "likely",
      "confirmed_by_ground_report": false,
      "radar_estimated_size_in": 1.5,
      "severe_hail_probability": null,
      "ground_report_size_in": 1.25,
      "ground_report_distance_mi": 9,
      "ground_report_count": 1
    }
  ],
  "wind_events": [
    {
      "date": "2025-03-04",
      "max_gust_mph": 90
    }
  ]
}

Endpoints

Lookups

Pipelines, stages, teammates and the event catalogue — what a dropdown is built from.

List pipelines and their stages

GET/pipelines

Returns

200Every pipeline, default first, with its stages in board order. A list of Pipeline objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/pipelines \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "object": "pipeline",
      "name": "Insurance",
      "is_default": true,
      "order": 0,
      "stages": [
        {
          "id": "8a7b6c5d-cccc-4000-8000-000000000010",
          "object": "pipeline_stage",
          "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
          "key": "lead",
          "label": "Lead",
          "order": 0,
          "is_completed": false,
          "is_lost": false
        },
        {
          "id": "8a7b6c5d-cccc-4000-8000-000000000011",
          "object": "pipeline_stage",
          "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
          "key": "claim_approved",
          "label": "Claim Approved",
          "order": 6,
          "is_completed": false,
          "is_lost": false
        }
      ]
    }
  ]
}

List pipeline stages

GET/stages

Every stage on every board. key is what you send and filter on; label is what to show a person. /pipeline_stages is the same list.

Returns

200The stages, default pipeline first, in board order. A list of PipelineStage objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/stages \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "id": "8a7b6c5d-cccc-4000-8000-000000000011",
      "object": "pipeline_stage",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "key": "claim_approved",
      "label": "Claim Approved",
      "order": 6,
      "is_completed": false,
      "is_lost": false
    }
  ]
}

List your team

GET/users

Returns

200The workspace's people. A list of User objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/users \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "id": "5d0e1c2b-7777-4000-8000-0000000000ab",
      "object": "user",
      "name": "Sam Carter",
      "email": "sam@ridgelineroofing.example",
      "role": "member"
    }
  ]
}

List every webhook event

GET/events

Returns

200The event catalogue, with the filters each one accepts. A list of EventDefinition objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/events \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "event": "job.stage_changed",
      "resource": "job",
      "label": "Job Stage Changed",
      "description": "A job moved to a different stage on the board.",
      "filters": [
        {
          "key": "stage",
          "label": "Stage",
          "kind": "stage"
        },
        {
          "key": "previous_stage",
          "label": "Previous stage",
          "kind": "stage"
        },
        {
          "key": "job_type",
          "label": "Job type",
          "kind": "enum",
          "values": [
            "insurance",
            "retail"
          ]
        },
        {
          "key": "pipeline_id",
          "label": "Pipeline",
          "kind": "pipeline"
        }
      ]
    }
  ]
}

Endpoints

Webhooks

Subscribe a URL to events.

List this key's webhooks

GET/webhooks

A key only ever sees the subscriptions it created.

Returns

200The subscriptions. A list of Webhook objects in data.

  • 401unauthorizedThe key is missing, wrong or revoked.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/webhooks \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": [
    {
      "id": "0f8c8c1b-dddd-4000-8000-000000000022",
      "object": "webhook",
      "event": "job.stage_changed",
      "target_url": "https://hooks.zapier.com/hooks/standard/1234567/abcdef/",
      "description": "Slack: approved claims",
      "filters": {
        "stage": "claim_approved"
      },
      "created_at": "2026-09-20T18:30:00.000Z",
      "disabled_at": null
    }
  ]
}

Subscribe to an event

POST/webhooks

Send event (one event, or "*" for every event including ones added later) or events (several). The URL must be https, public, and not a private or link-local address. The response carries the signing secret — once. Several events for one URL share one secret.

filters narrows a single-event subscription, e.g. {"stage": "Claim Approved"} on job.stage_changed fires only when a job enters that stage. GET /events lists what each event accepts.

Subscribing the same event, URL and filters twice returns the existing subscription. A read-only key can subscribe.

Headers

  • Idempotency-Keystring

    Any unique string (a UUID is ideal). A retry with the same key within 24 hours replays the first answer — with Idempotent-Replayed: true — instead of doing the work again. Reusing a key for a DIFFERENT request is a 409.

    Up to 255 characters

Request bodyapplication/json

  • eventstring

    One event, or "*".

  • eventsarray of string

    Several events for one URL.

  • target_urlstringuriRequired

    targetUrl works too (Zapier's spelling).

  • descriptionstring
  • filtersobject

    Only with a single event. See GET /events.

Returns

201Subscribed. One event returns the subscription; several return `{ "object": "list", "data": [...], "secret": "…" }`. A WebhookCreated object.

  • 400invalid_requestSomething in the request was wrong; field names what.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/webhooks \
  -H "Authorization: Bearer $HAILMATE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "event": "job.stage_changed",
  "target_url": "https://yourapp.example.com/hooks/hailmate",
  "filters": {
    "stage": "claim_approved"
  }
}'
Response · 201
{
  "id": "0f8c8c1b-dddd-4000-8000-000000000022",
  "object": "webhook",
  "event": "job.stage_changed",
  "target_url": "https://hooks.zapier.com/hooks/standard/1234567/abcdef/",
  "description": "Slack: approved claims",
  "filters": {
    "stage": "claim_approved"
  },
  "created_at": "2026-09-20T18:30:00.000Z",
  "disabled_at": null,
  "secret": "whsec_3a2b1c5f…"
}

Get a webhook

GET/webhooks/{id}

Path parameters

  • idstringuuidRequired

Returns

200The subscription. A Webhook object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/webhooks/0f8c8c1b-dddd-4000-8000-000000000022 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "0f8c8c1b-dddd-4000-8000-000000000022",
  "object": "webhook",
  "event": "job.stage_changed",
  "target_url": "https://hooks.zapier.com/hooks/standard/1234567/abcdef/",
  "description": "Slack: approved claims",
  "filters": {
    "stage": "claim_approved"
  },
  "created_at": "2026-09-20T18:30:00.000Z",
  "disabled_at": null
}

Unsubscribe

DELETE/webhooks/{id}

Answering a delivery with 410 Gone unsubscribes too.

Path parameters

  • idstringuuidRequired

Returns

200Removed. A Deleted object.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X DELETE https://app.hailmate.ai/api/v1/webhooks/0f8c8c1b-dddd-4000-8000-000000000022 \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true
}

See what an event delivers

GET/webhooks/samples/{event}

Up to three REAL recent records from your workspace, wrapped exactly as a delivery of that event wraps them. Use it to map fields before any event has happened.

Path parameters

  • eventstringRequired

Returns

200Sample deliveries. A list in data.

  • 404not_foundNo such record in this workspace.

Any request can also answer 401, 402, 429 or 500 — errors.

curl https://app.hailmate.ai/api/v1/webhooks/samples/job.created \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "object": "list",
  "data": []
}

Endpoints

OAuth

Log in with HailMate: the token endpoints for an app that connects on a person's behalf.

Get or refresh an access token

POST/oauth/token

The token endpoint of the OAuth 2.0 authorization-code flow. After the person presses Allow at https://app.hailmate.ai/oauth/authorize, your app is sent back with ?code=…&state=…; trade the code here within ten minutes. The access token lasts an hour — trade the refresh token for a new one. The refresh token does not change.

Authenticate your app with client_id and client_secret in the body or as HTTP Basic. The body may be form-encoded (the standard) or JSON. Errors use the OAuth standard's own shape: { "error": "invalid_grant", "error_description": "…" }. A code used twice disconnects the connection it made.

Request bodyapplication/x-www-form-urlencoded

  • grant_typestringRequired
    authorization_coderefresh_token
  • codestring

    For authorization_code.

  • redirect_uristringuri

    For authorization_code — the same address the person was sent back to.

  • refresh_tokenstring

    For refresh_token.

  • client_idstringRequired
  • client_secretstringRequired

Returns

200A token. An OAuthToken object.

  • 400invalid_requestThe code or refresh token is not valid (invalid_grant), or the request is malformed.
  • 401unauthorizedUnknown app or wrong secret (invalid_client).

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/oauth/token \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{
  "access_token": "hm_oat_1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l0z",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "hm_ort_8d2k6m1q9x4w7c3t0r5p6n2j8h1g4f7d3s9a2l6e",
  "scope": "write",
  "workspace_id": "5f0c2a8e-1b3d-4c7a-9e21-7a3b8d4c6e10",
  "workspace": "Ridgeline Roofing"
}

Disconnect

POST/oauth/revoke

RFC 7009. Send a refresh token to disconnect the connection — its tokens stop working and the webhooks it set up are switched off — or an access token to retire just that token. Always answers 200.

Request bodyapplication/x-www-form-urlencoded

  • tokenstringRequired
  • client_idstringRequired
  • client_secretstringRequired

Returns

200Done.

  • 401unauthorizedUnknown app or wrong secret.

Any request can also answer 401, 402, 429 or 500 — errors.

curl -X POST https://app.hailmate.ai/api/v1/oauth/revoke \
  -H "Authorization: Bearer $HAILMATE_API_KEY"
Response · 200
{}

Objects

What the API returns

Every record carries id and object. Fields are only ever added, so ignore any you do not recognise. A webhook delivery carries the same fields at its top level.

Error

The body of every error response. Branch on error.code.

Fields

  • errorobjectRequired
  • error.codestringRequired

    Machine-readable. Branch on this.

    unauthorizedforbiddennot_foundinvalid_requestconflictpayload_too_largerate_limitedplan_requiredmethod_not_allowedserver_error
  • error.messagestringRequired

    For a person. May be reworded.

  • error.fieldstring

    The request field that was wrong, when there was one.

  • error.request_idstring
  • error.doc_urlstringuriRequired
Error object
{
  "error": {
    "code": "invalid_request",
    "message": "A job needs a name.",
    "field": "name",
    "request_id": "req_jfvtxfboxyzopov1pi4d",
    "doc_url": "https://hailmate.ai/docs/api#errors"
  }
}

Ping

What GET /ping returns: the workspace a key belongs to, and what the key may do.

Fields

  • okboolean
  • objectstringalways "workspace"
  • workspace_idstringuuid
  • workspacestring | null

    The workspace's name.

  • api_versionstring
  • keyobject
  • key.namestring
  • key.accessstring
    readwrite

Returned by check a key

Ping object
{
  "ok": true,
  "object": "workspace",
  "workspace_id": "5f0c2a8e-1b3d-4c7a-9e21-7a3b8d4c6e10",
  "workspace": "Ridgeline Roofing",
  "api_version": "v1",
  "key": {
    "name": "Zapier",
    "access": "write"
  }
}

Deleted

What a delete returns.

Fields

  • idstringuuid
  • objectstring
  • deletedbooleanalways "true"
Deleted object
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true
}

DeletedSnapshot

What a *.deleted delivery carries — the record is gone, so these are the fields that identify your copy of it.

Fields

  • idstringuuid
  • objectstring
    jobcontacttask
  • deletedbooleanalways "true"
  • job_numberstring
  • namestring
  • addressstring
  • first_namestring
  • last_namestring
  • emailstring
  • phonestring
  • titlestring
  • job_idstringuuid
DeletedSnapshot object
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "deleted": true,
  "job_number": "JOB-00142",
  "name": "1804 Cedar Ridge Dr",
  "address": "1804 Cedar Ridge Dr"
}

PersonRef

A person on a job — the homeowner or the adjuster — in brief. Fetch the contact for everything else.

Fields

  • idstringuuid
  • namestring | null
  • emailstring | null
  • phonestring | null
PersonRef object
{
  "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "name": "Dana Reed",
  "email": "dana@example.com",
  "phone": "(972) 555-0148"
}

Job

The storm-restoration jobs on your pipeline boards.

Fields

  • idstringuuid
  • objectstringalways "job"
  • job_numberstring | null
  • namestring | null
  • job_typestring
    insuranceretail
  • stagestring | null

    The stage key. Filter on this.

  • stage_labelstring | null

    The stage as your board names it.

  • stage_is_completedboolean | null

    The stage is a won / completed column.

  • stage_is_lostboolean | null

    The stage is a lost column.

  • stage_entered_atstring | nulldate-time
  • pipeline_idstring | nulluuid
  • pipeline_namestring | null
  • addressstring | null
  • citystring | null
  • statestring | null

    Two-letter code.

  • postal_codestring | null
  • countystring | null
  • homeowner_idstring | nulluuid
  • homeownerPersonRef | null
  • adjuster_idstring | nulluuid
  • adjusterPersonRef | null
  • secondary_contact_idsarray of stringuuid
  • secondary_adjuster_idsarray of stringuuid
  • assigned_to_idstring | nulluuid

    The primary assignee.

  • assigned_to_namestring | null
  • assignee_idsarray of stringuuid

    Everyone on the job, primary included.

  • assignee_namesarray of string
  • insurance_companystring | null
  • claim_numberstring | null
  • policy_numberstring | null
  • date_of_lossstring | nulldate
  • damage_typesarray of string
  • tagsarray of string
  • lead_sourcestring | null
  • prioritystring | null
    lownormalhighurgent
  • mortgage_companystring | null
  • financing_methodstring | null
    cashcheckcredit_cardfinancingother
  • rcv_amountnumber | null

    Replacement cost value on the claim.

  • acv_amountnumber | null

    Actual cash value.

  • deductiblenumber | null
  • supplements_amountnumber | null
  • estimated_amountnumber | null
  • final_amountnumber | null

    Contract value on a retail job.

  • total_job_valuenumber | null

    What the job is worth — the same figure the Money tab shows.

  • amount_receivednumber | null

    Money received on the job so far.

  • balance_duenumber | null
  • contract_datestring | nulldate
  • installation_datestring | nulldate
  • archivedboolean
  • completed_atstring | nulldate-time
  • lost_atstring | nulldate-time
  • lost_reasonstring | null
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri

    Opens the job in HailMate.

  • portal_urlstring | nulluri

    The homeowner's job page — the same link "Copy Homeowner Link" gives.

Job object
{
  "id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "object": "job",
  "job_number": "JOB-00142",
  "name": "1804 Cedar Ridge Dr",
  "job_type": "insurance",
  "stage": "inspection_scheduled",
  "stage_label": "Inspection Scheduled",
  "stage_is_completed": false,
  "stage_is_lost": false,
  "stage_entered_at": "2026-09-16T14:02:00.000Z",
  "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "pipeline_name": "Insurance",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "county": "Collin",
  "homeowner_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "homeowner": {
    "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
    "name": "Dana Reed",
    "email": "dana@example.com",
    "phone": "(972) 555-0148"
  },
  "adjuster_id": null,
  "adjuster": null,
  "secondary_contact_ids": [],
  "secondary_adjuster_ids": [],
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "assignee_ids": [
    "5d0e1c2b-7777-4000-8000-0000000000ab"
  ],
  "assignee_names": [
    "Sam Carter"
  ],
  "insurance_company": "Example Mutual",
  "claim_number": "CLM-88213",
  "policy_number": null,
  "date_of_loss": "2026-09-12",
  "damage_types": [
    "hail"
  ],
  "tags": [],
  "lead_source": "Website",
  "priority": "normal",
  "mortgage_company": null,
  "financing_method": null,
  "rcv_amount": 24380.5,
  "acv_amount": 19240,
  "deductible": 2500,
  "supplements_amount": null,
  "estimated_amount": null,
  "final_amount": null,
  "total_job_value": 24380.5,
  "amount_received": 0,
  "balance_due": 24380.5,
  "contract_date": null,
  "installation_date": null,
  "archived": false,
  "completed_at": null,
  "lost_at": null,
  "lost_reason": null,
  "created_at": "2026-09-16T14:02:00.000Z",
  "updated_at": "2026-09-16T14:02:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa",
  "portal_url": "https://app.hailmate.ai/project/0f0f0f0f-3333-4000-8000-0000000000cc"
}

ContactType

What kind of contact someone is.

A string, one of:

homeownercommercialadjustercontractorsubcontractorinstall_crewinspectormortgage_companyother

Contact

Homeowners, adjusters, subcontractors and everyone else in your book.

Fields

  • idstringuuid
  • objectstringalways "contact"
  • first_namestring | null
  • last_namestring | null
  • full_namestring | null
  • emailstring | null
  • phonestring | null
  • companystring | null
  • typestring
    homeownercommercialadjustercontractorsubcontractorinstall_crewinspectormortgage_companyother
  • tradesarray of string

    For a subcontractor — gutters, siding…

  • addressstring | null
  • citystring | null
  • statestring | null
  • postal_codestring | null
  • notesstring | null
  • claim_numberstring | null
  • adjuster_typestring | null
  • adjuster_extensionstring | null
  • assigned_to_idstring | nulluuid
  • assigned_to_namestring | null
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
Contact object
{
  "id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "object": "contact",
  "first_name": "Dana",
  "last_name": "Reed",
  "full_name": "Dana Reed",
  "email": "dana@example.com",
  "phone": "(972) 555-0148",
  "company": null,
  "type": "homeowner",
  "trades": [],
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "notes": null,
  "claim_number": null,
  "adjuster_type": null,
  "adjuster_extension": null,
  "assigned_to_id": null,
  "assigned_to_name": null,
  "created_at": "2026-09-16T13:40:00.000Z",
  "updated_at": "2026-09-16T13:40:00.000Z",
  "url": "https://app.hailmate.ai/contact/b7c2d3e4-4444-4000-8000-0000000000dd"
}

Task

Tasks and appointments. An appointment is a task with an appointment_type.

Fields

  • idstringuuid
  • objectstringalways "task"
  • titlestring | null
  • descriptionstring | null
  • due_datestring | null

    Wall-clock — the local time the crew reads. No offset.

  • end_datestring | nulldate

    The last day of a task that blocks off several days.

  • duration_minutesinteger | null
  • prioritystring | null
    lownormalhigh
  • completedboolean
  • completed_atstring | nulldate-time
  • is_appointmentboolean
  • appointment_typestring | null
    inspectionadjuster_meetingbuild_day
  • outcomestring | null
    completedno_showrescheduledcanceled
  • customer_reminderstring | null

    Whether HailMate reminds the homeowner the day before.

    nonesmsemailboth
  • reminder_minutesinteger | null
  • job_idstring | nulluuid
  • contact_idstring | nulluuid
  • assigned_to_idstring | nulluuid
  • assigned_to_namestring | null
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
Task object
{
  "id": "d4e5f6a7-5555-4000-8000-0000000000ee",
  "object": "task",
  "title": "Adjuster meeting — 1804 Cedar Ridge Dr",
  "description": null,
  "due_date": "2026-10-02T15:00:00",
  "end_date": null,
  "duration_minutes": 60,
  "priority": "normal",
  "completed": false,
  "completed_at": null,
  "is_appointment": true,
  "appointment_type": "adjuster_meeting",
  "outcome": null,
  "customer_reminder": "sms",
  "reminder_minutes": 60,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "assigned_to_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "assigned_to_name": "Sam Carter",
  "created_at": "2026-09-16T14:10:00.000Z",
  "updated_at": "2026-09-16T14:10:00.000Z",
  "url": "https://app.hailmate.ai/task/d4e5f6a7-5555-4000-8000-0000000000ee"
}

Estimate

Estimates and proposals — made from one of your templates or as your standard proposal, then finished and sent in HailMate.

Fields

  • idstringuuid
  • objectstringalways "estimate"
  • estimate_numberstring | null
  • titlestring | null
  • document_typestring | null
    proposalestimate
  • statusstring | null
    draftsentviewedsignedexpireddeclined
  • signature_statusstring | null
  • totalnumber | null

    The selected package's price, else the base package. Null — never 0 — when it could not be computed.

  • package_totalsobject | null

    Every package's price, keyed by package.

  • upgrades_totalnumber | null

    Optional upgrades, quoted outside the package price.

  • selected_tierstring | null

    The package the homeowner chose.

  • job_idstring | nulluuid
  • valid_untilstring | nulldate-time
  • sent_atstring | nulldate-time
  • first_viewed_atstring | nulldate-time
  • last_viewed_atstring | nulldate-time
  • view_countinteger
  • signed_atstring | nulldate-time
  • signer_namestring | null
  • pdf_urlstring | nulluri
  • signed_pdf_urlstring | nulluri
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
  • view_urlstring | nulluri

    The homeowner's view of the estimate.

Estimate object
{
  "id": "a41c9e20-2222-4000-8000-0000000000e1",
  "object": "estimate",
  "estimate_number": "EST-0214",
  "title": "Roof replacement — 1804 Cedar Ridge Dr",
  "document_type": "proposal",
  "status": "sent",
  "signature_status": "pending",
  "total": 21900,
  "package_totals": {
    "good": 18450,
    "better": 21900,
    "best": 26400
  },
  "upgrades_total": 1250,
  "selected_tier": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "valid_until": "2026-10-28T00:00:00.000Z",
  "sent_at": "2026-09-28T15:10:00.000Z",
  "first_viewed_at": "2026-09-28T18:42:00.000Z",
  "last_viewed_at": "2026-09-28T19:05:00.000Z",
  "view_count": 3,
  "signed_at": null,
  "signer_name": null,
  "pdf_url": "https://files.example-cdn.com/estimates/EST-0214.pdf",
  "signed_pdf_url": null,
  "created_at": "2026-09-27T21:30:00.000Z",
  "updated_at": "2026-09-28T19:05:00.000Z",
  "url": "https://app.hailmate.ai/estimates/a41c9e20-2222-4000-8000-0000000000e1",
  "view_url": "https://app.hailmate.ai/estimate/6f1d3b52-9c7e-4a10-8f3b-2d4e5a6b7c8d"
}

Invoice

Draft invoices, totalled exactly as HailMate totals them; mark them sent, or void them.

Fields

  • idstringuuid
  • objectstringalways "invoice"
  • invoice_numberstring | null
  • titlestring | null
  • statusstring
    draftsentviewedpartially_paidpaidoverduevoidbad_debt
  • purposestring | null
    claim_scopedeductiblesupplementdepreciationcontractother
  • subtotalnumber | null
  • discount_amountnumber | null
  • tax_amountnumber | null
  • late_fee_amountnumber | null
  • total_amountnumber
  • amount_paidnumber
  • balance_duenumber

    total_amount - amount_paid, never below zero.

  • part_numberinteger | null

    When billed in parts, which part this is.

  • part_countinteger | null
  • issue_datestring | nulldate
  • due_datestring | nulldate
  • sent_atstring | nulldate-time
  • first_viewed_atstring | nulldate-time
  • paid_atstring | nulldate-time
  • job_idstring | nulluuid
  • contact_idstring | nulluuid
  • estimate_idstring | nulluuid
  • pdf_urlstring | nulluri
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
  • payment_urlstring | nulluri

    The homeowner's pay page — the same link "Copy Pay Link" gives.

Invoice object
{
  "id": "c90d7b31-3333-4000-8000-0000000000f2",
  "object": "invoice",
  "invoice_number": "INV-0311",
  "title": "Deductible",
  "status": "sent",
  "purpose": "deductible",
  "subtotal": 2500,
  "discount_amount": 0,
  "tax_amount": 0,
  "late_fee_amount": 0,
  "total_amount": 2500,
  "amount_paid": 0,
  "balance_due": 2500,
  "part_number": null,
  "part_count": null,
  "issue_date": "2026-09-28",
  "due_date": "2026-10-12",
  "sent_at": "2026-09-28T16:00:00.000Z",
  "first_viewed_at": null,
  "paid_at": null,
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "contact_id": "b7c2d3e4-4444-4000-8000-0000000000dd",
  "estimate_id": null,
  "pdf_url": "https://files.example-cdn.com/invoices/INV-0311.pdf",
  "created_at": "2026-09-28T15:55:00.000Z",
  "updated_at": "2026-09-28T16:00:00.000Z",
  "url": "https://app.hailmate.ai/jobs/invoice/c90d7b31-3333-4000-8000-0000000000f2",
  "payment_url": "https://app.hailmate.ai/invoice/0b7e2c19-5d4a-4f3e-9a1b-8c6d2e4f1a37"
}

PaymentType

What a payment was for.

A string, one of:

acvdeductiblesupplementdepreciationretailother

Payment

Money received against a job — carrier cheques, deductibles, card payments.

Fields

  • idstringuuid
  • objectstringalways "payment"
  • job_idstringuuid
  • invoice_idstring | nulluuid
  • amountnumber

    Negative for a refund.

  • payment_typestring
    acvdeductiblesupplementdepreciationretailother
  • payer_typestring
    insurancehomeownermortgage_companyother
  • payment_methodstring
    checkcashcardachfinancingother
  • statusstring
    expectedreceivedsent_to_mortgageendorseddeposited
  • check_numberstring | null
  • date_receivedstring | nulldate
  • date_depositedstring | nulldate
  • notesstring | null
  • is_refundboolean
  • refund_of_payment_idstring | nulluuid
  • onlineboolean

    Paid through HailMate's online payment page.

  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstring | nulluri
Payment object
{
  "id": "9fa3e1d2-5555-4000-8000-0000000000c3",
  "object": "payment",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "invoice_id": null,
  "amount": 13164,
  "payment_type": "acv",
  "payer_type": "insurance",
  "payment_method": "check",
  "status": "received",
  "check_number": "4471",
  "date_received": "2026-09-26",
  "date_deposited": null,
  "notes": "First ACV check from Example Mutual",
  "is_refund": false,
  "refund_of_payment_id": null,
  "online": false,
  "created_at": "2026-09-26T20:14:00.000Z",
  "updated_at": "2026-09-26T20:14:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

Note

Notes on a job's timeline.

Fields

  • idstringuuid
  • objectstringalways "note"
  • job_idstringuuid
  • contentstring
  • author_idstring | nulluuid

    Null for a note written through the API.

  • author_namestring | null
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
Note object
{
  "id": "3c8b1a07-6666-4000-8000-0000000000b4",
  "object": "note",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "content": "Adjuster meeting moved to Thursday 10am. Homeowner will be home.",
  "author_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "author_name": "Sam Carter",
  "created_at": "2026-09-27T14:20:00.000Z",
  "updated_at": "2026-09-27T14:20:00.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

File

Photos and documents on a job.

Fields

  • idstringuuid
  • objectstringalways "file"
  • job_idstring | nulluuid
  • namestring
  • categorystring
    photodocumentscopeestimatecontractother
  • mime_typestring | null
  • is_photoboolean
  • is_videoboolean
  • size_bytesinteger | null
  • descriptionstring | null

    The caption.

  • tagsarray of string
  • latitudenumber | null

    Where a photo was taken.

  • longitudenumber | null
  • taken_atstring | nulldate-time
  • uploaded_by_idstring | nulluuid
  • uploaded_by_namestring | null
  • download_urlstringuri
  • created_atstringdate-time
  • urlstring | nulluri
File object
{
  "id": "7e2d9c40-8888-4000-8000-0000000000a5",
  "object": "file",
  "job_id": "f2b1a0c4-1111-4000-8000-0000000000aa",
  "name": "north-slope-hits.jpg",
  "category": "photo",
  "mime_type": "image/jpeg",
  "is_photo": true,
  "is_video": false,
  "size_bytes": 1532410,
  "description": "Hail hits on the north slope, chalked",
  "tags": [
    "damage",
    "north slope"
  ],
  "latitude": 33.0726,
  "longitude": -96.7512,
  "taken_at": "2026-09-16T15:12:08.000Z",
  "uploaded_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "uploaded_by_name": "Sam Carter",
  "download_url": "https://files.example-cdn.com/jobs/f2b1a0c4/north-slope-hits.jpg",
  "created_at": "2026-09-16T15:12:40.000Z",
  "url": "https://app.hailmate.ai/job/f2b1a0c4-1111-4000-8000-0000000000aa"
}

KnockResult

The outcome a rep recorded at a door.

A string, one of:

interestednot_interestedcontactedno_answerdoor_hangerfollow_upappointment_scheduleddont_knockrenterno_damagecash_quotelost

Pin

Door knocks — pins on the canvassing map with a knock result.

Fields

  • idstringuuid
  • objectstringalways "pin"
  • pin_typestring
    knockinspectionjob
  • knock_resultstring | null
    interestednot_interestedcontactedno_answerdoor_hangerfollow_upappointment_scheduleddont_knockrenterno_damagecash_quotelost
  • addressstring | null
  • citystring | null
  • statestring | null
  • postal_codestring | null
  • latitudenumber
  • longitudenumber
  • homeowner_namestring | null
  • homeowner_first_namestring | null
  • homeowner_last_namestring | null
  • phonestring | null
  • emailstring | null
  • notesstring | null
  • job_idstring | nulluuid

    Set once the pin became a job.

  • created_by_idstringuuid
  • created_by_namestring | null
  • created_atstringdate-time
  • updated_atstringdate-time
  • map_urlstring | nulluri
  • urlstringuri
Pin object
{
  "id": "2b6f4e18-9999-4000-8000-0000000000d6",
  "object": "pin",
  "pin_type": "knock",
  "knock_result": "interested",
  "address": "1812 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "postal_code": "75024",
  "latitude": 33.0731,
  "longitude": -96.7519,
  "homeowner_name": "Chris Lane",
  "homeowner_first_name": "Chris",
  "homeowner_last_name": "Lane",
  "phone": "(972) 555-0193",
  "email": null,
  "notes": "Wants an inspection Saturday morning",
  "job_id": null,
  "created_by_id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "created_by_name": "Sam Carter",
  "created_at": "2026-09-27T17:45:00.000Z",
  "updated_at": "2026-09-27T17:45:00.000Z",
  "map_url": "https://www.google.com/maps?q=33.0731,-96.7519",
  "url": "https://app.hailmate.ai/canvassing"
}

LineItemInput

Fields

  • namestringRequired
  • descriptionstring
  • quantitynumber

    At least 0 · Default 1

  • unitstring

    sq, lf, ea…

  • unit_pricenumber

    Required on an invoice line. Negative on an invoice is a credit.

  • taxableboolean

    Invoices only.

    Default true

LineItemInput object
{
  "name": "string",
  "description": "string",
  "quantity": 1,
  "unit": "string",
  "unit_price": 0,
  "taxable": true
}

EstimateTemplate

Fields

  • idstringuuid
  • objectstringalways "estimate_template"
  • namestring
  • template_numberstring | null
  • created_atstringdate-time
  • updated_atstringdate-time
EstimateTemplate object
{
  "id": "7a1c9e02-2222-4000-8000-0000000000c3",
  "object": "estimate_template",
  "name": "Insurance roof replacement",
  "template_number": "TPL-0003",
  "created_at": "2026-08-30T15:00:00.000Z",
  "updated_at": "2026-09-20T18:30:00.000Z"
}

EstimateTemplateList

Fields

  • objectstringalways "list"
  • dataarray of EstimateTemplate
  • has_morebooleanalways "false"
  • next_cursornull
EstimateTemplateList object
{
  "object": "list",
  "data": [
    {
      "id": "7a1c9e02-2222-4000-8000-0000000000c3",
      "object": "estimate_template",
      "name": "Insurance roof replacement",
      "template_number": "TPL-0003",
      "created_at": "2026-08-30T15:00:00.000Z",
      "updated_at": "2026-09-20T18:30:00.000Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

OAuthTokenRequest

Fields

  • grant_typestringRequired
    authorization_coderefresh_token
  • codestring

    For authorization_code.

  • redirect_uristringuri

    For authorization_code — the same address the person was sent back to.

  • refresh_tokenstring

    For refresh_token.

  • client_idstringRequired
  • client_secretstringRequired
OAuthTokenRequest object
{
  "grant_type": "authorization_code",
  "code": "string",
  "redirect_uri": "https://app.hailmate.ai/…",
  "refresh_token": "string",
  "client_id": "string",
  "client_secret": "string"
}

OAuthRevokeRequest

Fields

  • tokenstringRequired
  • client_idstringRequired
  • client_secretstringRequired
OAuthRevokeRequest object
{
  "token": "string",
  "client_id": "string",
  "client_secret": "string"
}

OAuthToken

Fields

  • access_tokenstring

    hm_oat_… — send as Authorization: Bearer.

  • token_typestringalways "Bearer"
  • expires_ininteger

    Seconds — an hour.

  • refresh_tokenstring

    hm_ort_… — keep it secret; it does not change.

  • scopestring
    readwrite
  • workspace_idstringuuid
  • workspacestring | null

    The company that was connected.

OAuthToken object
{
  "access_token": "hm_oat_1q2w3e4r5t6y7u8i9o0p1a2s3d4f5g6h7j8k9l0z",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "hm_ort_8d2k6m1q9x4w7c3t0r5p6n2j8h1g4f7d3s9a2l6e",
  "scope": "write",
  "workspace_id": "5f0c2a8e-1b3d-4c7a-9e21-7a3b8d4c6e10",
  "workspace": "Ridgeline Roofing"
}

OAuthError

Fields

  • errorstring
    invalid_requestinvalid_clientinvalid_grantunsupported_grant_typeserver_error
  • error_descriptionstring
OAuthError object
{
  "error": "invalid_grant",
  "error_description": "That code has expired. Start the connection again."
}

StormList

Every property under hail of a chosen size, with the owner of record (read only).

Fields

  • idstringuuid
  • objectstringalways "storm_list"
  • namestring | null
  • statusstring | null
    buildingreadypartialfailed
  • sourcestring | null
    manualauto
  • window_fromstring | nulldate
  • window_tostring | nulldate
  • min_size_innumber | null
  • area_kindstring | null
  • territory_idstring | nulluuid
  • clipped_area_sq_minumber | null
  • property_capinteger | null
  • property_countinteger | null
  • skipped_duplicatesinteger | null
  • dedupe_daysinteger | null
  • credits_spentinteger | null
  • total_availableinteger | null
  • storm_datestring | nulldate
  • built_atstring | nulldate-time
  • created_atstringdate-time
  • updated_atstringdate-time
  • urlstringuri
StormList object
{
  "id": "e5a1c7d9-aaaa-4000-8000-0000000000e7",
  "object": "storm_list",
  "name": "Plano 1.25″+ — Sep 12",
  "status": "ready",
  "source": "manual",
  "window_from": "2026-09-12",
  "window_to": "2026-09-12",
  "min_size_in": 1.25,
  "area_kind": "drawn",
  "territory_id": null,
  "clipped_area_sq_mi": 4.2,
  "property_cap": 1000,
  "property_count": 412,
  "skipped_duplicates": 18,
  "dedupe_days": 90,
  "credits_spent": 412,
  "total_available": 430,
  "storm_date": "2026-09-12",
  "built_at": "2026-09-13T13:04:00.000Z",
  "created_at": "2026-09-13T13:02:00.000Z",
  "updated_at": "2026-09-13T13:04:00.000Z",
  "url": "https://app.hailmate.ai/canvassing/lists/e5a1c7d9-aaaa-4000-8000-0000000000e7"
}

StormListProperty

One property on a storm list, with the owner of record and the hail measured at that roof.

Fields

  • idstringuuid
  • objectstringalways "storm_list_property"
  • storm_list_idstringuuid
  • addressstring | null
  • citystring | null
  • statestring | null
  • zipstring | null
  • owner_namestring | null
  • owner_occupiedboolean | null

    Null when the county record did not say.

  • mailing_addressstring | null
  • mailing_citystring | null
  • mailing_statestring | null
  • mailing_zipstring | null
  • mail_deliverableboolean

    Our judgement — NOT a CASS or NCOA result.

  • mail_exclude_reasonstring | null
  • hail_size_innumber | null
  • hail_event_datestring | nulldate
  • nearest_report_minumber | null
  • nearest_report_size_innumber | null
  • year_builtinteger | null
  • property_usestring | null
  • is_residentialboolean | null
  • latitudenumber | null
  • longitudenumber | null
  • created_atstringdate-time
StormListProperty object
{
  "id": "d4b3a2c1-bbbb-4000-8000-0000000000f8",
  "object": "storm_list_property",
  "storm_list_id": "e5a1c7d9-aaaa-4000-8000-0000000000e7",
  "address": "1804 Cedar Ridge Dr",
  "city": "Plano",
  "state": "TX",
  "zip": "75024",
  "owner_name": "Dana Reed",
  "owner_occupied": true,
  "mailing_address": "1804 Cedar Ridge Dr",
  "mailing_city": "Plano",
  "mailing_state": "TX",
  "mailing_zip": "75024",
  "mail_deliverable": true,
  "mail_exclude_reason": null,
  "hail_size_in": 1.5,
  "hail_event_date": "2026-09-12",
  "nearest_report_mi": 1.8,
  "nearest_report_size_in": 1.75,
  "year_built": 2004,
  "property_use": "Single family",
  "is_residential": true,
  "latitude": 33.0726,
  "longitude": -96.7512,
  "created_at": "2026-09-13T13:04:00.000Z"
}

HailEvent

One hail day at the address.

Fields

  • datestringdate
  • size_innumber | null

    The size HailMate stands behind for this day at this address.

  • confidencestring | null
    confirmedlikelyradar
  • confirmed_by_ground_reportboolean
  • radar_estimated_size_innumber | null
  • severe_hail_probabilityinteger | null

    Percent.

  • ground_report_size_innumber | null
  • ground_report_distance_minumber | null
  • ground_report_countinteger
HailEvent object
{
  "date": "2026-09-12",
  "size_in": 1.5,
  "confidence": "confirmed",
  "confirmed_by_ground_report": true,
  "radar_estimated_size_in": 1.5,
  "severe_hail_probability": 80,
  "ground_report_size_in": 1.75,
  "ground_report_distance_mi": 1.8,
  "ground_report_count": 3
}

HailReport

Hail and damaging-wind history at an address.

Fields

  • objectstringalways "hail_report"
  • addressstring | null

    The address as it was found.

  • latitudenumber
  • longitudenumber
  • sincestringdate
  • hail_day_countinteger
  • largest_hail_innumber | null
  • last_hail_datestring | nulldate
  • hail_eventsarray of HailEvent
  • wind_eventsarray of object
  • wind_events[].datestringdate
  • wind_events[].max_gust_mphnumber | null

    Null when the report was damage with no measured gust.

HailReport object
{
  "object": "hail_report",
  "address": "1804 Cedar Ridge Dr, Plano, TX 75024, USA",
  "latitude": 33.0198,
  "longitude": -96.6989,
  "since": "2021-09-28",
  "hail_day_count": 2,
  "largest_hail_in": 1.5,
  "last_hail_date": "2025-03-25",
  "hail_events": [
    {
      "date": "2025-03-25",
      "size_in": 1.5,
      "confidence": "confirmed",
      "confirmed_by_ground_report": true,
      "radar_estimated_size_in": null,
      "severe_hail_probability": null,
      "ground_report_size_in": 1.5,
      "ground_report_distance_mi": 1.4,
      "ground_report_count": 11
    },
    {
      "date": "2024-05-28",
      "size_in": 1.5,
      "confidence": "likely",
      "confirmed_by_ground_report": false,
      "radar_estimated_size_in": 1.5,
      "severe_hail_probability": null,
      "ground_report_size_in": 1.25,
      "ground_report_distance_mi": 9,
      "ground_report_count": 1
    }
  ],
  "wind_events": [
    {
      "date": "2025-03-04",
      "max_gust_mph": 90
    }
  ]
}

PipelineStage

A column on one of your pipeline boards.

Fields

  • idstringuuid
  • objectstringalways "pipeline_stage"
  • pipeline_idstringuuid
  • keystring

    What you send and filter on.

  • labelstring

    What to show a person.

  • orderinteger
  • is_completedboolean
  • is_lostboolean
PipelineStage object
{
  "id": "8a7b6c5d-cccc-4000-8000-000000000011",
  "object": "pipeline_stage",
  "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "key": "claim_approved",
  "label": "Claim Approved",
  "order": 6,
  "is_completed": false,
  "is_lost": false
}

Pipeline

One of your pipeline boards, with its stages in board order.

Fields

  • idstringuuid
  • objectstringalways "pipeline"
  • namestring
  • is_defaultboolean
  • orderinteger | null
  • stagesarray of PipelineStage
Pipeline object
{
  "id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
  "object": "pipeline",
  "name": "Insurance",
  "is_default": true,
  "order": 0,
  "stages": [
    {
      "id": "8a7b6c5d-cccc-4000-8000-000000000010",
      "object": "pipeline_stage",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "key": "lead",
      "label": "Lead",
      "order": 0,
      "is_completed": false,
      "is_lost": false
    },
    {
      "id": "8a7b6c5d-cccc-4000-8000-000000000011",
      "object": "pipeline_stage",
      "pipeline_id": "1cf7d87b-7d99-4ba0-b277-0e88ac127e75",
      "key": "claim_approved",
      "label": "Claim Approved",
      "order": 6,
      "is_completed": false,
      "is_lost": false
    }
  ]
}

User

Someone on your team.

Fields

  • idstringuuid
  • objectstringalways "user"
  • namestring | null
  • emailstring | null
  • rolestring
    owneradminmember

Returned by list your team

User object
{
  "id": "5d0e1c2b-7777-4000-8000-0000000000ab",
  "object": "user",
  "name": "Sam Carter",
  "email": "sam@ridgelineroofing.example",
  "role": "member"
}

EventDefinition

A webhook event and the filters it accepts, from GET /events.

Fields

  • eventstring
  • resourcestring
  • labelstring
  • descriptionstring
  • filtersarray of object
  • filters[].keystring
  • filters[].labelstring
  • filters[].kindstring
    stageuserpipelineenumboolean
  • filters[].valuesarray of string
EventDefinition object
{
  "event": "job.stage_changed",
  "resource": "job",
  "label": "Job Stage Changed",
  "description": "A job moved to a different stage on the board.",
  "filters": [
    {
      "key": "stage",
      "label": "Stage",
      "kind": "stage"
    },
    {
      "key": "previous_stage",
      "label": "Previous stage",
      "kind": "stage"
    },
    {
      "key": "job_type",
      "label": "Job type",
      "kind": "enum",
      "values": [
        "insurance",
        "retail"
      ]
    },
    {
      "key": "pipeline_id",
      "label": "Pipeline",
      "kind": "pipeline"
    }
  ]
}

Webhook

Subscribe a URL to events.

Fields

  • idstringuuid
  • objectstringalways "webhook"
  • eventstring

    An event name, or "*" for every event.

  • target_urlstringuri
  • descriptionstring | null
  • filtersobject | null
  • created_atstringdate-time
  • disabled_atstring | nulldate-time
Webhook object
{
  "id": "0f8c8c1b-dddd-4000-8000-000000000022",
  "object": "webhook",
  "event": "job.stage_changed",
  "target_url": "https://hooks.zapier.com/hooks/standard/1234567/abcdef/",
  "description": "Slack: approved claims",
  "filters": {
    "stage": "claim_approved"
  },
  "created_at": "2026-09-20T18:30:00.000Z",
  "disabled_at": null
}

WebhookCreated

A webhook subscription as POST /webhooks returns it — the only API response that carries its secret.

Fields

  • idstringuuid
  • objectstringalways "webhook"
  • eventstring

    An event name, or "*" for every event.

  • target_urlstringuri
  • descriptionstring | null
  • filtersobject | null
  • created_atstringdate-time
  • disabled_atstring | nulldate-time
  • secretstring

    The signing secret. Returned ONCE.

WebhookCreated object
{
  "id": "0f8c8c1b-dddd-4000-8000-000000000022",
  "object": "webhook",
  "event": "job.stage_changed",
  "target_url": "https://hooks.zapier.com/hooks/standard/1234567/abcdef/",
  "description": "Slack: approved claims",
  "filters": {
    "stage": "claim_approved"
  },
  "created_at": "2026-09-20T18:30:00.000Z",
  "disabled_at": null,
  "secret": "whsec_3a2b1c5f…"
}

EventEnvelope

Every delivery is the record's own fields at the top level plus these. Dedupe on event_id: a retry or a resend carries the same one.

Fields

  • event_typestring
  • event_idstringuuid

    Also the X-HailMate-Delivery header.

  • event_atstringdate-time

    When the change happened.

  • event_workspace_idstringuuid
  • event_testboolean

    Present and true on a test send from Settings.

  • previous_stagestring | null

    job.stage_changed only.

  • previous_stage_labelstring | null

    job.stage_changed only.

  • changed_fieldsarray of string

    *.updated only — the public field names that changed.

  • previous_assigned_to_idstring | null

    job.assigned only.

  • previous_knock_resultstring | null

    pin.result_changed only.

EventEnvelope object
{
  "event_type": "job.stage_changed",
  "event_id": "2cb27b8c-4e1f-4a3b-9d2c-6f7e8a9b0c1d",
  "event_at": "2026-09-28T19:42:57.388Z",
  "event_workspace_id": "5f0c2a8e-1b3d-4c7a-9e21-7a3b8d4c6e10",
  "previous_stage": "inspection_complete",
  "previous_stage_label": "Inspection Complete"
}