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
This endpoint processes user decisions and forwards them to the originating AI service. The required payload structure varies based on the action’s response_type as defined in the notification.
Request
Endpoint: POST /api/v1/client/respond
Authentication: Requires Bearer token using user credentials
Request Body
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "approve",
"response_data": null
}
| Field | Type | Required | Description |
|---|
notification_id | string | Yes | UUID of the notification being answered |
action_id | string | Yes | Selected action identifier from the notification |
response_data | any | Conditional | Required for all response types except "simple" |
The response_data field must conform to the requirements of the action’s response_type. For details on the format for each response type, see the Response Types documentation.
Response
Success Response
Status Code: 200 OK
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "approve",
"status": "responded",
"responded_at": "2025-05-25T10:35:12Z"
}
| Field | Type | Description |
|---|
notification_id | string | UUID of the notification that was answered |
action_id | string | Identifier of the selected action |
status | string | Updated notification status, typically “responded” |
responded_at | datetime | Timestamp when the response was recorded |
Error Responses
| Status Code | Error Code | Description |
|---|
400 Bad Request | MISSING_REQUIRED_FIELD | Required field is missing from request |
400 Bad Request | INVALID_ACTION_ID | The specified action_id doesn’t exist for this notification |
400 Bad Request | INVALID_RESPONSE_DATA | Response data doesn’t match expected format |
401 Unauthorized | AUTH_INVALID_TOKEN | User token is invalid |
403 Forbidden | NOTIFICATION_ACCESS_DENIED | User does not have access to this notification |
404 Not Found | NOTIFICATION_NOT_FOUND | Notification with specified ID does not exist |
409 Conflict | NOTIFICATION_EXPIRED | Notification deadline has passed |
409 Conflict | NOTIFICATION_INVALIDATED | Service marked notification as invalid |
409 Conflict | NOTIFICATION_ALREADY_RESPONDED | Notification has already been answered |
422 Unprocessable Entity | CONSTRAINT_VIOLATION | Response violates defined constraints |
Response Type Examples
Here are examples of valid request bodies for each response type:
Simple Action
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "approve",
"response_data": null
}
Binary Choice
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "include_logs",
"response_data": true
}
Single Choice
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "select_action",
"response_data": "option1"
}
Multiple Choice
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "select_recipients",
"response_data": ["engineering", "security"]
}
Text Input
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "feedback",
"response_data": "The suggestion looks good overall, but we should consider the impact on mobile users."
}
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "set_threshold",
"response_data": 0.75
}
Scale/Range
{
"notification_id": "550e8400-e29b-41d4-a716-446655440000",
"action_id": "confidence_rating",
"response_data": 4
}
Examples
JavaScript Example
async function submitResponse(notificationId, actionId, responseData) {
try {
const response = await fetch(
'https://atp.example.com/api/v1/client/respond',
{
method: 'POST',
headers: {
'Authorization': 'Bearer user_token_xyz789',
'Content-Type': 'application/json'
},
body: JSON.stringify({
notification_id: notificationId,
action_id: actionId,
response_data: responseData
})
}
);
if (!response.ok) {
const errorData = await response.json();
throw new Error(`Error ${response.status}: ${errorData.message}`);
}
const data = await response.json();
console.log(`Response submitted successfully: ${data.status}`);
return data;
} catch (error) {
console.error('Error submitting response:', error);
throw error;
}
}
// Usage examples for different response types
submitResponse('550e8400-e29b-41d4-a716-446655440000', 'approve', null);
submitResponse('550e8400-e29b-41d4-a716-446655440000', 'include_logs', true);
submitResponse('550e8400-e29b-41d4-a716-446655440000', 'select_action', 'option1');
submitResponse('550e8400-e29b-41d4-a716-446655440000', 'feedback', 'Looks good!');
Python Example
import requests
def submit_response(token, notification_id, action_id, response_data=None):
url = 'https://atp.example.com/api/v1/client/respond'
payload = {
'notification_id': notification_id,
'action_id': action_id
}
# Only include response_data if it's not None
if response_data is not None:
payload['response_data'] = response_data
headers = {
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json'
}
try:
response = requests.post(url, json=payload, headers=headers)
response.raise_for_status()
data = response.json()
print(f"Response submitted successfully: {data['status']}")
return data
except requests.exceptions.HTTPError as e:
error_data = e.response.json()
print(f"Error {e.response.status_code}: {error_data['message']}")
raise
# Usage examples for different response types
submit_response('user_token_xyz789', '550e8400-e29b-41d4-a716-446655440000', 'approve')
submit_response('user_token_xyz789', '550e8400-e29b-41d4-a716-446655440000', 'include_logs', True)
submit_response('user_token_xyz789', '550e8400-e29b-41d4-a716-446655440000', 'select_action', 'option1')
submit_response('user_token_xyz789', '550e8400-e29b-41d4-a716-446655440000', 'feedback', 'Looks good!')
Error Handling
When submitting responses, it’s important to handle errors gracefully. Here’s a more comprehensive error handling approach:
async function submitResponseWithRetry(notificationId, actionId, responseData) {
const MAX_RETRIES = 3;
let attempt = 0;
while (attempt <= MAX_RETRIES) {
try {
const response = await fetch(
'https://atp.example.com/api/v1/client/respond',
{
method: 'POST',
headers: {
'Authorization': 'Bearer user_token_xyz789',
'Content-Type': 'application/json'
},
body: JSON.stringify({
notification_id: notificationId,
action_id: actionId,
response_data: responseData
})
}
);
if (response.ok) {
return await response.json();
}
const errorData = await response.json();
// Handle specific error cases
switch (errorData.code) {
case 'NOTIFICATION_EXPIRED':
case 'NOTIFICATION_INVALIDATED':
case 'NOTIFICATION_ALREADY_RESPONDED':
// Terminal state, don't retry
throw new Error(`${errorData.code}: ${errorData.message}`);
case 'INVALID_RESPONSE_DATA':
case 'CONSTRAINT_VIOLATION':
// Client error, don't retry
throw new Error(`${errorData.code}: ${errorData.message}`);
case 'RATE_LIMIT_EXCEEDED':
// Rate limiting, retry with backoff
const retryAfter = response.headers.get('Retry-After');
const delayMs = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delayMs));
attempt++;
continue;
}
// Server errors (5xx) are retryable
if (response.status >= 500) {
const delayMs = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delayMs));
attempt++;
continue;
}
// Other errors are considered permanent
throw new Error(`${errorData.code}: ${errorData.message}`);
} catch (error) {
// Network errors are retryable
if (error.name === 'TypeError' && attempt < MAX_RETRIES) {
const delayMs = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delayMs));
attempt++;
continue;
}
throw error;
}
}
// If we've exhausted retries
throw new Error('Maximum retry attempts reached');
}
Best Practices
- Validate Response Data: Verify that response data matches the expected format before submitting
- Handle Terminal States: Gracefully handle expired or invalidated notifications
- Implement Retries: Use exponential backoff for retrying transient failures
- Offline Support: Queue responses locally when offline and submit when connectivity is restored
- User Feedback: Provide immediate feedback to users while the response is being processed
- Security: Never log or expose sensitive response data