MercadoPago split

Cobros con split de pagos (marketplace): cada comercio (negocio) conecta su cuenta de Mercado Pago por OAuth y la plataforma retiene un marketplace_fee del 1,5% sobre cada cobro. El comercio recibe el resto. La app de Mercado Pago es de Sabado — el consumer nunca ve client_secret ni los tokens del comercio.

Orden del reparto (según doc oficial de MP): primero Mercado Pago descuenta su comisión, después se descuenta el marketplace_fee del saldo restante. El comercio recibe lo que queda.

Flujo típico

  1. El comercio conecta su MP: GET /v1/mercadopago/connect → redirigís su navegador al connect_url.
  2. Verificás estado con GET /v1/mercadopago/status.
  3. Cobrás: POST /v1/mercadopago/preferences → mandás el init_point al comprador.
  4. El comprador paga → recibís mp.payment.approved por webhook (ver Eventos de MercadoPago).
  5. Para cancelar/revertir un cobro: POST /v1/mercadopago/refunds → recibís mp.payment.refunded.

Conectar el comercio

GET /v1/mercadopago/connect

Devuelve la URL de autorización OAuth para que el comercio conecte su cuenta de Mercado Pago. Redirigí el navegador del dueño del comercio al connect_url.

Scope: mercadopago.write.

GET /v1/mercadopago/connect?tenant_ref=bruno-traslados
Authorization: Bearer TU_API_KEY

Respuesta:

{
  "tenant_ref": "bruno-traslados",
  "connect_url": "https://auth.mercadopago.com.ar/authorization?client_id=...&response_type=code&platform_id=mp&redirect_uri=...&state=..."
}

El state es one-time (CSRF + liga el callback con el comercio). El callback lo maneja Sabado; cuando el comercio autoriza, queda conectado y status lo refleja.

Errores:

Estado de conexión

GET /v1/mercadopago/status

Estado de conexión MercadoPago del comercio. Usalo para mostrar "Conectar" vs "Conectado ✓" en tu UI.

Scope: mercadopago.read.

GET /v1/mercadopago/status?tenant_ref=bruno-traslados
Authorization: Bearer TU_API_KEY

Respuesta:

{
  "tenant_ref": "bruno-traslados",
  "connected": true,
  "mp_user_id": "123456789",
  "connected_at": "2026-05-28T19:04:58+00:00"
}

connected: false (con mp_user_id y connected_at en null) cuando el comercio no conectó, o cuando su token fue revocado — en ese caso la plataforma marca la credencial como desconectada automáticamente, así que el status no miente.

Errores:

Crear preferencia (cobrar)

POST /v1/mercadopago/preferences

Crea una preferencia de Checkout Pro con split. La plataforma calcula el marketplace_fee (1,5% del total) y crea la preferencia con el token del comercio. Mandá el init_point al comprador (sandbox_init_point en pruebas).

Scope: mercadopago.write.

POST /v1/mercadopago/preferences
{
  "tenant_ref": "bruno-traslados",
  "external_reference": "ticket-42",
  "items": [
    {
      "title": "Viaje a Ricky Martin (2 lugares)",
      "quantity": 1,
      "unit_price": 46000,
      "currency_id": "ARS"
    }
  ],
  "payer_email": "ana@gmail.com",
  "back_urls": {
    "success": "https://tudominio.com/pago-ok",
    "pending": "https://tudominio.com/pago-pendiente",
    "failure": "https://tudominio.com/pago-error"
  }
}

Respuesta:

{
  "tenant_ref": "bruno-traslados",
  "preference_id": "123456789-abc...",
  "init_point": "https://www.mercadopago.com.ar/checkout/v1/redirect?pref_id=...",
  "sandbox_init_point": "https://sandbox.mercadopago.com.ar/checkout/v1/redirect?pref_id=...",
  "marketplace_fee": 690
}

marketplace_fee es el monto absoluto en ARS que retiene la plataforma (round(total * 0.015, 2)).

Errores:

Cancelar / reembolsar

POST /v1/mercadopago/refunds

Cancela/revierte un cobro: hace un reembolso total del pago con el token del comercio. Idempotente por payment_id (reintentar no genera un segundo reembolso). El reembolso dispara el webhook mp.payment.refunded, que es donde invalidás la entrada/venta del lado tuyo.

Scope: mercadopago.write.

POST /v1/mercadopago/refunds
{
  "tenant_ref": "bruno-traslados",
  "payment_id": "123456789"
}

payment_id: el id del pago de Mercado Pago (el que recibís en mp.payment.approved).

Respuesta:

{
  "tenant_ref": "bruno-traslados",
  "refund_id": "99001",
  "payment_id": "123456789",
  "amount": 46000,
  "status": "approved"
}

Un solo camino de invalidación. Si el comercio o el comprador hacen el refund directamente desde Mercado Pago en lugar de usar este endpoint, igual te llega el webhook mp.payment.refunded. Procesalo del mismo modo — no importa quién disparó el refund.

Errores: