REST API reference

Thryv API

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

Base URL
https://cotlet.dev/api/v1/thryv
Connects with
Your own Thryv Business Center account (primary admin for full access)
Integration page
Thryv
Thryv Endpoints
Endpoint Access Description
list_clients read Clients with contact details and tags, newest first.
get_client read Client card: contact details, tags, notes, client details, appointments, invoices and message history.
list_services read Services from your services menu, with their saved prices.
list_appointments read Calendar appointments in a date range, with client, service, staff and price.
list_invoices read Invoices from the Sales tab with client, total, balance due and dates.
list_conversations read Inbox conversations with the latest messages, across email, text and other connected channels.
list_reviews read Reviews from the Reputation dashboard, from every connected site, with rating and whether you replied.
add_client write New client card. Nothing is sent to the client.
book_appointment write New calendar appointment. Thryv emails the client a booking confirmation.
mark_no_show write Mark an appointment as a no-show, before its end time. May send your missed appointment email.
create_estimate write Itemized estimate on the client card, saved or sent for approval in the client portal.
create_invoice write Invoice on the client card, saved to send later or sent with an online payment link.
send_message write Message one or more clients, the same as Send Message on your dashboard.
reply_to_review write Post a public reply to a review from the Reputation dashboard.

POST https://cotlet.dev/api/v1/thryv/list_clients

Lists the clients on your account, newest first. Filter by name, email or tag to find a group such as everyone tagged "spring". Pages hold up to 100 clients; pass next_cursor back as cursor for the next page.

Parameters

Parameters: list_clients
NameTypeDescription
search string Name or email.
tag string Only clients with this tag.
limit integer 1 to 100. Default: 50.
cursor string Next page cursor from the previous call.

Request

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

Example response

{
  "clients": [
    {
      "client_id": "cl_8f2a91",
      "name": "Sample Client",
      "email": "client@example.com",
      "phone": "+1 555 0100",
      "tags": [
        "spring"
      ]
    },
    {
      "client_id": "cl_20b4d7",
      "name": "Jordan Hale",
      "email": "jordan@example.com",
      "phone": "+1 555 0101",
      "tags": [
        "spring",
        "lawn"
      ]
    }
  ],
  "next_cursor": null
}

Get client

read

POST https://cotlet.dev/api/v1/thryv/get_client

Returns one client card with contact details, tags, internal notes, appointments, invoices and the message history. Use it before replying or invoicing so your agent sees everything about the client.

Parameters

Parameters: get_client
NameTypeDescription
client_id required string Client ID from list_clients.

Request

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

Example response

{
  "client_id": "cl_8f2a91",
  "name": "Sample Client",
  "email": "client@example.com",
  "tags": [
    "spring"
  ],
  "notes": "Prefers morning visits.",
  "appointments": [
    {
      "appointment_id": "ap_40b2d8",
      "service": "Lawn treatment",
      "start": "2026-09-29T09:00:00-05:00"
    }
  ],
  "invoices": [
    {
      "invoice_id": "inv_2041",
      "total": "85.00",
      "balance_due": "0.00"
    }
  ],
  "messages": 3
}

POST https://cotlet.dev/api/v1/thryv/list_services

Returns the services on your services menu with their saved prices. Use the name as the service parameter of book_appointment.

Parameters

No parameters.

Request

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

Example response

{
  "services": [
    {
      "name": "Lawn treatment",
      "price": "85.00"
    },
    {
      "name": "Edging",
      "price": "25.00"
    }
  ]
}

POST https://cotlet.dev/api/v1/thryv/list_appointments

Lists calendar appointments between two dates, with client, service, staff and price. The range is at most 31 days. Filter by staff member to see one person's calendar.

Parameters

