Skip to main content

Overview

GoBlue uses API key-based authentication to secure access to your account data and messaging capabilities. This guide covers how to obtain, manage, and use API keys securely.

Authentication Methods

GoBlue supports two authentication approaches depending on the endpoint:

Form-Based (Webhooks)

Uses form ID in URL for webhook endpoints - no API key required

API Key (Direct Access)

Uses API key for direct API access to messages, forms, and account data

API Key Management

Obtaining Your API Key

1

Open GoBlue App

Launch the GoBlue app on your iOS device.
2

Navigate to Settings

Tap the “Settings” tab at the bottom of the screen.
3

Find API Access Section

Scroll to the “API Access” section where your API key is displayed.
4

Copy API Key

Tap the copy button to copy your API key to the clipboard.
Your API key is sensitive information. Never share it publicly or commit it to version control.

API Key Format

GoBlue API keys follow this format:
goblue_sk_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t
Structure:
  • Prefix: goblue_sk_ (indicates GoBlue secret key)
  • Key: 40-character alphanumeric string
  • Total Length: 50 characters

Authentication Implementation

URL Path Authentication

For message retrieval and some endpoints, include the API key in the URL path:
GET https://api.goblue.app/v1/messages/{api-key}
Example:
curl https://api.goblue.app/v1/messages/goblue_sk_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t

Header Authentication

For other endpoints, use the Authorization header:
Authorization: Bearer {api-key}
Example:
curl -H "Authorization: Bearer goblue_sk_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t" \
     https://api.goblue.app/v1/forms

Webhook Authentication

Webhook endpoints use form-based authentication:
POST https://api.goblue.app/v1/forms/{form-id}/webhook
The form-id serves as both the endpoint identifier and authentication token.

Programming Language Examples

JavaScript/Node.js

const GOBLUE_API_KEY = process.env.GOBLUE_API_KEY;

// URL path method
async function getMessages() {
  const response = await fetch(`https://api.goblue.app/v1/messages/${GOBLUE_API_KEY}`);
  return response.json();
}

// Header method
async function getForms() {
  const response = await fetch('https://api.goblue.app/v1/forms', {
    headers: {
      'Authorization': `Bearer ${GOBLUE_API_KEY}`,
      'Content-Type': 'application/json'
    }
  });
  return response.json();
}

// Webhook (no API key needed)
async function sendWebhook(formId, data) {
  const response = await fetch(`https://api.goblue.app/v1/forms/${formId}/webhook`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(data)
  });
  return response.json();
}

Python

import os
import requests

API_KEY = os.getenv('GOBLUE_API_KEY')
BASE_URL = 'https://api.goblue.app/v1'

# URL path method
def get_messages():
    url = f"{BASE_URL}/messages/{API_KEY}"
    response = requests.get(url)
    return response.json()

# Header method
def get_forms():
    url = f"{BASE_URL}/forms"
    headers = {
        'Authorization': f'Bearer {API_KEY}',
        'Content-Type': 'application/json'
    }
    response = requests.get(url, headers=headers)
    return response.json()

# Webhook (no API key needed)
def send_webhook(form_id, data):
    url = f"{BASE_URL}/forms/{form_id}/webhook"
    headers = {'Content-Type': 'application/json'}
    response = requests.post(url, json=data, headers=headers)
    return response.json()

PHP

<?php
class GoBlueAPI {
    private $apiKey;
    private $baseUrl = 'https://api.goblue.app/v1';
    
    public function __construct($apiKey) {
        $this->apiKey = $apiKey;
    }
    
    // URL path method
    public function getMessages() {
        $url = "{$this->baseUrl}/messages/{$this->apiKey}";
        return $this->makeRequest($url, 'GET');
    }
    
    // Header method
    public function getForms() {
        $url = "{$this->baseUrl}/forms";
        $headers = [
            "Authorization: Bearer {$this->apiKey}",
            "Content-Type: application/json"
        ];
        return $this->makeRequest($url, 'GET', null, $headers);
    }
    
    // Webhook (no API key needed)
    public function sendWebhook($formId, $data) {
        $url = "{$this->baseUrl}/forms/{$formId}/webhook";
        $headers = ["Content-Type: application/json"];
        return $this->makeRequest($url, 'POST', $data, $headers);
    }
    
    private function makeRequest($url, $method, $data = null, $headers = []) {
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ]);
        
        if ($data) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
        
        if ($httpCode !== 200) {
            throw new Exception("API request failed: HTTP {$httpCode}");
        }
        
        return json_decode($response, true);
    }
}

