Campaign Transmission Webhook

The Campaign Transmission Webhook is an endpoint that will be implemented on the integrating aggregator side. This endpoint is where Optitext will send SMS campaigns, after orchestration, to the aggregator at which point responsibility of transmitting the campaigns falls on the aggregator.

Overview

This document is intended for third-party developers building APIs that will receive requests from the OptitextAPI AggregatorService into their Campaign Transmission Webhook. The AggregatorService is a messaging client that forwards campaign message data to external aggregator Campaign Transmission Webhook for SMS/messaging delivery.

Request Format

HTTP Method and Headers

Optitext API will send POST requests to your endpoint with the following headers:

POST /your-endpoint-url
Content-Type: application/json
X-API-Key: {your-provided-api-key}
x-hub-signature: {hmac-signature}
User-Agent: {system-user-agent}

Request Body Structure

The request body contains a JSON payload with the following structure:

{
  "batchId": "string",
  "metadata": {
	  "appId": "int",
	  "brandId": "string",
	  "campaignId": "string",
    "campaignType": "int",
 	  "channelId" :"int",
	  "engagementId": "string",
    "isHashed": "boolean",
    "scheduledTime": "long",
	  "tenantId": "int"
  },
  "recipients": [
    {
      "message": "string"
      "mobileNumber": "string",
      "customerId": "string"
    }
  ],
}

Field Descriptions

FieldTypeRequiredDescription
batchIdstringOptionalUnique identifier for the message batch
metadata.appIdint
metadata.campaignIdstringOptionalCampaign identifier
metadata.campaignTypeint
metadata.channelIdint
metadata.engagementIdstringOptionalUnique identifier for the customer engagement
metadata.isHashedbool
metadata.scheduledTimenumberYesUnix timestamp (milliseconds) for when the message should be sent
metadata.tenantIdint
recipientsarrayOptionalArray of message recipients
recipients[].messagestringOptionalThe message content to send
recipients[].mobileNumberstringOptionalRecipient's mobile phone number
recipients[].customerIdstringOptionalUnique customer identifier

Sample Request

{
  "batchId": "batch-123",
  "metadata": {
    "appId": 123,
    "brandId": "betcash",
    "campaignId": "232522",
    "campaignType": 1,
    "channelId": 493,
    "engagementId": "aaabbbccc",
    "isHashed": false,
    "scheduledTime": 1704106200000,
    "tenantId": 1
  },
  "recipients": [
    {
      "message": "Hello! Your order is ready for pickup.",
      "mobileNumber": "+1234567890",
      "customerId": "customer-001"
    },
    {
      "message": "Hello! Your order is ready for pickup.",
      "mobileNumber": "+1234567891",
      "customerId": "customer-002"
    }
  ]
}

Authentication

API Key Authentication

Each request includes an X-API-Key header containing your unique API key. Validate this key on every request to ensure authenticity.

HMAC Signature Verification

All requests include an x-hub-signature header containing an HMAC signature for request validation. This signature is critical for security and must be verified.

Signature Format

The signature follows the format: {algorithm}={hash}

Examples:

  • sha256=a1b2c3d4e5f6...
  • sha1=f6e5d4c3b2a1...
  • sha512=1a2b3c4d5e6f...

Signature Generation Process

  1. The entire JSON request body is used as the payload
  2. HMAC is computed using your shared secret key
  3. The hash is converted to lowercase hexadecimal
  4. The algorithm prefix is added

Verification Steps

  1. Extract the algorithm and hash from the x-hub-signature header
  2. Recompute the HMAC using the request body and your secret key
  3. Compare the computed hash with the received hash
  4. Important: Use a constant-time comparison to prevent timing attacks

Supported Algorithms

AlgorithmHash LengthUse Case
SHA25664 charactersDefault, recommended
SHA140 charactersLegacy support
SHA512128 charactersEnhanced security

Sample Verification (Python)

import hmac
import hashlib

