Skip to main content
Recipe n8n Workflows and automation

How do you send funding rounds detected by Rodz to an n8n workflow?

Peter Cools · Updated on · 5 min read · View as Markdown

Short answer

Create a Fundraising signal in Rodz and paste the URL of an n8n Webhook node as its webhookUrl. Every round detected arrives as a POST with the amount, stage, investors and company. A Code node verifies the HMAC signature, an IF node filters by amount, then n8n routes it to your CRM or Slack. There is no native Rodz node: everything goes through the webhook. A lead costs 2 credits.

Key facts

  • A funding round costs 2 credits per lead, plus 0.5 credit per email found and 5 credits per phone found, charged on success only.
  • Every delivery is signed with HMAC-SHA256 (X-Webhook-Signature, X-Webhook-Timestamp) and carries an X-Webhook-Id that stays the same across retries.
  • A delivery that fails transiently (timeout or 5xx) is retried with exponential backoff, so the same round can arrive twice.
  • Rodz identifies 400,000+ signals a month (July to September 2026 average).
Cost : 2 credits per lead (+0.5 credit per email found) Setup time : 20 min n8n connects through a Rodz webhook or the API (no native Rodz app)

Before you start

  • A Rodz account with credits (the test account includes 100) and an API key (Integrations → API), which carries the webhook secret.
  • An n8n instance reachable from the internet (n8n Cloud, or self-hosted over HTTPS).
  • Self-hosted: the environment variable NODE_FUNCTION_ALLOW_BUILTIN=crypto, so the Code node can load the crypto module.
  • Your criteria: round types (seed, series_a...), minimum amount, headquarters country, industries.

Steps

  1. Step 1. Create the Webhook node in n8n

    In a new workflow, add a Webhook node: method POST, respond Immediately (Rodz expects a fast 2xx). In the options, turn on Raw Body: the signature is computed over the exact bytes received, not over re-serialized JSON.

    Copy the node’s production URL (not the test URL, which only answers while you listen manually).

  2. Step 2. Create the Fundraising signal with that URL

    In Rodz, add the Fund Raising signal and paste the n8n URL in the webhook field, or create it through the API. To receive a decision-maker at the funded company (not only the company), turn on persona targeting: without it, contact is "".

    Keep the signal as a draft while you test.

    Create it through the API (draft status)

    curl -X POST "https://api.rodz.io/api/v1/signals/fundraising" \
      -H "Authorization: Bearer $RODZ_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "name": "Series A+ in France",
        "webhookUrl": "https://n8n.example.com/webhook/rodz-funding",
        "dailyLeadLimit": 50,
        "status": "draft",
        "config": {
          "investmentTypes": ["series_a", "series_b"],
          "amountMin": 2000000,
          "announcedPeriod": "30d",
          "hqLocations": ["France"],
          "enablePersonaTargeting": true,
          "targetPersonas": ["CEO", "Finance Director"],
          "getEmails": true
        }
      }'
  3. Step 3. Verify the signature in a Code node

    Add a Code node (JavaScript, Run Once for All Items) after the Webhook. It recomputes the HMAC-SHA256 of timestamp + "." + raw body with your webhook secret (Integrations → API in Rodz), compares it in constant time and rejects stale messages. Keep the secret in an n8n environment variable, not in the code.

    n8n Code node: verify-rodz-signature.js

    const crypto = require('crypto');
    
    const SECRET = $env.RODZ_WEBHOOK_SECRET; // Integrations → API in Rodz
    const TOLERANCE_SECONDS = 300;
    
    const item = $input.first();
    const headers = item.json.headers || {};
    const signature = headers['x-webhook-signature'] || '';
    const timestamp = headers['x-webhook-timestamp'] || '';
    
    // Body exactly as received (Webhook node, Raw Body option).
    const raw = await this.helpers.getBinaryDataBuffer(0, 'data');
    
    const expected = crypto
      .createHmac('sha256', SECRET)
      .update(Buffer.concat([Buffer.from(`${timestamp}.`, 'utf8'), raw]))
      .digest('hex');
    
    const a = Buffer.from(expected, 'utf8');
    const b = Buffer.from(signature, 'utf8');
    if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
      throw new Error('Rodz webhook: invalid signature');
    }
    if (Math.abs(Date.now() / 1000 - Number(timestamp)) > TOLERANCE_SECONDS) {
      throw new Error('Rodz webhook: timestamp outside tolerance');
    }
    
    const payload = JSON.parse(raw.toString('utf8'));
    return [{ json: { webhookId: headers['x-webhook-id'], ...payload } }];
  4. Step 4. Filter and route the round

    Add an IF node on {{ $json.signal.funding_amount_usd }} (for example greater than or equal to 5,000,000) and drop test messages (signal.is_test true). Then wire the node of your choice: your CRM, a Slack message with signal.article_summary and signal.article_use_of_funds, or a spreadsheet row.

    Retries reuse the same X-Webhook-Id: before writing to the CRM, skip a webhookId you already processed (for example with the Remove Duplicates node on that field, or a lookup in your database).

  5. Step 5. Test, then activate

    Activate the n8n workflow, then send a test lead from Rodz: POST /api/v1/signals/{signal_id}/test-webhook. The response gives the status code n8n returned and signed: false means no API key is linked to the signal, so deliveries go out unsigned and the Code node will reject them. When everything is green, set the signal to Active.

    Send a test payload

    curl -X POST "https://api.rodz.io/api/v1/signals/$SIGNAL_ID/test-webhook" \
      -H "Authorization: Bearer $RODZ_API_KEY"