// Usage
$api = new GoBlueAPI($_ENV['GOBLUE_API_KEY']);
$messages = $api->getMessages();
?>

Ruby

require 'net/http'
require 'json'
require 'uri'

class GoBlueAPI
  BASE_URL = 'https://api.goblue.app/v1'
  
  def initialize(api_key)
    @api_key = api_key
  end
  
  # URL path method
  def get_messages
    uri = URI("#{BASE_URL}/messages/#{@api_key}")
    make_request(uri, Net::HTTP::Get)
  end
  
  # Header method
  def get_forms
    uri = URI("#{BASE_URL}/forms")
    request = Net::HTTP::Get.new(uri)
    request['Authorization'] = "Bearer #{@api_key}"
    request['Content-Type'] = 'application/json'
    make_request(uri, request)
  end
  
  # Webhook (no API key needed)
  def send_webhook(form_id, data)
    uri = URI("#{BASE_URL}/forms/#{form_id}/webhook")
    request = Net::HTTP::Post.new(uri)
    request['Content-Type'] = 'application/json'
    request.body = data.to_json
    make_request(uri, request)
  end
  
  private
  
  def make_request(uri, request)
    http = Net::HTTP.new(uri.host, uri.port)
    http.use_ssl = true
    
    response = http.request(request)
    
    unless response.code == '200'
      raise "API request failed: HTTP #{response.code}"
    end
    
    JSON.parse(response.body)
  end
end

# Usage
api = GoBlueAPI.new(ENV['GOBLUE_API_KEY'])
messages = api.get_messages

Security Best Practices

API Key Protection

Store API keys in environment variables, never in code:
# .env file
GOBLUE_API_KEY=goblue_sk_1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p7q8r9s0t
// Access in code
const apiKey = process.env.GOBLUE_API_KEY;
Never commit API keys to version control:
# .gitignore
.env
*.key
config/secrets.json
Use placeholder values in example files:
// config.example.js
module.exports = {
  goblueApiKey: 'your-api-key-here'
};
Additional security measures for production:
  • Use secret management services (AWS Secrets Manager, Azure Key Vault)
  • Rotate API keys periodically
  • Monitor API key usage for suspicious activity
  • Implement IP whitelisting if possible

HTTPS Only

Always use HTTPS when making API requests. HTTP requests may expose your API key during transmission.
// ✅ Correct - HTTPS
const response = await fetch('https://api.goblue.app/v1/messages/...');

// ❌ Never use HTTP
const response = await fetch('http://api.goblue.app/v1/messages/...');

Request Logging

When logging API requests, never log the full API key:
// ✅ Safe logging
console.log('API request', {
  url: url.replace(apiKey, 'sk_***'),
  method: 'GET',
  timestamp: new Date().toISOString()
});

// ❌ Dangerous - exposes API key
console.log('API request', { url, apiKey, method: 'GET' });

Error Handling

Authentication Errors

Cause: Invalid or missing API keyResponse:
{
  "status": "error",
  "message": "Invalid API key",
  "code": "AUTHENTICATION_ERROR",
  "details": {
    "provided": "goblue_sk_invalid...",
    "expected": "Valid GoBlue API key"
  }
}
Solutions:
  • Verify API key is correct
  • Check for extra spaces or characters
  • Ensure key hasn’t been regenerated
Cause: API key lacks required permissionsResponse:
{
  "status": "error",
  "message": "Insufficient permissions for this endpoint",
  "code": "PERMISSION_ERROR",
  "details": {
    "endpoint": "/v1/admin/users",
    "required": "admin_access",
    "current": "standard_access"
  }
}
Solutions:
  • Contact support for permission upgrade
  • Use appropriate endpoint for your access level

Implementing Error Handling

class GoBlueAuthError extends Error {
  constructor(message, code, details) {
    super(message);
    this.name = 'GoBlueAuthError';
    this.code = code;
    this.details = details;
  }
}

