Documentation
Get from signup to first email in under 15 minutes.
Quick start
1. Create an account at app.aitarax.com
2. Create an organisation and a brand
3. Configure your email settings (sector, style, CTA)
4. Create an API key from Settings → API keys
5. Send your first event
Authentication
All API requests require an API key passed in the X-API-Key header.
curl -X POST https://app.aitarax.com/api/v1/event/booking \
-H "Content-Type: application/json" \
-H "X-API-Key: atx_your_api_key_here" \
-d '{...}'Test events
Add "is_test": true to any event to mark it as a test. Test events are stored and visible in your dashboard but are never AI-processed, never billed, and are automatically deleted after 24 hours.
POST /api/v1/event/booking
{
"identifier": "TEST-001",
"start_at": "2026-04-15T10:00:00Z",
"status": "completed",
"is_test": true,
"customer": {
"email": "test@example.com",
"name": "Test Customer"
}
}Tip: Use test events to verify your integration before going live. Any email address containing @example.com is automatically flagged as a test event.
Booking event
Send a booking event when an appointment is created, updated, or completed.
POST /api/v1/event/booking
{
"identifier": "APT-2026-001",
"start_at": "2026-04-15T10:00:00Z",
"status": "completed",
"status_at": "2026-04-15T11:30:00Z",
"staff": "Sarah",
"customer": {
"email": "emma@example.com",
"name": "Emma de Vries",
"language": "nl",
"timezone": "Europe/Amsterdam"
},
"items": [
{ "name": "Haircut", "quantity": 1 },
{ "name": "Colour treatment", "quantity": 1 }
]
}| Field | Required | Description |
|---|---|---|
identifier | Recommended | Unique ID from your system. Used for duplicate detection and status updates. |
start_at | Required* | When the appointment starts. ISO 8601. Falls back to datetime. |
status | Recommended | Current status: scheduled, completed, cancelled, no-show. |
status_at | Recommended | When the status was set. Used for out-of-order import handling. |
staff | Optional | Staff member name. Included in AI context. |
customer | Required | Customer object. Must include email or identifier. |
items | Optional | Array of services. Included in AI context. |
is_test | Optional | Mark as test event. Auto-deleted after 24 hours. |
Order event
Send an order event when a purchase is placed or its status changes.
POST /api/v1/event/order
{
"identifier": "ORD-2026-1001",
"ordered_at": "2026-04-10T14:00:00Z",
"status": "delivered",
"status_at": "2026-04-12T16:00:00Z",
"customer": {
"email": "bakkerij@example.com",
"name": "Noord Bakkerij BV",
"identifier": "CUST-NB-002",
"identifier_source": "erp"
},
"items": [
{ "name": "Tarwebloem 25kg", "quantity": 40 },
{ "name": "Suiker fijn 25kg", "quantity": 20 }
]
}Customer fields
The customer object is the same across all event types. Customers are upserted on every event — fields are updated if they change.
| Field | Required | Description |
|---|---|---|
email | Required* | Customer email. Used for sending and deduplication. |
name | Recommended | Full name or company name. Used in AI-generated emails. |
date_birth | Optional | Date of birth. ISO 8601 date (e.g. 1990-05-15). Used in AI context. |
phone | Optional | Phone number in E.164 format (e.g. +31612345678). |
language | Optional | ISO 639-1 code (e.g. nl, en, fr). AI generates the email in this language. |
timezone | Optional | IANA timezone (e.g. Europe/Amsterdam). Used for optimal send timing. |
identifier | Optional | External customer ID from your system. Use with identifier_source. |
identifier_source | Optional | System that issued the identifier (e.g. shopify, erp, crm). |
tags | Optional | Array of strings for segmentation (e.g. ["vip", "wholesale"]). |
segment | Optional | Primary segment label (e.g. wholesale_nl). Used in AI context. |
is_subscribed | Optional | Subscription status. Set to false to suppress all emails for this customer. |
url_params | Optional | Custom URL parameters appended to links in emails. Scoped per event type (booking, order). |
Batch overview
Batch endpoints let you send up to 100 records in a single API call. Use them for historical imports, nightly syncs, or any situation where you have multiple records to process at once.
| Endpoint | Batch size | Use case |
|---|---|---|
POST /api/v1/event/booking/batch | 1–100 | Import historical bookings or sync multiple appointments at once. |
POST /api/v1/event/order/batch | 1–100 | Import historical orders or sync multiple purchases at once. |
POST /api/v1/customer/batch | 1–100 | Import or update customer records without sending an event. |
The process_from parameter
Both booking and order batch endpoints accept an optional process_from date. Events before this date are stored for AI context but are not processed for email sending and are not billed. Events on or after this date go through the full pipeline and are billed normally.
POST /api/v1/event/booking/batch
{
"process_from": "2025-01-01T00:00:00Z",
"events": [
{
"identifier": "APT-2023-001",
"start_at": "2023-06-10T10:00:00Z",
...
},
{
"identifier": "APT-2025-088",
"start_at": "2025-03-15T10:00:00Z",
...
}
]
}In this example, the 2023 event is stored as historical context only — no email is sent and it is not billed. The 2025 event goes through the full pipeline and is billed.
Choose process_from carefully. The AI uses all stored events — including historical ones — to understand each customer's behaviour and purchase patterns. If process_from is set too recently, the AI may only see a partial picture. For example, a customer who alternates between two products every year will appear to only buy one product if the window is too narrow. As a rule of thumb, set process_from at least 1–2 full purchase cycles before the date you want emails to start.
Response format
All batch endpoints return the same response shape. Partial success is possible — records that fail validation are listed in errors while valid records are still processed.
{
"created": 85,
"updated": 12,
"errors": [
{
"index": 3,
"message": "customer.email is required"
}
]
}Note: The index in each error refers to the zero-based position of the record in your request array. Always check the errors array even on a 200 response.
Batch bookings
Send up to 100 booking events in a single request. Each event in the array follows the same structure as a single booking event. Use the optional process_from parameter to split historical context from billable events.
POST /api/v1/event/booking/batch
{
"process_from": "2025-01-01T00:00:00Z",
"events": [
{
"identifier": "APT-2026-001",
"start_at": "2026-04-15T10:00:00Z",
"status": "completed",
"status_at": "2026-04-15T11:30:00Z",
"staff": "Sarah",
"is_test": false,
"customer": {
"email": "emma@example.com",
"name": "Emma de Vries",
"language": "nl",
"timezone": "Europe/Amsterdam",
"identifier": "cust_abc123",
"identifier_source": "shopify",
"is_subscribed": true
},
"items": [
{ "name": "Haircut", "quantity": 1 }
]
},
{
"identifier": "APT-2026-002",
"start_at": "2026-04-15T14:00:00Z",
"status": "completed",
"status_at": "2026-04-15T15:00:00Z",
"staff": "Tom",
"customer": {
"email": "jan@example.com",
"name": "Jan Bakker"
},
"items": [
{ "name": "Beard trim", "quantity": 1 }
]
}
]
}Tip: For historical imports, always include status_at so Aitarax can handle out-of-order records correctly. Use "is_test": true on all records while verifying your import.
Batch orders
Send up to 100 order events in a single request. Uses ordered_at instead of start_at. Supports the same optional process_from parameter as batch bookings.
POST /api/v1/event/order/batch
{
"process_from": "2025-01-01T00:00:00Z",
"events": [
{
"identifier": "ORD-2026-1001",
"ordered_at": "2026-04-10T14:00:00Z",
"status": "delivered",
"status_at": "2026-04-12T16:00:00Z",
"is_test": false,
"customer": {
"email": "bakkerij@example.com",
"name": "Noord Bakkerij BV",
"identifier": "CUST-NB-002",
"identifier_source": "erp",
"is_subscribed": true
},
"items": [
{ "name": "Tarwebloem 25kg", "quantity": 40 },
{ "name": "Suiker fijn 25kg", "quantity": 20 }
]
}
]
}Common use case: Nightly sync from your ERP or webshop. Query orders updated since your last sync and send the full batch in one call. The identifier field ensures duplicates are updated rather than re-created.
Batch customers
Import or update customer records without attaching an event. Useful for syncing your full customer base before sending events, or for updating subscription status and segments in bulk.
POST /api/v1/customer/batch
{
"customers": [
{
"email": "jane@example.com",
"name": "Jane Doe",
"date_birth": "1990-05-15",
"phone": "+31612345678",
"language": "en",
"timezone": "America/Chicago",
"identifier": "cust_abc123",
"identifier_source": "shopify",
"is_subscribed": true,
"url_params": {
"booking": {
"customer_id": "C123",
"utm_campaign": "followup",
"utm_source": "email"
},
"order": {
"customer_id": "C123",
"discount_code": "SAVE10"
}
}
}
]
}| Field | Required | Description |
|---|---|---|
email | Required* | Customer email. Primary key for upsert. |
name | Recommended | Full name or company name. |
date_birth | Optional | ISO 8601 date (e.g. 1990-05-15). |
phone | Optional | E.164 format (e.g. +31612345678). |
language | Optional | ISO 639-1 code. Used for AI email generation. |
timezone | Optional | IANA timezone. Used for optimal send timing. |
identifier | Optional | External ID. Use with identifier_source. |
identifier_source | Optional | System that issued the identifier (e.g. shopify, erp). |
is_subscribed | Optional | Set to false to suppress all emails for this customer. |
url_params | Optional | Custom URL parameters for email links. Scoped per event type. |
Note: Customer batch does not trigger any AI processing or email sends. It only creates or updates customer records. To trigger re-engagement emails, send events via the booking or order batch endpoints.
n8n
Connect Aitarax to any app using n8n's HTTP Request node. Works with n8n Cloud and self-hosted instances.
Step 1 — Store your API key as a credential
In n8n, go to Credentials → New → Header Auth. Set the name to X-API-Key and the value to your Aitarax API key. Save it as Aitarax API.
Step 2 — Add an HTTP Request node
Add an HTTP Request node to your workflow and configure it as follows:
Method: POST
URL: https://app.aitarax.com/api/v1/event/booking
Auth: Header Auth → Aitarax API
Body type: JSON
Body:
{
"identifier": "{{ $json.booking_id }}",
"start_at": "{{ $json.start_time }}",
"status": "{{ $json.status }}",
"status_at": "{{ $json.updated_at }}",
"staff": "{{ $json.staff_name }}",
"customer": {
"email": "{{ $json.customer_email }}",
"name": "{{ $json.customer_name }}",
"language": "{{ $json.customer_language }}",
"timezone": "{{ $json.customer_timezone }}"
},
"items": [
{ "name": "{{ $json.service_name }}", "quantity": 1 }
]
}Step 3 — Test with a test event
Add "is_test": true to your body while testing. The event will appear in your Aitarax dashboard and be automatically deleted after 24 hours.
For order events
Change the URL to /api/v1/event/order and replace start_at with ordered_at.
Method: POST
URL: https://app.aitarax.com/api/v1/event/order
Body:
{
"identifier": "{{ $json.order_id }}",
"ordered_at": "{{ $json.created_at }}",
"status": "{{ $json.fulfillment_status }}",
"status_at": "{{ $json.updated_at }}",
"customer": {
"email": "{{ $json.customer_email }}",
"name": "{{ $json.customer_name }}"
},
"items": {{ $json.line_items.map(i => ({ name: i.title, quantity: i.quantity })) }}
}Batch imports with n8n
Use the Schedule trigger and an Aggregate node to collect records and send them as a batch to /api/v1/event/booking/batch. The body must wrap your events in an events array (or customers for customer batch).
Method: POST
URL: https://app.aitarax.com/api/v1/event/booking/batch
Auth: Header Auth → Aitarax API
Body type: JSON
Body:
{
"events": {{ $json.all_bookings }}
}Common triggers: Use n8n's Webhook node to receive events in real time, or the Schedule node to batch-sync from your database at regular intervals. Both work well with Aitarax.
Zapier
Send events to Aitarax from any Zapier trigger using the Webhooks by Zapier action. No custom app needed.
Step 1 — Create a new Zap
Choose any trigger that fires when a booking or order is created or updated — for example Calendly → Invitee Created, Shopify → New Order, or Google Calendar → Event Started.
Step 2 — Add a Webhooks by Zapier action
Search for Webhooks by Zapier and select the POST action. Configure it as follows:
| Field | Value |
|---|---|
| URL | https://app.aitarax.com/api/v1/event/booking |
| Payload Type | JSON |
| Headers — Name | X-API-Key |
| Headers — Value | atx_your_api_key_here |
Step 3 — Map the data fields
In the Data section, map your trigger fields to the Aitarax event structure. Example for a booking:
identifier → [Booking ID from trigger] start_at → [Appointment Start Time] status → completed status_at → [Updated At] staff → [Staff Name] customer__email → [Customer Email] customer__name → [Customer Name] customer__language → nl items__0__name → [Service Name] items__0__quantity → 1
Note: Zapier uses double underscores (__) to represent nested JSON. So customer__email maps to {"customer": {"email": "..."}}.
Step 4 — Test the Zap
Before turning on your Zap, add is_test → true to your data fields and run a test. Check your Aitarax Events page to confirm the event arrived. Then remove is_test and publish.
Common Zapier triggers: Calendly (bookings), Shopify (orders), WooCommerce (orders), Acuity Scheduling (appointments), Mindbody (classes), Square (payments), and any app with a Zapier integration.
Make
Send events to Aitarax from Make (formerly Integromat) using the HTTP → Make a request module. Supports both real-time webhooks and scheduled batch syncs.
Step 1 — Create a new scenario
Add a trigger module for your source app — for example Calendly → Watch Events, Shopify → Watch Orders, or Webhooks → Custom webhook for real-time updates.
Step 2 — Add an HTTP module
Add the HTTP → Make a request module and configure it as follows:
| Setting | Value |
|---|---|
| URL | https://app.aitarax.com/api/v1/event/booking |
| Method | POST |
| Body type | Raw |
| Content type | application/json |
| Header — Name | X-API-Key |
| Header — Value | atx_your_api_key_here |
Step 3 — Build the request body
In the Request content field, paste the JSON body and map your trigger data using Make's variable picker ( button):
{
"identifier": "{{1.booking_id}}",
"start_at": "{{1.start_time}}",
"status": "{{1.status}}",
"status_at": "{{1.updated_at}}",
"staff": "{{1.staff_name}}",
"customer": {
"email": "{{1.customer.email}}",
"name": "{{1.customer.name}}",
"language": "{{1.customer.language}}",
"timezone": "{{1.customer.timezone}}"
},
"items": [
{
"name": "{{1.service_name}}",
"quantity": 1
}
]
}Step 4 — Handle multiple items
If your source app returns multiple line items, use Make's Iterator module before the HTTP module to loop through items and send one event per booking/order with all items included.
Step 5 — Test and activate
Add "is_test": true to your request body and run the scenario once. Verify the event appears in your Aitarax Events page, then remove is_test and activate the scenario.
Common Make triggers: Shopify, WooCommerce, Calendly, Acuity Scheduling, Google Sheets (for batch imports), Airtable, and any app with a Make integration or webhook support.
Rate limits
Each API key is rate limited per organisation. All three windows apply simultaneously — a request must pass all three.
| Window | Limit | Purpose |
|---|---|---|
| Per minute | 200 requests | Allows batch imports, blocks runaway loops |
| Per hour | 5,000 requests | Handles flash sales and high-volume periods |
| Per day | 50,000 requests | High-volume e-commerce ceiling |
Batch and rate limits: Each batch request counts as 1 request against your rate limit, regardless of how many records it contains. Sending 100 events in one batch call is far more efficient than 100 individual calls.
Rate limit headers are included in every response: X-RateLimit-Remaining-Minute, X-RateLimit-Remaining-Hour, X-RateLimit-Remaining-Day. When a limit is exceeded, the API returns HTTP 429 with a Retry-After header.
Error codes
| Code | Meaning |
|---|---|
200 | Success. Event created or duplicate detected. For batch requests, check the errors array for partial failures. |
400 | Bad request. Missing required field or invalid value. |
401 | Unauthorized. Missing or invalid API key. |
429 | Rate limit exceeded. Check Retry-After header. |
500 | Internal server error. Contact support. |