Parameters: list_appointments
NameTypeDescription
from required date First day.
to required date Last day, at most 31 days after from.
staff string Only this staff member.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/list_appointments \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"from":"2026-10-01","to":"2026-10-01"}'
Python
result = client.call("thryv", "list_appointments", {"from":"2026-10-01","to":"2026-10-01"})
Node.js
const result = await cotlet.call('thryv', 'list_appointments', {"from":"2026-10-01","to":"2026-10-01"});
CLI
cotlet call thryv list_appointments --data '{"from":"2026-10-01","to":"2026-10-01"}'

Example response

{
  "appointments": [
    {
      "appointment_id": "ap_40b2d8",
      "client": "Sample Client",
      "client_id": "cl_8f2a91",
      "service": "Lawn treatment",
      "start": "2026-10-13T09:00:00-05:00",
      "end": "2026-10-13T10:00:00-05:00",
      "staff": "Alex",
      "price": "85.00"
    },
    {
      "appointment_id": "ap_40b2d9",
      "client": "Jordan Hale",
      "client_id": "cl_20b4d7",
      "service": "Edging",
      "start": "2026-10-13T11:00:00-05:00",
      "end": "2026-10-13T11:30:00-05:00",
      "staff": "Alex",
      "price": "25.00"
    }
  ]
}

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

Lists invoices from the Sales tab with client, total, balance due and dates. Set unpaid_only to skip invoices paid in full. Pages hold up to 100 invoices.

Parameters

Parameters: list_invoices
NameTypeDescription
client_id string Only this client.
unpaid_only boolean Skip invoices paid in full.
limit integer 1 to 100. Default: 50.

Request

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

Example response

{
  "invoices": [
    {
      "invoice_id": "inv_2044",
      "client": "Jordan Hale",
      "client_id": "cl_20b4d7",
      "total": "110.00",
      "balance_due": "110.00",
      "issued": "2026-10-05",
      "due": "2026-10-19"
    }
  ]
}

POST https://cotlet.dev/api/v1/thryv/list_conversations

Lists inbox conversations with the latest messages, across email, text and the other channels you connected in Thryv. Filter by client to see one thread. Pages hold up to 50 conversations.

Parameters

Parameters: list_conversations
NameTypeDescription
client_id string Only this client.
limit integer 1 to 50. Default: 20.

Request

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

Example response

{
  "conversations": [
    {
      "conversation_id": "cv_77d2",
      "client": "Sample Client",
      "client_id": "cl_8f2a91",
      "channel": "text",
      "last_message": "Can we move Tuesday to 10:00?",
      "updated_at": "2026-10-10T16:02:00-05:00"
    }
  ]
}

POST https://cotlet.dev/api/v1/thryv/list_reviews

Lists reviews from the Reputation dashboard, from every site you connected, with rating, text and whether you replied. Use unanswered_only to see what needs a reply. Pass review_id to reply_to_review.

Parameters

Parameters: list_reviews
NameTypeDescription
unanswered_only boolean Skip reviews you already answered.
since date Only reviews posted on or after this date.

Request

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

Example response

{
  "reviews": [
    {
      "review_id": "rv_3b90c1",
      "site": "Google",
      "rating": 5,
      "author": "Dana K.",
      "text": "The lawn looks great.",
      "posted": "2026-10-08",
      "replied": false
    }
  ]
}

Add client

write

POST https://cotlet.dev/api/v1/thryv/add_client

Creates a client card. Nothing is sent to the client, and the card can be edited or removed in Thryv, so the call skips confirmation. Only the first name is required.

Parameters

Parameters: add_client
NameTypeDescription
first_name required string First name.
last_name string Last name.
email string Email address.
phone string Phone number.
tags string[] Tags to add.
notes string Internal notes, not shown to the client.

Request

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

Example response

{
  "client_id": "cl_8f2a91",
  "name": "Sam Lee",
  "email": "client@example.com",
  "tags": [
    "spring"
  ],
  "status": "created"
}

Book appointment

write Confirm

POST https://cotlet.dev/api/v1/thryv/book_appointment

