FromlyDocumentation
Get started

Events

What Fromly records on a contact's timeline by itself, and what each event carries. Your own events, sent through the API, sit beside these with the names and properties you give them.

How events work

Every event belongs to one contact and lands on their timeline. A live flow can start from most of them: by name for the lifecycle events, or through a trigger of its own for tags and lists.

An event recorded while importing history (a CSV import, the first sync of an integration) carries backfilled: true. It shows on the timeline and never starts a flow, so connecting an integration does not email everyone it brings in.

To send your own, see the API reference.

Contact

user.signed_upSigned up

Recorded by: The Supabase integration, for each new user. Your own code can also send it through the API.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
providerstring`supabase` when the Supabase integration recorded it.
userIdstringThe id of the user in your Supabase project.
{
  "provider": "supabase",
  "userId": "8f14e45f-ceea-467a-9c3b-2f1a4e1b5c6d"
}

email.unsubscribedUnsubscribed

Recorded by: Fromly, when someone unsubscribes from every email, from the unsubscribe page or because their mailbox provider says they did.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
reasonstring, optionalWhy, as a short token (`hard-bounce`, `repeated-soft-bounce`, `spam-report`) or an admin's words.
broadcastIdstring, optionalThe broadcast whose link they used, when it was one.
{
  "by": "recipient",
  "broadcastId": "2b1c9d4e-7a3f-4c1e-9b8d-5f6a7e8c9d0a"
}

contact.resubscribedResubscribed

Recorded by: Fromly, when someone who unsubscribed subscribes again from the unsubscribe page. Only they can.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
fromstringThe status they left: `UNSUBSCRIBED`.
tostringThe status they are in now, usually `SUBSCRIBED`.
{
  "by": "recipient",
  "from": "UNSUBSCRIBED",
  "to": "SUBSCRIBED"
}

contact.bouncedEmail bounced

Recorded by: Fromly, when an address turns out not to exist, or failed three times in a row. Nothing is emailed to it any more.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
reasonstring, optionalWhy, as a short token (`hard-bounce`, `repeated-soft-bounce`, `spam-report`) or an admin's words.
messageIdstring, optionalThe email that bounced.
bounceSubTypestring, optionalThe kind of bounce, as the delivery report names it.
softBouncesnumber, optionalSoft bounces in a row, when that is the reason.
{
  "by": "ses",
  "reason": "hard-bounce",
  "messageId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "bounceSubType": "NoEmail"
}

contact.complainedReported spam

Recorded by: Fromly, when someone reports an email as spam. Nothing is emailed to them ever again.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
reasonstring, optionalWhy, as a short token (`hard-bounce`, `repeated-soft-bounce`, `spam-report`) or an admin's words.
messageIdstring, optionalThe email they reported.
complaintTypestring, optionalThe feedback type, when the mailbox provider sent one.
{
  "by": "ses",
  "reason": "spam-report",
  "messageId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "complaintType": "abuse"
}

contact.suppressedBlocked

Recorded by: Fromly, when an admin blocks an address from the dashboard or the API.

Starts a flow: Never: history only

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
reasonstring, optionalWhy, as a short token (`hard-bounce`, `repeated-soft-bounce`, `spam-report`) or an admin's words.
{
  "by": "admin",
  "reason": "Asked us by phone"
}

contact.restoredRestored

Recorded by: Fromly, when an admin unblocks an address or clears a bounce.

Starts a flow: Never: history only

PropertyTypeDescription
bystringWhat did it: `ses` (a delivery report), `recipient` (the person, from an email), `admin` (the dashboard), `api` (the API, SDK or MCP).
fromstringThe status that was lifted: `SUPPRESSED` or `BOUNCED`.
tostringThe status the contact is in now.
{
  "by": "admin",
  "from": "BOUNCED",
  "to": "SUBSCRIBED"
}

Billing

trial.startedStarted a trial

