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.
Creating ATP Notifications
After registering your service, the next step is to create and send notifications. ATP provides a flexible notification system that supports various levels of complexity, from simple yes/no prompts to rich, structured data collection.
Notification Anatomy
An ATP notification consists of several key components:
Basic Information - Title, description, and priority
Actions - Possible user responses with associated response types
Metadata - Additional context for your application
Expiration - Optional timeout for time-sensitive notifications
Here’s a visual representation of a notification’s structure:
Basic Notifications
Let’s start with a simple notification that requires a basic yes/no response:
Python
from atp import ATPClient
client = ATPClient( api_key = "your_api_key" , service_id = "your_service_id" )
response = client.send_notification({
"title" : "Approve File Deletion" ,
"description" : "AI assistant wants to delete 15 temporary files to free up 250MB of space" ,
"priority" : "normal" ,
"actions" : [
{ "id" : "approve" , "label" : "Approve" , "response_type" : "simple" },
{ "id" : "reject" , "label" : "Reject" , "response_type" : "simple" }
]
})
notification_id = response[ "notification_id" ]
print ( f "Notification sent with ID: { notification_id } " )
JavaScript/Node.js
import { ATPClient } from '@atp/client' ;
const client = new ATPClient ({
apiKey: 'your_api_key' ,
serviceId: 'your_service_id'
});
async function sendBasicNotification () {
try {
const response = await client . sendNotification ({
title: 'Approve File Deletion' ,
description: 'AI assistant wants to delete 15 temporary files to free up 250MB of space' ,
priority: 'normal' ,
actions: [
{ id: 'approve' , label: 'Approve' , responseType: 'simple' },
{ id: 'reject' , label: 'Reject' , responseType: 'simple' }
]
});
const notificationId = response . notification_id ;
console . log ( `Notification sent with ID: ${ notificationId } ` );
return notificationId ;
} catch ( error ) {
console . error ( 'Failed to send notification:' , error );
}
}
Rich Notifications
ATP supports rich response types that allow collecting structured data from users:
Text Input
Collect free-form text from users:
# Python example
client.send_notification({
"title" : "Name the new project" ,
"description" : "Please provide a name for the new project you're creating" ,
"actions" : [
{
"id" : "submit_name" ,
"label" : "Submit" ,
"response_type" : "text" ,
"response_options" : {
"placeholder" : "Enter project name" ,
"max_length" : 50 ,
"min_length" : 3
}
},
{
"id" : "cancel" ,
"label" : "Cancel" ,
"response_type" : "simple"
}
]
})
Multiple Choice
Offer users predefined options to choose from:
# Python example
client.send_notification({
"title" : "Select deployment environment" ,
"description" : "Which environment should we deploy the latest changes to?" ,
"actions" : [
{
"id" : "deploy" ,
"label" : "Deploy" ,
"response_type" : "select" ,
"response_options" : {
"options" : [
{ "value" : "dev" , "label" : "Development" },
{ "value" : "staging" , "label" : "Staging" },
{ "value" : "production" , "label" : "Production" }
],
"allow_multiple" : False ,
"required" : True
}
},
{
"id" : "cancel" ,
"label" : "Cancel" ,
"response_type" : "simple"
}
]
})
Collect structured data with multiple fields:
# Python example
client.send_notification({
"title" : "Update User Profile" ,
"description" : "Please review and update your profile information" ,
"actions" : [
{
"id" : "update_profile" ,
"label" : "Update" ,
"response_type" : "form" ,
"response_options" : {
"fields" : [
{
"id" : "display_name" ,
"label" : "Display Name" ,
"type" : "text" ,
"required" : True ,
"default" : "Current Name"
},
{
"id" : "bio" ,
"label" : "Bio" ,
"type" : "textarea" ,
"max_length" : 500
},
{
"id" : "newsletter" ,
"label" : "Subscribe to newsletter" ,
"type" : "boolean" ,
"default" : False
}
]
}
},
{
"id" : "cancel" ,
"label" : "Cancel" ,
"response_type" : "simple"
}
]
})
JSON Schema
For complex data collection with validation, use JSON Schema:
# Python example
client.send_notification({
"title" : "Configure API Settings" ,
"description" : "Please review and update the API configuration" ,
"actions" : [
{
"id" : "update_config" ,
"label" : "Update" ,
"response_type" : "json" ,
"response_schema" : {
"type" : "object" ,
"properties" : {
"timeout_ms" : {
"type" : "integer" ,
"minimum" : 1000 ,
"maximum" : 60000
},
"retry" : {
"type" : "object" ,
"properties" : {
"enabled" : { "type" : "boolean" },
"max_attempts" : {
"type" : "integer" ,
"minimum" : 1 ,
"maximum" : 10
},
"backoff_factor" : {
"type" : "number" ,
"minimum" : 1.0 ,
"maximum" : 5.0
}
},
"required" : [ "enabled" , "max_attempts" ]
},
"environment" : {
"type" : "string" ,
"enum" : [ "development" , "staging" , "production" ]
}
},
"required" : [ "timeout_ms" , "environment" ]
}
},
{
"id" : "cancel" ,
"label" : "Cancel" ,
"response_type" : "simple"
}
]
})
Action Types
ATP supports different action types that determine what happens when a user responds:
Simple Actions
Simple actions require only a single click with no additional data:
# Python example
{
"id" : "approve" ,
"label" : "Approve" ,
"response_type" : "simple"
}
Data Collection Actions
These actions require additional information from the user:
# Python example
{
"id" : "provide_feedback" ,
"label" : "Submit Feedback" ,
"response_type" : "text" ,
"response_options" : {
"placeholder" : "Enter your feedback..." ,
"multiline" : True ,
"max_length" : 1000
}
}
Multi-step Actions
For more complex interactions, you can chain notifications based on initial responses:
# Python example for the first step
first_notification = client.send_notification({
"title" : "Review Generated Content" ,
"description" : "Please review the AI-generated blog post" ,
"actions" : [
{
"id" : "approve" ,
"label" : "Approve" ,
"response_type" : "simple"
},
{
"id" : "needs_revision" ,
"label" : "Needs Revision" ,
"response_type" : "simple"
}
],
"metadata" : {
"content_id" : "blog_post_123"
}
})
# In your webhook handler, when receiving a "needs_revision" response:
def handle_webhook ( payload ):
if payload[ "action_id" ] == "needs_revision" :
# Send a follow-up notification to collect revision details
client.send_notification({
"title" : "Specify Revisions Needed" ,
"description" : "Please provide details about the revisions needed" ,
"actions" : [
{
"id" : "submit_revisions" ,
"label" : "Submit" ,
"response_type" : "form" ,
"response_options" : {
"fields" : [
{
"id" : "revision_type" ,
"label" : "Type of Revision" ,
"type" : "select" ,
"options" : [
{ "value" : "content" , "label" : "Content Issues" },
{ "value" : "style" , "label" : "Style/Tone Issues" },
{ "value" : "factual" , "label" : "Factual Errors" },
{ "value" : "other" , "label" : "Other Issues" }
],
"allow_multiple" : True
},
{
"id" : "details" ,
"label" : "Revision Details" ,
"type" : "textarea" ,
"required" : True
}
]
}
}
],
"metadata" : {
"content_id" : payload[ "metadata" ][ "content_id" ],
"original_notification_id" : payload[ "notification_id" ]
}
})
Response Types Reference
ATP supports several response types to collect different kinds of data:
Type Description Response Data simpleBasic acknowledgment No additional data textFree-form text input String value selectChoose from options Selected value(s) formStructured data with multiple fields Object with field values jsonComplex structured data validated against JSON schema JSON object fileFile upload File metadata and content
Simple Response Type
{
"id" : "confirm" ,
"label" : "Confirm" ,
"response_type" : "simple"
}
Text Response Type
{
"id" : "provide_name" ,
"label" : "Submit" ,
"response_type" : "text" ,
"response_options" : {
"placeholder" : "Enter your name" ,
"multiline" : False ,
"max_length" : 100 ,
"min_length" : 2 ,
"required" : True
}
}
Select Response Type
{
"id" : "choose_option" ,
"label" : "Select" ,
"response_type" : "select" ,
"response_options" : {
"options" : [
{ "value" : "option1" , "label" : "Option 1" },
{ "value" : "option2" , "label" : "Option 2" },
{ "value" : "option3" , "label" : "Option 3" }
],
"allow_multiple" : False ,
"required" : True
}
}
{
"id" : "submit_form" ,
"label" : "Submit" ,
"response_type" : "form" ,
"response_options" : {
"fields" : [
{
"id" : "name" ,
"label" : "Name" ,
"type" : "text" ,
"required" : True
},
{
"id" : "age" ,
"label" : "Age" ,
"type" : "number" ,
"min" : 18 ,
"max" : 120
},
{
"id" : "interests" ,
"label" : "Interests" ,
"type" : "select" ,
"options" : [
{ "value" : "tech" , "label" : "Technology" },
{ "value" : "sports" , "label" : "Sports" },
{ "value" : "arts" , "label" : "Arts" }
],
"allow_multiple" : True
}
]
}
}
JSON Response Type
{
"id" : "submit_config" ,
"label" : "Submit" ,
"response_type" : "json" ,
"response_schema" : {
"type" : "object" ,
"properties" : {
"name" : { "type" : "string" },
"settings" : {
"type" : "object" ,
"properties" : {
"enabled" : { "type" : "boolean" },
"threshold" : { "type" : "number" }
}
},
"tags" : {
"type" : "array" ,
"items" : { "type" : "string" }
}
},
"required" : [ "name" , "settings" ]
}
}
Notification Constraints
When creating notifications, be aware of these constraints:
Limits
Title : Maximum 100 characters
Description : Maximum 1000 characters
Actions : Between 1 and 5 actions per notification
Action Labels : Maximum 50 characters
Priority Levels : “low”, “normal”, “high”, or “urgent”
Best Practices
Keep notifications concise - Use clear, direct language
Provide sufficient context - Ensure users understand why they’re being asked to respond
Limit the number of actions - Fewer choices lead to faster decisions
Use appropriate priority levels - Reserve “high” and “urgent” for time-sensitive notifications
Include helpful metadata - Store relevant context for later processing
Example: Well-designed Notification
# Python example of a well-designed notification
client.send_notification({
"title" : "Approve payment of $156.78 to Acme Corp" ,
"description" : "The AI assistant has prepared a payment of $156.78 to Acme Corp for April consulting services (Invoice #AC-2023-042)" ,
"priority" : "high" ,
"actions" : [
{
"id" : "approve" ,
"label" : "Approve Payment" ,
"response_type" : "simple"
},
{
"id" : "reject" ,
"label" : "Reject" ,
"response_type" : "text" ,
"response_options" : {
"placeholder" : "Reason for rejection (optional)" ,
"required" : False
}
},
{
"id" : "modify" ,
"label" : "Modify Amount" ,
"response_type" : "form" ,
"response_options" : {
"fields" : [
{
"id" : "amount" ,
"label" : "Payment Amount" ,
"type" : "number" ,
"required" : True ,
"default" : 156.78 ,
"min" : 0.01
},
{
"id" : "reason" ,
"label" : "Reason for change" ,
"type" : "text" ,
"required" : True
}
]
}
}
],
"expiration" : {
"expires_in" : 86400 # 24 hours in seconds
},
"metadata" : {
"invoice_id" : "AC-2023-042" ,
"vendor_id" : "ACME-001" ,
"payment_method" : "bank_transfer" ,
"department" : "operations"
}
})
Metadata allows you to include additional context with your notifications. This data will be returned with the response, helping you correlate responses with the original context:
# Python example with useful metadata
client.send_notification({
"title" : "Review content for publishing" ,
"description" : "Please review this AI-generated blog post before publishing" ,
"actions" : [
{ "id" : "approve" , "label" : "Approve" , "response_type" : "simple" },
{ "id" : "reject" , "label" : "Reject" , "response_type" : "simple" }
],
"metadata" : {
"content_id" : "post_12345" ,
"content_type" : "blog_post" ,
"author" : "ai_content_generator" ,
"generated_at" : "2023-04-15T10:30:00Z" ,
"word_count" : 750 ,
"topic" : "machine_learning" ,
"target_publication_date" : "2023-04-17"
}
})
The metadata will be included in the webhook response, allowing your system to process the response in context:
{
"notification_id" : "ntf_1Ab2Cd3Ef4" ,
"service_id" : "srv_9Xy8Wv7Ut6" ,
"action_id" : "approve" ,
"response_data" : null ,
"response_time" : "2023-04-15T14:22:10Z" ,
"metadata" : {
"content_id" : "post_12345" ,
"content_type" : "blog_post" ,
"author" : "ai_content_generator" ,
"generated_at" : "2023-04-15T10:30:00Z" ,
"word_count" : 750 ,
"topic" : "machine_learning" ,
"target_publication_date" : "2023-04-17"
}
}
Notification Expiration
For time-sensitive notifications, you can set an expiration time:
# Python example with expiration
client.send_notification({
"title" : "Approve urgent security patch deployment" ,
"description" : "Security patch for critical vulnerability CVE-2023-1234 needs approval" ,
"priority" : "urgent" ,
"actions" : [
{ "id" : "approve" , "label" : "Deploy Now" , "response_type" : "simple" },
{ "id" : "schedule" , "label" : "Schedule" , "response_type" : "select" ,
"response_options" : {
"options" : [
{ "value" : "1h" , "label" : "In 1 hour" },
{ "value" : "4h" , "label" : "In 4 hours" },
{ "value" : "8h" , "label" : "In 8 hours" }
]
}}
],
"expiration" : {
"expires_in" : 3600 # 1 hour in seconds
},
"metadata" : {
"vulnerability_id" : "CVE-2023-1234" ,
"severity" : "critical" ,
"systems_affected" : 12
}
})
When a notification expires:
It will no longer be displayed to users
Any pending responses will be rejected
You can optionally receive a webhook notification of the expiration
Testing Your Notifications
Before sending notifications to real users, it’s a good practice to test them thoroughly:
Using the Test Environment
# Python example for testing
from atp import ATPClient
# Use test credentials for development
test_client = ATPClient(
api_key = "sk_test_your_test_key" ,
service_id = "test_service_id"
)
# Send a test notification
test_response = test_client.send_notification({
"title" : "Test Notification" ,
"description" : "This is a test notification" ,
"actions" : [
{ "id" : "test_action" , "label" : "Test Action" , "response_type" : "simple" }
],
"metadata" : {
"is_test" : True
}
})
print ( f "Test notification sent with ID: { test_response[ 'notification_id' ] } " )
Simulating Responses
The ATP SDK provides test utilities for simulating user responses:
from atp.testing import TestClient
# Create a test client
test_client = TestClient()
# Simulate a user response
test_client.respond_to(notification_id, "test_action" )
# For actions with response data
test_client.respond_to(
notification_id,
"provide_feedback" ,
response_data = "This is test feedback"
)
Notification Design Best Practices
To create effective notifications that respect user attention:
Be clear and specific - Provide enough context for informed decisions
Use appropriate priority - Don’t overuse high priority
Group related notifications - Avoid notification fatigue
Respect privacy - Don’t include sensitive information in titles/descriptions
Set reasonable expirations - Match expiration time to urgency
Provide actionable options - Make action labels clear and specific
Include fallback options - Add “Cancel” or “Later” options when appropriate
Poor vs. Good Examples
❌ Poor Notification
client.send_notification({
"title" : "Approval needed" ,
"description" : "Please approve this action" ,
"actions" : [
{ "id" : "y" , "label" : "Yes" , "response_type" : "simple" },
{ "id" : "n" , "label" : "No" , "response_type" : "simple" }
]
})
✅ Good Notification
client.send_notification({
"title" : "Approve $530 expense report for Q2 client meeting" ,
"description" : "Expense report #ER-2023-089 includes: Hotel ($350), Meals ($120), Transportation ($60). All receipts verified." ,
"priority" : "normal" ,
"actions" : [
{ "id" : "approve" , "label" : "Approve Expense" , "response_type" : "simple" },
{ "id" : "reject" , "label" : "Reject" , "response_type" : "text" ,
"response_options" : { "placeholder" : "Reason for rejection" , "required" : true}},
{ "id" : "info" , "label" : "Request More Information" , "response_type" : "text" ,
"response_options" : { "placeholder" : "What additional information do you need?" , "required" : true}}
],
"metadata" : {
"expense_id" : "ER-2023-089" ,
"employee_id" : "EMP-456" ,
"department" : "sales" ,
"report_date" : "2023-04-10"
}
})
Verification: Knowledge Check
Before proceeding, let’s verify your understanding of notification creation:
If you understand these concepts, you’re ready to start creating effective notifications for your users.
Next Steps
Now that you know how to create notifications, the next step is learning how to process the responses you receive from users.
Processing Responses Learn how to handle and process user responses to your notifications