Books an appointment on your calendar for a client. Thryv emails the client a booking confirmation, plus any extra recipients you add. End time defaults to the service length and staff to the primary admin. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: book_appointment
NameTypeDescription
client_id required string Client ID from list_clients.
service required string Service name from list_services, or a custom title.
start required datetime ISO 8601 with time zone.
end datetime End time. Default: the service length.
staff string Staff member. Default: the primary admin.
price_type enum fixed, custom or no_fee. Default: the service setting.
price string Price for a fixed-price appointment.
additional_recipients string[] More emails that get the booking email.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/book_appointment \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_id":"cl_8f2a91","service":"Lawn treatment","start":"2026-10-13T09:00:00-05:00","staff":"Alex","price_type":"fixed","price":"85.00"}'
Python
result = client.call("thryv", "book_appointment", {"client_id":"cl_8f2a91","service":"Lawn treatment","start":"2026-10-13T09:00:00-05:00","staff":"Alex","price_type":"fixed","price":"85.00"})
Node.js
const result = await cotlet.call('thryv', 'book_appointment', {"client_id":"cl_8f2a91","service":"Lawn treatment","start":"2026-10-13T09:00:00-05:00","staff":"Alex","price_type":"fixed","price":"85.00"});
CLI
cotlet call thryv book_appointment --data '{"client_id":"cl_8f2a91","service":"Lawn treatment","start":"2026-10-13T09:00:00-05:00","staff":"Alex","price_type":"fixed","price":"85.00"}'

Example response

{
  "appointment_id": "ap_51c7e0",
  "client": "Sample Client",
  "service": "Lawn treatment",
  "start": "2026-10-13T09:00:00-05:00",
  "end": "2026-10-13T10:00:00-05:00",
  "staff": "Alex",
  "price": "85.00",
  "confirmation_sent_to": [
    "client@example.com"
  ]
}

Mark no-show

write Confirm

POST https://cotlet.dev/api/v1/thryv/mark_no_show

Marks one appointment as a no-show, before its end time. If you set up a missed appointment email in Thryv, it may go out to the client. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: mark_no_show
NameTypeDescription
appointment_id required string Appointment ID from list_appointments.

Request

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

Example response

{
  "appointment_id": "ap_40b2d9",
  "status": "no_show"
}

Create estimate

write Confirm

POST https://cotlet.dev/api/v1/thryv/create_estimate

Creates an itemized estimate on the client card. With send false it is only saved; with send true it goes to the client for approval in the client portal. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_estimate
NameTypeDescription
client_id required string Client ID from list_clients.
line_items required object[] List of items, each with description, quantity and unit_price.
notes string Notes shown on the estimate.
send boolean Send it to the client now. Default: false.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/create_estimate \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_id":"cl_8f2a91","line_items":[{"description":"Gutter cleaning","quantity":1,"unit_price":"140.00"},{"description":"Tree trimming","quantity":2,"unit_price":"95.00"}],"notes":"Based on your message of 10 Oct. Final price confirmed on site.","send":false}'
Python
result = client.call("thryv", "create_estimate", {"client_id":"cl_8f2a91","line_items":[{"description":"Gutter cleaning","quantity":1,"unit_price":"140.00"},{"description":"Tree trimming","quantity":2,"unit_price":"95.00"}],"notes":"Based on your message of 10 Oct. Final price confirmed on site.","send":False})
Node.js
const result = await cotlet.call('thryv', 'create_estimate', {"client_id":"cl_8f2a91","line_items":[{"description":"Gutter cleaning","quantity":1,"unit_price":"140.00"},{"description":"Tree trimming","quantity":2,"unit_price":"95.00"}],"notes":"Based on your message of 10 Oct. Final price confirmed on site.","send":false});
CLI
cotlet call thryv create_estimate --data '{"client_id":"cl_8f2a91","line_items":[{"description":"Gutter cleaning","quantity":1,"unit_price":"140.00"},{"description":"Tree trimming","quantity":2,"unit_price":"95.00"}],"notes":"Based on your message of 10 Oct. Final price confirmed on site.","send":false}'

