Back to home

    API Reference

    Technical documentation to integrate external systems with Auraltica via secure HTTP webhooks.

    Overview

    Auraltica Custom Webhooks let you send your orders, customers and products from any external system (ERP, custom platform, point-of-sale system, script) straight to your account. Once stored, the Auraltica chat can answer questions about them in natural language — with no need to connect a database.

    Each endpoint has a unique URL, a public API Key and a Signing Secret to verify the authenticity of every request via HMAC-SHA256.

    Prerequisites

    Authentication & security

    Every request requires four headers. Missing any of them results in immediate rejection:

    HeaderDescription
    Content-TypeAlways application/json.
    X-Auraltica-API-KeyYour public API Key (prefix awk_). Identifies the endpoint. 401 error if it doesn't match.
    X-Auraltica-TimestampUnix timestamp in seconds of when you send the request. Auraltica rejects requests more than ±5 minutes off the server clock — this prevents replay attacks. 400 error if missing or expired.
    X-Auraltica-HMAC-SHA256Base64 HMAC-SHA256 signature computed over timestamp + "." + body using the Signing Secret. Including the timestamp in the signature ensures it can't be reused. 401 error if it doesn't match.
    Optional headerDescription
    X-Idempotency-KeyUnique UUID per event. If Auraltica already processed an event with the same key, it returns 200 without re-inserting data. Useful for safe retries from your system.

    The Signing Secret is only shown when you create or rotate the endpoint. Store it in an environment variable. Never include it in source code or send it in the request.

    Send an event

    Make a POST to your endpoint URL with the four required headers:

    HTTP
    POST https://<project>.supabase.co/functions/v1/custom-webhook-receiver/<endpoint_path>
    Content-Type: application/json
    X-Auraltica-API-Key:       awk_abc123...
    X-Auraltica-Timestamp:     1719316800
    X-Auraltica-HMAC-SHA256:   <base64_hmac>
    X-Idempotency-Key:         550e8400-e29b-41d4-a716-446655440000   (optional)
    
    {
      "event_type": "order.created",
      "data": {
        "order_id": "ORD-001",
        "customer": "John Doe",
        "total": 1500.00,
        "currency": "USD"
      }
    }

    The full endpoint URL is shown in the Connectors panel next to the API Key.

    Possible responses

    CodeCauseRecommended action
    200Event received and ingested successfully.Nothing. Data already available in the chat.
    400Missing or expired timestamp (drift > 5 min), or invalid JSON.Sync the server clock. Do not retry automatically.
    401Wrong API Key or invalid HMAC signature.Check that the secret and the signing formula are correct.
    404Endpoint not found or disabled.Check the URL in the Connectors panel.
    413Payload larger than 1 MB.Split the payload into multiple requests.
    429Rate limit exceeded (N req/min configured on the endpoint).Wait the time indicated in Retry-After (seconds).

    Sign with HMAC-SHA256

    The signature is computed over timestamp + "." + body — the same principle Stripe uses. Including the timestamp in the signature ensures that an attacker who intercepts a valid request can't resend it later, because the timestamp will have expired.

    Formula
    signed_content  = timestamp_string + "." + body_string
    X-Auraltica-HMAC-SHA256 = Base64( HMAC-SHA256(signing_secret, signed_content) )

    Node.js

    JavaScript
    const crypto = require('crypto');
    
    async function sendWebhook(endpointUrl, apiKey, signingSecret, eventType, data) {
      const body = JSON.stringify({ event_type: eventType, data });
      const timestamp = String(Math.floor(Date.now() / 1000)); // Unix seconds
    
      const signedContent = timestamp + '.' + body;
      const signature = crypto
        .createHmac('sha256', signingSecret)
        .update(signedContent)
        .digest('base64');
    
      const res = await fetch(endpointUrl, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-Auraltica-API-Key': apiKey,
          'X-Auraltica-Timestamp': timestamp,
          'X-Auraltica-HMAC-SHA256': signature,
          'X-Idempotency-Key': crypto.randomUUID(),  // optional but recommended
        },
        body,
      });
    
      if (res.status === 429) {
        const retryAfter = res.headers.get('Retry-After') ?? '60';
        throw new Error(`Rate limit. Retry in ${retryAfter}s.`);
      }
      return res.json();
    }
    
    // Usage:
    await sendWebhook(
      process.env.AURALTICA_ENDPOINT_URL,
      process.env.AURALTICA_API_KEY,
      process.env.AURALTICA_SIGNING_SECRET,
      'order.created',
      { order_id: 'ORD-001', total: 1500, currency: 'USD' }
    );

    Python

    Python
    import hmac, hashlib, base64, json, time, uuid, os
    import requests
    
    def send_webhook(endpoint_url, api_key, signing_secret, event_type, data):
        body = json.dumps({"event_type": event_type, "data": data}, separators=(',', ':'))
        timestamp = str(int(time.time()))
    
        signed_content = timestamp + "." + body
        signature = base64.b64encode(
            hmac.new(signing_secret.encode(), signed_content.encode(), hashlib.sha256).digest()
        ).decode()
    
        resp = requests.post(endpoint_url, data=body, headers={
            "Content-Type": "application/json",
            "X-Auraltica-API-Key": api_key,
            "X-Auraltica-Timestamp": timestamp,
            "X-Auraltica-HMAC-SHA256": signature,
            "X-Idempotency-Key": str(uuid.uuid4()),  # optional
        })
    
        if resp.status_code == 429:
            retry_after = resp.headers.get("Retry-After", "60")
            raise Exception(f"Rate limit. Retry in {retry_after}s.")
    
        return resp.json()
    
    # Usage:
    send_webhook(
        os.environ["AURALTICA_ENDPOINT_URL"],
        os.environ["AURALTICA_API_KEY"],
        os.environ["AURALTICA_SIGNING_SECRET"],
        "order.created",
        {"order_id": "ORD-001", "total": 1500, "currency": "USD"}
    )

    PHP

    PHP
    <?php
    function sendWebhook(string $url, string $apiKey, string $secret, string $eventType, array $data): array {
        $body      = json_encode(['event_type' => $eventType, 'data' => $data]);
        $timestamp = (string) time();
        $signed    = $timestamp . '.' . $body;
        $signature = base64_encode(hash_hmac('sha256', $signed, $secret, true));
    
        $ch = curl_init($url);
        curl_setopt_array($ch, [
            CURLOPT_POST           => true,
            CURLOPT_POSTFIELDS     => $body,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER     => [
                'Content-Type: application/json',
                'X-Auraltica-API-Key: '       . $apiKey,
                'X-Auraltica-Timestamp: '     . $timestamp,
                'X-Auraltica-HMAC-SHA256: '   . $signature,
                'X-Idempotency-Key: '         . sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
                    mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0xffff),
                    mt_rand(0,0x0fff)|0x4000, mt_rand(0,0x3fff)|0x8000,
                    mt_rand(0,0xffff), mt_rand(0,0xffff), mt_rand(0,0xffff)),
            ],
        ]);
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);
    
        if ($httpCode === 429) {
            throw new RuntimeException('Rate limit exceeded. Check the Retry-After header.');
        }
        return json_decode($response, true);
    }
    
    // Usage:
    sendWebhook(
        $_ENV['AURALTICA_ENDPOINT_URL'],
        $_ENV['AURALTICA_API_KEY'],
        $_ENV['AURALTICA_SIGNING_SECRET'],
        'order.created',
        ['order_id' => 'ORD-001', 'total' => 1500, 'currency' => 'USD']
    );

    cURL / Bash

    Bash
    BODY='{"event_type":"order.created","data":{"order_id":"ORD-001","total":1500}}'
    SECRET="aws_your_signing_secret"
    API_KEY="awk_your_api_key"
    TIMESTAMP=$(date +%s)
    
    SIGNED="${TIMESTAMP}.${BODY}"
    SIG=$(echo -n "$SIGNED" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
    
    curl -X POST "$ENDPOINT_URL" \
      -H "Content-Type: application/json" \
      -H "X-Auraltica-API-Key: $API_KEY" \
      -H "X-Auraltica-Timestamp: $TIMESTAMP" \
      -H "X-Auraltica-HMAC-SHA256: $SIG" \
      -d "$BODY"

    Payload format per entity

    Every request must include an event_type field that indicates the data type, and a data field with the content. Auraltica stores the data in your account so the chat can query it.

    Supported events

    • order.created / order.updated / order.paid — store sales orders
    • order.cancelled / order.refunded — update the order status
    • customer.created / customer.updated — store customers
    • product.created / product.updated — store products

    Sales order

    JSON
    {
      "event_type": "order.created",
      "data": {
        "order_id":          "ORD-2024-001",     // required, unique identifier
        "date":              "2026-06-25T10:00:00Z", // optional, defaults to now()
        "customer":          "John Doe",          // customer name
        "email":             "john@email.com",
        "phone":             "+15551234567",
        "total":             2499.00,             // required
        "subtotal":          2200.00,
        "tax_amount":        299.00,
        "currency":          "USD",               // defaults to "USD"
        "financial_status":  "paid",              // paid | pending | refunded | cancelled
        "fulfillment_status":"fulfilled",          // fulfilled | unfulfilled | partial
        "note":              "Urgent order",
        "items": [
          {
            "sku":        "TSHIRT-BLUE-M",
            "title":      "Blue T-Shirt Size M",
            "qty":        2,
            "unit_price": 1100.00
          },
          {
            "sku":        "CAP-BLACK",
            "title":      "Black Cap",
            "qty":        1,
            "unit_price": 299.00
          }
        ]
      }
    }

    Customer

    JSON
    {
      "event_type": "customer.created",
      "data": {
        "customer_id":   "CUST-001",         // required, unique identifier
        "first_name":    "John",
        "last_name":     "Doe",
        "email":         "john@email.com",
        "phone":         "+15551234567",
        "total_spent":   5000.00,            // lifetime spend
        "total_orders":  3,                  // number of orders
        "city":          "New York",
        "state":         "NY",
        "country":       "United States",
        "zip":           "10001",
        "address":       "123 Main St",
        "note":          "VIP customer"
      }
    }

    Product

    JSON
    {
      "event_type": "product.created",
      "data": {
        "product_id":   "PROD-001",          // required, unique identifier
        "title":        "Blue T-Shirt",
        "description":  "100% cotton t-shirt, available in several sizes",
        "vendor":       "My Brand",
        "product_type": "Apparel",
        "status":       "active",            // active | inactive | archived
        "sku":          "TSHIRT-BLUE"
      }
    }

    Verify delivery

    You can review the history of received events directly from the panel:

    1. Go to Connectors and open the Custom Webhook connector.
    2. Find your endpoint and click View event history.
    3. You'll see each received request with its status: success rejected error

    A rejected status means the API Key or the HMAC signature didn't match what's registered in the system.

    Limits & security

    ControlValue / Behavior
    Max body size1 MB — 413 error before processing
    Rate limitConfigurable per endpoint (default 60 req/min). 429 error with Retry-After and X-RateLimit-Reset headers.
    Timestamp window±5 minutes. Requests outside the window are rejected (400) to prevent replay attacks.
    Signing algorithmHMAC-SHA256(secret, timestamp + "." + body) → Base64
    IdempotencyOptional X-Idempotency-Key header. A second attempt with the same key returns 200 without duplicating data.
    Secret storage256-bit AES-GCM at rest. Only shown in plaintext when created or rotated.
    TransportHTTPS required (endpoint on Supabase Edge Functions).
    Function timeout~30 s (standard Supabase Edge Functions limit)

    Best practices

    • Store AURALTICA_SIGNING_SECRET in environment variables or a vault — never in source code.
    • Always use X-Idempotency-Key when sending retries to avoid duplicating data.
    • Implement exponential backoff when you get a 429 — read the Retry-After header.
    • Rotate the secret immediately if you suspect it was compromised. Requests with the old secret are rejected instantly.
    • Make sure your server clock is synced (NTP). A difference over 5 minutes will cause a 400.