Skip to main content

Custom Funnel / nGrow integration guide.

K
Written by Kirill Slobodianiuk
Updated over 2 months ago

This guide specifies how nGrow is expecting your custom built webfunnels to send user events to our webhook.

πŸ”§ General Requirements

  • Our server will respond with a 2xx HTTP status within 1 second after receiving a webhook request.
    ​
    ​

  • If no such response is received, the event is considered undelivered.
    ​
    ​

  • Undelivered events should be retried automatically using an exponential backoff strategy:
    ​
    ​

delay(n) = n⁴ + 15 + rand(0, 29) Γ— (n + 1)

Where:

  • delay β€” delay in seconds before the next retry
    ​
    ​

  • n β€” retry attempt number (starting from 1)
    ​
    ​

  • rand(0, 29) β€” a random integer between 0 and 29
    ​
    ​


🌐 Webhook Endpoint

URL:

Please use webhook url provided to you during nGrow app onboarding on 'Select Funnel Builder' page
​https://email-webhooks.ngrow.ai/api/v1/web2wave-webhook/<ngrow_app_id>.

Each webhook request contains a JSON payload depending on the event type.


πŸ“₯ Supported Event Types

Event Type

Description

profile.updated

Fired when a user updates their profile. Email is required to be present.

onboarding.completed

Fired when the user completes onboarding.

purchase.completed

Fired on initial purchase, upsell, or recurring transaction.

subscription.renewed

Fired when an existing subscription is renewed.


πŸ“Œ Common Required Fields (all events)

{
"type": "string", // Event name
"funnel_id": "string", // The current funnel or paywall id
"project_id": "string", // Any consistent project_id, associated with app
"created_at": 1734392768, // UNIX time in UTC timezone
"profile": {
"id": "string",
"country": "string", // 2-digit ISO code
"city": "string",
"locale": "string", // ISO (e.g. en-us)
"time_zone": "string" // e.g. America/New_York
}
}


πŸ” Event-Specific Payloads

1. profile.updated

Triggered when user properties change. Must be fired when the user submits their email.

Required additional field:

"data": {
"email": "[email protected]"
}

Example:

{
"type": "profile.updated",
"created_at": 1734392768,
"funnel_id": "fun_01...",
"project_id": "01HP...",
"profile": {
"id": "pro_01...",
"country": "US",
"city": "New York",
"locale": "en-US",
"time_zone": "America/New_York"
},
"data": {
"email": "[email protected]"
}
}


2. onboarding.completed

Triggered when the user finishes the onboarding funnel.

After the funnel is completed, we expect the onboarding.completed event. In addition to the common fields, it must contain the data.replies attribute β€” an array of objects describing the user’s answers.

Each object in data.replies includes:

  • screen.custom_id β€” optional (screen name or text)
    ​
    ​

  • screen.id β€” screen ID
    ​
    ​

  • screen.index β€” screen position in the funnel
    ​
    ​

  • element.custom_id β€” optional (question name or label)
    ​
    ​

  • element.id β€” question ID
    ​
    ​

  • element.type β€” Options (single/multi choice) or Input (free text)
    ​
    ​

  • state.value β€” answer ID or text. If multiple options selected, values are comma-separated
    ​
    ​

Example:

{
"type": "onboarding.completed",
"created_at": 1734388235,
"data": {
"replies": [
{
"screen": {
"custom_id": "q_triggers",
"id": "W5mtQrrW",
"index": 22
},
"element": {
"custom_id": "q_triggers",
"id": "W5mtQrrW",
"type": "Options"
},
"state": {
"value": "nrWU6, 2ndrm, gefCv, family-issues, not-enough-me-time-or-self-care"
}
}
]
}
}


3. purchase.completed

Triggered on any type of user purchase.

Required fields in data:

  • id, created_at, price, currency
    ​
    ​

  • vendor_product_id, vendor_profile_id, vendor_transaction_id
    ​
    ​

Example:

{
"type": "purchase.completed",
"created_at": 1734349469,
"data": {
"id": "tra_...",
"currency": "USD",
"price": 3000,
"vendor_product_id": "prod_...",
"vendor_transaction_id": "in_..."
}
}


4. subscription.renewed

Fired when the subscription is renewed by the payment provider.

Required fields in data:

  • starts_at, vendor, vendor_subscription_id, vendor_transaction_id
    ​
    ​

Example:

{
"type": "subscription.renewed",
"created_at": 1734349469,
"data": {
"starts_at": "2024-09-14T13:44:02Z",
"vendor": "stripe",
"vendor_subscription_id": "sub_...",
"vendor_transaction_id": "in_..."
}
}

Did this answer your question?