Example response

{
  "estimate_id": "est_1180",
  "client_id": "cl_8f2a91",
  "total": "110.00",
  "status": "saved"
}

Create invoice

write Confirm

POST https://cotlet.dev/api/v1/thryv/create_invoice

Creates an invoice on the client card from line items. With send false it is saved to send later; with send true it goes to the client with an online payment link. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: create_invoice
NameTypeDescription
client_id required string Client ID from list_clients.
line_items required object[] List of items, each with description, quantity and unit_price.
send boolean Send it to the client now. Default: false.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/create_invoice \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_id":"client_8c41d2","line_items":["line items"]}'
Python
result = client.call("thryv", "create_invoice", {"client_id":"client_8c41d2","line_items":["line items"]})
Node.js
const result = await cotlet.call('thryv', 'create_invoice', {"client_id":"client_8c41d2","line_items":["line items"]});
CLI
cotlet call thryv create_invoice --data '{"client_id":"client_8c41d2","line_items":["line items"]}'

Example response

{
  "invoice_id": "inv_2051",
  "client_id": "cl_8f2a91",
  "line_items": [
    {
      "description": "Lawn treatment",
      "quantity": 1,
      "unit_price": "85.00"
    },
    {
      "description": "Edging",
      "quantity": 1,
      "unit_price": "25.00"
    }
  ],
  "total": "110.00",
  "balance_due": "110.00",
  "status": "draft"
}

Send message

write Confirm

POST https://cotlet.dev/api/v1/thryv/send_message

Sends a message to one or more clients, the same as Send Message on your dashboard. Subject and message text are required. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: send_message
NameTypeDescription
client_ids required string[] Client IDs from list_clients.
subject required string Subject line.
message required string Message text.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/send_message \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client_ids":["client ids"],"subject":"subject","message":"message"}'
Python
result = client.call("thryv", "send_message", {"client_ids":["client ids"],"subject":"subject","message":"message"})
Node.js
const result = await cotlet.call('thryv', 'send_message', {"client_ids":["client ids"],"subject":"subject","message":"message"});
CLI
cotlet call thryv send_message --data '{"client_ids":["client ids"],"subject":"subject","message":"message"}'

Example response

{
  "sent_to": [
    "cl_8f2a91",
    "cl_20b4d7"
  ],
  "subject": "Open slots next week",
  "status": "sent"
}

Reply to review

write Confirm

POST https://cotlet.dev/api/v1/thryv/reply_to_review

Posts a public reply to one review from the Reputation dashboard. The reply is visible to anyone who reads the review. By default you confirm each call; you can switch that off for this tool.

Parameters

Parameters: reply_to_review
NameTypeDescription
review_id required string Review ID from list_reviews.
text required string Reply text.

Request

cURL
curl -X POST https://cotlet.dev/api/v1/thryv/reply_to_review \
  -H "Authorization: Bearer $COTLET_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"review_id":"rv_3b90c1","text":"Thank you, Dana! Glad the lawn came back green after the fall treatment. See you in the spring."}'
Python
result = client.call("thryv", "reply_to_review", {"review_id":"rv_3b90c1","text":"Thank you, Dana! Glad the lawn came back green after the fall treatment. See you in the spring."})
Node.js
const result = await cotlet.call('thryv', 'reply_to_review', {"review_id":"rv_3b90c1","text":"Thank you, Dana! Glad the lawn came back green after the fall treatment. See you in the spring."});
CLI
cotlet call thryv reply_to_review --data '{"review_id":"rv_3b90c1","text":"Thank you, Dana! Glad the lawn came back green after the fall treatment. See you in the spring."}'

Example response

{
  "review_id": "rv_3b90c1",
  "status": "published"
}