REST API reference

Kickserv API

15 endpoints for Kickserv. Each one is a POST with a JSON body, called with your API key.

Base URL
https://cotlet.dev/api/v1/kickserv
Connects with
Your own Kickserv account (admin role for invoices and payments)
Integration page
Kickserv
Kickserv Endpoints
Endpoint Access Description
list_customers read Customers and contacts, searchable by name, email, phone or address.
get_customer read One customer with addresses, contacts, notes and jobs.
list_jobs read Jobs with status, service type, customer, assigned techs and scheduled date.
get_job read Full job: description, scope of work, charges, schedule events, time entries, notes and invoice status.
list_opportunities read Opportunities with customer, service type and whether an estimate was sent.
list_invoices read Invoices with customer, total, balance and whether they were sent and viewed.
create_customer write New person or company contact with service and billing address.
create_job write New job, or a new opportunity to estimate first, for a customer.
add_charge write Add one charge item to the estimate or invoice of a job or opportunity.
schedule_event write Add a work event to a job, optionally assigned to a technician.
log_time_entry write Record hours worked on a job by an employee.
send_estimate write Email the estimate of an opportunity to the customer.
generate_invoice write Create the invoice for a job from its charges. Nothing is sent.
send_invoice write Email the invoice of a job to the customer.
record_payment write Log a manual payment (check, cash, other) on a job and mark the invoice paid. No card is charged.

POST https://cotlet.dev/api/v1/kickserv/list_customers

Returns customers with their number, contact details and service address. Search matches name, email, phone and street address. Pass the customer_number to get_customer, create_job and the other tools.

Parameters

Parameters: list_customers
NameTypeDescription
query string Name, email, phone or street address.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/list_customers \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("kickserv", "list_customers")
Node.js
const result = await cotlet.call('kickserv', 'list_customers');
CLI
cotlet call kickserv list_customers

Example response

