Overview
The Messages API provides access to your message queue, allowing you to retrieve, manage, and track messages generated through your GoBlue forms. Messages are automatically created when webhook data is received and processed through your message templates.
Base URL
https://api.goblue.app/v1/messages
Authentication
Messages API endpoints use API key authentication via URL path. See Authentication for details.
URL Format:
https://api.goblue.app/v1/messages/{your-api-key}
Message Object
Properties
Unique identifier for the message (UUID format)
The processed message content with variables replaced
Phone number of the message recipient
Name of the message recipient (if available)
ID of the associated contact
ID of the form that generated this message
Name of the form that generated this message
Message status: queued, sent, failed, cancelled
Message priority: low, normal, high, urgent
Original webhook data that generated this message
Message template that was used to generate content
ISO timestamp when message is scheduled to be sent
ISO timestamp when message was actually sent
Reason for failure if status is ‘failed’
Number of retry attempts made
Additional message metadata and tracking information
ISO timestamp when message was created
ISO timestamp when message was last updated
Example Message Object
{
"id" : "m47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"content" : "Hi Sarah, thanks for your interest in web development! I'll review your project details and get back to you within 24 hours." ,
"recipientPhone" : "+1234567890" ,
"recipientName" : "Sarah Johnson" ,
"contactId" : "c47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"formId" : "f47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"formName" : "Website Contact Form" ,
"status" : "sent" ,
"priority" : "normal" ,
"webhookData" : {
"firstName" : "Sarah" ,
"lastName" : "Johnson" ,
"phoneNumber" : "+1234567890" ,
"serviceType" : "web development" ,
"companyName" : "TechStart Inc"
},
"templateUsed" : "Hi {{firstName}}, thanks for your interest in {{serviceType}}! I'll review your project details and get back to you within 24 hours." ,
"scheduledFor" : "2024-01-15T14:30:00Z" ,
"sentAt" : "2024-01-15T14:30:15Z" ,
"failureReason" : null ,
"retryCount" : 0 ,
"metadata" : {
"messageLength" : 127 ,
"variablesUsed" : [ "firstName" , "serviceType" ],
"source" : "webhook" ,
"ipAddress" : "192.168.1.100"
},
"createdAt" : "2024-01-15T14:30:00Z" ,
"updatedAt" : "2024-01-15T14:30:15Z"
}
Endpoints
Get All Messages
Retrieve your message queue with optional filtering and pagination.
curl https://api.goblue.app/v1/messages/YOUR_API_KEY
Query Parameters:
Page number for pagination
Number of messages per page (max: 100)
Filter by status: queued, sent, failed, cancelled
Filter by priority: low, normal, high, urgent
Filter messages created after this date (ISO format)
Filter messages created before this date (ISO format)
sortBy
string
default: "createdAt"
Sort field: createdAt, scheduledFor, sentAt, priority
Response:
{
"status" : "success" ,
"data" : {
"messages" : [
{
"id" : "m47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"content" : "Hi Sarah, thanks for your interest in web development!" ,
"recipientPhone" : "+1234567890" ,
"recipientName" : "Sarah Johnson" ,
"formName" : "Website Contact Form" ,
"status" : "sent" ,
"priority" : "normal" ,
"sentAt" : "2024-01-15T14:30:15Z" ,
"createdAt" : "2024-01-15T14:30:00Z"
}
],
"pagination" : {
"total" : 1247 ,
"page" : 1 ,
"limit" : 50 ,
"totalPages" : 25
},
"summary" : {
"queued" : 15 ,
"sent" : 1195 ,
"failed" : 8 ,
"cancelled" : 2
}
}
}
Get Message by ID
Retrieve a specific message by its ID.
curl https://api.goblue.app/v1/messages/YOUR_API_KEY/m47ac10b-58cc-4372-a567-0e02b2c3d479
Response:
{
"status" : "success" ,
"data" : {
"message" : {
"id" : "m47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"content" : "Hi Sarah, thanks for your interest in web development! I'll review your project details and get back to you within 24 hours." ,
"recipientPhone" : "+1234567890" ,
"recipientName" : "Sarah Johnson" ,
"contactId" : "c47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"formId" : "f47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"formName" : "Website Contact Form" ,
"status" : "sent" ,
"webhookData" : {
"firstName" : "Sarah" ,
"lastName" : "Johnson" ,
"serviceType" : "web development"
},
"templateUsed" : "Hi {{firstName}}, thanks for your interest in {{serviceType}}!" ,
"sentAt" : "2024-01-15T14:30:15Z" ,
"createdAt" : "2024-01-15T14:30:00Z"
}
}
}
Update Message Status
Update the status of a message (typically used by iOS Shortcuts to report delivery).
curl -X PUT https://api.goblue.app/v1/messages/YOUR_API_KEY/m47ac10b-58cc-4372-a567-0e02b2c3d479/status \
-H "Content-Type: application/json" \
-d '{
"status": "sent",
"sentAt": "2024-01-15T14:30:15Z"
}'
Request Body:
New status: queued, sent, failed, cancelled
ISO timestamp when message was sent (required for ‘sent’ status)
Reason for failure (required for ‘failed’ status)
Response:
{
"status" : "success" ,
"data" : {
"messageId" : "m47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"status" : "sent" ,
"sentAt" : "2024-01-15T14:30:15Z" ,
"updatedAt" : "2024-01-15T14:30:16Z"
}
}
Delete Message
Remove a message from the queue (only works for queued messages).
curl -X DELETE https://api.goblue.app/v1/messages/YOUR_API_KEY/m47ac10b-58cc-4372-a567-0e02b2c3d479
Response:
{
"status" : "success" ,
"message" : "Message deleted successfully" ,
"data" : {
"deletedId" : "m47ac10b-58cc-4372-a567-0e02b2c3d479"
}
}
Bulk Update Messages
Update multiple messages at once (useful for iOS Shortcuts batch operations).
curl -X PUT https://api.goblue.app/v1/messages/YOUR_API_KEY/bulk \
-H "Content-Type: application/json" \
-d '{
"messageIds": [
"m47ac10b-58cc-4372-a567-0e02b2c3d479",
"m58bd21c-69dd-5483-b678-1f13c3d4e580"
],
"status": "sent",
"sentAt": "2024-01-15T14:30:15Z"
}'
Response:
{
"status" : "success" ,
"data" : {
"updated" : 2 ,
"errors" : []
}
}
Get Message Analytics
Retrieve analytics and statistics for your messages.
curl https://api.goblue.app/v1/messages/YOUR_API_KEY/analytics?period=30d
Query Parameters:
Time period: 1d, 7d, 30d, 90d, 1y
Filter analytics by specific form
Timezone for date calculations
Response:
{
"status" : "success" ,
"data" : {
"analytics" : {
"totalMessages" : 1247 ,
"deliveryRate" : 95.8 ,
"averageResponseTime" : "2.3 minutes" ,
"statusBreakdown" : {
"sent" : 1195 ,
"queued" : 15 ,
"failed" : 8 ,
"cancelled" : 2
},
"dailyVolume" : [
{
"date" : "2024-01-15" ,
"sent" : 47 ,
"failed" : 1 ,
"queued" : 3
}
],
"topForms" : [
{
"formId" : "f47ac10b-58cc-4372-a567-0e02b2c3d479" ,
"formName" : "Website Contact Form" ,
"messageCount" : 567 ,
"deliveryRate" : 97.2
}
],
"failureReasons" : {
"invalid-phone" : 5 ,
"rate-limit" : 2 ,
"network-error" : 1
}
}
}
}
Message Queue Management
Processing Messages with iOS Shortcuts
The typical workflow for processing messages:
Fetch Queued Messages
Retrieve messages with status ‘queued’ const response = await fetch ( `https://api.goblue.app/v1/messages/ ${ API_KEY } ?status=queued&limit=10` );
const data = await response . json ();
const queuedMessages = data . data . messages ;
Send Message via iMessage
Use iOS Shortcuts to send the message content to the recipient
Update Message Status
Report successful delivery or failure await fetch ( `https://api.goblue.app/v1/messages/ ${ API_KEY } / ${ messageId } /status` , {
method: 'PUT' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
status: 'sent' ,
sentAt: new Date (). toISOString ()
})
});
Priority Handling
Messages can be prioritized for sending order:
Use Case : Time-sensitive messages (appointments, deadlines)
Processing : Send immediately, bypass normal queue{
"priority" : "urgent" ,
"content" : "URGENT: Your consultation is in 30 minutes..."
}
Use Case : Important business communications
Processing : Send before normal priority messages{
"priority" : "high" ,
"content" : "Thank you for your purchase! Here's your receipt..."
}
Use Case : Standard follow-ups and communications
Processing : Default queue processing{
"priority" : "normal" ,
"content" : "Hi John, thanks for your inquiry..."
}
Use Case : Promotional messages, newsletters
Processing : Send when queue is empty{
"priority" : "low" ,
"content" : "Check out our latest features..."
}
Retry Logic
Messages can be automatically retried on failure:
// Check for failed messages that can be retried
const response = await fetch ( `https://api.goblue.app/v1/messages/ ${ API_KEY } ?status=failed` );
const failedMessages = await response . json ();
for ( const message of failedMessages . data . messages ) {
if ( message . retryCount < 3 && message . failureReason !== 'invalid-phone' ) {
// Retry the message
await fetch ( `https://api.goblue.app/v1/messages/ ${ API_KEY } / ${ message . id } /status` , {
method: 'PUT' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
status: 'queued' // Move back to queue for retry
})
});
}
}
Message Templates and Variables
Template Processing
GoBlue processes templates by replacing variables with webhook data:
Template:
Hi {{firstName}}, thanks for your {{serviceType}} inquiry!
Budget: {{budget}}, Timeline: {{timeline}}
Webhook Data:
{
"firstName" : "Sarah" ,
"serviceType" : "web development" ,
"budget" : "$10,000" ,
"timeline" : "3 months"
}
Processed Message:
Hi Sarah, thanks for your web development inquiry!
Budget: $10,000, Timeline: 3 months
Handling Missing Variables
When webhook data doesn’t include a variable:
// Template: "Hi {{firstName}}, your {{serviceType}} project for {{companyName}} is ready!"
// Webhook: { "firstName": "John", "serviceType": "website" }
// Result: "Hi John, your website project for is ready!"
// Better template design:
// "Hi {{firstName}}, your {{serviceType}} project is ready!"
Variable Validation
Check which variables are used in templates:
function extractVariables ( template ) {
const regex = / \{\{ ( [ ^ } ] + ) \}\} / g ;
const variables = [];
let match ;
while (( match = regex . exec ( template )) !== null ) {
variables . push ( match [ 1 ]. trim ());
}
return [ ... new Set ( variables )]; // Remove duplicates
}
const template = "Hi {{firstName}}, thanks for your {{serviceType}} inquiry!" ;
const variables = extractVariables ( template );
console . log ( variables ); // ['firstName', 'serviceType']
Scheduled Messages
Delayed Sending
Messages can be scheduled for future delivery:
{
"content" : "Hi {{firstName}}, following up on your inquiry..." ,
"scheduledFor" : "2024-01-16T09:00:00Z" ,
"priority" : "normal"
}
Timezone Handling
// Schedule message for 9 AM in recipient's timezone
const moment = require ( 'moment-timezone' );
const scheduledTime = moment ()
. tz ( 'America/New_York' )
. hour ( 9 )
. minute ( 0 )
. second ( 0 )
. toISOString ();
// Message will include this in scheduledFor field
Canceling Scheduled Messages
// Cancel a scheduled message before it's sent
await fetch ( `https://api.goblue.app/v1/messages/ ${ API_KEY } / ${ messageId } /status` , {
method: 'PUT' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
status: 'cancelled'
})
});
Error Handling
Common Error Responses
Cause : Invalid message data or status{
"status" : "error" ,
"message" : "Invalid status transition" ,
"details" : {
"currentStatus" : "sent" ,
"requestedStatus" : "queued" ,
"message" : "Cannot move sent message back to queue"
}
}
Cause : Message ID doesn’t exist{
"status" : "error" ,
"message" : "Message not found" ,
"code" : "MESSAGE_NOT_FOUND"
}
Cause : Too many API requests{
"status" : "error" ,
"message" : "Rate limit exceeded" ,
"code" : "RATE_LIMIT_EXCEEDED" ,
"retryAfter" : 60
}
Handling Failed Messages
class MessageProcessor {
async handleFailedMessage ( message ) {
switch ( message . failureReason ) {
case 'invalid-phone' :
// Don't retry, update contact with invalid phone
await this . markContactInvalid ( message . contactId );
break ;
case 'rate-limit' :
// Retry after delay
await this . scheduleRetry ( message . id , '10 minutes' );
break ;
case 'network-error' :
// Immediate retry if under retry limit
if ( message . retryCount < 3 ) {
await this . requeueMessage ( message . id );
}
break ;
default :
// Log for manual review
console . error ( 'Unknown failure reason:' , message . failureReason );
}
}
}
Best Practices
Queue Management
Batch Processing Process messages in batches for better performance
Priority Handling Always process higher priority messages first
Retry Logic Implement smart retry logic for failed messages
Rate Limiting Respect rate limits to avoid service disruption
// Efficient message processing
class MessageQueue {
async processQueue ( batchSize = 10 ) {
// Get priority messages first
const priorities = [ 'urgent' , 'high' , 'normal' , 'low' ];
for ( const priority of priorities ) {
const messages = await this . getQueuedMessages ({
priority ,
limit: batchSize ,
status: 'queued'
});
if ( messages . length > 0 ) {
await this . processBatch ( messages );
break ; // Process one priority level at a time
}
}
}
async processBatch ( messages ) {
const promises = messages . map ( message =>
this . sendMessage ( message ). catch ( error => ({
messageId: message . id ,
error: error . message
}))
);
const results = await Promise . allSettled ( promises );
await this . updateMessageStatuses ( results );
}
}
Monitoring and Alerts
// Set up monitoring for message queue health
class MessageMonitor {
async checkQueueHealth () {
const analytics = await this . getMessageAnalytics ();
// Alert on high failure rate
if ( analytics . deliveryRate < 90 ) {
await this . sendAlert ( 'High message failure rate detected' );
}
// Alert on queue backup
const queueSize = analytics . statusBreakdown . queued ;
if ( queueSize > 100 ) {
await this . sendAlert ( `Message queue backed up: ${ queueSize } messages` );
}
// Alert on old queued messages
const oldMessages = await this . getQueuedMessages ({
createdBefore: new Date ( Date . now () - 60 * 60 * 1000 ) // 1 hour ago
});
if ( oldMessages . length > 0 ) {
await this . sendAlert ( ` ${ oldMessages . length } messages stuck in queue` );
}
}
}
Next Steps