Fourbyfour
WorkflowsUse CasesDocs
Get Started
PricingWorkflowsDocsAboutBlogCareerSupportDiscordPrivacyTerms

© 2026 Occupy Mars Private Limited. All rights reserved.

Getting Started

SDK

Platform

DocsIntroduction

Revenue workflows on autopilot

Track events. We handle the rest. Pre-built workflows recover payments, convert trials, and re-engage users, optimized across thousands of companies.

How it works

1

Track events

Call fbf.track() when things happen

2

Workflows trigger

Pre-built workflows match your events

3

Users notified

Right message, right channel, right time

4

Revenue recovered

Payments saved, trials converted, users retained

Pick your vertical

Each vertical has pre-built workflows optimized for your industry. Pick yours to see relevant events and examples.

SaaS

Subscription recovery, trial conversion, upsells

payment.failedtrial.started+2trial.ending+1 more

E-commerce

Cart recovery, order updates, reviews

cart.abandonedorder.placed+2order.delivered+1 more

Fintech

Payment reminders, KYC completion, reactivation

payment.duetransaction.failed+2kyc.incomplete+1 more

EdTech

Course engagement, streak recovery, certificates

course.enrolledcourse.abandoned+2streak.broken+1 more

Games

Player win-back, IAP prompts, achievements

player.inactivecurrency.low+2level.completed+1 more

Apps

Trial conversion, subscription recovery, reviews

trial.startedtrial.ending+2subscription.canceled+1 more

Installation

Install the SDK and initialize for your vertical.

Select your vertical

1. Install the SDK

1npm install @fourbyfour/sdk
TypeScript
Ln 1UTF-8

2. Initialize for your vertical

123456import { saas } from '@fourbyfour/sdk'; const fbf = saas({  apiKey: process.env.FOURBYFOUR_API_KEY,  projectId: process.env.FOURBYFOUR_PROJECT_ID});
TypeScript
Ln 6UTF-8

Get your API key from the dashboard. Each vertical gives you typed events and pre-built workflows optimized for your industry.

Quick Start

Two functions. That's all you need.

Select your vertical

fbf.track()

→ triggers Payment Recovery workflow
123456789// Payment failed → triggers recovery workflowawait fbf.track('payment.failed', {  userId: 'u_123',  amount: 99,  currency: 'USD',  plan: 'Pro',  subscriptionId: 'sub_456',  billingCycle: 'monthly'});
TypeScript
Ln 9UTF-8

fbf.notify()

→ helps us optimize delivery
1234567// Send context to help optimize deliveryawait fbf.notify({  userId: 'u_123',  timezone: 'America/New_York',  preferredChannel: 'email',  tier: 'premium'});
TypeScript
Ln 7UTF-8

What happens next?

When you call track('payment.failed'), our Payment Recovery workflow kicks in automatically. We handle timing, channel selection, message optimization, all tuned from patterns across thousands of companies.

AI Integration Generator

Answer a few questions about your stack and we'll generate a step-by-step integration guide that you can feed to your AI coding assistant (Claude Code, Cursor, Copilot, etc.).

What's your tech stack?

We'll generate code examples in your language.

How to use the generated guide:

  1. Complete the wizard above to generate your integration guide
  2. Copy the guide or download as a markdown file
  3. Open your AI coding assistant (Claude Code, Cursor, etc.)
  4. Paste the guide and ask it to "implement this integration"
  5. Replace YOUR_PROJECT_ID and YOUR_API_KEY with your actual values from the dashboard
  6. Review the changes and commit

Two Functions

Two functions. No PII. That's the entire SDK.

Select your vertical

fbf.track(event, payload)

Events that trigger workflows

1234567891011121314151617181920212223import { saas } from '@fourbyfour/sdk'; const fbf = saas({  apiKey: process.env.FOURBYFOUR_API_KEY,  projectId: process.env.FOURBYFOUR_PROJECT_ID}); // Minimum: just userId (we use defaults)await fbf.track('payment.failed', {  userId: 'u_123'}); // Full: everything you know (better optimization)await fbf.track('payment.failed', {  userId: 'u_123',  amount: 99,  currency: 'USD',  plan: 'Pro',  subscriptionId: 'sub_456',  billingCycle: 'monthly',  failureReason: 'card_declined',  attemptNumber: 1});
TypeScript
Ln 23UTF-8
fbf.notify(context)

Context that helps us optimize

12345678910// Send context anytime to help us optimize deliveryawait fbf.notify({  userId: 'u_123',  timezone: 'Asia/Kolkata',      // When to reach them  tier: 'premium',               // Priority signals  preferredChannel: 'whatsapp',  // Channel preference  language: 'en',                // Localization  ltv: 500,                      // Value signals  converted: true                // Feedback after conversion});
TypeScript
Ln 10UTF-8

Data Philosophy

Minimum (just userId)

Works out of the box. We use intelligent defaults optimized across thousands of companies.