{
  "customers": [
    {
      "customer_number": "2218",
      "name": "Lee Residence",
      "email": "lee@example.com",
      "phone": "555-0142",
      "service_address": "41 Maple St, Austin, TX 78701"
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/kickserv/get_customer

Returns one customer with service and billing addresses, saved contacts, special instructions, notes and the list of their jobs with status. Use it before creating a job so your agent reuses the right contact.

Parameters

Parameters: get_customer
NameTypeDescription
customer_number required string Customer number from list_customers.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/get_customer \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_number":"customer number"}'
Python
result = client.call("kickserv", "get_customer", {"customer_number":"customer number"})
Node.js
const result = await cotlet.call('kickserv', 'get_customer', {"customer_number":"customer number"});
CLI
cotlet call kickserv get_customer --data '{"customer_number":"customer number"}'

Example response

{
  "customer_number": "2218",
  "name": "Lee Residence",
  "billing_address": "41 Maple St, Austin, TX 78701",
  "contacts": [
    {
      "name": "Mrs. Lee",
      "email": "lee@example.com",
      "primary": true
    }
  ],
  "jobs": [
    {
      "job_number": "1037",
      "service_type": "Water heater replacement",
      "status": "complete"
    }
  ]
}

List jobs

read

POST https://cotlet.dev/api/v1/kickserv/list_jobs

Returns jobs 30 per page, filtered by status, scheduled date or technician. Use job_number in get_job and the write tools.

Parameters

Parameters: list_jobs
NameTypeDescription
status enum unscheduled, scheduled, in_progress, on_hold, canceled or complete.
scheduled enum today, tomorrow, yesterday, this_week, next_week, last_week, this_month, next_month, last_month, this_year or last_year.
employee string Only jobs assigned to this employee.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/list_jobs \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"complete","scheduled":"yesterday","page":1}'
Python
result = client.call("kickserv", "list_jobs", {"status":"complete","scheduled":"yesterday","page":1})
Node.js
const result = await cotlet.call('kickserv', 'list_jobs', {"status":"complete","scheduled":"yesterday","page":1});
CLI
cotlet call kickserv list_jobs --data '{"status":"complete","scheduled":"yesterday","page":1}'

Example response

{
  "jobs": [
    {
      "job_number": "1037",
      "service_type": "Water heater replacement",
      "customer": "Lee Residence",
      "status": "complete",
      "scheduled_on": "2026-10-09",
      "employees": [
        "Dana Ruiz"
      ]
    }
  ],
  "page": 1
}

Get job

read

POST https://cotlet.dev/api/v1/kickserv/get_job

Returns one job or opportunity with its internal description, the customer-facing scope of work, charges with the running total, schedule events, time entries, notes and whether an invoice exists and is paid.

Parameters

Parameters: get_job
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/get_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"job number"}'
Python
result = client.call("kickserv", "get_job", {"job_number":"job number"})
Node.js
const result = await cotlet.call('kickserv', 'get_job', {"job_number":"job number"});
CLI
cotlet call kickserv get_job --data '{"job_number":"job number"}'

Example response

{
  "job_number": "1042",
  "service_type": "Water heater replacement",
  "customer": "Lee Residence",
  "status": "new",
  "description": "Website lead: 40 gal tank leaking",
  "scope_of_work": "Replace the 40 gallon gas water heater.",
  "charges": [],
  "total": "0.00",
  "events": [],
  "time_entries": [],
  "invoice": null
}

POST https://cotlet.dev/api/v1/kickserv/list_opportunities

Returns opportunities from the Opportunities page. A new opportunity appears under the New tab; in the app an opportunity can be marked won or lost.

Parameters

Parameters: list_opportunities
NameTypeDescription
stage enum new, won or lost. Default: new.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/list_opportunities \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("kickserv", "list_opportunities")
Node.js
const result = await cotlet.call('kickserv', 'list_opportunities');
CLI
cotlet call kickserv list_opportunities

Example response

{
  "opportunities": [
    {
      "job_number": "1042",
      "service_type": "Water heater replacement",
      "customer": "Lee Residence",
      "stage": "new",
      "estimate_sent": false,
      "created_on": "2026-10-10"
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/kickserv/list_invoices

Returns the invoices shown on the Invoices page, from its unpaid or paid tab. Each has a sent flag and a viewed flag, the same as the blue letter and purple eye icons in the app.

Parameters

Parameters: list_invoices
NameTypeDescription
tab enum unpaid or paid. Default: unpaid.
page integer Page number. Default: 1.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/list_invoices \
  -H "Authorization: Bearer $COTLET_API_KEY"
Python
result = client.call("kickserv", "list_invoices")
Node.js
const result = await cotlet.call('kickserv', 'list_invoices');
CLI
cotlet call kickserv list_invoices

Example response

{
  "invoices": [
    {
      "job_number": "1037",
      "customer": "Lee Residence",
      "total": "480.00",
      "balance_remaining": "480.00",
      "sent": true,
      "viewed": true
    }
  ],
  "page": 1
}

POST https://cotlet.dev/api/v1/kickserv/create_customer

Creates a customer and returns its customer_number. It sends nothing to the customer and one edit in Kickserv undoes it, so it runs without asking first. Search with list_customers before creating one, to avoid duplicates.

Parameters

Parameters: create_customer
NameTypeDescription
name required string Person or company name.
is_company boolean Company instead of a person. Default: false.
email string Customer email.
phone string Phone number.
service_address object street, city, state, zip_code, country.
billing_address object Same fields. Default: the service address.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/create_customer \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"Jane Doe"}'
Python
result = client.call("kickserv", "create_customer", {"name":"Jane Doe"})
Node.js
const result = await cotlet.call('kickserv', 'create_customer', {"name":"Jane Doe"});
CLI
cotlet call kickserv create_customer --data '{"name":"Jane Doe"}'

Example response

{
  "customer_number": "2219",
  "name": "Rivera Dental",
  "status": "created"
}

Create job

write

POST https://cotlet.dev/api/v1/kickserv/create_job

Creates a job for a customer and returns its job_number. With as_opportunity set to true it creates an opportunity under the New tab instead. The description is internal and the scope of work is shown to the customer. It sends nothing to the customer, so it runs without asking first.

Parameters

Parameters: create_job
NameTypeDescription
customer_number required string Customer number from list_customers.
service_type required string Service type as named in your account.
description string Internal description, not shown to the customer.
scope_of_work string Customer-facing scope of work.
as_opportunity boolean Create an opportunity for an estimate instead of a job. Default: false.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/create_job \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"customer_number":"2231","service_type":"Water heater replacement","description":"Lead from website form, 11:40 p.m.: 40 gal tank leaking in garage","scope_of_work":"Inspect and replace the 40 gallon gas water heater.","as_opportunity":true}'
Python
result = client.call("kickserv", "create_job", {"customer_number":"2231","service_type":"Water heater replacement","description":"Lead from website form, 11:40 p.m.: 40 gal tank leaking in garage","scope_of_work":"Inspect and replace the 40 gallon gas water heater.","as_opportunity":True})
Node.js
const result = await cotlet.call('kickserv', 'create_job', {"customer_number":"2231","service_type":"Water heater replacement","description":"Lead from website form, 11:40 p.m.: 40 gal tank leaking in garage","scope_of_work":"Inspect and replace the 40 gallon gas water heater.","as_opportunity":true});
CLI
cotlet call kickserv create_job --data '{"customer_number":"2231","service_type":"Water heater replacement","description":"Lead from website form, 11:40 p.m.: 40 gal tank leaking in garage","scope_of_work":"Inspect and replace the 40 gallon gas water heater.","as_opportunity":true}'

Example response

{
  "job_number": "1051",
  "type": "opportunity",
  "stage": "new",
  "customer_number": "2218",
  "service_type": "Water heater replacement"
}

Add charge

write

POST https://cotlet.dev/api/v1/kickserv/add_charge

Adds one charge line and returns the running total of the job. Call it once per line. Nothing reaches the customer until you send the estimate or invoice, so it runs without asking first.

Parameters

Parameters: add_charge
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
item required string Charge item from your account, or a new item name.
description string Line description.
quantity string Decimal, e.g. 1 or 2.5. Default: 1.
price_per_unit string Price as a decimal, e.g. 129.00.
taxable boolean Apply sales tax. Default: the item setting.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/add_charge \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"1042","item":"Labor","description":"Remove old tank, install and test new heater","quantity":"3","price_per_unit":"95.00","taxable":false}'
Python
result = client.call("kickserv", "add_charge", {"job_number":"1042","item":"Labor","description":"Remove old tank, install and test new heater","quantity":"3","price_per_unit":"95.00","taxable":False})
Node.js
const result = await cotlet.call('kickserv', 'add_charge', {"job_number":"1042","item":"Labor","description":"Remove old tank, install and test new heater","quantity":"3","price_per_unit":"95.00","taxable":false});
CLI
cotlet call kickserv add_charge --data '{"job_number":"1042","item":"Labor","description":"Remove old tank, install and test new heater","quantity":"3","price_per_unit":"95.00","taxable":false}'

Example response

{
  "job_number": "1042",
  "charge": {
    "item": "Labor",
    "quantity": "2.5",
    "price_per_unit": "95.00",
    "line_total": "237.50"
  },
  "total": "886.50"
}

Schedule event

write Confirm

POST https://cotlet.dev/api/v1/kickserv/schedule_event

Adds an event with a start time, an optional end, a task type and an optional technician. Without a technician the event stays unassigned. Depending on your reminder settings, Kickserv can send reminders for the event. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: schedule_event
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
starts_at required datetime ISO 8601 with time zone.
ends_at datetime End of the event.
task_type string Task type as named in your account, e.g. Work. Default: Work.
employee string Technician to assign. Default: unassigned.
description string Notes for the technician.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/schedule_event \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"job number","starts_at":"2026-10-01T09:00:00Z"}'
Python
result = client.call("kickserv", "schedule_event", {"job_number":"job number","starts_at":"2026-10-01T09:00:00Z"})
Node.js
const result = await cotlet.call('kickserv', 'schedule_event', {"job_number":"job number","starts_at":"2026-10-01T09:00:00Z"});
CLI
cotlet call kickserv schedule_event --data '{"job_number":"job number","starts_at":"2026-10-01T09:00:00Z"}'

