Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sdk Laravel Package

mercadopago/sdk

Official Mercado Pago SDK for PHP. Add payments, checkout, subscriptions, and refunds to your Laravel or PHP app through a consistent API for managing preferences, customers, payments, and webhooks, making it easy to accept and process payments across Latin America.

View on GitHub
Deep Wiki
Context7

Getting Started

This is the deprecated MercadoPago SDK (mercadopago/sdk), last released 2019-04-15. Before writing a line of integration code, confirm the choice: for new work use mercadopago/dx-php (same vendor, active) — the API surface is close enough that this assessment doubles as a migration guide. Reach for mercadopago/sdk only if you are maintaining a legacy Laravel 5.x/6.x app pinned to it.

Minimal steps if you must:

composer require mercadopago/sdk

It declares PHP >=5.6 and pulls an old Guzzle/REST client. On Laravel 10/11 (PHP 8.2+) it will usually install but is untested against PHP 8 — expect deprecation notices and possible type errors.

Where to look first:

  • vendor/mercadopago/sdk/src/MercadoPago/SDK.php — entry point (setAccessToken, setIntegratorId, setCustomHeaders).
  • Entity classes next to it: Preference, Payment, Item, Payer, MerchantOrder, PaymentMethod.
  • The README in vendor/mercadopago/sdk/README.md — the only docs that match this version, not the current MercadoPago docs.

Configure the token the Laravel way, never inline:

// config/services.php
'mercadopago' => [
    'access_token' => env('MP_ACCESS_TOKEN'),
    'public_key'   => env('MP_PUBLIC_KEY'),
],
// app/Providers/AppServiceProvider.php  (boot)
\ MercadoPago\SDK::setAccessToken(config('services.mercadopago.access_token'));

First use case — a checkout preference with redirect:

$preference = new \MercadoPago\Preference();

$item = new \MercadoPago\Item();
$item->title = 'Pro plan';
$item->quantity = 1;
$item->unit_price = 49.90;

$preference->items = [$item];
$preference->external_reference = (string) $order->id;
$preference->back_urls = [
    'success' => route('checkout.success'),
    'failure' => route('checkout.failure'),
    'pending' => route('checkout.pending'),
];
$preference->auto_return = 'approved';
$preference->notification_url = route('webhooks.mercadopago');

$preference->save();

return redirect($preference->init_point);

Implementation Patterns

Wrap the SDK in a service, not controllers. The entity objects are mutable bags of public properties; keep them out of your domain layer.

class MercadoPagoGateway
{
    public function createPreference(Order $order): \MercadoPago\Preference
    {
        // build item/payer/back_urls from $order, save(), return
    }

    public function findPayment(string $id): ?\MercadoPago\Payment
    {
        return \MercadoPago\Payment::find_by_id($id) ?: null;
    }
}

Bind it via constructor injection so you can fake it in tests (see below) and keep the vendor class out of feature-test signatures.

Persist the identifiers. After $preference->save(), store preference->id and init_point on your order. After the payment lands, store payment->id against the same order. Webhooks are not guaranteed ordered or unique, so external_reference is your only reliable join key.

Webhook controller pattern. Exclude the route from CSRF, return 200 fast, then hand off to a queue:

// routes/api.php (stateless, no session/CSRF) or Route::post(...)->withoutMiddleware(...)
Route::post('/webhooks/mercadopago', [MercadoPagoWebhookController::class, 'handle']);

public function handle(Request $request)
{
    $paymentId = $request->input('data.id') ?? $request->input('id');

    ProcessMercadoPagoPayment::dispatch($paymentId)->onQueue('payments');

    return response()->noContent();
}

Inside the job, re-fetch from the API rather than trusting the payload — the notification body can be spoofed:

$payment = MercadoPago\Payment::find_by_id($paymentId);
if ($payment->status === 'approved' && $payment->external_reference === (string) $order->id) {
    // mark paid, idempotently
}

