How to send messages and receive notifications with the Messaging API v2
The GoToConnect Messaging API v2 allows applications to send messages across any type of inbox (shared or private) on any supported channel including SMS, WhatsApp, Facebook Messenger, Instagram, Email, and Web Chat.
In this guide, you will learn how to:
- Obtain an access token with the required scopes.
- Send messages on each supported channel using ready-to-use
curlexamples. - Set up a webhook subscription to receive messaging events in real time.
Prerequisites
This article assumes you can make API calls successfully which requires:
Authentication Scopes
| Scope | Description |
|---|---|
messaging.v1.send |
Send messages through the API |
messaging.v1.read |
Read messages, templates, and attachments |
messaging.v1.notifications.manage |
Manage notifications for messages and attachments |
When creating your OAuth client or Personal Access Token, ensure at minimum the
messaging.v1.send scope is enabled to follow the sending examples below. The
messaging.v1.read scope is required for the Retrieving Attachments
section. The messaging.v1.notifications.manage scope is required for the
webhook notifications section of this guide.
Note: The Messaging API v2 accepts the same scopes as Messaging API v1. Existing integrations do not need to re-authorize.
Usage Guidelines
The Messaging API assumes clients are implemented in such a way that unknown attributes are ignored. The addition of new response attributes may occur at any time, for any API response, without prior notice. This is not considered a break in backward-compatibility.
Permissions & Touchpoint Configuration
Before sending messages, ensure the caller has the appropriate permissions for the touchpoint used in the from field:
- Shared inbox (SMS/MMS, Web Chat, Email, WhatsApp, Facebook, Instagram): A phone number must be assigned to an inbox by an administrator. All users with the appropriate role on the inbox can then send and receive messages from that number in a shared environment.
- Private phone number (SMS/MMS): An administrator must grant texting permissions directly on the phone number for the user. Without this, the API returns a
403 Forbiddenerror.
Contact your GoTo account administrator to verify these permissions are in place before integrating.
Sending Messages
This section provides a copy-pasteable curl example for sending a message on each
supported channel. All examples use the
POST /accounts/{accountKey}/messages endpoint
with multipart/form-data encoding.
Conversation handling: In most cases, you do not need to specify a
conversationId. The API automatically adds sent messages to an existing open conversation between the owner touchpoint and contact touchpoints, or creates a new conversation under the inbox where the owner touchpoint is configured.
Replace {ACCESS_TOKEN} with your Bearer token and {accountKey} with your GoTo
account key. Your account key can be retrieved via the
Get Me endpoint.
SMS — Plain Text
Send a simple text message to a single phone number.
Touchpoint format: from and to must be E.164 phone numbers starting with +.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "SMS",
"from": "+15145551111",
"to": ["+15145552222"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Hello from GoTo!" }
}]
}]
};type=application/json'SMS — MMS with Attachment
Send a picture message by adding an attachments part. The attachmentName in the
request must match the filename in the form part.
Touchpoint format: Same as SMS plain text — E.164 phone numbers.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "SMS",
"from": "+15145551111",
"to": ["+15145552222"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Check out this photo!" }
}, {
"type": "image",
"attributes": { "attachmentName": "photo.jpg" }
}]
}]
};type=application/json' \
-F 'attachments=@photo.jpg;type=image/jpeg'SMS supports text and attachments combined in a single message. Max total attachment size: 2 MB.
SMS — Group MMS
Send a message to multiple recipients (up to 10) by adding more entries to the to array.
Touchpoint format: E.164 phone numbers.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "SMS",
"from": "+15145551111",
"to": ["+15145552222", "+15145553333", "+15145554444"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Hey team, meeting at 3pm!" }
}]
}]
};type=application/json'SMS is the only channel that supports multiple recipients per message (up to 10).
WhatsApp — Simple Text
Send a plain text message on WhatsApp. If the contact has messaged you within the last 24 hours, a simple message can be sent. Otherwise, a template message is required (see the WhatsApp Outbound Messaging section of the Messaging API v2 reference).
Touchpoint format: from is the numeric Meta WhatsApp phone number ID (not E.164).
to is the contact's E.164 phone number or BSUID (Business-Scoped User ID).
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "WHATSAPP",
"from": "137169456416846",
"to": ["+15145552222"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Thanks for reaching out! How can I help?" }
}]
}]
};type=application/json'WhatsApp does not support text and attachments combined. Send them as separate messages.
WhatsApp — Attachment
Send an attachment message (image, video, audio, or document) on WhatsApp.
Include the file as an attachments part and reference it by name in attachmentName.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "WHATSAPP",
"from": "137169456416846",
"to": ["+15145552222"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "image",
"attributes": {
"attachmentName": "photo.jpg",
"caption": "Check out this image!"
}
}]
}]
};type=application/json' \
-F 'attachments=@photo.jpg;type=image/jpeg'Web Chat
Send a message to an active web chat session.
Touchpoint format: from is the Widget ID. to is the session identifier.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "WEB_CHAT",
"from": "d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90",
"to": ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Hello! An agent will be with you shortly." }
}]
}]
};type=application/json'Facebook Messenger
Send a message to a Facebook user who has previously messaged your page.
Touchpoint format: from is your Facebook Page ID. to is the page-scoped user ID.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "FACEBOOK",
"from": "102345678901234",
"to": ["567890123456789"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Thanks for your message! We will get back to you soon." }
}]
}]
};type=application/json'Facebook does not support outbound-first messaging. The contact must have messaged your page first.
Send a message to an Instagram user who has previously messaged your page.
Touchpoint format: from is your Instagram Page ID. to is the page-scoped user ID.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "INSTAGRAM",
"from": "17841400123456789",
"to": ["67890123456"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Hi! Thanks for reaching out on Instagram." }
}]
}]
};type=application/json'Instagram does not support outbound-first messaging. The contact must have messaged your page first.
Reply to an existing email conversation. Email requires a conversationId —
you can only send messages within an existing conversation.
Touchpoint format: from and to are email addresses.
curl -X POST 'https://api.goto.com/messaging/v2/accounts/{accountKey}/messages' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-F 'request={
"channel": "EMAIL",
"from": "support@example.com",
"to": ["customer@example.com"],
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Thank you for contacting us. Your issue has been resolved." }
}]
}]
};type=application/json'Email does not support outbound-first messaging. A conversation must already exist before you can send a message. Use the
conversationIdfrom theINBOUND_MESSAGEwebhook notification that fires when the customer's email arrives (see Receiving Events below).
Email supports text and attachments combined in a single message, with no size limits on attachments. Add files using the
-F 'attachments=@file;type=...'syntax shown in the WhatsApp attachment example above.
Receiving Events with Webhook Notifications
When a subscription is active, the Messaging service delivers real-time events to your
webhook as HTTP POST requests. See the
Notification Channel overview
for details on delivery semantics, retry behavior, and channel lifecycle.
Note: While this guide focuses on webhooks, the Notification Channel API supports additional channel types. Webhooks are recommended for server-to-server integrations.
All webhook notifications share the following envelope structure:
{
"id": "456e7890-e12b-34d5-a678-901234567890",
"source": "inbox-notification",
"type": "INBOUND_MESSAGE",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:30:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": { }
}
}Where:
idis a unique identifier for this event.sourceis alwaysinbox-notification.typeidentifies the event type. See below for all supported values.usageis alwaysBACKGROUND.timestampis the ISO 8601 time when the event was created.ttlis the time-to-live for the event in seconds.content.accountKeyscopes the event to a specific account.content.payloadcontains the event-specific data (see the Notification Event Reference below).
Consumers should gracefully handle unknown
typevalues. New event types may be added without prior notice.
Supported Event Types
| Event Type | Description |
|---|---|
INBOUND_MESSAGE |
A message was received from an external party. |
OUTBOUND_MESSAGE |
A message was sent to an external party. |
DELIVERY_STATUS |
The delivery status of a sent message changed (e.g. delivered, failed). |
INBOUND_REACTION |
A reaction was received on a message from an external party. |
OUTBOUND_REACTION |
A reaction was sent on a message to an external party. |
Setting Up Notifications Step by Step
This walkthrough shows how to set up a webhook subscription and receive messaging
events end-to-end. Alice is a Super Admin for her organization (accountKey: 9502350087451835131). Her webhook is at https://mycompany.com/sms-webhook.
Step 1 — Create a Notification Channel
Follow the How to create a channel and receiving notifications from GoTo services
guide to create a webhook channel and obtain a channelId. You will need it in the next step.
Step 2 — Create an Organization Subscription
Using the channelId obtained in Step 1, create a
subscription that covers all touchpoints
in Alice's organization. This only needs to be done once.
Note: This endpoint requires a Super Admin bearer token.
curl -X POST "https://api.goto.com/messaging/v2/subscriptions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-d '{
"accountKey": "9502350087451835131",
"ownerEntity": "9502350087451835131",
"ownerEntityType": "ORGANIZATION",
"channelId": "Webhook.cfeb8e9a-495c-4e48-b3bf-fe1b4cf1cf76",
"eventTypes": ["INBOUND_MESSAGE", "OUTBOUND_MESSAGE", "DELIVERY_STATUS"]
}'The HTTP 201 Created response confirms the subscription:
{
"id": "MTIzNDp4eXo=",
"ownerEntity": "9502350087451835131",
"ownerEntityType": "ORGANIZATION",
"channelId": "Webhook.cfeb8e9a-495c-4e48-b3bf-fe1b4cf1cf76",
"eventTypes": ["INBOUND_MESSAGE", "OUTBOUND_MESSAGE", "DELIVERY_STATUS"]
}The subscription is bound to the user who created it. If that user is deactivated or loses Super Admin privileges, notifications will stop. Re-create the subscription with an active Super Admin if this occurs.
Step 3 — Receive an Inbound SMS
When Bob (+15559998888) sends a message to Alice (+15551234567), the webhook receives
an HTTP POST with an INBOUND_MESSAGE notification:
{
"id": "456e7890-e12b-34d5-a678-901234567890",
"source": "inbox-notification",
"type": "INBOUND_MESSAGE",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:30:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "123e4567-e89b-12d3-a456-426614174000",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"direction": "INBOUND",
"channel": "SMS",
"ownerTouchpoint": "+15551234567",
"contactTouchpoints": ["+15559998888"],
"authorTouchpoint": "+15559998888",
"body": "Hello Alice!",
"attachments": { "count": 0, "items": [] },
"timestamp": "2025-07-31T10:30:00Z"
}
}
}Your webhook must respond with an HTTP 2XX (e.g. 204 No Content).
Step 4 — Send an SMS Reply
Alice replies to Bob by sending a message via the API, as shown in the Sending Messages section above:
curl -X POST "https://api.goto.com/messaging/v2/accounts/9502350087451835131/messages" \
-H "Authorization: Bearer {ACCESS_TOKEN}" \
-F 'request={
"channel": "SMS",
"from": "+15551234567",
"to": ["+15559998888"],
"type": "simple",
"components": [{
"type": "body",
"components": [{
"type": "text",
"attributes": { "text": "Hi Bob!" }
}]
}]
};type=application/json'The HTTP 201 Created response confirms the sent message:
{
"id": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"accountKey": "9502350087451835131",
"timestamp": "2025-07-31T10:31:00Z",
"channel": "SMS",
"direction": "OUTBOUND",
"from": "+15551234567",
"to": ["+15559998888"],
"body": "Hi Bob!"
}If the subscription includes OUTBOUND_MESSAGE, the webhook also receives a notification:
{
"id": "789a1234-b56c-78d9-e012-345678901234",
"source": "inbox-notification",
"type": "OUTBOUND_MESSAGE",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:31:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"direction": "OUTBOUND",
"channel": "SMS",
"ownerTouchpoint": "+15551234567",
"contactTouchpoints": ["+15559998888"],
"authorTouchpoint": "+15551234567",
"body": "Hi Bob!",
"attachments": { "count": 0, "items": [] },
"timestamp": "2025-07-31T10:31:00Z"
}
}
}Step 5 — Receive a Delivery Status Update
Shortly after the outbound message is sent, the webhook receives a DELIVERY_STATUS
notification indicating whether the message was successfully delivered or failed:
{
"id": "abc12345-d678-90ef-a123-456789012345",
"source": "inbox-notification",
"type": "DELIVERY_STATUS",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:32:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"ownerTouchpoint": "+15551234567",
"contactTouchpoint": "+15559998888",
"timestamp": "2025-07-31T10:32:00Z",
"deliveryStatus": {
"code": 1000,
"description": "DELIVERED",
"retryable": false
}
}
}
}See the deliveryStatus.code table in the
Subscriptions API reference for all status codes.
Notification Event Reference
This section documents the payload of each event type delivered to your webhook.
INBOUND_MESSAGE
Delivered when a message is received from an external party. The payload fields use
ownerTouchpoint (the inbox/touchpoint that owns the conversation), contactTouchpoints
(the external party), and authorTouchpoint (who sent this specific message).
{
"id": "456e7890-e12b-34d5-a678-901234567890",
"source": "inbox-notification",
"type": "INBOUND_MESSAGE",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:30:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "123e4567-e89b-12d3-a456-426614174000",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"direction": "INBOUND",
"channel": "SMS",
"ownerTouchpoint": "+15551234567",
"contactTouchpoints": ["+15559998888"],
"authorTouchpoint": "+15559998888",
"body": "Hello!",
"attachments": { "count": 0, "items": [] },
"timestamp": "2025-07-31T10:30:00Z"
}
}
}OUTBOUND_MESSAGE
Delivered when a message is sent to an external party. authorTouchpoint is the owner's
touchpoint and direction is OUTBOUND.
{
"id": "789a1234-b56c-78d9-e012-345678901234",
"source": "inbox-notification",
"type": "OUTBOUND_MESSAGE",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:31:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"direction": "OUTBOUND",
"channel": "SMS",
"ownerTouchpoint": "+15551234567",
"contactTouchpoints": ["+15559998888"],
"authorTouchpoint": "+15551234567",
"body": "Hi Bob!",
"attachments": { "count": 0, "items": [] },
"timestamp": "2025-07-31T10:31:00Z"
}
}
}DELIVERY_STATUS
Delivered when the delivery status of an outbound message changes (e.g. a failure is
detected). See the deliveryStatus.code table in the
Subscriptions API reference for all status codes.
{
"id": "abc12345-d678-90ef-a123-456789012345",
"source": "inbox-notification",
"type": "DELIVERY_STATUS",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:32:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"ownerTouchpoint": "+15551234567",
"contactTouchpoint": "+15559998888",
"timestamp": "2025-07-31T10:32:00Z",
"deliveryStatus": {
"code": 4000,
"description": "INVALID_DESTINATION",
"retryable": false
}
}
}
}INBOUND_REACTION
Delivered when an external party reacts to a message (e.g. a WhatsApp emoji reaction).
{
"id": "bcd23456-e789-01fg-b234-567890123456",
"source": "inbox-notification",
"type": "INBOUND_REACTION",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:33:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "123e4567-e89b-12d3-a456-426614174000",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"emoji": "👍",
"timestamp": "2025-07-31T10:33:00Z"
}
}
}OUTBOUND_REACTION
Delivered when an agent sends a reaction to an external party's message.
{
"id": "cde34567-f890-12gh-c345-678901234567",
"source": "inbox-notification",
"type": "OUTBOUND_REACTION",
"usage": "BACKGROUND",
"timestamp": "2025-07-31T10:34:00Z",
"ttl": 604800,
"content": {
"accountKey": "9502350087451835131",
"payload": {
"messageId": "234f5678-f90a-12b3-c456-536725285111",
"conversationId": "987fcdeb-51a2-43d1-b789-123456789abc",
"emoji": "✅",
"timestamp": "2025-07-31T10:34:00Z"
}
}
}Retrieving Attachments
When an INBOUND_MESSAGE or OUTBOUND_MESSAGE notification includes attachments, the
attachments field contains metadata for each file:
"attachments": {
"count": 1,
"items": [
{
"name": "document.pdf",
"contentType": "application/pdf",
"size": 1024000,
"attachmentId": "123e4567-e89b-12d3-a456-426614174000"
}
]
}To download the file, use the
GET /accounts/{accountKey}/attachments/{attachmentId}
endpoint with the attachmentId from the notification. The endpoint returns an
HTTP 302 redirect to a pre-signed download URL.
Required scope:
messaging.v1.read
curl -L -X GET 'https://api.goto.com/messaging/v2/accounts/{accountKey}/attachments/123e4567-e89b-12d3-a456-426614174000' \
-H 'Authorization: Bearer {ACCESS_TOKEN}' \
-o document.pdfThe pre-signed URL expires after 60 seconds. Follow the redirect immediately and do not store the URL for later use. The
-Lflag tells curl to follow the redirect automatically.
- How do I get started?
- How to create a developer account
- How to create an OAuth client
- How to obtain an OAuth access token
- How to obtain an OAuth access token using a Personal Access Token
- How to obtain an OAuth access token (in Node.js)
- How to Obtain and Use Refresh Tokens
- Migrating to New Token Retrieval with authentication.logmeininc.com
- How to use GoToConnect API to fetch account users and lines
- How to create, update and delete account users via Admin API
- Call Events Screen Pop Tutorial
- Send SMS tutorial
- How to use Voice Admin APIs
- How to create a channel and receiving notifications from GoTo services
- How to subscribe to and get call events
- Fetching Call Events Reports
- Make and Receive Calls using the Devices and Calls API
- How to send messages and receive notifications with the Messaging API v2
- GoTo Connect APIs Host Migration
- GoToWebinar webhooks
- How to use GoToWebinar webhooks
- What API information is available for GoToMyPC?
- How to Setup an Integration with Central
- How to Setup an Integration with Rescue
- Rescue iOS and Andriod SDK
- Introduction
- Java SDK
- .NET SDK
- Direct login migration
- How to use Postman API collections
- How much do the GoTo APIs cost?
- How do I get support for the APIs?
- Rate Limiting