Example response

{
  "job_number": "1050",
  "event_id": "ev_3381",
  "task_type": "Work",
  "starts_at": "2026-10-15T09:00:00-05:00",
  "employee": "Dana Ruiz",
  "job_status": "scheduled"
}

POST https://cotlet.dev/api/v1/kickserv/log_time_entry

Adds a time entry to the job and returns it. Hours are a decimal. It reaches no one and an admin can delete the entry in Kickserv, so it runs without asking first.

Parameters

Parameters: log_time_entry
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
hours required string Number of hours as a decimal, e.g. 2.5.
date required date Day the work was done.
employee required string Employee name.
billable boolean Billable time. Default: true.
note string What was done.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/log_time_entry \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"job number","hours":"hours","date":"2026-10-01","employee":"employee"}'
Python
result = client.call("kickserv", "log_time_entry", {"job_number":"job number","hours":"hours","date":"2026-10-01","employee":"employee"})
Node.js
const result = await cotlet.call('kickserv', 'log_time_entry', {"job_number":"job number","hours":"hours","date":"2026-10-01","employee":"employee"});
CLI
cotlet call kickserv log_time_entry --data '{"job_number":"job number","hours":"hours","date":"2026-10-01","employee":"employee"}'

Example response

{
  "job_number": "1049",
  "time_entry_id": "te_7702",
  "employee": "Dana Ruiz",
  "date": "2026-10-09",
  "hours": "2.5",
  "billable": true,
  "note": "Installed water heater"
}

