Skip to main content
MercadoPago’s customer management allows you to store customer information and tokenized cards for faster checkout and recurring payments.

Why use customer management

Storing customers and cards enables:
  • Faster checkout: Customers don’t re-enter card details
  • Recurring payments: Charge saved cards for subscriptions
  • Better UX: Display saved payment methods
  • PCI compliance: Cards are tokenized and stored by MercadoPago
The package never stores raw card data. All card information is tokenized and stored securely by MercadoPago.

Creating customers

<?php

use Fitodac\LaravelMercadoPago\Services\CustomerService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

final class CustomerController
{
    public function store(
        Request $request,
        CustomerService $customerService
    ): JsonResponse {
        $payload = $request->validate([
            'email' => ['required', 'email'],
            'first_name' => ['sometimes', 'string'],
            'last_name' => ['sometimes', 'string'],
        ]);

        $customer = $customerService->create($payload);

        return response()->json($customer, 201);
    }
}

Customer payload structure

Minimal payload

{
  "email": "[email protected]"
}

Complete payload

{
  "email": "[email protected]",
  "first_name": "Ada",
  "last_name": "Lovelace",
  "phone": {
    "area_code": "11",
    "number": "12345678"
  },
  "identification": {
    "type": "DNI",
    "number": "12345678"
  },
  "default_address": {
    "street_name": "Calle Falsa",
    "street_number": 123,
    "zip_code": "1234"
  },
  "metadata": {
    "user_id": "98765",
    "account_type": "premium"
  }
}

Field validation rules

FieldRuleDescription
emailrequired, emailCustomer’s email address
first_namesometimes, stringFirst name
last_namesometimes, stringLast name
phonesometimes, arrayPhone number object
identificationsometimes, arrayID document
default_addresssometimes, arrayAddress object
metadatasometimes, arrayCustom data
Validation rules are defined in src/Http/Requests/CreateCustomerRequest.php

Customer response

Successful customer creation returns:
{
  "ok": true,
  "data": {
    "id": "1234567-abc123def456",
    "email": "[email protected]",
    "first_name": "Ada",
    "last_name": "Lovelace",
    "phone": {...},
    "identification": {...},
    "default_address": {...},
    "cards": [],
    "date_created": "2026-03-10T10:30:00.000-03:00",
    "date_last_updated": "2026-03-10T10:30:00.000-03:00",
    "metadata": {...}
  },
  "meta": []
}
The id field is the customer identifier needed for card operations.

Retrieving customers

public function show(
    string $customerId,
    CustomerService $customerService
): JsonResponse {
    $customer = $customerService->get($customerId);
    
    return response()->json($customer);
}

Managing customer cards

Adding cards

Add a tokenized card to a customer:
use Fitodac\LaravelMercadoPago\Services\CardService;

public function storeCard(
    string $customerId,
    Request $request,
    CardService $cardService
): JsonResponse {
    $payload = $request->validate([
        'token' => ['required', 'string'],
    ]);

    $card = $cardService->create($customerId, $payload);

    return response()->json($card, 201);
}
Card tokens are obtained using MercadoPago.js on the frontend. Never send raw card data to your server.

Card response

{
  "ok": true,
  "data": {
    "id": "9876543",
    "customer_id": "1234567-abc123def456",
    "expiration_month": 12,
    "expiration_year": 2028,
    "first_six_digits": "450995",
    "last_four_digits": "3704",
    "payment_method": {
      "id": "visa",
      "name": "Visa",
      "payment_type_id": "credit_card"
    },
    "cardholder": {
      "name": "ADA LOVELACE",
      "identification": {...}
    },
    "date_created": "2026-03-10T10:30:00.000-03:00"
  },
  "meta": []
}

Deleting cards

public function destroyCard(
    string $customerId,
    string $cardId,
    CardService $cardService
): JsonResponse {
    $result = $cardService->delete($customerId, $cardId);
    
    return response()->json($result);
}

Common patterns

Creating customer on user registration

Automatically create MercadoPago customers when users register:
use App\Models\User;
use Fitodac\LaravelMercadoPago\Services\CustomerService;

