Skip to main content
Webhooks let you connect your Peanuts helpers to external services like Zapier, Make, n8n, or your own servers. When an entry is created, Peanuts sends a POST request with the entry data to your configured URL.

What Are Webhooks?

Webhooks are automated HTTP requests that Peanuts sends to your specified URL whenever certain events occur. Think of them as real-time notifications that carry your data to other systems.

Real-Time Delivery

Data is sent immediately when entries are created - no polling required

Universal Compatibility

Connect to Zapier, Make, n8n, or any webhook-compatible service

Secure Signatures

Optional HMAC signatures verify that requests come from Peanuts

Delivery Tracking

View delivery history with status codes and error messages

Setting Up a Webhook

1

Open Integrations

Navigate to your helper and tap the Settings (gear) icon, then scroll to Integrations.
2

Expand Webhook Settings

Tap the Outgoing Webhook accordion to reveal the configuration options.
3

Enable Webhook

Toggle Enable webhook to activate webhook delivery for this helper.
4

Enter Webhook URL

Paste the URL where you want to receive the webhook POST requests.Examples:
  • https://hooks.zapier.com/hooks/catch/123456/abcdef
  • https://hook.us1.make.com/abc123xyz
  • https://n8n.yourserver.com/webhook/peanuts
  • https://api.yourapp.com/webhooks/peanuts
5

Test the Connection

Click the Test button (flask icon) to send a test payload and verify your endpoint is receiving data correctly.
6

Save Configuration

Tap Save to apply the webhook configuration.
Webhook configuration interface

Webhook Payload Format

Every webhook request is a POST request with a JSON body containing event details:
{
  "event": "entry.created",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "helper": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Expense Tracker",
    "command": "/expense"
  },
  "entry": {
    "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "data": {
      "amount": 42.50,
      "category": "Food",
      "description": "Lunch meeting",
      "date": "2024-01-15"
    },
    "created_at": "2024-01-15T10:30:00.000Z"
  }
}

Payload Fields

FieldTypeDescription
eventstringEvent type: entry.created, entry.updated, or entry.deleted
timestampstringISO 8601 timestamp when the webhook was sent
helper.idstringUnique identifier (UUID) of the helper
helper.namestringDisplay name of the helper
helper.commandstringTelegram command for the helper
entry.idstringUnique identifier (UUID) of the entry
entry.dataobjectAll field values from the entry
entry.created_atstringWhen the entry was originally created

HTTP Headers

Every webhook request includes these headers:
POST /your-webhook-endpoint HTTP/1.1
Content-Type: application/json
User-Agent: Peanuts-Webhook/1.0
X-Peanuts-Signature: sha256=abc123... (if signing secret is configured)
HeaderDescription
Content-TypeAlways application/json
User-AgentIdentifies the request as coming from Peanuts
X-Peanuts-SignatureHMAC-SHA256 signature (only if signing secret is set)

Signing Secret (Security)

For production use, we strongly recommend adding a Signing Secret to verify that webhook requests genuinely come from Peanuts. Create a random string (32+ characters recommended). You can use a password generator or run:
openssl rand -hex 32
Paste the secret in the Signing Secret field in your webhook configuration. When receiving webhooks, verify the X-Peanuts-Signature header matches the expected signature.

Signature Verification Examples

const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-peanuts-signature'];
  const isValid = verifyWebhookSignature(req.body, signature, YOUR_SECRET);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  // Process the webhook...
  res.status(200).send('OK');
});
import hmac
import hashlib
import json

def verify_webhook_signature(payload, signature, secret):
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        json.dumps(payload).encode(),
        hashlib.sha256
    ).hexdigest()

    return hmac.compare_digest(signature, expected)

