Skip to main content

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

id
string
required
Unique identifier for the message (UUID format)
content
string
required
The processed message content with variables replaced
recipientPhone
string
required
Phone number of the message recipient
recipientName
string
Name of the message recipient (if available)
contactId
string
required
ID of the associated contact
formId
string
required
ID of the form that generated this message
formName
string
required
Name of the form that generated this message
status
string
required
Message status: queued, sent, failed, cancelled
priority
string
required
Message priority: low, normal, high, urgent
webhookData
object
Original webhook data that generated this message
templateUsed
string
required
Message template that was used to generate content
scheduledFor
string
ISO timestamp when message is scheduled to be sent
sentAt
string
ISO timestamp when message was actually sent
failureReason
string
Reason for failure if status is ‘failed’
retryCount
number
required
Number of retry attempts made
metadata
object
Additional message metadata and tracking information
createdAt
string
required
ISO timestamp when message was created
updatedAt
string
required
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
default:"1"
Page number for pagination
limit
number
default:"50"
Number of messages per page (max: 100)
status
string
Filter by status: queued, sent, failed, cancelled
formId
string
Filter by form ID
contactId
string
Filter by contact ID
priority
string
Filter by priority: low, normal, high, urgent
createdAfter
string
Filter messages created after this date (ISO format)
createdBefore
string
Filter messages created before this date (ISO format)
sortBy
string
default:"createdAt"
Sort field: createdAt, scheduledFor, sentAt, priority
sortOrder
string
default:"desc"
Sort order: asc or desc
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:
status
string
required
New status: queued, sent, failed, cancelled
sentAt
string
ISO timestamp when message was sent (required for ‘sent’ status)
failureReason
string
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:
period
string
default:"30d"
Time period: 1d, 7d, 30d, 90d, 1y
formId
string
Filter analytics by specific form
timezone
string
default:"UTC"
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:
1

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;
2

Send Message via iMessage

Use iOS Shortcuts to send the message content to the recipient
3

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

Performance Optimization

// 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