---
title: "Charge repeat customers"
description: "Build fast, one-click checkout experiences for returning customers using saved payment methods and customer IDs."
canonical: "https://studio.inttegro.com/guides/charge-repeat-customers"
format: inttegro-machine-docs/v1
language: "Java"
sdk_version: "v8.3.0"
reader_profile: optional
reader_manifest: "https://studio.inttegro.com/machine/java/readers/index.json"
reader_identification: "Optional: declare your client only if known and your current-session capabilities; use reader_manifest for supplemental recommendations."
preamble_estimated_tokens: 561
model_token_report: "https://studio.inttegro.com/machine/token-report.json"
preamble_questions: 5
preamble_source: "curated"
recommended_mcp_tools: ["get_integration_guide","check_integration_readiness","create_order"]
estimated_tokens: 3390
token_estimate_method: "utf8_bytes_divided_by_4"
---

## Machine preamble

**Summary:** Reuse a returning customer and, when appropriate, their saved payment method without skipping confirmation or creating a charge from the wrong customer context.

### Five questions

#### Q1. Which identifiers should be retained from the first purchase?

Save the customer ID and saved payment-method ID from the successful order, associated with your own signed-in user. The [Orders reference](https://studio.inttegro.com/machine/java/api/orders.md) owns their response shapes; [Customers](https://studio.inttegro.com/machine/java/api/customers.md) owns later customer lookup.

#### Q2. How is a repeat order created?

In [Create an order](https://studio.inttegro.com/machine/java/api/orders.md#create-an-order), reference the existing customer and optionally a saved payment method instead of resending full personal and wallet details. Include the new line items and preserve a stable idempotency key for that purchase.

#### Q3. Does a saved method make payment silent?

No. A saved method removes re-entry, not necessarily customer confirmation. Check the rail's [payment-method settings](https://studio.inttegro.com/machine/java/api/payment-methods.md#payment-method-settings) and follow the payment's returned next action, including OTP when required.

#### Q4. What if the customer wants another method?

Use the guide's alternate-method path and the [Orders create contract](https://studio.inttegro.com/machine/java/api/orders.md#create-an-order) rather than assuming the stored method is still reusable. Verify that the chosen method belongs to the intended customer before initiating payment.

#### Q5. Which MCP calls help with the customer boundary?

An authenticated client can use [get_customer](https://studio.inttegro.com/machine/java/inttegro-mcp/tools.md#get_customer) for saved context and [create_order](https://studio.inttegro.com/machine/java/inttegro-mcp/tools.md#create_order) for an unpaid purchase. [pay_order](https://studio.inttegro.com/machine/java/inttegro-mcp/tools.md#pay_order) requires exact confirmation before charging; new details and OTP stay in secure Checkout. Read [get_order](https://studio.inttegro.com/machine/java/inttegro-mcp/tools.md#get_order) for the outcome.

## Document content

# Charge repeat customers

Repeat customers expect fast, frictionless checkout. Instead of asking them to re-enter their name, email, and payment details every time, use the customer and payment method IDs from their first purchase to create instant checkout flows. This guide shows you how to charge returning customers with saved payment methods and how to handle cases where they want to use a different payment method.

> Mcp Guide Callout is interactive content. Use the canonical page to view it.

## How it works

After a customer's first successful payment, Inttegro automatically creates a customer record and attaches their payment method to it. You'll find [`order(…).payment(…).customer(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) and [`order(…).payment(…).paymentMethod(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) in the order response. Store these IDs in your database linked to your user account. When the customer returns, reference them with `customerId(…)` and optionally `paymentMethodId(…)` instead of passing full details. Inttegro handles OTP delivery and payment confirmation just like the first time, but checkout is faster because you're not collecting information again.

## Choose your integration approach

Select how you want to charge repeat customers:

### With saved payment method

The simplest repeat customer flow uses both `customerId(…)` and `paymentMethodId(…)` for instant, one-click checkout. The customer doesn't need to re-enter any information—just confirm the OTP and the payment completes.

**Charge with saved method — POST /orders/create**

```java
import com.inttegro.Client;
import com.inttegro.orders.OrderCreateParams;
import com.inttegro.RequestMeta;
import com.inttegro.orders.OrderLineItemParams;
import com.inttegro.orders.ProductLineItemParams;
import com.inttegro.products.ProductType;
import com.inttegro.prices.PriceParams;
import com.inttegro.money.Currency;

public class Example {
  public static void main(String[] args) throws Exception {
    var client = new Client(System.getenv("INTTEGRO_API_KEY"));
    var params = OrderCreateParams.builder()
      .requestMeta(RequestMeta.builder()
          .idempotencyKey("order_repeat_001")
          .build())
      .executePayment(true)
      .customerId("cu_abc123")
      .paymentMethodId("pm_saved_method")
      .lineItem(OrderLineItemParams.product(ProductLineItemParams.builder()
            .type(ProductType.DIGITAL)
            .name("Premium Subscription")
            .quantity(1L)
            .price(PriceParams.of(Currency.GHS, 5000))
            .build()))
      .build();
    var result = client.orders().create(params);
  }
}
```

### Response

> **Note:**
>
> This is a partial response showing key attributes. See the complete [Order
> object](https://studio.inttegro.com/machine/java/api/orders.md#the-order-object) for all available fields.

```json
{
  "order": {
    "id": "or_repeat_xyz",
    "status": "requires_payment",
    "customer": {
      "id": "cu_abc123",
      "name": "Gloria Kesewaa",
      "email_address": "gloria@example.com"
    },
    "payment": {
      "id": "py_new_attempt",
      "status": "requires_action",
      "payment_method": {
        "id": "pm_saved_method",
        "type": "mobile_money",
        "network": "mtn",
        "account_number": "0544998605"
      },
      "next_action": {
        "type": "confirm_payment",
        "confirm_payment": {
          "expires_at": "2025-01-13T10:08:00Z",
          "request": {
            "recipient": "0544998605",
            "sent_via": "sms"
          }
        }
      }
    }
  }
}
```

**What's different**:

- No `customerData(…)` or `paymentMethodData(…)` needed—everything is already on file
- Inttegro sends OTP to the phone number associated with the saved payment method
- Customer confirms with OTP just like the first purchase

The confirmation step is identical to first-time payments. Submit the returned order ID, payment ID, confirmation-request ID, and the customer's token as shown in [Confirm a payment](https://studio.inttegro.com/machine/java/api/orders.md#confirm-a-payment).

### With new payment method

Sometimes a repeat customer wants to use a different payment method—maybe they're using a different mobile money provider or their old number changed. Provide `customerId(…)` with new `paymentMethodData(…)` to attach the new payment method to the existing customer. Inttegro creates a new payment method record and charges it, while keeping the customer's profile and history intact.

**Charge with new method — POST /orders/create**

```java
import com.inttegro.Client;
import com.inttegro.orders.OrderCreateParams;
import com.inttegro.RequestMeta;
import com.inttegro.paymentmethods.PaymentMethodData;
import com.inttegro.paymentmethods.PaymentMethodType;
import com.inttegro.paymentmethods.MobileMoneyParams;
import com.inttegro.paymentmethods.MobileMoneyNetwork;
import com.inttegro.orders.OrderLineItemParams;
import com.inttegro.orders.ProductLineItemParams;
import com.inttegro.products.ProductType;
import com.inttegro.prices.PriceParams;
import com.inttegro.money.Currency;

public class Example {
  public static void main(String[] args) throws Exception {
    var client = new Client(System.getenv("INTTEGRO_API_KEY"));
    var params = OrderCreateParams.builder()
      .requestMeta(RequestMeta.builder()
          .idempotencyKey("order_new_method_001")
          .build())
      .executePayment(true)
      .customerId("cu_abc123")
      .paymentMethodData(PaymentMethodData.builder()
          .type(PaymentMethodType.MOBILE_MONEY)
          .mobileMoney(MobileMoneyParams.builder()
              .network(MobileMoneyNetwork.TELECEL)
              .accountNumber("0501234567")
              .build())
          .build())
      .lineItem(OrderLineItemParams.product(ProductLineItemParams.builder()
            .type(ProductType.PHYSICAL)
            .name("Running Shoes")
            .quantity(1L)
            .price(PriceParams.of(Currency.GHS, 35000))
            .build()))
      .build();
    var result = client.orders().create(params);
  }
}
```

### Response

> **Note:**
>
> This is a partial response showing key attributes. See the complete [Order
> object](https://studio.inttegro.com/machine/java/api/orders.md#the-order-object) for all available fields.

```json
{
  "order": {
    "id": "or_new_method_xyz",
    "status": "requires_payment",
    "customer": {
      "id": "cu_abc123",
      "name": "Gloria Kesewaa",
      "email_address": "gloria@example.com"
    },
    "payment": {
      "id": "py_new_method",
      "status": "requires_action",
      "payment_method": {
        "id": "pm_new_telecel",
        "type": "mobile_money",
        "network": "telecel",
        "account_number": "0501234567"
      },
      "next_action": {
        "type": "confirm_payment",
        "confirm_payment": {
          "expires_at": "2025-01-13T10:15:00Z",
          "request": {
            "recipient": "0501234567",
            "sent_via": "sms"
          }
        }
      }
    }
  }
}
```

**What happened**:

- New [`order(…).payment(…).paymentMethod(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) created (`pm_new_telecel`) and attached to existing customer
- OTP sent to the new phone number (0501234567)
- Customer record remains the same, but now has multiple payment methods on file
- Save the new [`order(…).payment(…).paymentMethod(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) for future use

## Subscription renewals

Store the customer and payment-method IDs when a customer subscribes. For each
renewal, use the saved-method request shown above, give the order a unique
idempotency key for that billing period, and use the current plan as its line
item. If the returned payment requires confirmation, ask the customer to
complete it. Mark the renewal paid only after the order reports a successful
payment.

## Testing

Use an application configured for the test environment. Create the first test order to obtain customer and payment-method IDs, then use those IDs on the repeat order. If the response requires confirmation, follow [Confirm a payment](https://studio.inttegro.com/machine/java/api/orders.md#confirm-a-payment) with `orderId(…)`, `payment_id`, `confirmation_id`, and the test token supplied for that environment. Do not hardcode a universal token value.

## Key tips

**Store both IDs**: Always save [`order(…).payment(…).customer(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) and [`order(…).payment(…).paymentMethod(…).id(…)`](https://java.inttegro.dev/v8.3.0/com/inttegro/orders/Order.html) from the response after the first payment. You need the customer ID to associate future orders and the payment method ID for fast checkout.

**Customer profile vs payment method**: A customer can have multiple payment methods. When you use `customerId(…)` + `paymentMethodData(…)`, you're adding a new payment method to an existing customer. When you use `customerId(…)` + `paymentMethodId(…)`, you're charging an existing payment method.

**Payment method verification**: All payment methods require OTP confirmation, even saved ones. This protects both you and the customer—it proves the customer has access to the phone at the time of payment.

**Handle expired payment methods**: Phone numbers change, accounts get closed. If a payment fails with an expired or invalid payment method error, prompt the customer to add a new payment method using the `customerId(…)` + `paymentMethodData(…)` pattern.

## Next steps

- **[Accept a payment](https://studio.inttegro.com/machine/java/guides/accept-a-payment.md)** - First-time customer payment flow
- **[Retry a failed payment](https://studio.inttegro.com/machine/java/guides/retry-a-payment.md)** - Retry failed payments with alternative methods
- **[Order now, pay later](https://studio.inttegro.com/machine/java/guides/order-now-pay-later.md)** - Defer payment to a later time
- **[Orders API](https://studio.inttegro.com/machine/java/api/orders.md)** - Complete API reference

You now know how to build fast, one-click checkout for repeat customers while maintaining security through OTP verification.
