A
Atlas
...

Webhooks

Webhooks notify your server when submissions arrive. Configure a URL and Atlas will POST submission data to it in real-time.

Configuration

  • Go to Form Settings → General (under Delivery Settings)
  • Enter your Webhook URL (e.g., https://yourserver.com/webhook)
  • (Optional) Enable Wait for webhook confirmation for file uploads
  • Save
  • You can also configure webhooks at the project level to receive all submissions.

    Webhook Payload

    json
    {
      "event": "submission.created",
      "timestamp": "2024-01-15T10:30:00.000Z",
      "form": {
        "id": "form-uuid",
        "public_id": "abc123xyz",
        "slug": "contact",
        "name": "Contact Form"
      },
      "submission": {
        "id": "550e8400-e29b-41d4-a716-446655440000",
        "data": {
          "name": "John Doe",
          "email": "john@example.com",
          "message": "Hello!"
        },
        "files": [
          {
            "id": "file-uuid",
            "field": "attachment",
            "filename": "document.pdf",
            "type": "application/pdf",
            "size": 102400
          }
        ],
        "metadata": {
          "ip": "192.168.1.1",
          "user_agent": "Mozilla/5.0...",
          "submitted_from": "https://example.com/contact"
        },
        "created_at": "2024-01-15T10:30:00.000Z"
      }
    }

    Webhook Headers

    Each webhook request includes these headers:

    HeaderDescription
    Content-Typeapplication/json
    X-Webhook-SignatureHMAC signature for verification
    X-Webhook-AttemptAttempt number (1, 2, 3...)
    X-Submission-IdThe submission ID

    Signature Verification

    Webhooks include an HMAC-SHA256 signature to verify authenticity. Always verify signatures in production.

    Generate a Webhook Secret

  • Go to Project Settings → Security
  • Generate or view your Webhook Secret
  • Verify the Signature

    javascript
    const crypto = require('crypto');
    
    function verifyWebhook(payload, signature, secret) {
      const expected = 'sha256=' + crypto
        .createHmac('sha256', secret)
        .update(payload)
        .digest('hex');
    
      return crypto.timingSafeEqual(
        Buffer.from(signature),
        Buffer.from(expected)
      );
    }
    
    // Express.js example
    app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
      const signature = req.headers['x-webhook-signature'];
      const payload = req.body.toString();
    
      if (!verifyWebhook(payload, signature, process.env.WEBHOOK_SECRET)) {
        return res.status(401).send('Invalid signature');
      }
    
      const data = JSON.parse(payload);
      console.log('New submission:', data.submission.id);
    
      res.status(200).send('OK');
    });

    Python Example

    python
    import hmac
    import hashlib
    
    def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
        expected = 'sha256=' + hmac.new(
            secret.encode(),
            payload,
            hashlib.sha256
        ).hexdigest()
        return hmac.compare_digest(signature, expected)

    PHP Example

    php
    function verifyWebhook($payload, $signature, $secret) {
        $expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);
        return hash_equals($expected, $signature);
    }

    Retry Behavior

    If your server doesn't respond with a 2xx status code, Atlas retries with exponential backoff:

    AttemptDelay
    1Immediate
    21 minute
    35 minutes
    430 minutes
    52 hours

    After 5 failed attempts, the webhook is marked as failed. You can manually retry from the dashboard.

    Response Requirements

    Your webhook endpoint should:

  • Respond within 30 seconds
  • Return a 2xx status code (200, 201, 204)
  • Handle duplicate deliveries idempotently
  • Wait for Confirmation

    For file uploads, you may want to confirm the webhook was received before showing success to the user.

    Enable Wait for webhook confirmation in form settings. When enabled:

  • User submits form with files
  • Atlas uploads files and saves submission
  • Atlas sends webhook and waits for response
  • Only then redirects user (with ?webhook=delivered)
  • If webhook fails, user still gets redirected but with ?webhook=pending.

    Testing Webhooks

    Using ngrok

    bash
    ngrok http 3000
    # Use the ngrok URL as your webhook URL

    Using RequestBin

  • Go to requestbin.com
  • Create a bin and copy the URL
  • Use it as your webhook URL for testing
  • Manual Retry

    From the submission detail page in your dashboard, click Retry Webhook to resend.

    Accessing Files

    Files in the webhook payload include IDs, not URLs. To download files:

    bash
    curl "https://atlasforms.app/api/v1/files/{file_id}?token={access_token}" \
      -H "Authorization: Bearer fep_your_api_key"

    Or generate a signed URL from the API.

    Best Practices

  • Always verify signatures - Prevents spoofed webhooks
  • Respond quickly - Do heavy processing async
  • Handle duplicates - Use submission ID as idempotency key
  • Log everything - Makes debugging easier
  • Use queues - Process webhooks in background jobs