Skip to main content

API Reference

Peanuts uses an outgoing webhook architecture to integrate with external systems. Rather than exposing a REST API for you to query, Peanuts pushes data to your endpoints in real-time when events occur.
Pro Plan Feature — Webhook integrations require a Pro subscription or higher.

How It Works

When an entry is created, updated, or deleted in any of your Helpers, Peanuts automatically sends an HTTP POST request to your configured webhook URL.

Benefits of Push Architecture

BenefitDescription
Real-timeReceive data instantly when events occur
No pollingEliminates the need for scheduled API calls
SecureYour data stays in Peanuts until you receive it
SimpleJust set up an endpoint and start receiving data

TypeScript Types

Use these interfaces to type your webhook handlers:
/**
 * The complete webhook event payload sent by Peanuts
 */
interface WebhookEvent {
  /** The type of event that triggered the webhook */
  event: "entry.created" | "entry.updated" | "entry.deleted";
  
  /** ISO 8601 timestamp of when the event occurred */
  timestamp: string;
  
  /** Information about the Helper that owns the entry */
  helper: HelperInfo;
  
  /** The entry data that triggered the event */
  entry: EntryData;
}

/**
 * Metadata about the Helper (mini-app)
 */
interface HelperInfo {
  /** Unique identifier for the Helper */
  id: string;
  
  /** Display name of the Helper */
  name: string;
  
  /** The slash command used to create this Helper */
  command: string;
}

/**
 * The entry that was created, updated, or deleted
 */
interface EntryData {
  /** Unique identifier for the entry */
  id: string;
  
  /** 
   * Dynamic key-value pairs matching the Helper's field configuration.
   * Keys are field names, values depend on field type.
   */
  data: Record<string, unknown>;
  
  /** ISO 8601 timestamp of when the entry was created */
  created_at: string;
}
The entry.data structure is dynamic and matches the fields you’ve configured in your Helper. A meal tracker might have { calories: 450, meal_type: "lunch" } while an expense tracker might have { amount: 29.99, category: "Transport" }.

Payload Structure

Here’s a complete example of a webhook payload:
{
  "event": "entry.created",
  "timestamp": "2025-01-15T14:32:00.000Z",
  "helper": {
    "id": "abc123-def456-789",
    "name": "Daily Expenses",
    "command": "/expenses"
  },
  "entry": {
    "id": "entry-789-xyz",
    "data": {
      "amount": 42.50,
      "category": "Food & Dining",
      "description": "Team lunch at Olive Garden",
      "date": "2025-01-15"
    },
    "created_at": "2025-01-15T14:32:00.000Z"
  }
}

Event Types

EventTrigger
entry.createdA new entry is added via voice, Telegram, or web
entry.updatedAn existing entry is modified
entry.deletedAn entry is removed from the Helper

HTTP Request Details

Peanuts sends webhooks as HTTP POST requests with the following characteristics:
PropertyValue
MethodPOST
Content-Typeapplication/json
User-AgentPeanuts-Webhook/1.0
Timeout30 seconds

Request Headers

POST /your-webhook-endpoint HTTP/1.1
Host: your-server.com
Content-Type: application/json
User-Agent: Peanuts-Webhook/1.0
X-Peanuts-Signature: sha256=a1b2c3d4e5f6...

Security & Authentication

All webhook requests are signed using HMAC-SHA256 to verify authenticity.

Signature Verification

The X-Peanuts-Signature header contains the signature in the format:
sha256={hex_encoded_signature}
To verify:
  1. Extract the signature from the header (remove sha256= prefix)
  2. Compute HMAC-SHA256 of the raw request body using your webhook secret
  3. Compare the signatures using a timing-safe comparison
import { createHmac, timingSafeEqual } from 'crypto';

function verifySignature(
  payload: string, 
  signature: string, 
  secret: string
): boolean {
  const expected = createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  
  const sig = signature.replace('sha256=', '');
  
  return timingSafeEqual(
    Buffer.from(sig, 'hex'),
    Buffer.from(expected, 'hex')
  );
}
Always verify signatures in production to prevent spoofed requests. Your webhook secret is available in your Helper’s integration settings.

Response Requirements

Your endpoint should respond quickly to acknowledge receipt:
ResponseMeaning
2xxSuccess — delivery confirmed
4xxClient error — will not retry
5xxServer error — will retry

Retry Policy

If your endpoint returns a 5xx error or times out, Peanuts will retry with exponential backoff:
  1. 1st retry: 1 minute after initial failure
  2. 2nd retry: 5 minutes after 1st retry
  3. 3rd retry: 30 minutes after 2nd retry
After 3 failed attempts, the delivery is marked as failed. You can view delivery history in the Helper’s webhook settings.
Acknowledge webhooks quickly (return 200) and process data asynchronously. This prevents timeouts and ensures reliable delivery.

Quick Start