Homebase360 API (1.3.0)

Download OpenAPI specification:

API for integration with Homebase360 customer and job management system

Health Check

Test API authentication

Simple endpoint to verify API key authentication is working correctly. Returns basic information about the authenticated business account.

Authorizations:
ApiKeyAuth

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/ping" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Customers

Get customers

Retrieves customer information based on search criteria. Multiple search parameters can be combined and will return customers matching ANY of the provided criteria (logical OR). If no criteria is provided, returns empty array.

Authorizations:
ApiKeyAuth
query Parameters
customerId
string
Example: customerId=Ekk9AvDeDihAEU8CMT0W

Specific customer ID to look for

phone
string
Example: phone=+13031234567

Customer's mobile phone number (E.164 format, e.g. +13038284444)

email
string
Example: email=john.smith@example.com

Customer's email address

name
string
Example: name=deri

Fuzzy, typo-tolerant search by customer name (first, last, or display name). E.g. "deri" matches "Derick". Returns up to limit matches, ordered by relevance; not paginated (no cursor).

identifiers
string
Example: identifiers=abc123,+13038284444,john@example.com

Comma-separated list of customer IDs, phone numbers, or email addresses (max 100 identifiers)

limit
integer <= 100
Default: 25
Example: limit=50

Maximum number of results to return (max 100, default 25)

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/customers?customerId=Ekk9AvDeDihAEU8CMT0W" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ]
}

Create a new customer

Creates a new customer with the provided information. Requires at least firstName or lastName, and at least one contact method (phone or email).

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
firstName
string

Customer's first name

lastName
string

Customer's last name

object (Phone)

All phone numbers must be in E.164 format (e.g. +13038284444)

email
Array of strings

List of email addresses (max 2). Can also provide as comma or semicolon-separated string.

address
Array of strings

List of physical addresses (max 2). Can also provide as semicolon or asterisk-separated string.

notes
string
Default: ""

Additional notes about the customer

tags
Array of strings

Tags for categorization. Can also provide as comma, semicolon, or asterisk-separated string.

notifications
boolean
Default: true

Whether the customer should receive notifications

Responses

Request samples