Example payload

What the Webhook node receives for one round, with persona targeting on (without it, `contact` is `""`).

{
  "signal": {
    "id": "d4f5a6b7-c8d9-4e0f-a1b2-c3d4e5f6a7b8",
    "name": "Series A+ in France",
    "type": "fundraising",
    "last_signal": "Fundraising",
    "last_signal_date": "2026-10-09",
    "funding_type": "venture",
    "funding_stage": "Series A",
    "funding_amount": 6000000,
    "funding_amount_usd": 6500000,
    "funding_currency": "EUR",
    "investors": ["Example Ventures Fund", "Angel Investor"],
    "num_investors": 2,
    "funding_total_usd": 8200000,
    "announcement_date": "2026-10-08",
    "article_summary": "Northwind Robotics raised a EUR 6M Series A to expand across Europe.",
    "article_use_of_funds": "Hiring 20 engineers and opening Germany.",
    "article_source_url": "https://news.example.com/northwind-robotics-series-a"
  },
  "contact": {
    "lead_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "created_at": "2026-10-09T08:05:00+00:00",
    "first_name": "Claire",
    "last_name": "Martin",
    "email": "claire.martin@northwind-robotics.example",
    "phone": "",
    "title": "CEO",
    "location": "Nantes, Pays de la Loire, France",
    "country_code": "FR",
    "city": "Nantes",
    "linkedin_profile_url": "https://www.linkedin.com/in/claire-martin-example",
    "sales_navigator_profile_url": "",
    "matched_persona": "CEO"
  },
  "company": {
    "name": "Northwind Robotics",
    "website": "https://northwind-robotics.example",
    "linkedin_url": "https://www.linkedin.com/company/northwind-robotics-example",
    "industry": "Automation Machinery Manufacturing",
    "hq_country_code": "FR",
    "hq_city": "Nantes",
    "employee_range": "51-200"
  }
}

The fields that matter for routing a round

FieldContentUse in n8n
signal.funding_stageRound stage (Seed, Series A…)IF branches per stage
signal.funding_amount_usdAmount in US dollarsPriority threshold
signal.investorsList of investorsMention in the Slack message
signal.announcement_dateAnnouncement dateFreshness of the round
signal.article_summarySummary of the announcementSlack message or CRM note text
signal.article_use_of_fundsPlanned use of the moneyOutreach angle (hiring, expansion…)
contact.*Targeted decision-maker (with personas on)Contact creation
company.websiteCompany websiteAccount deduplication key

A typical workflow

  1. Webhook (POST, Raw Body, respond immediately).
  2. Code: signature check, then the lead JSON.
  3. IF: signal.is_test true → stop; funding_amount_usd below the threshold → a spreadsheet row only.
  4. Remove Duplicates on webhookId.
  5. CRM: look up the account by domain, create or update it, then the contact.
  6. Slack: a message to the territory rep with the summary and the use of funds.

If you need no custom logic, HubSpot and lemlist are native Rodz destinations: see funding rounds to HubSpot and funding rounds to lemlist.

Troubleshooting

  • The Code node rejects everything: check that Raw Body is on, that the secret belongs to the API key linked to the signal, and that the test reports signed: true.
  • require('crypto') is refused: self-hosted, add NODE_FUNCTION_ALLOW_BUILTIN=crypto to n8n’s environment.
  • Nothing arrives: the workflow must be active and the URL must be the Webhook node’s production URL.

Frequently asked questions

Is there a native Rodz node in n8n?

No. The integration goes through the signal’s webhook: Rodz POSTs every lead to your Webhook node URL. To read or create signals from n8n, use the HTTP Request node with the Rodz API and your key in an Authorization: Bearer header.

Why turn on Raw Body in the Webhook node?

The HMAC signature covers the exact bytes of the body received. If you recompute it over JSON that was parsed and re-serialized, key order or whitespace changes and the check fails.

What happens if n8n is down?

A timeout or a 5xx response triggers retries with exponential backoff. A 4xx response is treated as permanent and is not retried. After a long outage, POST /api/v1/signals/{signal_id}/replay-webhook resends every lead of the signal (signal.is_replay true).

How do I avoid duplicates in my CRM?

Deduplicate on the X-Webhook-Id header, which is the same on every attempt of one delivery. On the Rodz side, the signal’s duplicate handling also stops the same company from being delivered twice.

Which currency are the amounts in?

funding_amount is in the announced currency (funding_currency) and funding_amount_usd in US dollars. Filter on funding_amount_usd to compare rounds from different countries; the signal’s amountMin filter is in USD too.

Sources

Try it on your own market

Create an account: 100 free credits to test, no credit card.