Recorded by: The Stripe integration.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
subscriptionIdstringThe Stripe subscription id.
customerIdstringThe Stripe customer id.
statusstringThe subscription status after the change, as Stripe names it.
mrrCentsnumberMonthly revenue after the change, in cents.
currencystringThree-letter currency code, lowercase.
planstringThe plan name.
previousStatusstring, optionalThe status before the change, when one was known.
previousMrrCentsnumber, optionalMonthly revenue before the change, in cents.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "subscriptionId": "sub_1Q2w3E",
  "customerId": "cus_9Kp2Lm",
  "status": "trialing",
  "mrrCents": 0,
  "currency": "usd",
  "plan": "Pro"
}

trial.endingTrial ending soon

Recorded by: Nothing yet: a flow listening for it never starts.

Starts a flow: Not yet: nothing records it

No properties.

trial.endedTrial ended

Recorded by: The Stripe integration.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
subscriptionIdstringThe Stripe subscription id.
customerIdstringThe Stripe customer id.
statusstringThe subscription status after the change, as Stripe names it.
mrrCentsnumberMonthly revenue after the change, in cents.
currencystringThree-letter currency code, lowercase.
planstringThe plan name.
previousStatusstring, optionalThe status before the change, when one was known.
previousMrrCentsnumber, optionalMonthly revenue before the change, in cents.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "subscriptionId": "sub_1Q2w3E",
  "customerId": "cus_9Kp2Lm",
  "status": "active",
  "mrrCents": 2900,
  "currency": "usd",
  "plan": "Pro",
  "previousStatus": "trialing",
  "previousMrrCents": 0
}

subscription.createdSubscribed

Recorded by: The Stripe integration.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
subscriptionIdstringThe Stripe subscription id.
customerIdstringThe Stripe customer id.
statusstringThe subscription status after the change, as Stripe names it.
mrrCentsnumberMonthly revenue after the change, in cents.
currencystringThree-letter currency code, lowercase.
planstringThe plan name.
previousStatusstring, optionalThe status before the change, when one was known.
previousMrrCentsnumber, optionalMonthly revenue before the change, in cents.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "subscriptionId": "sub_1Q2w3E",
  "customerId": "cus_9Kp2Lm",
  "status": "active",
  "mrrCents": 2900,
  "currency": "usd",
  "plan": "Pro"
}

subscription.updatedSubscription changed

Recorded by: The Stripe integration, when the status, price, quantity or revenue changes.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
subscriptionIdstringThe Stripe subscription id.
customerIdstringThe Stripe customer id.
statusstringThe subscription status after the change, as Stripe names it.
mrrCentsnumberMonthly revenue after the change, in cents.
currencystringThree-letter currency code, lowercase.
planstringThe plan name.
previousStatusstring, optionalThe status before the change, when one was known.
previousMrrCentsnumber, optionalMonthly revenue before the change, in cents.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "subscriptionId": "sub_1Q2w3E",
  "customerId": "cus_9Kp2Lm",
  "status": "active",
  "mrrCents": 4900,
  "currency": "usd",
  "plan": "Team",
  "previousStatus": "active",
  "previousMrrCents": 2900
}

subscription.canceledCancelled

Recorded by: The Stripe integration.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
subscriptionIdstringThe Stripe subscription id.
customerIdstringThe Stripe customer id.
statusstringThe subscription status after the change, as Stripe names it.
mrrCentsnumberMonthly revenue after the change, in cents.
currencystringThree-letter currency code, lowercase.
planstringThe plan name.
previousStatusstring, optionalThe status before the change, when one was known.
previousMrrCentsnumber, optionalMonthly revenue before the change, in cents.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "subscriptionId": "sub_1Q2w3E",
  "customerId": "cus_9Kp2Lm",
  "status": "canceled",
  "mrrCents": 2900,
  "currency": "usd",
  "plan": "Pro",
  "previousStatus": "active",
  "previousMrrCents": 2900
}