Content type
application/json
{
  • "firstName": "John",
  • "lastName": "Smith",
  • "phone": {
    },
  • "email": [
    ],
  • "address": [
    ],
  • "notes": "Prefers afternoon appointments",
  • "tags": [
    ],
  • "notifications": true
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update an existing customer

Updates an existing customer's information

Authorizations:
ApiKeyAuth
path Parameters
customerId
required
string

ID of the customer to update

Request Body schema: application/json
required
firstName
string

Customer's first name

lastName
string

Customer's last name

object (Phone)

All phone numbers must be in E.164 format (e.g. +13038284444)

email
Array of strings

List of email addresses

address
Array of strings

List of physical addresses

notes
string

Additional notes about the customer

tags
Array of strings

Tags for categorization

notifications
boolean

Whether the customer should receive notifications

Responses

Request samples

Content type
application/json
{
  • "firstName": "John",
  • "lastName": "Smith Updated",
  • "phone": {
    },
  • "notes": "Updated notes",
  • "notifications": false
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Jobs

Get jobs/schedule

Retrieves jobs based on search criteria.

  • No params → current day's jobs (ordered by start time).
  • customerId alone → all jobs for that customer, ordered newest-first by dateAdded (paginate with cursor).
  • sort=dateAdded → all jobs ordered by creation date (defaults to newest-first).
  • sort=lastUpdated → all jobs ordered by last modification time (defaults to newest-first). Useful for change-feed / sync integrations that need to surface recent edits and reschedules.
  • startDate/endDate → jobs whose start falls in the range, ordered by start time.

When sort is provided, the default today-window filter is NOT applied — the caller almost always wants results across all time, not just today.

Authorizations:
ApiKeyAuth
query Parameters
jobId
string

Specific job ID to look for

customerId
string

Filter jobs by customer ID. When used alone, returns all jobs for that customer ordered newest-first by dateAdded.

startDate
string <date-time>

Start date in ISO 8601 format (e.g. "2023-05-15T00:00:00Z") - jobs starting on/after this date

endDate
string <date-time>

End date in ISO 8601 format (e.g. "2023-05-15T23:59:59Z") - jobs starting on/before this date

sort
string
Enum: "dateAdded" "lastUpdated"

Sort field.

  • dateAdded — order by creation date (newest-first by default).
  • lastUpdated — order by last modification time (newest-first by default). Useful for change-feed integrations. Any other value returns 400.
orderDirection
string
Enum: "asc" "desc"

Sort direction. Defaults to desc when sort is provided (or customerId is used alone), asc otherwise.

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Create a new job

Creates a new job associated with a customer

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
customerId
required
string

Customer ID (must exist in your account)

start
required
string <date-time>

Start date and time in ISO 8601 format

end
required
string <date-time>

End date and time in ISO 8601 format (must be after start)

required
Array of objects (LineItem) non-empty

List of items/services for the job (minimum 1 item required)

note
string
Default: ""

Note for the job (optional)

LeadSource (string) or object

Lead source information (optional). Accepts string format or legacy object format for backwards compatibility

salespersonEmail
string

Email of an existing employee to set as the salesperson on the lead source (used with string leadSource). The salesperson gains view access to the job. If no employee matches, the job is still created without a salesperson.

Responses

Request samples

Content type
application/json
{
  • "customerId": "Ekk9AvDeDihAEU8CMT0W",
  • "start": "2023-05-15T14:30:00Z",
  • "end": "2023-05-15T16:30:00Z",
  • "lineItems": [
    ],
  • "note": "Please call customer before arrival"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update an existing job

Updates an existing job's information. Passing lineItems replaces the whole list and recomputes the job total — to change one item, use POST /v1/jobs/{jobId}/line-items. Line-item changes are rejected once the job has been paid (409); other fields stay editable.

Authorizations:
ApiKeyAuth
path Parameters
jobId
required
string

ID of the job to update

Request Body schema: application/json
required
start
string <date-time>

New start date and time in ISO 8601 format

end
string <date-time>

New end date and time in ISO 8601 format

note
string

New note for the job

Array of strings or string

Replacement assignment — array of employee emails, or a comma-separated string. [] clears all assignments.

Array of objects (LineItem)

Replacement array of line items (recomputes the job total). To change one item, use the line-items endpoint instead.

leadSource
string (LeadSource)

Source of the lead. Use "Online" for online sources, "Direct" for direct contact/referrals, or provide a custom source name (e.g., "Facebook Ad", "Google Ads", "Referral Partner"). Custom sources will be automatically created and associated with your business.

salespersonEmail
string

Email of an existing employee to set as the salesperson on the lead source (grants them view access to the job). Send "" or null to clear the salesperson. Returns 400 if no employee matches the email.

Responses

Request samples

Content type
application/json
{
  • "start": "2023-05-15T15:00:00Z",
  • "end": "2023-05-15T17:00:00Z",
  • "note": "Customer requested a later time"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Edit a job's line items

Edits a job's line items with surgical operations instead of replacing the whole list — so you can change, add, or remove a single item without re-sending (and risking the loss of) the others.

Operations are applied in order against the current list:

  • add — append a new item
  • update — change only the provided fields of a matched item (the rest are kept)
  • remove — delete a matched item
  • replace_all — replace the whole list (must be the only operation)

Items are matched by name (case-insensitive); when several items share a name, pass a 0-based index to disambiguate. The job total is recomputed automatically. Removing the last remaining item is rejected. Once the job has been paid, line-item edits are rejected (409).

Authorizations:
ApiKeyAuth
path Parameters
jobId
required
string

ID of the job to edit

Request Body schema: application/json
required
required
Array of objects (LineItemOperation) non-empty

Ordered list of line-item operations to apply

Responses

Request samples

Content type
application/json
{
  • "operations": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Tasks

Get tasks

Retrieves tasks (to-dos / reminders, optionally attached to a customer), with cursor-based pagination.

  • No params → today's scheduled tasks, ordered by start. Unscheduled tasks (no start) are excluded — pass sort=createdAt to list all tasks.
  • taskId → that single task.
  • startDate/endDate → tasks whose start falls in the range, ordered by start (combinable with status/employeeId; not combinable with customerId).
  • status, employeeId, or customerId → equality filters, paginated by document id.
  • sort=createdAt / sort=updatedAt → all tasks (including unscheduled), newest-first. Applies to the otherwise-unfiltered listing.
Authorizations:
ApiKeyAuth
query Parameters
taskId
string

Specific task ID to look for

customerId
string

Filter tasks for a specific customer

status
string
Enum: "pending" "completed"

Filter by completion status

employeeId
string

Filter by assigned employee's user ID

startDate
string <date-time>

ISO 8601 — tasks starting on/after this time

endDate
string <date-time>

ISO 8601 — tasks starting on/before this time

sort
string
Enum: "createdAt" "updatedAt"

Order all tasks by creation or last-update time (newest-first by default). Applies to the otherwise-unfiltered listing; any other value returns 400.

orderDirection
string
Enum: "asc" "desc"

Sort direction. Defaults to asc for date/today-window queries, desc when sort is provided.

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Create a new task

Creates a task (to-do / reminder), optionally attached to a customer and assigned to employees. title and instructions are required.

When assignees and notification methods are set, assigned employees are notified automatically; when a reminder is set, it is delivered automatically before the task's start time.

Notes:

  • start and end must BOTH be provided or BOTH omitted (a task is either scheduled or unscheduled).
  • reminder requires start/end (it fires relative to start).
  • Tasks created via the API have no human creator, so createdBy is null. An unassigned task has no viewers and will not appear in any technician's in-app task list — assign at least one employee for it to be visible in the app.
Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
title
required
string

Task title (required; may be empty string but not null)

instructions
required
string

Task details/instructions (required; may be empty string but not null)

customerId
string

Existing customer ID to attach to the task (optional)

start
string <date-time>

Start date/time, ISO 8601. Must be paired with end.

end
string <date-time>

End date/time, ISO 8601. Must be paired with start.

assignedTo
Array of strings

Array of employee emails to assign the task to (optional)

reminder
string
Default: "none"
Enum: "none" "start" "thirtyMin" "oneHour" "twoHour" "fiveHour" "twentyFourHour"

Single reminder before start (default none). Requires start/end.

object (NotificationMethods)

Notification preferences applied to both assignment and reminder notifications.

note
string

Initial note added to the task's note history (optional)

Responses

Request samples

Content type
application/json
{
  • "title": "Call customer to confirm",
  • "instructions": "Confirm the Tuesday window cleaning appointment.",
  • "customerId": "Ekk9AvDeDihAEU8CMT0W",
  • "start": "2026-06-16T09:00:00-06:00",
  • "end": "2026-06-16T09:30:00-06:00",
  • "assignedTo": [
    ],
  • "reminder": "oneHour",
  • "notificationMethods": {
    },
  • "note": "High-priority customer"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update an existing task

Updates a task. Only the provided fields change. Set status to completed to mark a task done (or pending to reopen it); completedBy is null for API-driven completions. A provided note is appended to the task's note history. Reassigning employees (adding new ones) notifies the newly-assigned employees automatically.

Notes:

  • start and end must be updated together. Pass both as null to clear the schedule.
  • Changing reminder resets its sent-state so the new reminder can fire; a non-none reminder requires the task to have a start (existing or set in the same call).
  • Pass assignedTo as [] to unassign everyone. Any email that doesn't match an employee returns 400.
Authorizations:
ApiKeyAuth
path Parameters
taskId
required
string

ID of the task to update

Request Body schema: application/json
required
status
string
Enum: "pending" "completed"

completed marks the task done; pending reopens it

title
string
instructions
string
start
string or null <date-time>

New start, ISO 8601. Pass together with end; pass both as null to clear the schedule.

end
string or null <date-time>

New end, ISO 8601. Pass together with start.

assignedTo
Array of strings

Full replacement list of employee emails. [] clears assignments.

reminder
string
Enum: "none" "start" "thirtyMin" "oneHour" "twoHour" "fiveHour" "twentyFourHour"

Single reminder before start

object (NotificationMethods)

Notification preferences applied to both assignment and reminder notifications.

note
string

Note appended to the task's note history

Responses

Request samples

Content type
application/json
Example
{
  • "status": "completed",
  • "note": "Confirmed with customer."
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Employees

Get employees

Retrieves the business's employees (team members), with cursor-based pagination. Read-only.

Use this to discover employee names, emails, and ids — pass an employee's email to dispatchedTo (jobs) or assignedTo (tasks/leads) when assigning work, and their employeeId to the employeeId filter on GET /v1/tasks (and similar).

  • No params → all employees, ordered by first name.
  • employeeId → that single employee (scoped to your business).
  • email → exact (case-insensitive) match.
  • search → case-insensitive substring match on name (first + last + display) and email.
Authorizations:
ApiKeyAuth
query Parameters
employeeId
string

Fetch a specific employee by ID

email
string

Exact email address (case-insensitive)

search
string

Substring to match against employee name or email

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Leads

Get leads

Retrieves leads based on search criteria.

Non-archived leads are returned by default. Pass includeArchived=true to include archived leads alongside, or includeArchived=only to return archived leads only.

Ordering (all served by a single archived + dateAdded composite index):

  • No other filter (only the default archived filter applies) → newest-first by dateAdded.
  • startDate / endDate filter applied → ordered by dateAdded ascending. Filters operate on dateAdded.
  • customerId, status, or employeeId filter applied → results paginated in document-ID order.
Authorizations:
ApiKeyAuth
query Parameters
leadId
string

Fetch a specific lead by ID

customerId
string

Fetch all leads for a specific customer

status
string
Enum: "new" "first_contact" "second_contact" "third_contact" "on_hold"

Filter by lead status

employeeId
string

Filter by assigned employee ID

startDate
string <date-time>

ISO-8601 date — only return leads with dateAdded on or after this date

endDate
string <date-time>

ISO-8601 date — only return leads with dateAdded on or before this date

includeArchived
string
Enum: "true" "only"

Archive filter. true includes archived leads alongside non-archived. only returns archived leads only. Omitted (default) returns non-archived only.

cursor
string

Cursor token from a previous response (nextPageToken) to retrieve the next page of results

limit
integer <= 100
Default: 25

Maximum number of results to return

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/leads?status=new&limit=10" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ]
}

Create a new lead

Creates a new lead with smart customer lookup/creation. This intelligent endpoint handles three scenarios:

Scenario 1: Existing Customer by ID Provide the customerId field to create a lead for an existing customer. Returns 404 if customer not found.

Scenario 2: Phone-based Lookup/Merge Provide customer details including phone.mobile. The API will:

  • Search for an existing customer with that mobile phone number
  • If found: Merge new data with existing customer, update customer record, create lead
  • If not found: Create new customer, create lead

Scenario 3: New Customer Provide customer details without customerId or phone.mobile. The API will:

  • Always create a new customer
  • Create lead for the new customer

You can either provide a customerId, or a name and a contact method: firstName/lastName and any-phone/email.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
customerId
string

Method 1: Existing customer ID

firstName
string

Method 2: Customer's first name (at least firstName or lastName required if using customer details)

lastName
string

Method 2: Customer's last name (at least firstName or lastName required if using customer details)

object (Phone)

All phone numbers must be in E.164 format (e.g. +13038284444)

email
Array of strings

Method 2: List of email addresses

address
Array of strings

Method 2: List of physical addresses

notes
string

Method 2: Additional notes about the customer

tags
Array of strings

Method 2: Tags for categorization

notifications
boolean

Method 2: Whether customer should receive notifications

Array of objects (LineItem)

Array of line items (optional for leads)

note
string

Note about the lead

leadSource
string (LeadSource)

Source of the lead. Use "Online" for online sources, "Direct" for direct contact/referrals, or provide a custom source name (e.g., "Facebook Ad", "Google Ads", "Referral Partner"). Custom sources will be automatically created and associated with your business.

status
string
Default: "new"
Enum: "new" "first_contact" "second_contact" "third_contact" "on_hold"

Initial status of the lead

assignedTo
Array of strings

Array of employee IDs to assign the lead to

Responses

Request samples

Content type
application/json
Example
{
  • "customerId": "Ekk9AvDeDihAEU8CMT0W",
  • "lineItems": [
    ],
  • "note": "Customer interested in monthly service",
  • "leadSource": "Online",
  • "status": "new"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update an existing lead

Updates an existing lead's information. Only non-archived leads can be updated.

Authorizations:
ApiKeyAuth
path Parameters
leadId
required
string

ID of the lead to update

Request Body schema: application/json
required
status
string
Enum: "new" "first_contact" "second_contact" "third_contact" "on_hold"

Updated lead status

note
string

Updated note for the lead

Array of objects (LineItem)

Replacement array of line items

assignedTo
Array of strings

Replacement array of employee IDs

leadSource
string (LeadSource)

Source of the lead. Use "Online" for online sources, "Direct" for direct contact/referrals, or provide a custom source name (e.g., "Facebook Ad", "Google Ads", "Referral Partner"). Custom sources will be automatically created and associated with your business.

Responses

Request samples

Content type
application/json
{
  • "status": "first_contact",
  • "note": "Called customer, discussed options. Following up next week."
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Edit a lead's line items

Edits a lead's line items with surgical operations instead of replacing the whole list — so you can change, add, or remove a single item without re-sending (and risking the loss of) the others.

Operations are applied in order against the current list:

  • add — append a new item
  • update — change only the provided fields of a matched item (the rest are kept)
  • remove — delete a matched item
  • replace_all — replace the whole list (must be the only operation)

Items are matched by name (case-insensitive); when several items share a name, pass a 0-based index to disambiguate. Removing the last remaining item is rejected. Converted leads cannot be edited.

Authorizations:
ApiKeyAuth
path Parameters
leadId
required
string

ID of the lead to edit

Request Body schema: application/json
required
required
Array of objects (LineItemOperation) non-empty

Ordered list of line-item operations to apply

Responses

Request samples

Content type
application/json
{
  • "operations": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Estimates

Get estimates

Retrieves estimates (quotes) based on search criteria.

Ordering:

  • No filters → newest-created first by dateAdded.
  • sort=lastUpdated → most-recently-modified first.
  • startDate / endDate → ordered by dateAdded ascending (filters operate on dateAdded).
  • customerId alone → newest-created first.
Authorizations:
ApiKeyAuth
query Parameters
estimateId
string

Fetch a specific estimate by ID (short-circuits all other filters)

customerId
string

Fetch all estimates for a specific customer

startDate
string <date-time>

ISO-8601 date — only return estimates with dateAdded on or after this date

endDate
string <date-time>

ISO-8601 date — only return estimates with dateAdded on or before this date

sort
string
Enum: "dateAdded" "lastUpdated"

Sort field — dateAdded (creation time) or lastUpdated (last modification). Unknown values return 400.

orderDirection
string
Enum: "asc" "desc"

Sort direction. Defaults to desc for sortable branches, asc for date-range queries.

cursor
string

Cursor token from a previous response (nextPageToken) to retrieve the next page of results

limit
integer <= 100
Default: 25

Maximum number of results to return

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/estimates?limit=10" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Create an estimate

Creates an estimate (an unsent draft quote). Provide either an existing customerId or new-contact details (a name plus phone or email), in which case a customer is found-or-created automatically — the same contract as creating a lead.

The estimate is created in the pending public status with no sent timestamp (a draft). Delivering the estimate to the customer (PDF + email/SMS) remains an in-app action; this endpoint does not send anything.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
customerId
string

Method 1: Existing customer ID

firstName
string

Method 2: Customer's first name (at least firstName or lastName required if using customer details)

lastName
string

Method 2: Customer's last name (at least firstName or lastName required if using customer details)

object (Phone)

All phone numbers must be in E.164 format (e.g. +13038284444)

email
Array of strings

Method 2: List of email addresses

address
Array of strings

Method 2: List of physical addresses

Array of objects (LineItem)

Services/products being quoted. Defaults to a single placeholder item if omitted.

note
string

Note shown on the estimate

leadSource
string (LeadSource)

Source of the lead. Use "Online" for online sources, "Direct" for direct contact/referrals, or provide a custom source name (e.g., "Facebook Ad", "Google Ads", "Referral Partner"). Custom sources will be automatically created and associated with your business.

salespersonEmail
string

Email of an existing employee to set as the salesperson on the lead source

Responses

Request samples

Content type
application/json
{
  • "customerId": "cust456",
  • "lineItems": [
    ],
  • "note": "Quote for spring cleaning"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update an existing estimate

Updates an existing estimate. Only the provided fields change. Updatable fields are lineItems, note, and leadSource. Passing lineItems replaces the whole array and recomputes the total — to change a single item, prefer POST /estimates/{estimateId}/line-items.

Approved estimates (the customer accepted the quote) and estimates already converted to a job are immutable and return 409.

Authorizations:
ApiKeyAuth
path Parameters
estimateId
required
string

ID of the estimate to update

Request Body schema: application/json
required
Array of objects (LineItem)

Replacement array of line items (recomputes the total). To change one item, use the line-items endpoint instead.

note
string

Updated note shown on the estimate

leadSource
string (LeadSource)

Source of the lead. Use "Online" for online sources, "Direct" for direct contact/referrals, or provide a custom source name (e.g., "Facebook Ad", "Google Ads", "Referral Partner"). Custom sources will be automatically created and associated with your business.

salespersonEmail
string

Email of an existing employee to set as the salesperson (used with leadSource)

Responses

Request samples

Content type
application/json
{
  • "note": "Updated quote after site visit",
  • "lineItems": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Edit an estimate's line items

Edits an estimate's line items with surgical operations instead of replacing the whole list — so you can change, add, or remove a single item without re-sending (and risking the loss of) the others.

Operations are applied in order against the current list:

  • add — append a new item
  • update — change only the provided fields of a matched item (the rest are kept)
  • remove — delete a matched item
  • replace_all — replace the whole list (must be the only operation)

Items are matched by name (case-insensitive); when several items share a name, pass a 0-based index to disambiguate. The estimate total is recomputed automatically. Removing the last remaining item is rejected. Approved or converted-to-job estimates are immutable (409).

Authorizations:
ApiKeyAuth
path Parameters
estimateId
required
string

ID of the estimate to edit

Request Body schema: application/json
required
required
Array of objects (LineItemOperation) non-empty

Ordered list of line-item operations to apply

Responses

Request samples

Content type
application/json
{
  • "operations": [
    ]
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Messages

Send an SMS/MMS message

Sends an SMS or MMS message to a customer's mobile phone. Requires an active Enterprise subscription. Subject to daily rate limits (500 SMS/day).

Provide either mobilePhone or customerId (or both):

  • mobilePhone: must be the phone.mobile of an existing customer
  • customerId: customer must have a valid phone.mobile on file
  • Both: mobilePhone must match the customer's phone.mobile
Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
mobilePhone
string

Customer's mobile phone in E.164 format. Must belong to an existing customer.

customerId
string

Customer ID. Customer must have a mobile phone on file.

message
string <= 200 characters

Message text. Max 200 characters. Required if no mediaUrl.

mediaUrl
string <uri>

HTTPS URL of media to send as MMS. Required if no message.

Responses

Request samples

Content type
application/json
Example
{
  • "mobilePhone": "+13031234444",
  • "message": "Your appointment is confirmed for tomorrow at 2pm"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

List messages (texts and calls)

Lists messages across all of the business's conversations, newest-first by createdAt. Returns both text messages and calls (calls are stored as message documents). Use this to pull "messages from a given time period" and to see what came in and whether it was answered.

Data availability (forward-only): text messages are returned from the date this endpoint was deployed onward — historical texts are not surfaced by this business-wide query. Calls are available for full history. To read an entire single thread including older messages, use GET /conversations/{phone}/messages.

Authorizations:
ApiKeyAuth
query Parameters
direction
string
Enum: "inbound" "outbound"

Filter by message direction

type
string
Enum: "text" "call"

Filter by message type

startDate
string <date-time>

Only messages at/after this ISO 8601 time

endDate
string <date-time>

Only messages at/before this ISO 8601 time

automated
string
Enum: "true" "false" "exclude"

Filter automated (system) messages. "exclude" is an alias for "false" (human-only) — useful to ignore appointment-reminder noise. Applies to texts; calls have no automated flag.

phone
string

Scope to one customer's thread (E.164)

customerId
string

Scope to one customer's thread by customer ID

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/messages?direction=inbound&limit=25" \
  -H "x-api-key: your-api-key-here"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Get messaging stats and limits

Returns the current messaging usage stats and daily rate limits for the business.

Authorizations:
ApiKeyAuth

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/messages/stats" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Conversations

List conversations

Lists conversations (one per customer phone number), newest-first by lastMessageTime. Built to answer "which conversations are unanswered?".

Two ways to find unanswered threads:

  • awaitingReply=true — the precise signal: a customer messaged or called in and no human has replied since (automated reminders do not count as a reply). Reflects activity from when this feature was deployed onward.
  • unread=true — the broad signal: the thread is marked unread. Works across all history, including pre-feature conversations.

unansweredForMinutes=N returns awaiting-reply threads whose last inbound was more than N minutes ago — ideal for "alert me to anything unanswered too long".

Authorizations:
ApiKeyAuth
query Parameters
awaitingReply
string
Value: "true"

Only threads awaiting a human reply

unread
string
Value: "true"

Only threads marked unread (legacy-safe; works across all history)

unansweredForMinutes
integer

Only awaiting-reply threads whose last inbound is older than N minutes

phone
string

Fetch a single conversation by customer phone (E.164)

customerId
string

Fetch a single conversation by customer ID

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/conversations?awaitingReply=true&limit=25" \
  -H "x-api-key: your-api-key-here"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Get one conversation's messages

Returns the full message thread (texts and calls) for a single customer phone number, newest-first. Unlike GET /messages, this reads the thread directly and therefore includes older, pre-feature messages too (direction/type are inferred for those legacy messages).

Authorizations:
ApiKeyAuth
path Parameters
phone
required
string

Customer phone number in E.164 (e.g. +13031234444)

query Parameters
direction
string
Enum: "inbound" "outbound"

Filter by message direction

type
string
Enum: "text" "call"

Filter by message type

startDate
string <date-time>

Only messages at/after this ISO 8601 time

endDate
string <date-time>

Only messages at/before this ISO 8601 time

limit
integer <= 100
Default: 50

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/conversations/+13031234444/messages?limit=25" \
  -H "x-api-key: your-api-key-here"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Subscriptions

Get service subscriptions

Retrieves recurring service subscriptions (plans sold to your customers). Results are sanitized — internal Firestore plumbing and Stripe connect-account metadata are stripped before being returned.

Legacy subscriptions bill via Stripe and keep the original Stripe-backed shape. Subscriptions with billingVersion: "v3" are billed by the internal engine (card or offline collection) and additionally expose their billing intent (paymentCollection), cadence (billingConfig), visit schedule, term, and billing-schedule working set, plus a compact v3Billing summary block with their price, cadence, and next processing time.

Results are always returned newest-first by createdAt.

Authorizations:
ApiKeyAuth
query Parameters
subscriptionId
string

Fetch a specific subscription by ID

customerId
string

Filter subscriptions by customer ID

status
string
Enum: "draft" "sent" "pending" "active" "paused" "completed" "canceled" "cancelled" "incomplete" "past_due"

Filter by subscription lifecycle status (pending/paused/completed are v3-engine statuses)

limit
integer <= 100
Default: 25

Maximum number of results to return (max 100)

cursor
string

Cursor token for pagination (returned as nextPageToken from the previous response).

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/subscriptions?status=active&limit=25" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Create a subscription draft

Creates a v3 service subscription as a DRAFT built from one of the business's subscription templates, optionally sending the customer the review-and-sign link (email/SMS). The API never activates or charges: the customer reviews, signs, and (for auto_card) enters payment through the normal accept-link flow, exactly as if the draft was created in the dashboard.

Visits are seeded automatically on the template's cadence (evenly spread from the start month); the visit grid can be fine-tuned in the dashboard while the subscription is a draft.

With send, the response status is "sent" when at least one channel (email/SMS) succeeded, otherwise the doc stays "draft" and can be re-sent from the dashboard.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
customerId
required
string

Existing customer ID

templateId
required
string

Subscription template to build from

requestId
string^[A-Za-z0-9_-]{6,64}$

Optional idempotency token, bound to the request payload (first write wins). Retrying with the same requestId and the IDENTICAL body returns the subscription's current state without modifying it — nothing is overwritten and an already-sent subscription is never re-sent (a failed send is retried). The same requestId with a different body is a 409. Recommended for any integration that retries on timeouts.

startDate
string^\d{4}-\d{2}-\d{2}$

Service/billing anchor date, strictly YYYY-MM-DD (default today). Invalid calendar dates (e.g. 2026-02-30) and ISO datetimes are rejected — a timezone offset could shift the anchor a calendar day.

object
dayOfMonth
integer [ 1 .. 28 ]

billing_cycle only — calendar billing day. Defaults to the start date's day (clamped to 28); note the dashboard's creation form defaults to the 1st instead.

Array of objects

Recurring price line items; defaults to the template's line items

object
note
string

Internal note on the subscription

boolean or object

true sends the review link to the customer's own contact info (email and/or mobile). An object sends to EXACTLY the channels provided — { email } never also texts the customer's phone on file, and an object without email or phone is a 400. Strictly validated — any value other than true, false, or an object is rejected with a 400 (a string like "false" will never trigger a send).

Responses

Request samples

Content type
application/json
{
  • "customerId": "string",
  • "templateId": "string",
  • "requestId": "string",
  • "startDate": "2026-08-01",
  • "paymentCollection": {
    },
  • "dayOfMonth": 1,
  • "lineItems": [
    ],
  • "discount": {
    },
  • "note": "string",
  • "send": true
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Get a subscription's invoices

Retrieves the permanent payment ledger of one subscription, newest first. Invoice kind distinguishes scheduled bills ("bill"), standalone technician tips ("tip"), and post-payment job balances ("balance"). Money fields ending in Cents are integer cents.

Authorizations:
ApiKeyAuth
path Parameters
subscriptionId
required
string
query Parameters
limit
integer <= 100
Default: 25
cursor
string

Cursor token for pagination

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/subscriptions/sub_abc123/invoices?limit=25" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Subscription Templates

Get subscription templates

Retrieves the business's subscription templates — the recurring-plan blueprints (cadence, term, pricing line items, optional linked agreement) that subscriptions are built from.

Authorizations:
ApiKeyAuth
query Parameters
templateId
string

Fetch a specific template by ID

limit
integer <= 100
Default: 25
cursor
string

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/subscription-templates" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Create a subscription template

Creates a subscription template. When lineItems are provided the display amount is derived from their subtotal (dashboard behavior); linking an agreement via agreementTemplateId forces requireSignature: true and clears inline terms.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
title
required
string
description
string
type
required
string
Enum: "fixed" "indefinite"
duration
integer

Term length in YEARS (required when type is "fixed")

visits
required
integer [ 1 .. 12 ]

Visits per year

paymentFrequency
required
string
Enum: "weekly" "bi-weekly" "monthly" "quarterly" "tri-annual" "6 months" "yearly"
Array of objects
amount
string

Legacy flat amount — only used when no lineItems

initialPriceEnabled
boolean
initialPrice
string

Required when initialPriceEnabled is true

initialPriceTaxRate
object or null

The initial price's own tax — both name and a numeric 0-100 rate required; malformed values are rejected, never coerced to 0%.

allowOtherPayments
boolean

Offer alternate payment methods at checkout on subscriptions built from this template

requireSignature
boolean

Only takes effect when there is something to sign (inline terms or a linked agreement); normalized to false otherwise

object

Inline terms (ignored when an agreement is linked)

agreementTemplateId
string

Link an existing agreement (must be active and enabled for service subscriptions)

Responses

Request samples

Content type
application/json
{
  • "title": "string",
  • "description": "string",
  • "type": "fixed",
  • "duration": 0,
  • "visits": 1,
  • "paymentFrequency": "weekly",
  • "lineItems": [
    ],
  • "amount": "string",
  • "initialPriceEnabled": true,
  • "initialPrice": "string",
  • "initialPriceTaxRate": { },
  • "allowOtherPayments": true,
  • "requireSignature": true,
  • "terms": {
    },
  • "agreementTemplateId": "string"
}

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Update a subscription template

Updates a subscription template. Only provided fields change; amount re-derives when lineItems change. Existing subscriptions keep their embedded template snapshot — edits only affect future subscriptions built from the template.

Authorizations:
ApiKeyAuth
path Parameters
templateId
required
string
Request Body schema: application/json
required
object

Any subset of the create-template fields

Responses

Request samples

Content type
application/json
{ }

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}

Agreements

Get agreements

Retrieves the business's agreements — the structured agreement documents (sections, content bodies, branding) that subscription templates link via agreementTemplateId. Read-only: agreements are created and edited in the dashboard. Subscriptions embed a frozen snapshot at creation, so agreement edits only affect future subscriptions.

Authorizations:
ApiKeyAuth
query Parameters
agreementId
string
limit
integer <= 100
Default: 25
cursor
string

Responses

Request samples

curl -X GET "https://us-central1-homebase-360.cloudfunctions.net/api/v1/agreements" \
  -H "x-api-key: your-api-key-here" \
  -H "Content-Type: application/json"

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ],
  • "nextPageToken": "string"
}

Webhooks

Subscribe to webhook events

Registers a URL to receive HTTP POST callbacks whenever the specified events occur on the authenticated business. Used by REST-Hook integrations such as Zapier.

Each subscription is scoped to the API key that created it: deactivating the API key auto-deletes its subscriptions. Subscriptions created through this endpoint do NOT appear in the Homebase360 dashboard webhook list (which is reserved for webhooks the user adds manually).

Common event names: customer.created, customer.details_changed, job.created, job.details.line_items_changed, job.status_changed, lead.created, lead.details_changed, lead.status_updated. See the full list in webhooks/webhookEvents.js.

Authorizations:
ApiKeyAuth
Request Body schema: application/json
required
url
required
string <uri>

Fully-qualified http(s) URL Homebase360 will POST to

events
required
Array of strings

One or more event names from the registry

Responses

Request samples

Content type
application/json
{}

Response samples

Content type
application/json
{}

List webhook subscriptions for this API key

Returns every webhook endpoint created via this API key, newest first. Endpoints created from the Homebase360 dashboard are NOT included. Signing secrets are never returned in this response.

Authorizations:
ApiKeyAuth

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": [
    ]
}

Unsubscribe a webhook

Removes a subscription previously created with POST /webhooks. Only subscriptions owned by the calling API key can be deleted; attempting to delete an endpoint owned by another key (or one created from the dashboard) returns 404.

Authorizations:
ApiKeyAuth
path Parameters
endpointId
required
string
Example: ep_a1b2c3d4e5f6a1b2c3d4e5f6

Opaque ID returned from the create call

Responses

Response samples

Content type
application/json
{
  • "success": true,
  • "data": {
    }
}