class RegisterController
{
    public function register(
        Request $request,
        CustomerService $customerService
    ) {
        $user = User::create([
            'name' => $request->name,
            'email' => $request->email,
            'password' => bcrypt($request->password),
        ]);

        // Create MercadoPago customer
        $customer = $customerService->create([
            'email' => $user->email,
            'first_name' => $user->first_name,
            'last_name' => $user->last_name,
            'metadata' => [
                'user_id' => (string) $user->id,
            ],
        ]);

        // Store customer ID
        $user->update([
            'mercadopago_customer_id' => data_get($customer, 'id'),
        ]);

        return $user;
    }
}

Listing customer cards

Retrieve customer data including saved cards:
use Fitodac\LaravelMercadoPago\Services\CustomerService;

Route::get('/profile/payment-methods', function (CustomerService $service) {
    $customerId = auth()->user()->mercadopago_customer_id;
    $customer = $service->get($customerId);
    
    $cards = collect(data_get($customer, 'cards', []))->map(fn($card) => [
        'id' => data_get($card, 'id'),
        'brand' => data_get($card, 'payment_method.id'),
        'last_four' => data_get($card, 'last_four_digits'),
        'expiration' => sprintf(
            '%s/%s',
            data_get($card, 'expiration_month'),
            data_get($card, 'expiration_year')
        ),
    ]);
    
    return view('profile.payment-methods', compact('cards'));
});

Charging a saved card

Process payment using a customer’s saved card:
use Fitodac\LaravelMercadoPago\Services\PaymentService;

public function chargeCard(
    Request $request,
    PaymentService $paymentService
): JsonResponse {
    $user = auth()->user();
    
    $payment = $paymentService->create([
        'transaction_amount' => $request->amount,
        'token' => $request->card_token,  // From saved card
        'description' => 'Subscription renewal',
        'installments' => 1,
        'payment_method_id' => 'visa',
        'payer' => [
            'id' => $user->mercadopago_customer_id,
            'email' => $user->email,
        ],
        'external_reference' => "SUBSCRIPTION-{$user->id}",
    ]);
    
    return response()->json($payment);
}

Syncing customer data

Keep MercadoPago customer data in sync with your application:
use App\Models\User;
use Fitodac\LaravelMercadoPago\Services\CustomerService;

class SyncCustomerDataJob
{
    public function handle(CustomerService $service)
    {
        User::whereNotNull('mercadopago_customer_id')
            ->chunk(100, function ($users) use ($service) {
                foreach ($users as $user) {
                    try {
                        $customer = $service->get($user->mercadopago_customer_id);
                        
                        // Update local cache
                        $user->update([
                            'mercadopago_cards_count' => count(data_get($customer, 'cards', [])),
                            'mercadopago_synced_at' => now(),
                        ]);
                    } catch (\Exception $e) {
                        \Log::warning("Failed to sync customer {$user->id}", [
                            'error' => $e->getMessage(),
                        ]);
                    }
                }
            });
    }
}

Frontend card tokenization

This package handles backend operations only. For frontend card tokenization, integrate MercadoPago.js separately.
Basic frontend flow for saving cards:
// 1. Initialize MercadoPago.js
const mp = new MercadoPago('YOUR_PUBLIC_KEY');

// 2. Create card token
const cardToken = await mp.createCardToken({
    cardNumber: '4509 9536 9623 3704',
    cardholderName: 'ADA LOVELACE',
    cardExpirationMonth: '12',
    cardExpirationYear: '2028',
    securityCode: '123',
    identificationType: 'DNI',
    identificationNumber: '12345678'
});

// 3. Send token to backend
await fetch('/api/customers/cards', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ token: cardToken.id })
});

Best practices

Store customer IDs locally

Always store MercadoPago customer IDs in your database:
Schema::table('users', function (Blueprint $table) {
    $table->string('mercadopago_customer_id')->nullable()->unique();
});

Handle customer creation idempotently

Prevent duplicate customer creation:
if ($user->mercadopago_customer_id) {
    // Customer already exists
    return $customerService->get($user->mercadopago_customer_id);
}

// Create new customer
$customer = $customerService->create([...]);

Use metadata for linking

Store your application IDs in metadata:
$customer = $customerService->create([
    'email' => $user->email,
    'metadata' => [
        'user_id' => (string) $user->id,
        'account_created_at' => $user->created_at->toIso8601String(),
    ],
]);

Next steps

Processing Payments

Process payments with saved cards

Handling Webhooks

Handle payment notifications

Testing

Test with demo users and cards

Build docs developers (and LLMs) love