# In your webhook handler:
@app.route('/webhook', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Peanuts-Signature')
    is_valid = verify_webhook_signature(
        request.json, 
        signature, 
        YOUR_SECRET
    )

    if not is_valid:
        return 'Invalid signature', 401

    # Process the webhook...
    return 'OK', 200
function verifyWebhookSignature($payload, $signature, $secret) {
    $expected = 'sha256=' . hash_hmac(
        'sha256', 
        json_encode($payload), 
        $secret
    );

    return hash_equals($signature, $expected);
}

// In your webhook handler:
$signature = $_SERVER['HTTP_X_PEANUTS_SIGNATURE'] ?? '';
$payload = json_decode(file_get_contents('php://input'), true);

if (!verifyWebhookSignature($payload, $signature, YOUR_SECRET)) {
    http_response_code(401);
    exit('Invalid signature');
}

// Process the webhook...
http_response_code(200);
echo 'OK';

Delivery History

Peanuts tracks every webhook delivery attempt so you can monitor and troubleshoot issues.

Delivery Statuses

StatusIconDescription
Success✓ GreenWebhook was delivered and your server responded with 2xx status
Failed✕ RedDelivery failed - check the error message for details
Pending○ YellowDelivery is in progress (rare, usually resolves quickly)
The delivery history shows the last 10 deliveries for each helper, including HTTP status codes, error messages, retry attempts, and relative timestamps.
  1. Create a new Zap and choose Webhooks by Zapier as the trigger
  2. Select Catch Hook as the trigger event
  3. Copy the webhook URL provided by Zapier
  4. Paste it into your Peanuts webhook configuration
  5. Send a test from Peanuts to set up your Zap fields
  6. Add any actions you want (Google Sheets, Slack, Email, etc.)
  7. Create a new Scenario
  8. Add a Webhooks module as the first step
  9. Choose Custom webhook
  10. Copy the webhook URL
  11. Paste it into Peanuts and send a test
  12. Make will auto-detect your data structure
  13. Add a Webhook node to your workflow
  14. Set the HTTP Method to POST
  15. Copy the Production or Test webhook URL
  16. Configure it in Peanuts
  17. Use the Listen for Test Event to verify the connection
  18. Open your Google Sheet and go to Extensions → Apps Script
  19. Deploy a web app that receives POST requests:
function doPost(e) {
  const sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
  const data = JSON.parse(e.postData.contents);

  sheet.appendRow([
    data.timestamp,
    data.helper.name,
    JSON.stringify(data.entry.data)
  ]);

  return ContentService.createTextOutput('OK');
}
  1. Deploy as web app and use the URL in Peanuts
  2. Create a Slack App at api.slack.com
  3. Enable Incoming Webhooks
  4. Create a webhook for your channel
  5. Use a middleware service (Zapier/Make) to transform Peanuts data to Slack format
Or create a simple proxy server that reformats the payload for Slack’s API.

Best Practices

Only use HTTPS URLs for webhooks to ensure data is encrypted in transit Respond with 200 status code as fast as possible - do heavy processing asynchronously Always configure a signing secret for production to prevent spoofed requests Use the entry ID to detect and handle potential duplicate deliveries gracefully

Troubleshooting

Common causes:
  • Your server returned a non-2xx status code
  • The URL is unreachable (firewall, DNS, or server down)
  • Request timed out (server took too long to respond)
Solutions:
  • Check your server logs for errors
  • Verify the URL is accessible from the internet
  • Ensure your server responds within 30 seconds
  • Check if your firewall allows requests from Peanuts
The test button sends requests directly from your browser. Real webhooks come from Peanuts servers. Check:
  • Your server accepts POST requests from any origin
  • No IP-based restrictions blocking Peanuts servers
  • The URL is publicly accessible (not localhost)
Possible issues:
  • Secret mismatch between Peanuts and your server
  • Payload is being modified before verification (parsed twice, whitespace changes)
  • Using wrong hashing algorithm (should be HMAC-SHA256)
Debug steps:
  1. Log the raw signature header you receive
  2. Log the signature you compute
  3. Ensure you’re using the raw JSON string, not a re-serialized object
Webhooks only fire when:
  • The webhook is enabled in settings
  • A valid URL is configured
  • An entry is created (updates/deletes coming soon)
Check your helper’s integration settings to verify the configuration.

Technical Specifications

Webhooks are processed asynchronously and do not block entry creation. If a webhook fails, your entry is still saved successfully.

Request Details

PropertyValue
HTTP MethodPOST
Content-Typeapplication/json
Timeout30 seconds
Retry PolicyNo automatic retries (currently)
Max Payload Size~100KB

Response Expectations

Your endpoint should:
  • Return a 2xx status code (200, 201, 202, 204) for success
  • Respond within 30 seconds
  • Handle the JSON body appropriately
Any non-2xx response is recorded as a failed delivery.

Credit Usage

Webhooks are included with all plans at no additional credit cost. There are no per-webhook charges.
Get entries delivered directly to your inbox Generate and schedule PDF reports

Required Screenshots

PathDescription
/images/integrations/webhook-setup.pngWebhook configuration interface showing URL field, secret field, and test button
/images/integrations/webhook-history.pngDelivery history panel showing success/failed deliveries with timestamps

Key Fixes Applied

  1. No 4-space indentation - All content starts at column 0 to prevent accidental code blocks
  2. Proper Mintlify components - , , , , , , , , , , , , “ all properly closed
  3. Clean Markdown tables - Tables have no leading whitespace and use backticks for field names
  4. Code fences at column 0 - All code blocks start flush left
  5. Proper list formatting - Using standard Markdown numbered lists inside accordions