Send estimate

write Confirm

POST https://cotlet.dev/api/v1/kickserv/send_estimate

Emails the estimate to the main customer of the job and copies the addresses you add. Subject and message come from your Messaging Templates unless you set them. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_estimate
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
to string[] Recipient emails. Default: the main customer of the job.
cc string[] Extra emails to copy.
subject string Email subject. Default: your Messaging Templates subject.
message string Custom message. Default: your Messaging Templates message.
attach_pdf boolean Also attach a PDF copy. Default: your Messaging Templates setting.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/send_estimate \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"job number"}'
Python
result = client.call("kickserv", "send_estimate", {"job_number":"job number"})
Node.js
const result = await cotlet.call('kickserv', 'send_estimate', {"job_number":"job number"});
CLI
cotlet call kickserv send_estimate --data '{"job_number":"job number"}'

Example response

{
  "job_number": "1042",
  "status": "sent",
  "sent_to": [
    "lee@example.com"
  ],
  "cc": [
    "office@example.com"
  ],
  "total": "886.50"
}

POST https://cotlet.dev/api/v1/kickserv/generate_invoice

Creates the invoice from the charges on the job, the same as Generate Invoice in the job header, and returns its total. It sends nothing to the customer and the invoice can be edited afterwards, so it runs without asking first.

Parameters

Parameters: generate_invoice
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/generate_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"job number"}'
Python
result = client.call("kickserv", "generate_invoice", {"job_number":"job number"})
Node.js
const result = await cotlet.call('kickserv', 'generate_invoice', {"job_number":"job number"});
CLI
cotlet call kickserv generate_invoice --data '{"job_number":"job number"}'

Example response

{
  "job_number": "1037",
  "invoice_status": "not_sent",
  "total": "480.00",
  "balance_remaining": "480.00"
}

Send invoice

write Confirm

POST https://cotlet.dev/api/v1/kickserv/send_invoice

Emails the invoice to the main customer of the job and copies the addresses you add. The invoice then shows as sent on the Invoices page. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_invoice
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
to string[] Recipient emails. Default: the main customer of the job.
cc string[] Extra emails to copy.
subject string Email subject. Default: your Messaging Templates subject.
message string Custom message. Default: your Messaging Templates message.
attach_pdf boolean Also attach a PDF copy. Default: your Messaging Templates setting.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/send_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"1037"}'
Python
result = client.call("kickserv", "send_invoice", {"job_number":"1037"})
Node.js
const result = await cotlet.call('kickserv', 'send_invoice', {"job_number":"1037"});
CLI
cotlet call kickserv send_invoice --data '{"job_number":"1037"}'

Example response

{
  "job_number": "1037",
  "invoice_status": "sent",
  "sent_to": [
    "lee@example.com"
  ],
  "total": "480.00",
  "balance_remaining": "480.00"
}

Record payment

write Confirm

POST https://cotlet.dev/api/v1/kickserv/record_payment

Logs the payment type on the job, then marks the invoice paid when mark_paid is true. Kickserv does not bring the balance to zero for manual payments on its own, so the type is recorded first. No card is charged. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: record_payment
NameTypeDescription
job_number required string Job number from list_jobs, list_opportunities or get_job.
amount required string Amount as a decimal, e.g. 480.00.
method required string Payment type as named in your account, e.g. Check.
paid_on date Default: today.
mark_paid boolean Mark the invoice paid afterwards. Default: true.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/kickserv/record_payment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"job_number":"1051","amount":"150.00","method":"Cash","paid_on":"2026-10-12","mark_paid":false}'
Python
result = client.call("kickserv", "record_payment", {"job_number":"1051","amount":"150.00","method":"Cash","paid_on":"2026-10-12","mark_paid":False})
Node.js
const result = await cotlet.call('kickserv', 'record_payment', {"job_number":"1051","amount":"150.00","method":"Cash","paid_on":"2026-10-12","mark_paid":false});
CLI
cotlet call kickserv record_payment --data '{"job_number":"1051","amount":"150.00","method":"Cash","paid_on":"2026-10-12","mark_paid":false}'

Example response

{
  "job_number": "1037",
  "amount": "480.00",
  "method": "Check",
  "paid_on": "2026-10-10",
  "invoice_status": "paid",
  "balance_remaining": "0.00"
}