payment.succeededPaid

Recorded by: The Stripe integration, for each paid invoice or charge.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
invoiceIdstring, optionalThe Stripe invoice id, for a subscription payment.
chargeIdstring, optionalThe Stripe charge id, for a payment found while importing history.
amountCentsnumberThe amount paid, in cents.
currencystringThree-letter currency code, lowercase.
attemptCountnumber, optionalHow many attempts the invoice took.
refundedboolean, optionalWhether the charge was refunded since.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "invoiceId": "in_1Q2w3E4r",
  "amountCents": 2900,
  "currency": "usd",
  "attemptCount": 1
}

payment.failedPayment failed

Recorded by: The Stripe integration, once per failed attempt.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
invoiceIdstringThe Stripe invoice id.
amountCentsnumberThe amount due, in cents.
currencystringThree-letter currency code, lowercase.
attemptCountnumberWhich attempt failed.
{
  "invoiceId": "in_1Q2w3E4r",
  "amountCents": 2900,
  "currency": "usd",
  "attemptCount": 2
}

Lists

list.addedAdded to a list

Recorded by: Fromly, when someone is put on a list: by the rule for new contacts, by hand, through the API or by a flow.

Starts a flow: Yes, through “When added to a list”

PropertyTypeDescription
listIdstringThe list id.
listNamestringThe list name when it happened.
bystringWhat did it: `auto` (the workspace rule for new contacts), `manual` (the dashboard), `api` (the API, SDK or MCP), `automation` (a flow step), `import` (a CSV import).
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "listId": "5d41402a-bc4b-4a76-b9c7-19a0e1b2c3d4",
  "listName": "Newsletter",
  "by": "auto"
}

list.subscribedJoined a list

Recorded by: Fromly, when someone puts themselves back on a list from the unsubscribe page.

Starts a flow: Yes, through “When added to a list”

PropertyTypeDescription
listIdstringThe list id.
listNamestringThe list name when it happened.
broadcastIdstring, optionalThe broadcast whose link they used.
{
  "listId": "5d41402a-bc4b-4a76-b9c7-19a0e1b2c3d4",
  "listName": "Newsletter"
}

list.unsubscribedLeft a list

Recorded by: Fromly, when someone leaves a list from the unsubscribe page or a mail client's unsubscribe button.

Starts a flow: Yes, as an event trigger

PropertyTypeDescription
listIdstringThe list id.
listNamestringThe list name when it happened.
broadcastIdstring, optionalThe broadcast whose link they used.
{
  "listId": "5d41402a-bc4b-4a76-b9c7-19a0e1b2c3d4",
  "listName": "Newsletter",
  "broadcastId": "2b1c9d4e-7a3f-4c1e-9b8d-5f6a7e8c9d0a"
}

list.removedRemoved from a list

Recorded by: Fromly, when someone is taken off a list by hand, through the API or by a flow.

Starts a flow: Never: history only

PropertyTypeDescription
listIdstringThe list id.
listNamestringThe list name when it happened.
bystringWhat did it: `auto` (the workspace rule for new contacts), `manual` (the dashboard), `api` (the API, SDK or MCP), `automation` (a flow step), `import` (a CSV import).
{
  "listId": "5d41402a-bc4b-4a76-b9c7-19a0e1b2c3d4",
  "listName": "Newsletter",
  "by": "manual"
}

Tags

tag.addedTagged

Recorded by: Fromly, when a tag is added by hand or through the API, and the Stripe integration for the billing tags. A tag added by a flow step records nothing, so flows cannot chain on tags.

Starts a flow: Yes, through “When a tag is added”

PropertyTypeDescription
tagstringThe tag key.
backfilledboolean, optionalTrue when the event was recorded while importing history (an import, a first sync). It shows on the timeline and never starts a flow.
{
  "tag": "beta-testers"
}