Everything you need to integrate Aficial into your system
Send a scoped Aficial API key as a header with every request. Keys are shown once, stored only as hashes, and can be revoked.
x-api-key: afc_live_abcdefghij_your_secret_part_here
Alternatively: Authorization: Bearer afc_live_abcdefghij_your_secret_part_here
Authenticated admins create keys through API key management. Webhook ingest requires the scope webhook:write.
curl -X POST https://aficial.ai/api/api-keys \
-H "Content-Type: application/json" \
-H "Cookie: sb-access-token=USER_SESSION" \
-d '{
"name": "Shop webhook",
"scopes": ["webhook:write"],
"rateLimitPerMinute": 120
}'The OpenAPI document is available at /api/openapi.
/api/webhookThe webhook endpoint accepts data that the agent uses to answer customer inquiries. More data means better answers.
The agent uses this data automatically. If a customer asks about order #4521 and you sent this order via webhook, the agent can provide tracking number, status and details.
curl -X POST https://aficial.ai/api/webhook \
-H "Content-Type: application/json" \
-H "x-api-key: afc_live_abcdefghij_your_secret_part_here" \
-d '{
"type": "order",
"order": {
"order_number": "4521",
"status": "shipped",
"tracking_number": "DE-2026-4521-89",
"carrier": "DHL",
"customer_email": "max@example.com",
"customer_name": "Max Müller",
"items": [
{ "name": "Wireless Headphones Pro", "qty": 2, "price": 59.95 },
{ "name": "Ladestation", "qty": 1, "price": 29.99 }
],
"total": 149.89,
"currency": "EUR",
"ordered_at": "2026-03-12T10:30:00Z",
"shipped_at": "2026-03-14T06:42:00Z"
}
}'{ "success": true, "message": "Order data received" }curl -X POST https://aficial.ai/api/webhook \
-H "Content-Type: application/json" \
-H "x-api-key: afc_live_abcdefghij_your_secret_part_here" \
-d '{
"type": "customer",
"customer": {
"email": "max@example.com",
"name": "Max Müller",
"company": "Müller GmbH",
"phone": "+49 123 456789",
"tier": "premium",
"lifetime_value": 2450.00,
"orders_count": 18,
"since": "2024-01-15",
"tags": ["vip", "enterprise"]
}
}'curl -X POST https://aficial.ai/api/webhook \
-H "Content-Type: application/json" \
-H "x-api-key: afc_live_abcdefghij_your_secret_part_here" \
-d '{
"type": "product",
"product": {
"sku": "WHP-001",
"name": "Wireless Headphones Pro",
"price": 59.95,
"currency": "EUR",
"in_stock": true,
"category": "Audio",
"description": "Kabellose Kopfhörer mit Active Noise Cancelling",
"return_policy": "14 Tage Rückgabe, Originalverpackung nötig"
}
}'Any events the agent uses as context:
curl -X POST https://aficial.ai/api/webhook \
-H "Content-Type: application/json" \
-H "x-api-key: afc_live_abcdefghij_your_secret_part_here" \
-d '{
"type": "event",
"event": "shipping_delay",
"data": {
"region": "EU",
"delay_days": 2,
"reason": "Wetterbedingungen",
"affected_orders": ["4521", "4522", "4530"]
}
}'Max Payload: 100 KB. Format: JSON. Any structure, the agent processes everything.
Every AI reply gets a unique CSAT token. Customers can use it to rate.
GET /api/csat?token=CSAT_TOKEN
curl -X POST https://aficial.ai/api/csat \
-H "Content-Type: application/json" \
-d '{
"token": "CSAT_TOKEN",
"rating": 5,
"comment": "Schnelle und hilfreiche Antwort"
}'Rating: 1-5. Comment: optional, max 500 characters. Each token can only be rated once.
Authenticated endpoint. The signed-in user redeems a code for their organization.
curl -X POST https://aficial.ai/api/activate \
-H "Content-Type: application/json" \
-H "Cookie: sb-access-token=USER_SESSION" \
-d '{
"code": "HELLOFRESH"
}'{
"success": true,
"plan": "starter",
"trialDays": 14,
"trialEnds": "2026-04-06T12:00:00.000Z",
"message": "Aktiviert! Ihr 14-Tage Testzeitraum läuft."
}GET /api/health
{
"status": "healthy",
"uptime": 42.5,
"totalMs": 155,
"checks": {
"supabase": { "status": "ok", "ms": 56 },
"redis": { "status": "ok", "ms": 104 },
"anthropic": { "status": "ok" }
},
"version": "1.0.0"
}Aficial can notify your system when something happens. Configure webhook URLs in the dashboard under Integrations.
email.receivedNew email receivedreply.sentReply sentemail.escalatedEmail escalated to teamsla.breachedSLA deadline exceededcsat.receivedNew CSAT rating{
"event": "reply.sent",
"timestamp": "2026-03-23T14:30:00Z",
"data": {
"emailId": "abc-123",
"replyId": "def-456",
"category": "order_status"
}
}Every webhook is signed with HMAC-SHA256:
X-Aficial-Signature: sha256=a1b2c3d4e5... X-Aficial-Event: reply.sent
// Node.js Verification
const crypto = require('crypto');
const signature = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(JSON.stringify(body))
.digest('hex');
const valid = signature === header.split('=')[1];When exceeded you will receive 429 Too Many Requests with Retry-After Header.
{
"error": "Token and rating required"
}Official SDKs are planned. Until then any HTTP client works. Example for the webhook endpoint:
const res = await fetch('https://aficial.ai/api/webhook', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'afc_live_abcdefghij_your_secret_part_here',
},
body: JSON.stringify({
type: 'order',
order: { order_number: '4521', status: 'shipped' },
}),
});
console.log(await res.json());import requests
res = requests.post(
'https://aficial.ai/api/webhook',
headers={'x-api-key': 'afc_live_abcdefghij_your_secret_part_here'},
json={'type': 'order', 'order': {'order_number': '4521', 'status': 'shipped'}},
)
print(res.json())$ch = curl_init('https://aficial.ai/api/webhook');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'x-api-key: afc_live_abcdefghij_your_secret_part_here',
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'type' => 'order',
'order' => ['order_number' => '4521', 'status' => 'shipped'],
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);require 'net/http'
require 'json'
uri = URI('https://aficial.ai/api/webhook')
req = Net::HTTP::Post.new(uri, {
'Content-Type' => 'application/json',
'x-api-key' => 'afc_live_abcdefghij_your_secret_part_here',
})
req.body = { type: 'order', order: { order_number: '4521', status: 'shipped' } }.to_json
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
puts res.body