Goals Live
Goals turn chat into a measurable funnel. Define a URL pattern that means "converted" (checkout success, a thank-you page, a signup confirmation) and message.com matches it automatically against pages visitors view after a conversation, attributed by visitor and agent when possible.
CRUD (list, get, create, update, delete) is live. There is no manual conversion-attribution endpoint and no per-goal report endpoint yet: completions are recorded automatically, and cross-goal reporting lives on the Reports API.
How a goal matches
A goal has one condition: an operator and a value matched against the URL of a page the visitor loads (via the widget's page-view tracking). There is no event-based, tag-based, or revenue-triggered goal kind.
| Operator | Matches when the URL... |
|---|---|
contains | Contains value as a substring. |
equals | Is exactly value. |
starts-with | Starts with value. |
ends-with | Ends with value. |
regex | Matches value as a regular expression. |
Completions are deduplicated per visitor within a 24-hour window. An optional valueCents on the goal assigns a fixed value to every completion (e.g., a flat $49 per signup); there is no per-completion custom amount.
List goals
Code samples
curl 'https://app.message.com/api/v1/goals' \
-H 'Authorization: Bearer YOUR_WORKSPACE_JWT'const res = await fetch('https://app.message.com/api/v1/goals', {
headers: { Authorization: 'Bearer ' + token }
});
const { goals } = await res.json();import requests
r = requests.get(
"https://app.message.com/api/v1/goals",
headers={"Authorization": f"Bearer {token}"},
)
goals = r.json()["goals"]require "net/http"
require "json"
uri = URI("https://app.message.com/api/v1/goals")
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) do |http|
req = Net::HTTP::Get.new(uri)
req["Authorization"] = "Bearer #{token}"
http.request(req)
end
goals = JSON.parse(res.body)["goals"]<?php
$ctx = stream_context_create([
"http" => ["method" => "GET", "header" => "Authorization: Bearer $token"]
]);
$goals = json_decode(file_get_contents("https://app.message.com/api/v1/goals", false, $ctx), true)["goals"];Get one goal
{
"id": "uuid",
"name": "Checkout success",
"condition": { "operator": "contains", "value": "/checkout/success" },
"valueCents": null,
"status": "active",
"createdAt": "2026-05-13T15:30:00Z"
}Create a goal
| Field | Type | Description |
|---|---|---|
| namerequired | string | Display name. Shown in reports. |
| conditionrequired | object | URL match rule: { operator, value }. See operators above. |
| valueCentsoptional | integer | Fixed value in cents assigned to every completion. Omit for an unvalued goal. |
{
"name": "Checkout success",
"condition": { "operator": "contains", "value": "/checkout/success" },
"valueCents": 4900
}Update / pause a goal
Partial update of name, condition, or valueCents. Set status to paused or archived to stop matching without deleting the goal.
Delete a goal
List completions
The per-completion list and totals for a date range (query params from / to, default last 7 days). This is the only way to see individual conversions for one goal; there is no separate "report" endpoint.
{
"completions": [
{
"id": "uuid",
"url": "https://acme.com/checkout/success?order=4567",
"valueCents": 4900,
"completedAt": "2026-05-13T15:36:00Z",
"visitorId": "uuid",
"conversationId": "uuid",
"attributedAgentId": "uuid",
"attributedAgentName": "Alex Lee"
}
],
"total": 1,
"totalValueCents": 4900
}Cross-goal reporting
For conversions across all goals (not scoped to one goal ID), see the Reports API.
Errors
| Code | When |
|---|---|
400 invalid_body | Payload failed validation, including an unparseable regex condition. |
404 not_found | Goal does not exist in this workspace. |
Common pitfalls
- Defining a goal on a vanity URL. The thank-you page must be unique to the conversion. If
/checkout/successis also reachable from a marketing campaign, your goal over-counts. - Expecting event-based or tag-based goals. There is only one condition shape: a URL operator/value pair. Build your conversion flow around a distinct URL.
- Looking for a manual attribution endpoint. There isn't one. Completions are recorded automatically from the visitor's browsing after a conversation, deduplicated per visitor per 24 hours.