Idempotency table. Create mercadopago_events with a unique index on payment_id (or the notification id). Insert-or-skip before processing. This SDK gives you no dedupe; you own it.

Status handling. Map payment->status (pending, approved, authorized, in_process, rejected, refunded, cancelled, charged_back) to your own state enum. Use status_detail for logging only — it's provider-specific prose.

Testing. Set MP_ACCESS_TOKEN to a TEST-... credential in .env.testing and use sandbox test users for payer flows. Since the SDK is static (SDK::setAccessToken), faking is awkward: prefer testing your MercadoPagoGateway contract with a fake implementation, and cover the webhook job against a fake gateway. Mock the static entity calls only as a last resort.

Integration tips.

  • Register a MercadoPagoServiceProvider (or the AppServiceProvider boot shown above) so token config happens once, not per request handler.
  • Send X-Integrator-Id via SDK::setIntegratorId() only if MercadoPago has issued you one; harmless otherwise.
  • Log every outbound call with the order id and MercadoPago's response body; the SDK throws bare \Exception with little context.
  • Route notifications through notification_url and poll Payment::find_by_id after redirects; the redirect is a UX signal, not proof of payment.

Gotchas and Tips

It is deprecated — treat it as a security dependency. The repo is literally named DEPRECATED-sdk-php, 0 stars, no releases since April 2019. No patches for CVEs, no PHP 8 fixes, no support for MercadoPago's newer Checkout/Orders APIs. Plan the migration to mercadopago/dx-php on your next touch of this code; in most cases it is composer remove + composer require mercadopago/dx-php and a review of property access (Preference, Payment, Item names mostly carry over, accessors differ). Keep this package quarantined behind your gateway class so the swap is one file.

PHP 8 / Guzzle conflicts. Old Guzzle constraints collide with Laravel 9+ defaults. If composer require fails, you'll be tempted to use --ignore-platform-reqs — don't for production. That's the signal to migrate instead.

Static global state. SDK::setAccessToken() is process-global. In Octane or queue workers that switch credentials per tenant, tokens leak across requests. Set the token at the start of every job/request that uses the SDK, or avoid multi-tenant use entirely.

auto_return requires HTTPS back_urls. Locally, drop auto_return and use init_point manually, or tunnel with a public HTTPS URL. notification_url likewise must be publicly reachable — localhost and 127.0.0.1 silently never deliver.

Credential prefixes matter. TEST- tokens work only with sandbox users and sandbox credentials; APP_USR- for production. Mixing them yields 401/invalid access token with no hint about the cause.

Currency and amounts. unit_price is a float — send 49.9, not "49,90", and match the currency configured on the MercadoPago account. Fractional cents get rounded by the API, so reconcile against transaction_amount in the webhook, not your local value.

Webhook signatures. This SDK predates x-signature verification helpers. Validate the x-signature / x-request-id HMAC yourself, or at minimum re-fetch the payment from the API before mutating state. Never mark an order paid from the notification payload alone.

Duplicates and ordering. MercadoPago retries notifications; you will receive the same payment_id multiple times. Combined with out-of-order delivery (an approved arriving after a later refunded re-poll), the safe pattern is: always find_by_id, compare date_last_updated / status against what you already stored, and move state forward only.

Debugging. The SDK swallows the HTTP response on many failures. Catch \Exception, log getMessage() plus your own request context, and reproduce with a raw curl against https://api.mercadopago.com/v1/payments/{id} with the same bearer token — the API response tells you what the SDK won't. Also check MercadoPago\SDK::$errors/the entity's error property after save(); save() can return false without throwing.

Extension points. SDK::setCustomHeaders() and setIntegratorId() are the hooks available; there is no middleware pipeline, no PSR-18 injection, no event system. If you need retries, timeouts, or observability, wrap the SDK calls in your own gateway and add Http::retry-style behavior there — you cannot configure it inside this package.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource