NueForm

Tester les Webhooks

How to test NueForm webhooks during local development using ngrok, webhook.site, curl, and the NueForm API.

Testing webhooks during development requires your endpoint to be reachable from the public internet. This guide covers several approaches, from quick inspection tools to full local development setups.

Option 1: webhook.site (Quick Inspection)

webhook.site provides a temporary public URL that captures and displays incoming HTTP requests. This is the fastest way to see what NueForm sends without writing any code.

  1. Go to webhook.site.
  2. Copy the unique URL (e.g., https://webhook.site/abc123-def456-...).
  3. Set it as your form's webhook URL:
bash
curl -X PUT https://app.nueform.com/api/v1/webhooks/form/YOUR_FORM_ID \
  -H "Authorization: Bearer nf_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://webhook.site/abc123-def456-..." }'
  1. Submit a response to your form.
  2. Refresh webhook.site to see the captured request, including headers, body, and the X-NueForm-Signature.

webhook.site is great for inspection but does not let you run custom verification logic. Use it to understand the payload format, then move to a local server for full testing.

Option 2: ngrok (Local Development)

ngrok creates a secure tunnel from a public URL to your local machine. This lets you receive real webhook deliveries on your development server.

Setup

  1. Install ngrok:
bash
# macOS (Homebrew)
brew install ngrok

# Or download from https://ngrok.com/download
  1. Start your local webhook server (e.g., on port 3001):
bash
node server.js
# or
python app.py
  1. Start an ngrok tunnel:
bash
ngrok http 3001
  1. Copy the HTTPS forwarding URL from the ngrok output:
text
Forwarding  https://a1b2c3d4.ngrok-free.app -> http://localhost:3001
  1. Set the ngrok URL as your webhook endpoint:
bash
curl -X PUT https://app.nueform.com/api/v1/webhooks/form/YOUR_FORM_ID \
  -H "Authorization: Bearer nf_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://a1b2c3d4.ngrok-free.app/webhooks/nueform" }'
  1. Submit a response to your form. The webhook will arrive at your local server.

Inspecting Traffic

ngrok provides a local web interface at http://localhost:4040 where you can inspect all requests passing through the tunnel, replay them, and view headers and response codes.

Free ngrok URLs change every time you restart ngrok. Remember to update your webhook URL in NueForm when you get a new tunnel URL. Consider upgrading to a paid ngrok plan for a stable subdomain.

Option 3: curl (Simulating Payloads)

You can use curl to send test webhook payloads to your local server without going through NueForm at all. This is useful for testing your verification and processing logic in isolation.

Generating a Signed Test Payload

First, create a test payload and sign it with your webhook secret:

bash
# Your webhook secret (from the NueForm API or dashboard)
SECRET="a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1b2"

# The test payload
PAYLOAD='{
  "event": "form.submitted",
  "formId": "507f1f77bcf86cd799439011",
  "formTitle": "Test Form",
  "responseId": "507f1f77bcf86cd799439022",
  "answers": [
    { "questionId": "507f1f77bcf86cd799439033", "value": "Test answer" },
    { "questionId": "507f1f77bcf86cd799439044", "value": 5 }
  ],
  "submittedAt": "2025-03-15T14:32:07.123Z"
}'

# Compute the HMAC-SHA256 signature
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

echo "Signature: $SIGNATURE"

Sending the Signed Request

bash
curl -X POST http://localhost:3001/webhooks/nueform \
  -H "Content-Type: application/json" \
  -H "X-NueForm-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

One-Liner

Combine everything into a single command:

bash
SECRET="your_secret_here"
PAYLOAD='{"event":"form.submitted","formId":"507f1f77bcf86cd799439011","formTitle":"Test Form","responseId":"507f1f77bcf86cd799439022","answers":[{"questionId":"q1","value":"hello"}],"submittedAt":"2025-03-15T14:32:07.123Z"}'
SIGNATURE=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')

curl -X POST http://localhost:3001/webhooks/nueform \
  -H "Content-Type: application/json" \
  -H "X-NueForm-Signature: $SIGNATURE" \
  -d "$PAYLOAD"

Testing Signature Rejection

To verify that your endpoint correctly rejects invalid signatures, send a request with a wrong signature:

bash
curl -X POST http://localhost:3001/webhooks/nueform \
  -H "Content-Type: application/json" \
  -H "X-NueForm-Signature: 0000000000000000000000000000000000000000000000000000000000000000" \
  -d '{"event":"form.submitted","formId":"test","formTitle":"Test","responseId":"test","answers":[],"submittedAt":"2025-03-15T14:32:07.123Z"}'

Your endpoint should return 401 Unauthorized.

Option 4: Node.js Test Script

Create a standalone Node.js script to quickly sign and send test payloads:

javascript
import crypto from 'crypto';

const SECRET = process.env.NUEFORM_WEBHOOK_SECRET || 'your_secret_here';
const ENDPOINT = process.env.WEBHOOK_URL || 'http://localhost:3001/webhooks/nueform';

const payload = JSON.stringify({
  event: 'form.submitted',
  formId: '507f1f77bcf86cd799439011',
  formTitle: 'Customer Feedback Survey',
  responseId: crypto.randomUUID().replace(/-/g, '').slice(0, 24),
  answers: [
    { questionId: 'q_name', value: 'Jane Doe' },
    { questionId: 'q_email', value: 'jane@example.com' },
    { questionId: 'q_rating', value: 4 },
    { questionId: 'q_feedback', value: 'Great product!' },
    { questionId: 'q_features', value: ['Feature A', 'Feature C'] },
  ],
  submittedAt: new Date().toISOString(),
});

const signature = crypto
  .createHmac('sha256', SECRET)
  .update(payload)
  .digest('hex');

const response = await fetch(ENDPOINT, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-NueForm-Signature': signature,
  },
  body: payload,
});

console.log(`Status: ${response.status}`);
console.log(`Body: ${await response.text()}`);

Run it with:

bash
NUEFORM_WEBHOOK_SECRET=your_secret node test-webhook.mjs

Option 5: Trigger a Real Submission

The most thorough way to test is to submit an actual response to your form:

  1. Configure your webhook URL (per-form or global) to point to your test endpoint.
  2. Open your published form in a browser.
  3. Fill out and submit the form.
  4. Observe the webhook delivery on your endpoint.

This tests the entire pipeline end-to-end, including answer validation, quiz scoring, and the actual payload NueForm generates.

Debugging Failed Deliveries

If your webhook endpoint is not receiving requests, work through this checklist:

1. Verify the URL is configured

bash
# Check per-form webhook
curl https://app.nueform.com/api/v1/webhooks/form/YOUR_FORM_ID \
  -H "Authorization: Bearer nf_your_api_key"

# Check global webhooks
curl https://app.nueform.com/api/v1/webhooks/global \
  -H "Authorization: Bearer nf_your_api_key"

2. Verify the URL is reachable

bash
# Test that your endpoint accepts POST requests
curl -X POST https://your-endpoint.com/webhooks/nueform \
  -H "Content-Type: application/json" \
  -d '{"test": true}'

3. Check for a webhook secret

Webhooks are only dispatched if your account has a webhook secret set. Verify:

bash
curl https://app.nueform.com/api/v1/webhooks/secret \
  -H "Authorization: Bearer nf_your_api_key"

If the response shows a secret, you are good. If not, one will be auto-generated by this request.

4. Check your plan

Webhooks require a Pro plan or higher. Verify your plan status in the NueForm dashboard under your account settings.

5. Check the timeout

NueForm has a 5-second timeout. If your endpoint takes longer to respond, the request will be aborted. Make sure you return 200 OK immediately and process data in the background.

6. Check firewall and network rules

Ensure your server allows incoming POST requests from external sources. If you are behind a firewall or VPN, you may need to allowlist NueForm's IP ranges or use ngrok.

Common Testing Mistakes

MistakeSolution
Using express.json() middleware before signature verificationUse express.raw({ type: 'application/json' }) on the webhook route
Testing with a revoked or expired API keyGenerate a fresh API key
Forgetting to enable global webhooksSet "enabled": true on each global webhook entry
Using HTTP instead of HTTPS for the webhook URLNueForm sends to whatever URL you provide, but use HTTPS in production
Not checking for a webhook secretEnsure your account has a webhook secret before expecting deliveries

Next Steps

Dernière mise à jour : 6 avril 2026