Skip to main content

Documentation Index

Fetch the complete documentation index at: https://atp.hypertext.studio/llms.txt

Use this file to discover all available pages before exploring further.

Overview

For clients unable to maintain persistent WebSocket connections, the REST polling endpoint provides an alternative notification retrieval mechanism. This approach supports battery-constrained devices and simplified client implementations.

Fetch Pending Notifications

Endpoint: GET /api/v1/client/notifications
Authentication: Requires Bearer token using user credentials

Query Parameters

ParameterTypeRequiredDescription
statusstringNoFilter by notification state, e.g., “pending” (default: all)
limitintegerNoMaximum notifications to return (default: 50, max: 100)
cursorstringNoPagination cursor from previous response
service_idstringNoFilter by originating service ID
projectstringNoFilter by project identifier
sortstringNoSort order, either “newest” or “oldest” (default: “newest”)

Response

{
  "notifications": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "version": "1.0",
      "timestamp": "2025-05-25T10:30:00Z",
      "deadline": "2025-05-25T11:00:00Z",
      "service": {
        "id": "lovelace-ide",
        "name": "Lovelace IDE",
        "icon": "https://lovelace.dev/icon.png"
      },
      "context": {
        "title": "Deploy to Production?",
        "description": "New version 2.1.0 is ready for deployment to production servers.",
        "project": "backend-api",
        "metadata": {
          "version": "2.1.0",
          "changes": 47,
          "test_coverage": "98.3%"
        }
      },
      "actions": [
        {
          "id": "approve",
          "label": "Approve Deployment",
          "response_type": "simple",
          "flags": ["irreversible"]
        },
        {
          "id": "reject",
          "label": "Reject",
          "response_type": "text",
          "constraints": {
            "placeholder": "Reason for rejection"
          }
        }
      ],
      "status": "delivered"
    },
    // Additional notifications...
  ],
  "pagination": {
    "next_cursor": "cursor_for_next_page",
    "has_more": true,
    "total_count": 156
  }
}
The pagination object contains:
FieldTypeDescription
next_cursorstringCursor to use for fetching the next page
has_morebooleanIndicates if more results are available
total_countintegerTotal count of matching notifications
The pagination mechanism ensures efficient retrieval of large notification sets while maintaining consistent ordering.

Error Responses

Status CodeError CodeDescription
400 Bad RequestINVALID_PARAMETERInvalid query parameter
401 UnauthorizedAUTH_INVALID_TOKENUser token is invalid
429 Too Many RequestsRATE_LIMIT_EXCEEDEDRate limit exceeded

Fetch Single Notification

Endpoint: GET /api/v1/client/notifications/{id}
Authentication: Requires Bearer token using user credentials

Path Parameters

ParameterTypeDescription
idstringThe UUID of the notification to retrieve

Response

Returns a single notification object with the same structure as in the list endpoint.

Error Responses

Status CodeError CodeDescription
401 UnauthorizedAUTH_INVALID_TOKENUser token is invalid
403 ForbiddenNOTIFICATION_ACCESS_DENIEDUser does not have access to this notification
404 Not FoundNOTIFICATION_NOT_FOUNDNotification with specified ID does not exist

Acknowledge Notification

Endpoint: POST /api/v1/client/notifications/{id}/acknowledge
Authentication: Requires Bearer token using user credentials
This endpoint allows clients to acknowledge receipt of a notification, updating its status to acknowledged.

Path Parameters

ParameterTypeDescription
idstringThe UUID of the notification to acknowledge

Response

Status Code: 200 OK
{
  "notification_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "acknowledged",
  "acknowledged_at": "2025-05-25T10:32:15Z"
}

Error Responses

Status CodeError CodeDescription
401 UnauthorizedAUTH_INVALID_TOKENUser token is invalid
403 ForbiddenNOTIFICATION_ACCESS_DENIEDUser does not have access to this notification
404 Not FoundNOTIFICATION_NOT_FOUNDNotification with specified ID does not exist
409 ConflictNOTIFICATION_ALREADY_RESPONDEDNotification has already been responded to

Examples

Fetch Pending Notifications - JavaScript