async function authenticatedRequest(url, options = {}) {
  try {
    const response = await fetch(url, {
      ...options,
      headers: {
        'Authorization': `Bearer ${process.env.GOBLUE_API_KEY}`,
        'Content-Type': 'application/json',
        ...options.headers
      }
    });
    
    if (!response.ok) {
      const errorData = await response.json();
      
      if (response.status === 401 || response.status === 403) {
        throw new GoBlueAuthError(
          errorData.message,
          errorData.code,
          errorData.details
        );
      }
      
      throw new Error(`HTTP ${response.status}: ${errorData.message}`);
    }
    
    return response.json();
    
  } catch (error) {
    if (error instanceof GoBlueAuthError) {
      console.error('Authentication failed:', error.message);
      
      // Handle specific auth errors
      switch (error.code) {
        case 'AUTHENTICATION_ERROR':
          // Invalid API key - check configuration
          throw new Error('Please check your GoBlue API key configuration');
          
        case 'PERMISSION_ERROR':
          // Insufficient permissions - use different endpoint
          throw new Error('This operation requires additional permissions');
          
        default:
          throw error;
      }
    }
    
    throw error; // Re-throw other errors
  }
}

API Key Rotation

When to Rotate

Scheduled Rotation

Rotate keys every 90 days as a security best practice

Security Incident

Immediately rotate if key may have been compromised

Team Changes

Rotate when team members with key access leave

System Changes

Rotate during major system upgrades or migrations

Rotation Process

1

Generate New Key

Contact GoBlue support to generate a new API key while keeping the old one active.
2

Update Applications

Update all applications and integrations to use the new API key.
3

Test Thoroughly

Verify all integrations work with the new key before deactivating the old one.
4

Deactivate Old Key

Once confirmed working, have the old API key deactivated.
5

Monitor

Monitor for any failed requests that might indicate missed integrations.

Rate Limiting with Authentication

API keys are subject to rate limiting:

Standard Limits

1,000 requests per hour per API key

Burst Allowance

Up to 100 requests per minute for short bursts

Rate Limit Headers

Authentication requests include rate limit information:
HTTP/1.1 200 OK
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 987
X-RateLimit-Reset: 1640995200
X-RateLimit-Burst-Limit: 100
X-RateLimit-Burst-Remaining: 95

Handling Rate Limits

async function rateLimitAwareRequest(url, options) {
  const response = await fetch(url, options);
  
  // Check rate limit headers
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));
  const reset = parseInt(response.headers.get('X-RateLimit-Reset'));
  
  if (remaining < 10) {
    const resetTime = new Date(reset * 1000);
    console.warn(`Rate limit nearly exceeded. Resets at: ${resetTime}`);
  }
  
  if (response.status === 429) {
    const retryAfter = response.headers.get('Retry-After') || 60;
    throw new Error(`Rate limited. Retry after ${retryAfter} seconds`);
  }
  
  return response;
}

Testing Authentication

Development Testing

# Test API key validity
curl -I https://api.goblue.app/v1/messages/YOUR_API_KEY

# Expected response for valid key
HTTP/2 200
content-type: application/json
x-ratelimit-limit: 1000
x-ratelimit-remaining: 999

# Expected response for invalid key  
HTTP/2 401
content-type: application/json

Automated Testing

describe('GoBlue API Authentication', () => {
  const validApiKey = process.env.GOBLUE_API_KEY;
  const invalidApiKey = 'goblue_sk_invalid';
  
  test('should authenticate with valid API key', async () => {
    const response = await fetch(`https://api.goblue.app/v1/messages/${validApiKey}`);
    expect(response.status).toBe(200);
  });
  
  test('should reject invalid API key', async () => {
    const response = await fetch(`https://api.goblue.app/v1/messages/${invalidApiKey}`);
    expect(response.status).toBe(401);
    
    const data = await response.json();
    expect(data.code).toBe('AUTHENTICATION_ERROR');
  });
  
  test('should include rate limit headers', async () => {
    const response = await fetch(`https://api.goblue.app/v1/messages/${validApiKey}`);
    
    expect(response.headers.get('X-RateLimit-Limit')).toBeTruthy();
    expect(response.headers.get('X-RateLimit-Remaining')).toBeTruthy();
  });
});

Support and Troubleshooting

Common Issues

Symptoms: 401 errors despite having an API keyTroubleshooting:
  1. Verify the key is copied correctly (check for extra spaces)
  2. Ensure you’re using the latest key from the app
  3. Test with a simple curl request
  4. Check if the key was recently regenerated
Symptoms: Authentication works sometimes but fails other timesTroubleshooting:
  1. Check for rate limiting (429 responses)
  2. Verify all application instances use the same key
  3. Look for network connectivity issues
  4. Monitor for API key rotation events
Symptoms: 403 errors for certain endpointsTroubleshooting:
  1. Verify you’re using the correct endpoint
  2. Check if your account has the required permissions
  3. Contact support for permission questions
  4. Review API documentation for endpoint requirements

Getting Help

Next Steps