> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fyatu.com/llms.txt
> Use this file to discover all available pages before exploring further.

# SaaS Companies

> Accept subscription payments from African customers for your SaaS product with Fyatu's payment collection API.

Unlock the African market for your SaaS product. FYATU enables you to accept subscription payments via local payment methods that your African customers actually use.

## The Challenge

SaaS companies targeting African markets encounter:

* **Low card penetration** - Most potential customers don't have international cards
* **Payment failures** - African cards often declined by international processors
* **Currency issues** - Customers prefer paying in local currencies
* **Churn from payment failures** - Involuntary churn due to payment method issues
* **Complex billing** - Managing subscriptions across different payment methods

## The FYATU Solution

<CardGroup cols={2}>
  <Card title="Fyatu Payments" icon="wallet">
    Accept payments from 1M+ Fyatu users paying from their wallets
  </Card>

  <Card title="Subscription Billing" icon="repeat">
    Recurring payment support with retry logic
  </Card>

  <Card title="Multi-Currency" icon="coins">
    Price in local currencies, receive USD
  </Card>

  <Card title="Payouts" icon="money-bill-wave">
    Pay African affiliates and partners to their Fyatu wallets
  </Card>
</CardGroup>

## Subscription Integration

### Create Subscription Payment

```javascript theme={null}
// New subscription signup
async function createSubscription(user, plan) {
  const subscription = await Subscription.create({
    userId: user.id,
    planId: plan.id,
    amount: plan.price,
    currency: 'USD',
    interval: plan.interval, // monthly, yearly
    status: 'pending_payment'
  });

  // Create payment for first billing cycle
  const collection = await fyatu.collections.create({
    amount: plan.price,
    currency: 'USD',
    reference: `SUB-${subscription.id}-1`,
    description: `${plan.name} - ${plan.interval} subscription`,
    customer: {
      email: user.email,
      name: user.fullName,
      externalId: user.id
    },
    metadata: {
      subscriptionId: subscription.id,
      planId: plan.id,
      billingCycle: 1,
      type: 'subscription'
    },
    redirectUrl: `https://app.yoursaas.com/subscription/activated`,
    webhookUrl: 'https://api.yoursaas.com/webhooks/fyatu'
  });

  return {
    subscription,
    checkoutUrl: collection.checkoutUrl
  };
}
```

### Handle Subscription Activation

```javascript theme={null}
app.post('/webhooks/fyatu', async (req, res) => {
  const event = req.body;

  if (event.type === 'collection.completed') {
    const { subscriptionId, billingCycle } = event.data.metadata;

    if (subscriptionId) {
      const subscription = await Subscription.findById(subscriptionId);

      if (billingCycle === 1) {
        // First payment - activate subscription
        subscription.status = 'active';
        subscription.activatedAt = new Date();
        subscription.currentPeriodStart = new Date();
        subscription.currentPeriodEnd = calculatePeriodEnd(subscription.interval);

        // Grant access
        await grantPlanAccess(subscription.userId, subscription.planId);

        // Send welcome email
        await sendWelcomeEmail(subscription.userId);
      } else {
        // Renewal payment
        subscription.currentPeriodStart = new Date();
        subscription.currentPeriodEnd = calculatePeriodEnd(subscription.interval);

        // Extend access
        await extendAccess(subscription.userId, subscription.currentPeriodEnd);
      }

      subscription.lastPaymentAt = new Date();
      subscription.lastPaymentId = event.data.id;
      await subscription.save();
    }
  }

  res.status(200).send('OK');
});
```

### Renewal Reminders

```javascript theme={null}
// Daily job: send renewal reminders
async function sendRenewalReminders() {
  const expiringIn3Days = await Subscription.findAll({
    where: {
      status: 'active',
      currentPeriodEnd: {
        [Op.between]: [
          addDays(new Date(), 2),
          addDays(new Date(), 3)
        ]
      }
    }
  });

  for (const subscription of expiringIn3Days) {
    const user = await User.findById(subscription.userId);
    const plan = await Plan.findById(subscription.planId);

    // Create renewal payment link
    const collection = await fyatu.collections.create({
      amount: plan.price,
      currency: 'USD',
      reference: `SUB-${subscription.id}-${subscription.billingCycle + 1}`,
      description: `${plan.name} renewal`,
      customer: { email: user.email },
      metadata: {
        subscriptionId: subscription.id,
        billingCycle: subscription.billingCycle + 1,
        type: 'subscription_renewal'
      },
      expiresAt: subscription.currentPeriodEnd.toISOString()
    });

    // Send reminder email with payment link
    await sendRenewalReminder(user.email, {
      planName: plan.name,
      amount: plan.price,
      renewalDate: subscription.currentPeriodEnd,
      paymentLink: collection.checkoutUrl
    });
  }
}
```

### Handle Expired Subscriptions

```javascript theme={null}
// Daily job: handle expired subscriptions
async function handleExpiredSubscriptions() {
  const expiredSubscriptions = await Subscription.findAll({
    where: {
      status: 'active',
      currentPeriodEnd: { [Op.lt]: new Date() }
    }
  });

  for (const subscription of expiredSubscriptions) {
    // Grace period: 3 days
    const gracePeriodEnd = addDays(subscription.currentPeriodEnd, 3);

    if (new Date() > gracePeriodEnd) {
      // Suspend access
      subscription.status = 'past_due';
      await subscription.save();

      await revokeAccess(subscription.userId);
      await sendSubscriptionExpiredEmail(subscription.userId);
    }
  }
}
```

## Pricing Tiers

Offer different pricing for African markets:

```javascript theme={null}
const plans = {
  starter: {
    name: 'Starter',
    prices: {
      USD: 29,
      KES: 3500,  // ~20% discount
      NGN: 35000, // ~20% discount
      CDF: 70000  // ~20% discount
    }
  },
  professional: {
    name: 'Professional',
    prices: {
      USD: 99,
      KES: 12000,
      NGN: 120000,
      CDF: 240000
    }
  },
  enterprise: {
    name: 'Enterprise',
    prices: {
      USD: 299,
      KES: 35000,
      NGN: 350000,
      CDF: 700000
    }
  }
};

