Email & text customers
Email or text a customer about a job, a contact or a company, exactly like the Email and Text buttons in TruTec, and read texting conversations and message templates.
View as MarkdownThese endpoints do what the Email and Text buttons on a job, contact or customer page do. The message goes out, and it's logged on the job and on the customer's timeline so the whole team sees it.
Warning
send-email and send-text reach a real customer. Confirm the recipient and the wording before you call them, especially from an AI assistant. Nothing else on this page sends anything.
Who it comes from. Emails go from the API key creator's connected Gmail or Outlook mailbox, so replies land in their inbox. Without one, they go from the workspace's TruTec sender with replies going to the key creator, unless the workspace requires a connected mailbox (Settings › Email accounts). Texts go from the workspace's own texting number, which an owner sets up in TruTec.
Merge fields. {{contact_first_name}}, {{contact_name}}, {{company_name}}, {{location_address}}, {{my_name}} and {{my_company}} in a subject or message are filled in with the customer's details when it's sent. GET /v1/message-templates lists them with their values for a customer.
Who can't be reached. An email to an address on the workspace's unsubscribe list, or marked do not contact on any of its contacts, is refused with 403 Do not contact. A text is refused (422 Text not sent, with the reason in message) when the number texted STOP, the contact is marked do not contact, it's outside 8am–9pm in the workspace's time zone, the workspace hit its daily texting limit, or the workspace has no texting number.
Writes need Write jobs; reads need Read jobs. Writes act as the user who created the key (Authentication); if that person has left the workspace, sends are refused with 403 Key owner unavailable.
Email#
Email the customer about a job#
POST /v1/jobs/{id}/send-email
Permission: Write jobs
| Field | Type | Required | Description |
|---|---|---|---|
to |
array or string | Yes | Up to 10 email addresses (a list, or one comma-separated string). |
cc |
array or string | No | Up to 10 addresses. |
subject |
string | Yes | Up to 255 characters. |
body |
string | Yes | The message as plain text (up to 20,000 characters). |
body_html |
string | No | A formatted version (paragraphs, bold, lists, links). When sent, the plain text is made from it. |
contact_id |
integer | No | The person it's logged against. Default: the job's primary contact. |
task_id |
integer | No | A follow-up on the job this email answers: the email becomes its notes. |
complete_task |
boolean | No | With task_id, also mark that follow-up done. |
curl -X POST "https://trutec.ai/api/v1/jobs/70412/send-email" \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"to": ["[email protected]"],
"subject": "Sealcoat schedule for Northgate Plaza",
"body": "Hi {{contact_first_name}},\n\nWe can start Monday the 20th. Does that work?\n\nThanks"
}'
{
"data": {
"sent": true,
"to": ["[email protected]"],
"cc": [],
"subject": "Sealcoat schedule for Northgate Plaza",
"job_id": 70412,
"contact_id": 5521,
"client_account_id": 812,
"from_email": "[email protected]",
"sent_with": "connected_mailbox",
"job_activity_id": 991204,
"contact_activity_id": 44120,
"task": null
}
}
sent_with is connected_mailbox (the user's own Gmail or Outlook) or trutec (the workspace's TruTec sender). When the mailbox refuses the email, the call returns 502 Email not sent with the mailbox's reason, and nothing is logged as sent.
Email a contact#
POST /v1/contacts/{id}/send-email
Permission: Write jobs
Same body as above, without contact_id, task_id and complete_task. Logged on the contact and their company.
Email a customer company#
POST /v1/client-accounts/{id}/send-email
Permission: Write jobs
Same body as the job email, with contact_id (optional, one of the company's people) and without the follow-up fields. Logged on the company.
Texts#
Text the customer about a job#
POST /v1/jobs/{id}/send-text
Permission: Write jobs
| Field | Type | Required | Description |
|---|---|---|---|
body |
string | Yes | Up to 1,600 characters. Merge fields are filled in. |
contact_id |
integer | No | Who to text. Default: the job's primary contact. |
phone |
string | No | Which of the contact's numbers (default: their primary mobile), or a number to text when the job has no contact. |
template_id |
string | No | The text template used, for reporting. |
curl -X POST "https://trutec.ai/api/v1/jobs/70412/send-text" \
-H "X-API-Key: sk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"body": "Hi {{contact_first_name}}, crews arrive 7am Monday. Please keep the lot clear."}'
{
"data": {
"sent": true,
"conversation_id": 3310,
"message_id": 44188,
"to_phone": "+15125550143",
"body": "Hi Pat, crews arrive 7am Monday. Please keep the lot clear.",
"contact_id": 5521,
"job_id": 70412,
"sent_at": "2026-10-14T15:02:11Z"
}
}
Text a contact#
POST /v1/contacts/{id}/send-text
Permission: Write jobs
Takes body, phone, template_id, and job_id to also log it on a job.
Conversations#
List text conversations#
GET /v1/text-conversations
Permission: Read jobs
One conversation per customer phone number, most recent first. Filter by contact_id, client_account_id, phone or unread=true; page with limit (default 50, maximum 200) and offset.
| Field | Type | Description |
|---|---|---|
id |
integer | |
phone |
string | E.164, for example +15125550143. |
contact, client_account |
object or null | {id, name}. |
unread |
boolean | A text came in that nobody has read in TruTec. |
opted_out |
boolean | They texted STOP. |
last_direction, last_message_preview, last_message_at, last_inbound_at |
The latest text. | |
owner_user_id |
integer or null | Whose conversation it is. |
Get a conversation#
GET /v1/text-conversations/{id}
Permission: Read jobs
The conversation with its texts in messages, oldest first: the newest 200, with has_older: true when there are more (pass before_id, the oldest message id you have, to page back). Each message has id, direction (inbound or outbound), body, status, sent_by ({id, name} for outbound texts), job_id and created_at. Reading a conversation doesn't mark it read in TruTec.
Emails sent and received on a job are on its timeline: GET /v1/jobs/{id}/activity?type=email (Notes & tasks).
Templates#
List message templates#
GET /v1/message-templates
Permission: Read jobs
The workspace's saved CRM email templates (kind=email, the default) or text templates (kind=text), with id, name, subject, body_text, body_html and is_default, plus merge_fields (token, label, value). Pass job_id, contact_id or client_account_id to fill the merge fields with that customer's details. Templates are edited in TruTec (Settings › Email templates).