Guides

Webhooks

Receive new funding signals at your endpoint the moment they happen, no polling.

Overview

A webhook is an HTTP POST that Fundup AI sends to a URL you control the moment a company raises funding, so the signal comes to you in real time instead of you polling for it.

The recommended pattern: webhook + endpoint

Let the webhook tell you when something happens, then call the REST API on demand only for the companies that matter, to pull key contacts, the full profile, tech stack, and more. Used this way you act on fresh signals instantly and stay comfortably within rate limits.

Set up a webhook

Webhooks are configured in the dashboard, not via the API. Go to Settings → Integrations → Webhooks → Connect and provide:

Configuration

  • Endpoint URL: a public HTTP/HTTPS URL that accepts POST requests. HTTPS is strongly recommended.
  • Authentication key: optional. Leave it blank and one is generated for you. It is sent on every request as Authorization: Bearer <key> so you can verify the call really came from Fundup AI.
  • Test endpoint: sends a representative sample event so you can confirm connectivity before going live.

After connecting, choose which events you want to receive (below). You can change the auth key, the URL, and the event preferences at any time from the same screen.

Event types

Two notification preferences control what is delivered. Both send the same payload shape (event: "trigger_published"); they differ only in which companies trigger a call.

ICP Match Alerts

Default: ON

Fires when a newly funded company matches your ICP at 60% or above. The match score is included as userContext.icpMatch.

All Funding Alerts

Default: OFF

Fires for every new funding announcement, not just your ICP matches. For these, userContext.icpMatch is null.

Headers & delivery

Each event is delivered as a single JSON POST with these headers:

Request
POST https://your-domain.com/webhook
Content-Type: application/json
User-Agent: Fundup-AI-Webhook/1.0
Authorization: Bearer YOUR_WEBHOOK_AUTH_KEY

Delivery behavior

  • Success = any 2xx response (200, 201, or 202). Anything else is treated as a failed delivery.
  • Timeout: Fundup AI waits up to 10 seconds for a response, so acknowledge quickly and process asynchronously.
  • Deduplicated: each funding event is delivered to you at most once. Still, key off trigger.id on your side to stay idempotent.
  • Real time: events are sent shortly after a new round is detected, evaluated against recent funding activity.

Payload

Every event uses the trigger_published envelope. Here is a full funding example:

POST body: application/json
{
  "event": "trigger_published",
  "timestamp": "2026-05-12T09:31:00Z",
  "trigger": {
    "id": "trigger_789",
    "type": "funding",
    "subtype": "Series A",
    "publishedAt": "2026-05-12T00:00:00Z",
    "evidence": {
      "fundingId": "funding_456",
      "amount": "$15M",
      "amountNumeric": 15000000,
      "amountUsd": 15000000,
      "currency": "USD",
      "stage": "Series A",
      "announceDate": "2026-05-12T00:00:00",
      "investors": [
        { "name": "Sequoia Capital", "type": "lead" },
        { "name": "Andreessen Horowitz", "type": "participant" }
      ]
    }
  },
  "company": {
    "id": "company_123",
    "name": "Sample Tech Corp",
    "logo": "https://static.fundup.ai/logos/company_123.png",
    "country": "United States",
    "industry": "Fintech",
    "description": "AI-powered payments infrastructure for SMBs.",
    "tags": [ { "name": "SaaS", "slug": "saas" } ],
    "websiteUrl": "https://example.com",
    "techStack": ["React", "Postgres"],
    "techStackCategories": ["Frontend", "Database"]
  },
  "allTriggers": [
    {
      "id": "trigger_789",
      "type": "funding",
      "subtype": "Series A",
      "publishedAt": "2026-05-12T00:00:00Z"
    }
  ],
  "userContext": {
    "icpMatch": 87,
    "userNote": "",
    "trackingStatus": null
  }
}

Field reference

Field Type Description
eventstringAlways trigger_published.
timestampstringISO-8601 UTC time the event was sent.
trigger.idstringUnique trigger id, use it to deduplicate.
trigger.typestringSignal type, e.g. funding.
trigger.subtypestring | nullFor funding, the stage (e.g. Series A).
trigger.evidenceobjectSignal detail. For funding: fundingId, amount, amountUsd, currency, stage, announceDate, investors[].
companyobjectCompany summary: id, name, country, industry, tags, websiteUrl, techStack.
allTriggersarrayAll currently active triggers for this company.
userContext.icpMatchnumber | nullICP score 0–100 for ICP alerts; null for All Funding alerts.
userContext.trackingStatusstring | nullYour saved status for the company, if any.

The company.id and trigger.evidence.fundingId are the keys you pass to the REST API (e.g. GET /companies/{id} or /companies/{id}/contacts) to pull deeper detail on demand.

Verifying requests

If you set an authentication key, every request carries it as a bearer token. Reject anything that doesn't match, compare with a constant-time check.

Node / Express
app.post("/webhook", (req, res) => {
  const auth = req.get("Authorization") || "";
  const expected = `Bearer ${process.env.FUNDUP_WEBHOOK_KEY}`;
  if (auth.length !== expected.length ||
      !crypto.timingSafeEqual(Buffer.from(auth), Buffer.from(expected))) {
    return res.sendStatus(401);
  }

  res.sendStatus(200);              // acknowledge fast (10s timeout)

  const { event, company, trigger, userContext } = req.body;
  // enqueue for async processing, then call the REST API for deeper detail:
  //   GET /api/v1/companies/{company.id}
  //   GET /api/v1/companies/{company.id}/contacts
});

Best practices

  • Respond 2xx immediately, then process asynchronously. You have a 10-second window.
  • Verify the bearer token on every request and serve your endpoint over HTTPS.
  • Deduplicate on trigger.id so a re-delivery never double-processes.
  • Fetch detail on demand: use the webhook to know what changed, then call the API only for the companies you care about.