# Instant Card Top-Ups

This guide explains how to implement **Instant Card Top-Ups**, allowing your customers to fund their Solaris accounts immediately using external debit/credit cards or digital wallets (Google Pay/Apple Pay).

## Overview

### How it works

The **Instant Top-Up** feature is a collaboration between Solaris and [Stripe](https://stripe.com) (the Acquirer).

1. **Collection:** Stripe collects the card details and processes the payment in your frontend.
2. **Settlement:** Solaris credits the funds to the customer's account immediately upon successful authorization.
3. **Reconciliation:** The actual funds settle from Stripe to Solaris in a background cycle (typically T+2).


To implement this, you must integrate both the **Solaris API** (for account crediting) and the **Stripe SDK** (for payment processing).

### Product flow

The following sequence diagram illustrates the interaction between your App, Solaris, and Stripe.

Diagram: Top-Up product flow
## User journey

1. **Initiation:** The customer enters a Top-Up amount in your app.
2. **Validation (Client-Side):** Perform a soft validation in your UI to ensure the amount is within the [allowed limits](#limits-and-compliance).
3. **Creation:** You call Solaris `POST /topups`. Solaris performs hard validation and returns a Stripe `client_secret`.
4. **Payment:** You pass this secret to the Stripe SDK.
  * *Recommendation:* Use Stripe's **PaymentSheet** UI component for the best compliance and user experience.
5. **Authentication:** The customer authorizes the payment (including 3DS challenge if required).
6. **Execution:** Stripe confirms the payment to Solaris.
7. **Crediting:** Solaris instantly credits the customer's account.


Abandoned Sessions
**Critical Implementation Detail:**
If a customer starts a Top-Up but abandons the flow (e.g., closes the app during 3DS), the Top-Up remains in `ACCEPTED` status.

* **Impact:** This "pending" amount counts towards the customer's monthly Top-Up limit.
* **Action:** You **must** call the [Cancel Endpoint](#cancel-top-up) if the session is abandoned.


## Prerequisites

Before implementing Top-Ups, ensure you have:

1. **Onboarded Customers:** [Persons](/guides/get-started/digital-banking/onboard-person) with active accounts.
2. **Stripe Configuration:** Obtained your publishable keys from your Partner Manager.


### Apple Pay configuration

If you intend to offer Apple Pay, you must split the configuration between your Apple Developer account and Solaris:

1. **Merchant ID:** Register an Apple Merchant ID in your Apple Developer account. [See Stripe Documentation](https://stripe.com/docs/apple-pay?platform=ios#merchantid).
2. **Certificates:** Contact your Solaris Account Manager. Solaris manages the certificate exchange between your Merchant ID and the Solaris Stripe account.


## 1. Integrate Stripe SDK

You must implement the Stripe SDK in your mobile or web application to securely collect card data.

### Core concepts

* **PaymentIntent:** The object representing the transaction. Solaris creates this on Stripe's behalf.
* **PaymentSheet:** Stripe's pre-built UI component. It handles card collection, validation, and 3DS authentication automatically.
* **Billing Address:** You **must** pre-fill the billing address in the Stripe SDK using the customer's address stored in Solaris (`line1`, `postal_code`, `city`, `country`).


### SDK resources

Use the official Stripe documentation to install and configure the SDKs.

Web (Stripe.js)
* [Integration Guide](https://stripe.com/docs/payments/accept-a-payment?platform=web)
* [Reference](https://stripe.com/docs/js)
* [PaymentIntents Reference](https://stripe.com/docs/js/payment_intents)


Android
* [Integration Guide](https://stripe.com/docs/payments/accept-a-payment?platform=android)
* [SDK Reference](https://stripe.dev/stripe-android/)
* [Example App: PaymentSheet](https://github.com/stripe/stripe-android/tree/master/paymentsheet-example)


iOS
* [Integration Guide](https://stripe.com/docs/payments/accept-a-payment?platform=ios)
* [SDK Reference](https://stripe.dev/stripe-ios/docs/index.html)
* [Example Apps](https://github.com/stripe/stripe-ios/tree/master/Example)


Server-Side Code
Ignore Stripe's documentation regarding server-side implementation. Solaris handles all backend interactions (creating PaymentIntents, webhooks, secrets) for you.

### Handling errors

Your solution must handle errors returned by the Stripe SDK (e.g., card declines, network issues).

* [Stripe Error Handling Guide](https://docs.stripe.com/error-handling)
* [Stripe Error Codes](https://stripe.com/docs/error-codes)
* [Card Decline Codes](https://stripe.com/docs/declines/codes)


## 2. Subscribe to webhooks

Listen for these events to update your UI in real-time.

| Webhook Event | Description |
|  --- | --- |
| `ACQUIRER_TOPUP_EXECUTED` | **Success.** Funds have been credited to the customer's account. |
| `ACQUIRER_TOPUP_DECLINED` | **Failure.** Solaris declined the Top-Up (e.g., blocked account). | Check the `decline_reason` field in the payload to inform the user. |
| `ACQUIRER_TOPUP_PAYMENT_FAILED` | **Payment Error.** The card charge failed (e.g., insufficient funds). Status remains `ACCEPTED`. | Check `acquirer_decline_code` (e.g., `card_declined`) to prompt the user to retry with a different card. |


* [**Webhook Reference**](/api-reference/onboarding/webhooks)


## 3. Top-Up lifecycle

### Limits and compliance

Ensure your UI respects these limits to prevent unnecessary API errors:

* **Transaction Limit:** Default **2,000.00 EUR** per Top-Up.
* **Monthly Cumulative Limit:** The maximum total amount a customer can top up per month. This is defined by the **Solaris Compliance Team**.
* *Note:* Contact your Partner Manager to confirm the specific limits configured for your solution.


### Create a Top-Up

Call this endpoint to initialize the payment. Solaris validates limits and creates the underlying PaymentIntent with Stripe.

**Request Parameters:**

* `amount`: The value (in cents) and currency.
* `payment_method_id`:
  * Set to `null` for a new card.
  * Set to an existing ID (retrieved from [List Payment Methods](#manage-saved-cards)) to use a saved card.


**Response:**

* `client_secret`: Pass this to the Stripe SDK to initialize the `PaymentSheet`.
* `instruction_id`: The Solaris reference for this operation.



```json
// POST /v1/persons/{person_id}/accounts/{account_id}/topups
{
  "amount": {
    "value": 10000,
    "currency": "EUR"
  },
  "payment_method_id": null
}
```

Create Top-Up
View endpoint definition.

Retrieve Top-Up
Check status.

### Handle the payment (Client-Side)

Use the `client_secret` from the response to show the Stripe UI.

* **Success:** Stripe notifies Solaris -> Solaris triggers `ACQUIRER_TOPUP_EXECUTED`.
* **Failure:** Stripe returns an error to your app.


### Cancel a Top-Up

If the user cancels the flow or the app crashes, call this endpoint to release the limit reservation.


```json
// POST /v1/persons/{person_id}/accounts/{account_id}/topups/{topup_id}/cancel
{
  "cancellation_reason": "abandoned"
}
```

Cancel Top-Up
Release the reservation.

## 4. Manage saved cards

You can allow customers to save their card details for faster future Top-Ups. Solaris retrieves these "Payment Methods" directly from Stripe.

### List payment methods

Retrieve all cards stored for a specific customer.


```json
// GET /v1/persons/{person_id}/topups/payment_methods
[
  {
    "person_id": "18de883f507d49b8a074519c73cecper",
    "payment_method_id": "pm_123456789",
    "card_last4": "4242",
    "card_brand": "visa"
  }
]
```

### Delete payment method

Remove a saved card.


```json
// DELETE /v1/persons/{person_id}/topups/payment_methods/{payment_method_id}
{
  "payment_method_id": "pm_123456789"
}
```

List Methods
Get saved cards.

Delete Method
Remove a card.

## Appendix: Status definitions

| Status | Description |
|  --- | --- |
| `ACCEPTED` | **Pending.** Top-Up created. Waiting for user to complete payment in Stripe SDK. |
| `CONFIRMED` | **Authorized.** Payment successful at Stripe. Waiting for Solaris to credit funds (usually instant). |
| `EXECUTED` | **Success.** Funds credited to customer account. |
| `DECLINED` | **Failed.** Solaris rejected the Top-Up (e.g., account blocked). |
| `CANCELLED` | **Aborted.** User abandoned the flow or you called the cancel endpoint. |