def verify_signature(payload, signature_header, secret_key):
    """Verify HMAC signature from AggregatorService"""

    if not signature_header or '=' not in signature_header:
        return False

    algorithm, received_hash = signature_header.split('=', 1)

    # Compute HMAC
    if algorithm == 'sha256':
        computed_hmac = [hmac.new](http://hmac.new)(
            secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha256
        )
    elif algorithm == 'sha1':
        computed_hmac = [hmac.new](http://hmac.new)(
            secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha1
        )
    elif algorithm == 'sha512':
        computed_hmac = [hmac.new](http://hmac.new)(
            secret_key.encode('utf-8'),
            payload.encode('utf-8'),
            hashlib.sha512
        )
    else:
        return False

    computed_hash = computed_hmac.hexdigest().lower()

    # Constant-time comparison
    return [hmac.compare](http://hmac.compare)_digest(computed_hash, received_hash)

Response Requirements

Success Responses

Return any 2xx HTTP status code to indicate successful processing:

  • 200 OK - Standard success response

Response Body (Optional)

You may optionally return a JSON response body, but it's not required for successful processing:

{
  "message": "Message processed successfully",
  "processedAt": "2024-01-01T12:30:00Z",
  "batchId": "batch-123"
}

Response Headers

No specific response headers are required, but standard headers are recommended:

HTTP/1.1 200 OK
Content-Type: application/json
Date: Mon, 01 Jan 2024 12:30:00 GMT

Error Handling

Retryable Errors

The AggregatorService will retry requests for the following HTTP status codes:

Status CodeUse CaseRetry Behaviour
429 Too Many RequestsRate limit exceeded, should retry with backoffWill retry
500 Internal Server ErrorServer internal error, temporary issueWill retry
503 Service UnavailableService temporarily unavailableWill retry

Note: Network connectivity issues (HttpRequestException) and request timeouts (TaskCanceledException) will also trigger retries through the Google Cloud Functions retry mechanism.

Non-Retryable Errors (Client Errors)

Return appropriate 4xx status codes for client errors. These will NOT be retried:

Status CodeUse CaseRetry Behaviour
400 Bad RequestInvalid request format or parametersNo retry
401 UnauthorizedAuthentication failed or missing credentialsNo retry
403 ForbiddenAccess denied, insufficient permissionsNo retry
404 Not FoundEndpoint or resource not foundNo retry
405 Method Not AllowedHTTP method not supportedNo retry
406 Not AcceptableRequest format not acceptableNo retry
409 ConflictRequest conflicts with current state (e.g., unique constraints for referential integrity)No retry
410 GoneResource no longer availableNo retry
422 Unprocessable EntityRequest validation failed or business logic errorNo retry

Important: All other non-2xx status codes not explicitly listed as retryable will be treated as non-retryable errors and will cause the campaign to abort.

Error Response Body

For error responses, include a descriptive error message:

{
  "error": "Invalid message format",
  "message": "The 'recipients' field is required",
  "code": "MISSING_RECIPIENTS"
}

Security Considerations

HMAC Signature Validation

  • Always verify the HMAC signature before processing requests
  • Use constant-time comparison to prevent timing attacks
  • Reject requests with invalid or missing signatures
  • Store your HMAC secret key securely (environment variables, key management systems)

API Key Security

  • Validate the API key on every request
  • Use secure key storage mechanisms
  • Implement rate limiting based on API key
  • Log authentication failures for monitoring

Network Security

  • Use HTTPS endpoints only
  • Implement appropriate firewall rules
  • Consider IP allowlisting if possible
  • Monitor for suspicious traffic patterns

Retry Behaviour

AggregatorService Retry Logic

The AggregatorService implements the following retry behaviour based on HTTP status codes and exception types:

Retryable Conditions

Requests will be retried for:

  • HTTP 429 Too Many Requests (rate limit exceeded)
  • HTTP 500 Internal Server Error (temporary server issue)
  • HTTP 503 Service Unavailable (temporary service outage)
  • Network connectivity issues (HttpRequestException)
  • Request timeouts (TaskCanceledException)

Non-Retryable Conditions

Requests will NOT be retried for:

  • HTTP 400 Bad Request (invalid payload or parameters)
  • HTTP 401 Unauthorized (authentication failed)
  • HTTP 403 Forbidden (access denied)
  • HTTP 404 Not Found (endpoint or resource not found)
  • HTTP 405 Method Not Allowed (HTTP method not supported)
  • HTTP 406 Not Acceptable (request format not acceptable)
  • HTTP 409 Conflict (request conflicts with current state)
  • HTTP 410 Gone (resource no longer available)
  • HTTP 422 Unprocessable Entity (business logic errors)
  • All other non-2xx status codes not explicitly listed as retryable

Retry Configuration

  • Maximum retries: Handled by Google Cloud Functions (typically 3 attempts)
  • Retry interval: Exponential backoff (~10s, 20s, 30s+)
  • Dead letter handling: Failed messages go to a dead letter queue after max attempts
  • Timeout: Requests may timeout and be retried

Recommendations for Your API

  • Implement idempotency using batchId or engagementId to handle duplicate requests
  • Use circuit breakers to prevent cascading failures
  • Implement graceful degradation for partial service outages
  • Return appropriate HTTP status codes to control retry behaviour

Testing and Validation

Webhook Testing

You can test your endpoint using the provided test utilities:

  1. Signature Generation Script: Use scripts/signature/generate_[signature.py](http://signature.py) to create test signatures
  2. Mock Service: Reference scripts/mock-service/ for testing examples

Test Scenarios

Implement test cases for:

  1. Valid Request Processing
    • Proper JSON structure
    • Valid HMAC signature
    • Correct API key
  2. Authentication Failures
    • Invalid API key (return 401/403)
    • Missing/invalid HMAC signature (return 401/403)
  3. Payload Validation
    • Missing required fields (return 400)
    • Invalid data types (return 400)
    • Business logic errors (return 422)
  4. Error Conditions
    • Internal server errors (return 5xx)
    • Service unavailable (return 503)
  5. Edge Cases
    • Empty recipients array
    • Very large message payloads
    • Special characters in message content

Sample Test Request

curl -X POST https://your-endpoint.com/webhook \
  -H "Content-Type: application/json" \
  -H "X-API-Key: your-api-key" \
  -H "x-hub-signature: sha256=a1b2c3d4..." \
  -d '{
    "batchId": "test-batch-123",
    "engagementId": "test-engagement-456",
    "metadata": {
      "campaignId": "test-campaign",
      "numberOfCustomers": 1,
      "numberOfDroppedCustomers": 0,
      "region": "US",
      "senderId": "test-sender"
    },
    "recipients": [{
      "content": {"message": "Test message"},
      "mobileNumber": "+1234567890",
      "customerId": "test-customer"
    }],
    "scheduledTime": 1704106200000
  }'

Configuration Requirements

When registering your endpoint with OptitextAPI, provide:

  1. Endpoint URL: Your HTTPS webhook URL
  2. API Key: Unique key for request authentication
  3. HMAC Secret: Shared secret for signature verification
  4. HMAC Algorithm: Preferred algorithm (sha256 recommended)
  5. Sender ID: Your unique sender identifier

Support and Troubleshooting

Common Issues

  1. Signature Verification Failures
    • Ensure you're using the raw request body for HMAC computation
    • Verify the algorithm matches (sha256, sha1, sha512)
    • Use constant-time comparison for security
  2. Authentication Errors
    • Validate API key format and storage
    • Check for typos in header names (X-API-Key, x-hub-signature)
  3. Retry Loops
    • Return 2xx status codes for successful processing
    • Use 4xx codes to prevent retries for permanent failures
    • Implement idempotency to handle duplicate requests

Monitoring Recommendations

  • Log all incoming requests with relevant metadata
  • Monitor signature verification success rates
  • Track response times and error rates
  • Alert on unusual traffic patterns or authentication failures

For additional support or questions about this integration, please refer to the OptitextAPI documentation or contact the development team.