// Get price for user's region
function getPriceForUser(plan, userCurrency) {
  return plans[plan].prices[userCurrency] || plans[plan].prices.USD;
}
```

## One-Time Purchases

For lifetime deals or add-ons:

```javascript theme={null}
// Sell lifetime license
async function purchaseLifetimeLicense(user, product) {
  const collection = await fyatu.collections.create({
    amount: product.price,
    currency: 'USD',
    reference: `LTD-${user.id}-${product.id}`,
    description: `${product.name} - Lifetime License`,
    customer: {
      email: user.email,
      externalId: user.id
    },
    metadata: {
      productId: product.id,
      type: 'lifetime_deal'
    }
  });

  return collection.checkoutUrl;
}

// Purchase add-on
async function purchaseAddon(user, subscription, addon) {
  const collection = await fyatu.collections.create({
    amount: addon.price,
    currency: 'USD',
    reference: `ADDON-${subscription.id}-${addon.id}`,
    description: `Add-on: ${addon.name}`,
    customer: { email: user.email },
    metadata: {
      subscriptionId: subscription.id,
      addonId: addon.id,
      type: 'addon'
    }
  });

  return collection.checkoutUrl;
}
```

## Refunds

Handle subscription refunds:

```javascript theme={null}
async function refundSubscription(subscriptionId, reason) {
  const subscription = await Subscription.findById(subscriptionId);
  const lastPayment = await Payment.findById(subscription.lastPaymentId);

  // Calculate prorated refund
  const daysUsed = daysBetween(subscription.currentPeriodStart, new Date());
  const totalDays = daysBetween(subscription.currentPeriodStart, subscription.currentPeriodEnd);
  const refundAmount = lastPayment.amount * (1 - daysUsed / totalDays);

  const refund = await fyatu.refunds.create(lastPayment.collectionId, {
    amount: Math.round(refundAmount * 100) / 100,
    reason: reason,
    reference: `REF-${subscriptionId}-${Date.now()}`
  });

  // Cancel subscription
  subscription.status = 'cancelled';
  subscription.cancelledAt = new Date();
  await subscription.save();

  // Revoke access
  await revokeAccess(subscription.userId);

  return refund;
}
```

## Affiliate Payouts

Pay African affiliates for referrals:

```javascript theme={null}
// Monthly affiliate payout
async function processAffiliatePayouts() {
  const affiliates = await Affiliate.findAll({
    where: { pendingPayout: { [Op.gt]: 0 } }
  });

  for (const affiliate of affiliates) {
    if (affiliate.pendingPayout >= 50) { // Minimum payout
      try {
        const payout = await fyatu.payouts.create({
          amount: affiliate.pendingPayout,
          currency: 'USD',
          reference: `AFF-${affiliate.id}-${Date.now()}`,
          description: 'Affiliate commission payout',
          recipient: {
            accountId: affiliate.fyatuAccountId
          },
          metadata: {
            affiliateId: affiliate.id,
            referralCount: affiliate.monthlyReferrals
          }
        });

        affiliate.pendingPayout = 0;
        affiliate.lastPayoutAt = new Date();
        affiliate.lastPayoutId = payout.id;
        await affiliate.save();
      } catch (error) {
        console.error(`Affiliate payout failed: ${affiliate.id}`, error);
      }
    }
  }
}
```

## Why Fyatu for SaaS?

| Benefit               | Description                                      |
| --------------------- | ------------------------------------------------ |
| **1M+ Users**         | Access Fyatu's growing user base across Africa   |
| **Instant Payments**  | Customers pay from their Fyatu wallet in seconds |
| **No Failed Cards**   | Wallet payments don't fail like card payments    |
| **Reduced Churn**     | Reliable payments reduce involuntary churn       |
| **Affiliate Payouts** | Pay affiliates directly to their Fyatu wallets   |

Fyatu users can fund their wallets using various local payment methods, giving your SaaS access to African customers without managing multiple payment integrations.

## Best Practices

### 1. Promote Fyatu as a Payment Option

Highlight Fyatu as a reliable payment method for your African customers. Users can fund their Fyatu wallet using their preferred local payment method and pay you seamlessly.

### 2. Send Payment Reminders

* 7 days before renewal
* 3 days before renewal
* Day of renewal
* After grace period expires

### 3. Reduce Involuntary Churn

* Multiple payment attempts
* Grace periods for expired subscriptions
* Clear renewal payment links
* Easy account management

## Getting Started

<Steps>
  <Step title="Sign Up">
    Create a [FYATU business account](https://web.fyatu.com)
  </Step>

  <Step title="Configure Collection App">
    Set up your app for subscription payments
  </Step>

  <Step title="Integrate">
    Add FYATU to your subscription flow
  </Step>

  <Step title="Test">
    Test subscription and renewal flows
  </Step>

  <Step title="Launch">
    Start accepting payments from African customers
  </Step>
</Steps>

## Resources

* [Collections API](/v3/api-reference/collections/create)
* [Refunds API](/v3/api-reference/refunds/create)
* [Payouts API](/v3/api-reference/payouts/create)
* [Webhooks Guide](/v3/concepts/webhooks)
