purchase, upgrade, signup, churn, or any other product event in Amplitude, you can pipe those events into Greenflash with one destination — no SDKs, no app code. Conversation analyses immediately get a downstream-outcome layer: which conversations led to revenue, which led to refunds, which churned silently.
How it works
Amplitude has built-in Event Streaming destinations that POST the Amplitude HTTP V2 batch format ({ events: [...] }) to a URL of your choice. Greenflash gives you a per-product URL to point it at. The flow:
- Your app sends an event to Amplitude (
amplitude.track('purchase', { revenue: 49 })or equivalent). - Amplitude evaluates your destination’s event filters and decides whether to forward.
- Amplitude POSTs a batch of events (up to 1,000) to your Greenflash URL.
- Greenflash authenticates the URL token, maps each event in the batch to a Greenflash business event, infers positive / negative / neutral influence, and attaches it to the product you connected.
- The next conversation analysis Greenflash runs has those events as outcome context.
Before you start
- A Greenflash product to enrich with Amplitude events. Create one under Settings → Products if you don’t have one.
- Amplitude org admin or destination admin access so you can create an event streaming destination.
- (Optional) A list of the events worth forwarding. Forwarding everything works but is rarely what you want — page views and exposure events are noise for Greenflash.
Setup
1. Create the connection in Greenflash
- Open Settings → Connect → Events in the Greenflash web app.
- Click Connect on the Amplitude card.
- Pick the product the stream should feed and click Create source.
- Copy the destination URL. Greenflash shows it once. If you lose it, rotate the token from the connection row and update Amplitude.
2. Add the destination in Amplitude
- In Amplitude, open Data → Destinations and click Add Destination.
- Choose Event Stream (HTTP API destination) — the one that posts JSON over HTTP.
- Set the destination URL to the Greenflash URL. Use
POSTandContent-Type: application/json. - Under the destination’s Event filters, select which events should stream. Allow only your business events (signup, activate, purchase, subscribe, refund, cancel) — Amplitude defaults to forwarding everything, so this is where you control volume and quality.
- Save the destination. The connection row in Greenflash flips to Active on the first event.
Greenflash ignores the
api_key in Amplitude’s request body — your URL token is the only auth. You can leave Amplitude’s destination key field empty or set it to any placeholder.3. Send a test event
Trigger a real event from your app, replay one from Amplitude’s destination logs, or post the HTTP V2 batch shape directly to confirm the round trip:received is 0, the payload didn’t match the HTTP V2 shape — check that you’re using { events: [...] } with each event containing event_type.
How events are mapped
Greenflash applies these defaults to every Amplitude event:| Amplitude field | Greenflash field |
|---|---|
event_type | eventType |
user_id (falls back to device_id) | externalUserId |
time (ms since epoch) | eventAt |
insert_id | insertId (prefixed amplitude:) — used for idempotency |
revenue (or price * quantity if no revenue) | value (with valueType: currency) |
event_properties + revenue fields (revenue, price, quantity, revenueType) | properties |
Identity hints (used for user & organization attribution)
Greenflash reads a handful of fields fromuser_properties and groups to attach the event to the right user and organization. Sending these means Greenflash can auto-create the user / org if it hasn’t seen them yet, instead of leaving the event unattached.
| Amplitude field | Greenflash field |
|---|---|
user_properties.email | userHints.email |
user_properties.first_name + user_properties.last_name (or user_properties.name) | userHints.name |
groups.organization or groups.company (or user_properties.organization_id) | externalOrganizationId |
user_properties.organization_name (or user_properties.company) | organizationHints.name |
Attribution: how events tie to users, orgs, and conversations
Users. Events match an existing Greenflash user byexternalUserId first, then by email. If no match exists and the event carries an email, Greenflash upserts a new user automatically using the user_properties above. Anonymous events (no email) keep userId = null rather than creating a row per device.
Organizations. Same idea, scoped to externalOrganizationId. Org upsert only runs when groups.organization (or equivalent) is present — never by name.
Conversations. Add gf_conversation_id to event_properties to attach the event to a specific Greenflash conversation. Otherwise, the event auto-attaches to the user’s most-recent conversation in this product within the last 15 minutes; if that doesn’t match, conversationId stays null.
Users and orgs auto-created from analytics carryproperties.created_from = 'analytics'andproperties.source = 'amplitude'. When you later identify them via the Greenflash SDK using the sameexternalUserId, the existing row is reused.
Influence (positive / negative / neutral)
- Positive when
revenue > 0(orprice * quantity > 0), or the event name matchessignup,signed_up,upgrade,purchase,subscribe,convert,activate,complete, ororder_completed. - Negative when
revenue < 0(Amplitude’s refund convention), or the event name matcheschurn,cancel,unsubscribe,refund,downgrade,delete,failed, orerror. - Neutral otherwise.
snake_case, kebab-case, PascalCase, and Title Case With Spaces.
Override the defaults
Add any of these magic properties inside the event’sevent_properties and Greenflash will respect them — no Greenflash-side configuration needed.
| Property | Effect |
|---|---|
gf_event_type | Override the Greenflash event name (the original Amplitude name stays in properties) |
gf_influence | Force positive, negative, or neutral |
gf_quality_impact_score | Numeric override from -1.0 to 1.0 — fine-grained weight |
gf_value | Override the event value (string or number) |
gf_value_type | One of currency, numeric, text, boolean |
gf_conversation_id | Attach this event to a specific Greenflash conversation (externalConversationId) |
Filtering: what to forward
Filter on the Amplitude side, not inside Greenflash. Amplitude’s destination Event filter is more expressive than anything we’d reasonably build — property comparisons, segment-style conditions, transformations. We deliberately don’t expose a denylist UI inside Greenflash: the only Greenflash-side knob is the magic-property overrides above, applied per event inevent_properties.
The fewer noisy events you forward, the sharper your Greenflash analyses get. Use Amplitude’s destination filter to allow only the events that represent real outcomes (signup, activate, purchase, subscribe, refund, cancel) — Amplitude defaults to forwarding everything, which usually isn’t what you want.
SaaS conversion funnel
SaaS conversion funnel
Forward
signup, trial_started, activated, subscription_started, subscription_upgraded, subscription_cancelled. Greenflash infers influence from these names automatically.E-commerce
E-commerce
Forward
purchase and refund (or your equivalents). Always include the top-level revenue field so Greenflash can dollar-weight outcomes per conversation. Use a negative revenue with revenueType: "Refund" for refunds.Product-led growth
Product-led growth
Forward activation milestones (
workspace_created, integration_connected, aha_moment_reached). Add gf_influence: 'positive' if the event name doesn’t already match Greenflash’s defaults.Hard-mute a stream temporarily
Hard-mute a stream temporarily
Don’t want to edit Amplitude’s filters for a short outage or experiment? Pause the connection from its row in Settings → Connect → Events. The Greenflash receiver returns
204 while paused so Amplitude stops retrying. Re-enable to resume — no token rotation, no Amplitude change.Response codes & limits
| Code | Meaning |
|---|---|
200 | Batch received and processed. Body includes received, accepted, dropped. |
204 | Connection is paused or disconnected in Greenflash. Returned deliberately so Amplitude stops retrying. |
400 | Payload didn’t match the Amplitude HTTP V2 schema, or JSON was invalid. |
401 | URL token is invalid, the connection has been rotated, or the optional shared secret header is missing / wrong. |
404 | Provider segment of the URL is wrong (e.g. you pointed Amplitude at the /posthog/ URL). |
413 | More than 1,000 events in a single batch. The whole batch is dropped — configure Amplitude to split larger batches. |
500 | Greenflash couldn’t look up the connection. Safe to retry. |
Security
The URL is path-authenticated: the token segment is generated per connection, stored only as ascrypt hash, and verified in constant time on every request. The api_key in Amplitude’s request body is ignored.
For defense in depth, you can configure a shared secret alongside the URL token. The secret is communicated to Greenflash on every request via a custom HTTP header — there’s no body field or query parameter.
- In Amplitude, open your destination and go to Custom Headers.
- Add a header with name
x-greenflash-secretand value<your-secret>(any string you pick, 8+ characters). - Provide the same secret to Greenflash on the connection so we can match it.
x-greenflash-secret header is missing or doesn’t match with 401.
Rotating the URL invalidates the previous token immediately. Events sent to the old URL return 401. Update the URL on the Amplitude destination to resume delivery.
Troubleshooting
Connection still says ''Awaiting first event''
Connection still says ''Awaiting first event''
- The destination is enabled and your events match its filter.
- The URL has no trailing slash.
- You’re using the Event Stream (HTTP API) destination type, not a managed integration that may transform the payload to a non-V2 shape.
- Check Amplitude’s destination logs for non-2xx responses to see what Greenflash returned.
Refunds aren't showing up as negative
Refunds aren't showing up as negative
Amplitude refunds use
revenueType: "Refund" with a negative revenue number. Make sure your destination’s payload includes the top-level revenue field — Greenflash reads it from there, not from event_properties.Getting 413 errors
Getting 413 errors
The batch contained more than 1,000 events. Greenflash drops the entire batch above that cap. Reduce the destination’s batch size in Amplitude.
Anonymous users showing as ''unknown''
Anonymous users showing as ''unknown''
Amplitude events without
user_id fall back to device_id for the Greenflash externalUserId. If neither is set, the event arrives unattributed. Make sure your destination forwards both fields.Lost the URL
Lost the URL
Open the Amplitude row under Settings → Connect → Events and click Rotate URL. The old token is invalidated immediately. Paste the new URL into the Amplitude destination.
Duplicate events
Duplicate events
Greenflash deduplicates on the
amplitude:<insert_id> insert id. Amplitude SDKs set insert_id automatically; if you’re posting events directly to the URL, include a stable insert_id per event.Next
How Greenflash uses events
What changes in your analyses once events start flowing.
Public Events API
Skip the webhook and post events directly if you want full control.