123await fbf.track('payment.failed', {  userId: 'u_123'});
TypeScript
Ln 3UTF-8

Full (everything you know)

Better optimization. More context = smarter timing, channels, and messaging.

123456await fbf.track('payment.failed', {  userId: 'u_123',  amount: 99,  plan: 'Pro',  // ... everything helps});
TypeScript
Ln 6UTF-8

The key: Send what you have, when you have it. No need to block on missing fields. We fill gaps with smart defaults, then improve as you send more.

What Goes Where

trackNo PII

Business events: amount, plan, cartTotal

notifyNo PII

User context: timezone, tier, preferences

resolverTransient

Delivery info: email, phone, name

FunctionData TypeExamplePII?
trackBusiness eventsamount, plan, cartTotalNo
notifyUser contexttimezone, tier, preferencesNo
resolverDelivery infoemail, phone, nameYes (transient)

Notice: PII only flows through your resolver endpoint, fetched just-in-time, used for delivery, never stored. See the Resolver section.

Resolver

Just-in-time PII. Your data stays in your system until the moment of delivery.

How It Works

1

Workflow triggers

User event matches a workflow

2

We call your resolver

Request only needed fields

3

You return PII

Email, phone, name: what's needed

4

We deliver & discard

Used for send, never stored

Request & Response

We send:

{}JSON
1234567891011POST /api/fourbyfour/resolveHeaders:  x-fbf-signature: sha256=... Body:{  "userId": "u_123",  "fields": ["email", "name"],  "workflowId": "payment-recovery",  "channel": "email"}
JSON
Ln 11UTF-8

You respond:

{}JSON
123456789101112HTTP 200 OK {  "email": "user@example.com",  "name": "John"} // Or if user not found:HTTP 404 Not Found{  "error": "User not found"}
JSON
Ln 12UTF-8

Implementation

12345678910111213141516171819202122232425// Express / Next.js API routeapp.post('/api/fourbyfour/resolve', async(req, res) => {  // Verify the request is from Fourbyfour  const signature = req.headers['x-fbf-signature'];  if(!verifySignature(signature, req.body, process.env.FBF_WEBHOOK_SECRET)) {    return res.status(401).json({ error: 'Invalid signature' });  }   const { userId, fields, workflowId, channel } = req.body;   // Fetch user from your database  const user = await db.users.findById(userId);  if(!user) {    return res.status(404).json({ error: 'User not found' });  }   // Return only requested fields  const response: Record<string, string> = {};   if(fields.includes('email')) response.email = user.email;  if(fields.includes('name')) response.name = user.firstName;  if(fields.includes('phone')) response.phone = user.phone;   res.json(response);});
TypeScript
Ln 25UTF-8

Fields by Channel

Email
email+ name
SMS
phone+ name
WhatsApp
phone+ name
Push
pushToken+ name, device
ChannelRequiredOptional
Emailemailname
SMSphonename
WhatsAppphonename
PushpushTokenname, device

Why This Architecture

Privacy by Design

  • • PII never leaves your system until needed
  • • We request only what the channel requires
  • • Data used for delivery, then discarded

Always Fresh

  • • No stale emails or phones
  • • User updates their info? Next send has it
  • • User deletes account? Returns 404, we skip

You Stay in Control

  • • Return only what you want to share
  • • Add business logic (block certain users)
  • • GDPR compliant by default

Workflows

63 pre-built workflows optimized across thousands of companies. Just track the event. We handle timing, channels, and messaging.

SaaS: Convert trials based on how they're using the product

How it works

1

Track event

Call fbf.track()

2

Workflow triggers

Matches your event

3

We optimize

Timing, channel, message

4

Revenue recovered

Payments, trials, users

View all SaaS events and examples

Channels

We deliver via the optimal channel. You just provide the resolver endpoint. We handle the rest.

Email

Best for: detailed info, rich content

email

SMS

Best for: urgent, time-sensitive

phone

WhatsApp

Best for: conversational, global

phone

Push

Best for: real-time, mobile

pushToken

How We Select Channels

1

User Preference

If you sent preferredChannel via notify(), we start there.

2

Context Analysis

We consider timezone, urgency, past engagement, and message type.

3

Cross-org Learning

We know "users in this segment convert 2x better via WhatsApp".

What We Optimize

Timing→ Send at 10am local

User's timezone is IST

Channel→ Use SMS over email

Past engagement higher on SMS

Frequency→ Wait before next

User received message yesterday

Urgency→ Escalate to SMS

Payment fails in 24h

SignalExampleImpact
TimingUser's timezone is ISTSend at 10am local time
ChannelPast engagement higher on SMSUse SMS over email
FrequencyUser received message yesterdayWait before next touch
UrgencyPayment fails in 24hEscalate to SMS

Automatic Fallbacks

If a channel fails or isn't available, we automatically try the next best option:

Email fails→Try SMS→Try Push