# Split payments (marketplace)

Cobrá en nombre de usuarios conectados y retení una comisión de marketplace con el header Vexor-Account y el parámetro marketplace_fee.

> [!WARNING]
> El SDK `vexor` de npm (Stripe, MercadoPago, PayPal, Square, Talo) está **deprecado**: ya no se mantiene y no debe usarse. vexorpay es hoy una **API REST sobre Stripe, siempre en USD, sin SDK oficial**. Migración: <https://developers.vexorpay.com/docs/migracion-desde-el-sdk>

Fuente: <https://developers.vexorpay.com/docs/api/split-payments>

La API permite que una **app de marketplace** cobre **en nombre de sus usuarios conectados** y retenga una **comisión**. La app se autentica con su propia API key (o con un token OAuth de la app) y opera sobre el conectado mandando su id en el header `Vexor-Account`.

> Este flujo requiere que el usuario conectado haya autorizado la app (conexión activa). La creación y gestión de la app se hace desde el dashboard, no por API.

## Header `Vexor-Account`

En cualquier request autenticado mandá el id del usuario conectado:

```
Vexor-Account: <connected_user_id>
```

- La API valida que el dueño de la credencial tenga una **conexión activa** con ese usuario y en el **mismo modo** (prueba o producción). Si no, responde `403 invalid_connected_account`.
- La operación actúa sobre el conectado (los cobros quedan a su nombre) y se atribuye a la app.
- Sin el header, el comportamiento es el normal: la credencial opera sobre su propia cuenta.
- Con tokens OAuth de app, el header exige el scope `account:operate` (si falta, `403 insufficient_scope`).

## Parámetro `marketplace_fee`

Al crear un link (`POST /api/v1/payment-links`) podés fijar la comisión de la app:

```jsonc
"marketplace_fee": { "type": "percent", "value": 1000 }   // 1000 = 10% (puntos base)
"marketplace_fee": { "type": "fixed",   "value": 250 }    // 250 = USD 2,50 (centavos)
```

- `type: "percent"` → `value` en **puntos base** (bps); `type: "fixed"` → `value` en **centavos** de USD.
- Requiere el header `Vexor-Account`. La comisión se **fija en el link** y es inmutable: cada cobro la hereda (no se puede pisar por checkout individual).
- Se valida contra el peor caso: el neto del conectado debe quedar por encima de cero (`net_below_zero`) y la comisión no puede superar el **90%** del monto (`marketplace_fee_exceeds_limit`, con `detail.max_percent`).
- En las respuestas, un link creado con comisión incluye el bloque `marketplace_fee` (`{ type, value }`).

> La comisión se acredita **siempre al dueño de la app**, nunca a un `marketplace_user_id` que venga en el body.

## Webhooks

Cuando un cobro aplica una comisión de marketplace se emite el evento `marketplace.fee.created`, y los eventos derivados de ese cobro (`payment.completed` / `refunded` / `disputed` y `dispute.resolved`) incluyen el bloque `data.marketplace_fee`. Ver [Webhooks salientes](/docs/api/webhooks).

## Cuentas conectadas

### Listar

`GET /api/v1/connected-accounts`

Lista las conexiones **activas** de la app, con paginación por cursor (`limit`, `starting_after`, `ending_before`).

```bash
curl "https://api.vexorpay.com/api/v1/connected-accounts?limit=10" \
  -H "Authorization: Bearer vxp_live_tu_clave"
```

```json
{
  "data": [
    {
      "id": "66f1c1e2c8a4b0d1f2e3a4b5",
      "connected_user_id": "66f1c1e2c8a4b0d1f2e3a4a1",
      "name": "Tienda de Ana",
      "email": "ana@ejemplo.com",
      "mode": "live",
      "scopes": ["read", "links:write", "account:operate"],
      "created_at": "2026-01-02T12:00:00.000Z",
      "revoked_at": null,
      "sandbox": false
    }
  ],
  "has_more": false,
  "total_count": 1,
  "url": "/v1/connected-accounts?limit=10"
}
```

### Obtener

`GET /api/v1/connected-accounts/{id}`

Devuelve el detalle de una conexión (activa o revocada). `404 not_found` si no existe o es de otra app o modo.

### Revocar

`DELETE /api/v1/connected-accounts/{id}`

Revoca la conexión **de forma idempotente**: revoca los tokens OAuth del conectado para esa app, borra el consentimiento y deja la conexión en `status: revoked`. Revocar una conexión ya revocada devuelve el mismo estado.

```bash
curl -X DELETE https://api.vexorpay.com/api/v1/connected-accounts/66f1c1e2c8a4b0d1f2e3a4b5 \
  -H "Authorization: Bearer vxp_live_tu_clave"
```

## Errores

| Error | HTTP | Causa |
| --- | --- | --- |
| `invalid_connected_account` | 403 | El header `Vexor-Account` apunta a una cuenta sin conexión activa de la app, o la credencial no es de una app de marketplace. |
| `marketplace_fee_exceeds_limit` | 400 | La comisión supera el tope del 90% del monto; `detail.max_percent` indica el tope. |
| `net_below_zero` | 400 | Con esa comisión el neto del conectado no queda por encima de cero. |
| `not_found` | 404 | No existe esa conexión en la app. |
