A
Atlas
...

Form Submission Endpoint

The form submission endpoint accepts data from your frontend forms.

Endpoint

http
POST /f/{form_id}

Each form has a unique form_id (e.g., abc123xyz). Find it in your form settings.

Request Formats

JSON (recommended for JavaScript)

bash
curl -X POST https://atlasforms.app/f/abc123xyz \
  -H "Content-Type: application/json" \
  -d '{"name": "John", "email": "john@example.com"}'

Form URL-encoded (HTML forms)

bash
curl -X POST https://atlasforms.app/f/abc123xyz \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "name=John&email=john@example.com"

Multipart Form Data (with file uploads)

bash
curl -X POST https://atlasforms.app/f/abc123xyz \
  -F "name=John" \
  -F "email=john@example.com" \
  -F "attachment=@document.pdf"

Response Formats

JSON Response (default for AJAX)

When Accept: application/json or Content-Type: application/json:

json
{
  "success": true,
  "submission_id": "550e8400-e29b-41d4-a716-446655440000",
  "files": [
    {
      "id": "file-uuid",
      "filename": "document.pdf",
      "type": "application/pdf",
      "size": 102400
    }
  ]
}

Redirect Response (HTML forms)

For standard HTML form submissions, users are redirected to:

  • Your configured Success Redirect URL, or
  • A default success page
  • Query parameters are appended:

    https://yoursite.com/thank-you?submission_id=xxx&status=success

    Success Redirect

    Configure a redirect URL in your form settings:

  • Go to Form Settings → General (under Delivery Settings)
  • Set Success Redirect to your thank-you page URL
  • The redirect includes:

  • submission_id - The unique submission ID
  • status - Always success
  • files - Number of uploaded files (if any)
  • webhook - delivered or pending (if webhook confirmation enabled)
  • Spam Protection

    Honeypot Fields

    Add hidden honeypot fields to catch bots:

    html
    <form action="https://atlasforms.app/f/abc123xyz" method="POST">
      <!-- Honeypot - hide with CSS -->
      <input type="text" name="_gotcha" style="display:none" tabindex="-1" autocomplete="off">
    
      <!-- Real fields -->
      <input type="text" name="name" required>
      <input type="email" name="email" required>
      <button type="submit">Send</button>
    </form>

    If _gotcha or _honeypot contains a value, the submission is silently rejected (bots fill all fields).

    Turnstile CAPTCHA

    Enable Cloudflare Turnstile in form settings for additional protection:

    html
    <form action="https://atlasforms.app/f/abc123xyz" method="POST">
      <input type="text" name="name" required>
      <input type="email" name="email" required>
    
      <!-- Turnstile widget -->
      <div class="cf-turnstile" data-sitekey="your-site-key"></div>
    
      <button type="submit">Send</button>
    </form>
    
    <script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>

    Reserved Fields

    These field names are reserved and automatically stripped:

    FieldPurpose
    _gotchaHoneypot spam protection
    _honeypotHoneypot spam protection
    _csrfCSRF token
    cf-turnstile-responseTurnstile token
    _turnstileTokenTurnstile token (JS)

    CORS

    The endpoint supports CORS for JavaScript submissions:

  • Access-Control-Allow-Origin: Your configured origins
  • Access-Control-Allow-Methods: POST, OPTIONS
  • Access-Control-Allow-Headers: Content-Type, X-Atlas-Key
  • Configure allowed origins in Form Settings → Security → Allowed Origins.

    Localhost Testing

    Localhost submissions require:

  • Form must be in Sandbox Mode
  • Your IP must be registered in form settings
  • See Security → Localhost Testing for details.

    Optional: For JavaScript apps, you can add extra security with a Sandbox API Key:

    javascript
    await fetch('https://atlasforms.app/f/abc123', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-Atlas-Key': process.env.ATLAS_FORM_KEY  // From .env.local
      },
      body: JSON.stringify(data)
    })

    Rate Limiting

    Submissions are rate limited per IP address:

    DefaultLimit
    Standard60 requests/minute
    CustomizableVia project settings

    Rate limit headers:

    X-RateLimit-Limit: 60
    X-RateLimit-Remaining: 55
    X-RateLimit-Reset: 2024-01-15T10:31:00Z

    Error Responses

    400 Bad Request

    Invalid data or content type.

    json
    { "error": "Invalid content type" }

    403 Forbidden

  • Form is inactive
  • Origin not allowed
  • IP blocked
  • Localhost not allowed (live mode)
  • IP not registered (sandbox mode)
  • json
    { "error": "Origin not allowed" }
    json
    { "error": "Localhost not allowed in live mode. Use sandbox mode for local development." }
    json
    { "error": "IP not registered for sandbox mode. Register your IP in form settings.", "your_ip": "73.45.123.100" }

    404 Not Found

    Form doesn't exist.

    json
    { "error": "Form not found" }

    429 Too Many Requests

    Rate limit exceeded.

    json
    { "error": "Rate limit exceeded. Please try again later.", "retry_after": 45 }

    402 Payment Required

    Feature requires upgrade (e.g., file uploads on Starter plan).

    json
    { "error": "File uploads require a paid plan", "upgrade_url": "..." }