Skip to main content
Unlike preferences that redirect users to MercadoPago’s checkout, direct payments allow you to process card payments within your own application using tokenized card data.

Payment flow overview

1

Tokenize card data

Use MercadoPago’s JavaScript SDK (MercadoPago.js) to securely tokenize card information in the browser. This happens client-side and never exposes raw card data to your server.
2

Send token to your backend

Your frontend sends the card token and payment details to your Laravel backend.
3

Create payment

Your backend uses PaymentService to process the payment with MercadoPago’s API.
4

Handle response

Process the payment response and update your application state accordingly.

Creating payments

<?php

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

final class MercadoPagoPaymentController
{
    public function store(
        Request $request,
        PaymentService $paymentService
    ): JsonResponse {
        $payload = $request->validate([
            'transaction_amount' => ['required', 'numeric', 'min:0.01'],
            'token' => ['required', 'string'],
            'description' => ['required', 'string'],
            'installments' => ['required', 'integer', 'min:1'],
            'payment_method_id' => ['required', 'string'],
            'payer' => ['required', 'array'],
            'payer.email' => ['required', 'email'],
        ]);

        $payment = $paymentService->create($payload);

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

Payment payload structure

Required fields

{
  "transaction_amount": 100.50,
  "token": "CARD_TOKEN",
  "description": "Payment description",
  "installments": 1,
  "payment_method_id": "visa",
  "payer": {
    "email": "[email protected]"
  }
}

Complete payload example

{
  "transaction_amount": 250.00,
  "token": "CARD_TOKEN_FROM_JS_SDK",
  "description": "Premium subscription - Monthly",
  "installments": 3,
  "payment_method_id": "visa",
  "issuer_id": 310,
  "payer": {
    "email": "[email protected]",
    "identification": {
      "type": "DNI",
      "number": "12345678"
    }
  },
  "external_reference": "ORDER-12345",
  "notification_url": "https://your-app.com/api/mercadopago/webhooks",
  "metadata": {
    "user_id": "98765",
    "order_id": "12345"
  }
}

Field validation rules

FieldRuleDescription
transaction_amountrequired, numeric, min:0.01Payment amount
tokenrequired, stringCard token from JS SDK
descriptionrequired, stringPayment description
installmentsrequired, integer, min:1Number of installments
payment_method_idrequired, stringPayment method (visa, master, etc)
issuer_idsometimes, integerCard issuer ID
payerrequired, arrayPayer information
payer.emailrequired, emailPayer’s email
payer.identificationsometimes, arrayID document
external_referencesometimes, stringYour order reference
notification_urlsometimes, urlWebhook URL
metadatasometimes, arrayCustom metadata
Validation rules are defined in src/Http/Requests/CreatePaymentRequest.php

Payment methods

Common payment method IDs:
  • visa - Visa
  • master - Mastercard
  • amex - American Express
  • debcabal - Cabal Débito
  • debmaster - Maestro

Getting available payment methods

Query available payment methods for your account:
use Fitodac\LaravelMercadoPago\Services\PaymentMethodService;

Route::get('/payment-methods', function (PaymentMethodService $service) {
    return response()->json($service->all());
});
Or use the demo endpoint:
curl http://localhost:8000/api/mercadopago/payment-methods

Retrieving payment status

After creating a payment, you can retrieve its current status:
use Fitodac\LaravelMercadoPago\Services\PaymentService;

public function show(
    string $paymentId,
    PaymentService $paymentService
): JsonResponse {
    $payment = $paymentService->get($paymentId);
    
    return response()->json($payment);
}

Payment response structure

Successful payment creation returns:
{
  "ok": true,
  "data": {
    "id": 123456789,
    "status": "approved",
    "status_detail": "accredited",
    "transaction_amount": 100.50,
    "currency_id": "ARS",
    "description": "Payment for order 1001",
    "payment_method_id": "visa",
    "payment_type_id": "credit_card",
    "installments": 1,
    "date_created": "2026-03-10T10:30:00.000-03:00",
    "date_approved": "2026-03-10T10:30:01.000-03:00",
    "payer": {
      "email": "[email protected]",
      "identification": {...}
    },
    "card": {
      "first_six_digits": "450995",
      "last_four_digits": "3704",
      "cardholder": {...}
    },
    "external_reference": "ORDER-12345"
  },
  "meta": []
}

Payment statuses

StatusDescription
approvedPayment approved and credited
pendingPayment pending (e.g., awaiting processing)
in_processPayment being processed
rejectedPayment rejected
cancelledPayment cancelled
refundedPayment refunded
charged_backPayment charged back

Status details

The status_detail field provides additional context:
  • accredited - Payment successfully credited
  • pending_contingency - Pending review
  • pending_review_manual - Manual review required
  • cc_rejected_bad_filled_card_number - Invalid card number
  • cc_rejected_bad_filled_date - Invalid expiration date
  • cc_rejected_bad_filled_security_code - Invalid CVV
  • cc_rejected_insufficient_amount - Insufficient funds
  • cc_rejected_high_risk - Rejected by fraud prevention

Handling payment responses

Success scenario

$payment = $paymentService->create($payload);

if (data_get($payment, 'status') === 'approved') {
    // Payment approved
    Order::where('id', $orderId)->update([
        'payment_id' => data_get($payment, 'id'),
        'status' => 'paid',
    ]);
    
    return response()->json([
        'success' => true,
        'payment_id' => data_get($payment, 'id'),
    ]);
}

Rejection scenario

if (data_get($payment, 'status') === 'rejected') {
    $detail = data_get($payment, 'status_detail');
    
    return response()->json([
        'success' => false,
        'message' => 'Payment rejected',
        'reason' => $detail,
    ], 422);
}

Pending scenario

if (in_array(data_get($payment, 'status'), ['pending', 'in_process'])) {
    return response()->json([
        'success' => true,
        'pending' => true,
        'message' => 'Payment is being processed',
    ]);
}
Never rely solely on the immediate payment response. Always implement webhook handling for definitive payment status updates.

Common patterns

Linking payments to orders

$order = Order::findOrFail($request->order_id);

$payment = $paymentService->create([
    'transaction_amount' => $order->total,
    'token' => $request->card_token,
    'description' => "Payment for order {$order->id}",
    'installments' => $request->installments,
    'payment_method_id' => $request->payment_method_id,
    'payer' => [
        'email' => $order->customer_email,
    ],
    'external_reference' => "ORDER-{$order->id}",
    'metadata' => [
        'order_id' => $order->id,
        'user_id' => auth()->id(),
    ],
]);

if (data_get($payment, 'status') === 'approved') {
    $order->update([
        'mercadopago_payment_id' => data_get($payment, 'id'),
        'status' => 'paid',
    ]);
}

Error handling

try {
    $payment = $paymentService->create($payload);
    
    return response()->json([
        'success' => true,
        'payment' => $payment,
    ]);
} catch (\Exception $e) {
    \Log::error('Payment creation failed', [
        'error' => $e->getMessage(),
        'payload' => $payload,
    ]);
    
    return response()->json([
        'success' => false,
        'message' => 'Payment processing failed',
    ], 500);
}

Frontend integration notes

This package handles backend payment processing. For frontend card tokenization, you’ll need to integrate MercadoPago.js separately. The package provides MERCADOPAGO_PUBLIC_KEY for frontend use.
Basic frontend flow:
  1. Load MercadoPago.js with your public key
  2. Collect card data in your form
  3. Use mp.createCardToken() to tokenize card
  4. Send token to your Laravel backend
  5. Backend processes payment using PaymentService

Next steps

Handling Webhooks

Process payment status notifications

Refunds

Learn how to refund payments

Managing Customers

Store customer data and cards

Build docs developers (and LLMs) love