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
| 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. |
List clients
readPOST 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
| Name | Type | Description |
|---|---|---|
| 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 -X POST https://cotlet.dev/api/v1/thryv/list_clients \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("thryv", "list_clients") const result = await cotlet.call('thryv', 'list_clients'); 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
readPOST 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
| Name | Type | Description |
|---|---|---|
| client_id required | string | Client ID from list_clients. |
Request
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"}' result = client.call("thryv", "get_client", {"client_id":"client_8c41d2"}) const result = await cotlet.call('thryv', 'get_client', {"client_id":"client_8c41d2"}); 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
} List services
readPOST 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 -X POST https://cotlet.dev/api/v1/thryv/list_services \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("thryv", "list_services") const result = await cotlet.call('thryv', 'list_services'); cotlet call thryv list_services Example response
{
"services": [
{
"name": "Lawn treatment",
"price": "85.00"
},
{
"name": "Edging",
"price": "25.00"
}
]
} List appointments
readPOST 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
| Name | Type | Description |
|---|---|---|
| from required | date | First day. |
| to required | date | Last day, at most 31 days after from. |
| staff | string | Only this staff member. |
Request
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"}' result = client.call("thryv", "list_appointments", {"from":"2026-10-01","to":"2026-10-01"}) const result = await cotlet.call('thryv', 'list_appointments', {"from":"2026-10-01","to":"2026-10-01"}); 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"
}
]
} List invoices
readPOST 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
| Name | Type | Description |
|---|---|---|
| client_id | string | Only this client. |
| unpaid_only | boolean | Skip invoices paid in full. |
| limit | integer | 1 to 100. Default: 50. |
Request
curl -X POST https://cotlet.dev/api/v1/thryv/list_invoices \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("thryv", "list_invoices") const result = await cotlet.call('thryv', 'list_invoices'); 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"
}
]
} List conversations
readPOST 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
| Name | Type | Description |
|---|---|---|
| client_id | string | Only this client. |
| limit | integer | 1 to 50. Default: 20. |
Request
curl -X POST https://cotlet.dev/api/v1/thryv/list_conversations \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("thryv", "list_conversations") const result = await cotlet.call('thryv', 'list_conversations'); 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"
}
]
} List reviews
readPOST 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
| Name | Type | Description |
|---|---|---|
| unanswered_only | boolean | Skip reviews you already answered. |
| since | date | Only reviews posted on or after this date. |
Request
curl -X POST https://cotlet.dev/api/v1/thryv/list_reviews \
-H "Authorization: Bearer $COTLET_API_KEY" result = client.call("thryv", "list_reviews") const result = await cotlet.call('thryv', 'list_reviews'); 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
writePOST 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
| Name | Type | Description |
|---|---|---|
| first_name required | string | First name. |
| last_name | string | Last name. |
| string | Email address. | |
| phone | string | Phone number. |
| tags | string[] | Tags to add. |
| notes | string | Internal notes, not shown to the client. |
Request
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"}' result = client.call("thryv", "add_client", {"first_name":"first name"}) const result = await cotlet.call('thryv', 'add_client', {"first_name":"first name"}); 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"
} 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
| Name | Type | Description |
|---|---|---|
| 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 -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"}' 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"}) 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"}); 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"
]
} 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
| Name | Type | Description |
|---|---|---|
| appointment_id required | string | Appointment ID from list_appointments. |
Request
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"}' result = client.call("thryv", "mark_no_show", {"appointment_id":"appointment_8c41d2"}) const result = await cotlet.call('thryv', 'mark_no_show', {"appointment_id":"appointment_8c41d2"}); cotlet call thryv mark_no_show --data '{"appointment_id":"appointment_8c41d2"}' Example response
{
"appointment_id": "ap_40b2d9",
"status": "no_show"
} 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
| Name | Type | Description |
|---|---|---|
| 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 -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}' 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}) 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}); 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"
} 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
| Name | Type | Description |
|---|---|---|
| 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 -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"]}' result = client.call("thryv", "create_invoice", {"client_id":"client_8c41d2","line_items":["line items"]}) const result = await cotlet.call('thryv', 'create_invoice', {"client_id":"client_8c41d2","line_items":["line items"]}); 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"
} 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
| Name | Type | Description |
|---|---|---|
| client_ids required | string[] | Client IDs from list_clients. |
| subject required | string | Subject line. |
| message required | string | Message text. |
Request
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"}' result = client.call("thryv", "send_message", {"client_ids":["client ids"],"subject":"subject","message":"message"}) const result = await cotlet.call('thryv', 'send_message', {"client_ids":["client ids"],"subject":"subject","message":"message"}); 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"
} 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
| Name | Type | Description |
|---|---|---|
| review_id required | string | Review ID from list_reviews. |
| text required | string | Reply text. |
Request
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."}' 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."}) 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."}); 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"
}