async function fetchPendingNotifications() {
  try {
    const response = await fetch(
      'https://atp.example.com/api/v1/client/notifications?status=pending&limit=20',
      {
        headers: {
          'Authorization': 'Bearer user_token_xyz789'
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    
    const data = await response.json();
    
    // Process notifications
    for (const notification of data.notifications) {
      displayNotification(notification);
    }
    
    // Store pagination cursor for next request
    if (data.pagination.has_more) {
      sessionStorage.setItem('notifications_cursor', data.pagination.next_cursor);
    }
    
    return data;
  } catch (error) {
    console.error('Error fetching notifications:', error);
    throw error;
  }
}

Fetch Pending Notifications - Python

import requests

def fetch_pending_notifications(token, cursor=None, limit=20):
    url = 'https://atp.example.com/api/v1/client/notifications'
    
    params = {
        'status': 'pending',
        'limit': limit
    }
    
    if cursor:
        params['cursor'] = cursor
    
    headers = {
        'Authorization': f'Bearer {token}'
    }
    
    response = requests.get(url, params=params, headers=headers)
    response.raise_for_status()
    
    data = response.json()
    
    # Process notifications
    for notification in data['notifications']:
        display_notification(notification)
    
    # Return pagination cursor for next request
    next_cursor = None
    if data['pagination']['has_more']:
        next_cursor = data['pagination']['next_cursor']
    
    return data['notifications'], next_cursor

Acknowledge Notification - JavaScript

async function acknowledgeNotification(notificationId) {
  try {
    const response = await fetch(
      `https://atp.example.com/api/v1/client/notifications/${notificationId}/acknowledge`,
      {
        method: 'POST',
        headers: {
          'Authorization': 'Bearer user_token_xyz789',
          'Content-Type': 'application/json'
        }
      }
    );
    
    if (!response.ok) {
      throw new Error(`HTTP error ${response.status}`);
    }
    
    const data = await response.json();
    console.log(`Notification ${notificationId} acknowledged`);
    
    return data;
  } catch (error) {
    console.error('Error acknowledging notification:', error);
    throw error;
  }
}

Polling Strategy

For applications that use REST polling instead of WebSockets, implement an efficient polling strategy to minimize battery consumption and server load:
  1. Adaptive Polling: Adjust polling frequency based on notification activity
  2. Background Polling: Use platform-specific background fetch capabilities for mobile apps
  3. Exponential Backoff: Increase polling interval after periods of inactivity
  4. Priority-Based: Poll more frequently for high-priority projects or services

Example Adaptive Polling Strategy

class AdaptivePoller {
  constructor(options = {}) {
    this.minInterval = options.minInterval || 30000; // 30 seconds
    this.maxInterval = options.maxInterval || 300000; // 5 minutes
    this.scaleFactor = options.scaleFactor || 1.5;
    this.currentInterval = this.minInterval;
    this.timer = null;
    this.lastNotificationCount = 0;
  }
  
  start(callback) {
    this.stop();
    
    const poll = async () => {
      try {
        const result = await callback();
        
        // Adjust polling interval based on activity
        if (result.notifications.length > 0) {
          // Activity detected, decrease interval
          this.currentInterval = this.minInterval;
          this.lastNotificationCount = result.notifications.length;
        } else if (this.lastNotificationCount === 0) {
          // No recent activity, increase interval
          this.currentInterval = Math.min(
            this.currentInterval * this.scaleFactor,
            this.maxInterval
          );
        } else {
          // Had notifications before but none now, reset counter
          this.lastNotificationCount = 0;
        }
      } catch (error) {
        console.error('Polling error:', error);
        // Increase interval on error
        this.currentInterval = Math.min(
          this.currentInterval * this.scaleFactor,
          this.maxInterval
        );
      }
      
      // Schedule next poll
      this.timer = setTimeout(poll, this.currentInterval);
    };
    
    // Start polling
    poll();
  }
  
  stop() {
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
  }
}

// Usage
const poller = new AdaptivePoller();
poller.start(fetchPendingNotifications);

Best Practices

  1. Use WebSockets When Possible: Prefer WebSocket connections for real-time updates when available
  2. Efficient Polling: Implement adaptive polling to reduce server load and battery consumption
  3. Use Pagination: Always handle pagination correctly to retrieve all notifications
  4. Cache Results: Cache notification data to reduce redundant API calls
  5. Batch Operations: Use the bulk acknowledge endpoint for marking multiple notifications
  6. Error Handling: Implement proper error handling and retries for network failures