Checkout API
The Checkout API provides a unified way to process payments, create customers, and manage payment instruments in a single operation for React Native applications.
checkout
The modern, recommended method for processing payments with cards and bank accounts in your mobile app.
const { checkout } = useEasy();
const result = await checkout({
customer_creation: true,
customer_details: {
first_name: "John",
last_name: "Doe",
email: "[email protected]",
},
source: {
type: "PAYMENT_CARD",
cardNumberElement: cardNumberRef,
cardExpirationDateElement: expiryRef,
cardVerificationCodeElement: cvcRef,
name: "Primary Card",
},
line_items: [{ price_id: "price_123", quantity: 1 }],
});
Parameters
The checkout method accepts two different parameter types:
New Customer Checkout
interface CreateCheckoutNewCustomer {
customer_creation: true;
customer_details: {
first_name: string;
last_name: string;
email: string;
phone?: string;
personal_address?: Address;
};
source: PaymentCardParams | BankAccountParams;
line_items: LineItem[];
metadata?: Record<string, unknown>;
}
Existing Customer Checkout
interface CreateCheckoutExistingCustomer {
customer_creation: false;
identity_id: string; // Customer ID (note: use identity_id, not customer_id)
source: string | PaymentCardParams | BankAccountParams; // Can be existing PI ID
line_items: LineItem[];
metadata?: Record<string, unknown>;
}
Payment Source Types
Payment Card
interface PaymentCardParams {
type: "PAYMENT_CARD";
cardNumberElement: RefObject<ICardNumberElement>;
cardExpirationDateElement: RefObject<ICardExpirationDateElement>;
cardVerificationCodeElement: RefObject<ICardVerificationCodeElement>;
name?: string;
address?: Address;
}
Bank Account
interface BankAccountParams {
type: "BANK_ACCOUNT";
accountType: "CHECKING" | "SAVINGS";
routingElement: RefObject<ITextElement>;
accountElement: RefObject<ITextElement>;
name?: string;
}
Line Items
interface LineItem {
price_id: string;
quantity: number;
}
Returns
Promise<
ApiResponse<{
transfer?: TransferData;
orderId?: string;
subscriptions: (SubscriptionData & {
order_id: string;
order_number: string;
})[];
}>
>;
Complete Examples
New Customer with Card Payment
import {
useEasy,
CardNumberElement,
CardExpirationDateElement,
CardVerificationCodeElement,
} from "@easylabs/react-native";
import { useRef, useState } from "react";
import { View, TextInput, Button, StyleSheet, Alert } from "react-native";
function CheckoutScreen() {
const { checkout } = useEasy();
// Form refs
const cardNumberRef = useRef(null);
const expiryRef = useRef(null);
const cvcRef = useRef(null);
// Form state
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
if (!firstName || !lastName || !email) {
Alert.alert("Error", "Please fill in all fields");
return;
}
setLoading(true);
try {
const result = await checkout({
customer_creation: true,
customer_details: {
first_name: firstName,
last_name: lastName,
email: email,
},
source: {
type: "PAYMENT_CARD",
cardNumberElement: cardNumberRef,
cardExpirationDateElement: expiryRef,
cardVerificationCodeElement: cvcRef,
name: `${firstName} ${lastName}`,
},
line_items: [{ price_id: "price_abc123", quantity: 1 }],
metadata: {
platform: "mobile",
app_version: "1.0.0",
},
});
Alert.alert("Payment Successful!", `Order ID: ${result.data.orderId}`);
console.log("Transfer ID:", result.data.transfer?.id);
} catch (error) {
Alert.alert("Payment Failed", error.message);
console.error("Checkout error:", error);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="First Name"
value={firstName}
onChangeText={setFirstName}
/>
<TextInput
style={styles.input}
placeholder="Last Name"
value={lastName}
onChangeText={setLastName}
/>
<TextInput
style={styles.input}
placeholder="Email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
/>
<CardNumberElement
btRef={cardNumberRef}
placeholder="Card Number"
style={styles.cardInput}
/>
<CardExpirationDateElement
btRef={expiryRef}
placeholder="MM/YY"
style={styles.cardInput}
/>
<CardVerificationCodeElement
btRef={cvcRef}
placeholder="CVC"
style={styles.cardInput}
/>
<Button
title={loading ? "Processing..." : "Pay $25.00"}
onPress={handleCheckout}
disabled={loading}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 12,
marginBottom: 16,
},
cardInput: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 12,
marginBottom: 16,
},
});
Existing Customer Checkout
import { useEasy } from "@easylabs/react-native";
import { useState } from "react";
import { View, Button, Alert } from "react-native";
function QuickCheckout({ customerId, paymentInstrumentId, priceId }) {
const { checkout } = useEasy();
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
const result = await checkout({
customer_creation: false,
identity_id: customerId,
source: paymentInstrumentId, // Use existing payment method
line_items: [{ price_id: priceId, quantity: 1 }],
});
Alert.alert("Success", "Payment processed!");
} catch (error) {
Alert.alert("Error", error.message);
} finally {
setLoading(false);
}
};
return (
<View>
<Button
title={loading ? "Processing..." : "Complete Purchase"}
onPress={handleCheckout}
disabled={loading}
/>
</View>
);
}
Bank Account Payment
import { useEasy, TextElement } from "@easylabs/react-native";
import { useRef, useState } from "react";
import { View, TextInput, Button, StyleSheet, Alert } from "react-native";
import { Picker } from "@react-native-picker/picker";
function BankCheckout() {
const { checkout } = useEasy();
const routingRef = useRef(null);
const accountRef = useRef(null);
const [firstName, setFirstName] = useState("");
const [lastName, setLastName] = useState("");
const [email, setEmail] = useState("");
const [accountType, setAccountType] = useState("CHECKING");
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
const result = await checkout({
customer_creation: true,
customer_details: {
first_name: firstName,
last_name: lastName,
email: email,
},
source: {
type: "BANK_ACCOUNT",
accountType: accountType,
routingElement: routingRef,
accountElement: accountRef,
name: `${firstName} ${lastName}`,
},
line_items: [{ price_id: "price_xyz789", quantity: 1 }],
});
Alert.alert("Success", "Payment initiated!");
} catch (error) {
Alert.alert("Error", error.message);
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<TextInput
style={styles.input}
placeholder="First Name"
value={firstName}
onChangeText={setFirstName}
/>
<TextInput
style={styles.input}
placeholder="Last Name"
value={lastName}
onChangeText={setLastName}
/>
<TextInput
style={styles.input}
placeholder="Email"
value={email}
onChangeText={setEmail}
keyboardType="email-address"
/>
<Picker
selectedValue={accountType}
onValueChange={setAccountType}
style={styles.picker}
>
<Picker.Item label="Checking" value="CHECKING" />
<Picker.Item label="Savings" value="SAVINGS" />
</Picker>
<TextElement
btRef={routingRef}
placeholder="Routing Number"
style={styles.input}
/>
<TextElement
btRef={accountRef}
placeholder="Account Number"
style={styles.input}
/>
<Button
title={loading ? "Processing..." : "Pay with Bank Account"}
onPress={handleCheckout}
disabled={loading}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
},
input: {
borderWidth: 1,
borderColor: "#ccc",
borderRadius: 8,
padding: 12,
marginBottom: 16,
},
picker: {
marginBottom: 16,
},
});
Multiple Line Items
const result = await checkout({
customer_creation: true,
customer_details: {
first_name: "Alice",
last_name: "Johnson",
email: "[email protected]",
},
source: {
type: "PAYMENT_CARD",
cardNumberElement: cardNumberRef,
cardExpirationDateElement: expiryRef,
cardVerificationCodeElement: cvcRef,
name: "Alice Johnson",
},
line_items: [
{ price_id: "price_product_1", quantity: 2 },
{ price_id: "price_product_2", quantity: 1 },
{ price_id: "price_shipping", quantity: 1 },
],
metadata: {
order_notes: "Gift wrap requested",
referral_code: "FRIEND20",
},
});
Error Handling
Handle common checkout errors:
try {
const result = await checkout(checkoutData);
Alert.alert("Success", "Payment processed!");
} catch (error) {
if (error.message.includes("card")) {
Alert.alert("Card Error", "Please check your card details and try again.");
} else if (error.message.includes("insufficient")) {
Alert.alert("Insufficient Funds", "Your card was declined.");
} else if (error.message.includes("network")) {
Alert.alert("Network Error", "Please check your connection and try again.");
} else {
Alert.alert("Error", "Payment failed. Please try again.");
}
console.error("Checkout error:", error);
}
Validation
Validate checkout data before submission:
const validateCheckout = (data) => {
if (data.customer_creation && !data.customer_details) {
throw new Error("Customer details are required");
}
if (!data.customer_creation && !data.identity_id) {
throw new Error("Customer ID is required");
}
if (!data.line_items || data.line_items.length === 0) {
throw new Error("At least one line item is required");
}
if (!data.source) {
throw new Error("Payment source is required");
}
return true;
};
Best Practices
1. Loading States
Always show loading indicators during checkout:
const [loading, setLoading] = useState(false);
const handleCheckout = async () => {
setLoading(true);
try {
await checkout(data);
} finally {
setLoading(false);
}
};
2. Secure Data
Never log or store sensitive payment data:
// ❌ Don't do this
console.log("Card number:", cardNumber);
// ✅ Do this
console.log("Checkout successful:", result.data.orderId);
3. User Feedback
Provide clear feedback for all outcomes:
try {
const result = await checkout(data);
Alert.alert(
"Payment Successful",
`Your order #${result.data.orderId} has been placed!`,
[{ text: "OK", onPress: () => navigation.navigate("OrderConfirmation") }],
);
} catch (error) {
Alert.alert(
"Payment Failed",
"Please check your payment information and try again.",
[{ text: "OK" }],
);
}
4. Metadata
Include useful metadata for tracking:
metadata: {
platform: Platform.OS,
app_version: Constants.expoConfig?.version,
user_agent: "Mobile App",
campaign: "summer_sale",
}