{
  "info": {
    "name": "vexorpay API",
    "_postman_id": "vexorpay-api-v1",
    "description": "Colección de la API pública de vexorpay (v1) con todos los endpoints ya configurados.\n\nEn producción, la API exige la suscripción a vexorpay (USD 9/mes con impuestos incluidos, 30 días de prueba gratis): sin ella, cualquier endpoint responde 402 subscription_required. En sandbox no se exige.\n\n## Cómo usarla\n\n1. Descargá esta colección y abrí Postman (escritorio o web).\n2. Import → elegí este archivo (o arrastralo a Postman).\n3. En las Variables de la colección, completá apiKey con tu clave real (vxp_live_...). Las claves se crean en el dashboard → Desarrolladores; las de prueba (vxp_test_...) se crean desde dashboard.sandbox.vexorpay.com y se usan contra https://api.sandbox.vexorpay.com/api/v1. baseUrl ya apunta a producción (https://api.vexorpay.com/api/v1).\n\nTodos los requests usan Authorization: Bearer {{apiKey}} (heredado de la colección). Los POST idempotentes (payment-links, orders/{id}/refund y payouts) aceptan el header Idempotency-Key para evitar duplicados. El modo lo define la API key, no hay parámetro sandbox en los requests.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "type": "string",
      "value": "https://api.vexorpay.com/api/v1",
      "description": "Base de la API pública (producción): https://api.vexorpay.com/api/v1"
    },
    {
      "key": "apiKey",
      "type": "string",
      "value": "vxp_live_tu_clave_aqui",
      "description": "Tu API key (vxp_live_...). Se crea en el dashboard → Desarrolladores. Para sandbox usá una clave vxp_test_... contra https://api.sandbox.vexorpay.com."
    },
    {
      "key": "linkId",
      "type": "string",
      "value": "",
      "description": "ID de un payment link (ej: id de la respuesta de POST /payment-links)."
    },
    {
      "key": "disputeId",
      "type": "string",
      "value": "",
      "description": "ID local de una disputa (ej: id de GET /disputes)."
    },
    {
      "key": "orderId",
      "type": "string",
      "value": "",
      "description": "ID de una venta de Polar (ej: id de GET /orders)."
    },
    {
      "key": "customerId",
      "type": "string",
      "value": "",
      "description": "ID de un cliente de Polar (ej: id de GET /customers)."
    },
    {
      "key": "subscriptionId",
      "type": "string",
      "value": "",
      "description": "ID de una suscripción (ej: id de GET /subscriptions)."
    },
    {
      "key": "payoutId",
      "type": "string",
      "value": "",
      "description": "ID de un retiro de Polar (de GET /payouts)."
    },
    {
      "key": "eventId",
      "type": "string",
      "value": "",
      "description": "ID de un evento (evt_...)."
    },
    {
      "key": "connectedAccountId",
      "type": "string",
      "value": "",
      "description": "ID de una conexión de una app de marketplace (AppConnection.id), de GET /connected-accounts."
    },
    {
      "key": "connectedUserId",
      "type": "string",
      "value": "",
      "description": "ID del usuario conectado para el header Vexor-Account (cuentas conectadas)."
    }
  ],
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "item": [
    {
      "name": "General",
      "item": [
        {
          "name": "Health",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/health",
              "host": ["{{baseUrl}}"],
              "path": ["health"]
            },
            "description": "Verifica que la API esté arriba (sin autenticación)."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Payment Links",
      "item": [
        {
          "name": "Crear link de pago",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "",
                "description": "Opcional: protege contra duplicados si repetís la misma petición."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 19,\n  \"title\": \"Ebook UX en 30 días\",\n  \"description\": \"Acceso inmediato al PDF.\",\n  \"reference\": \"CATALOGO-UX\",\n  \"metadata\": {\n    \"sku\": \"UX-30\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payment-links",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links"]
            },
            "description": "Crea un link de pago reutilizable en Polar (Merchant of Record). Mínimo USD 4. La referencia es opcional pero útil para identificar la venta. Requiere Polar conectado (400 account_not_connected) y la organización lista para cobrar (409 polar_not_ready). La respuesta trae checkoutUrl (checkout de Polar). El modo lo define la API key: con una clave vxp_test_... creás un link de prueba contra api.sandbox.vexorpay.com."
          },
          "response": []
        },
        {
          "name": "Crear link recurrente (suscripción)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "",
                "description": "Opcional: protege contra duplicados si repetís la misma petición."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"type\": \"recurring\",\n  \"title\": \"Membresía mensual\",\n  \"description\": \"Acceso mensual a la comunidad.\",\n  \"reference\": \"MEMBRESIA\",\n  \"prices\": [\n    {\n      \"amount\": 9,\n      \"interval\": \"month\",\n      \"interval_count\": 1,\n      \"trial_period_days\": 7,\n      \"description\": \"Plan mensual\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payment-links",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links"]
            },
            "description": "Crea un link de pago recurrente (suscripción) en Polar. Cada plan tiene mínimo USD 4 (o 0 para un plan gratis de precio fijo); interval: day | week | month | year. La respuesta trae checkoutUrl (checkout de Polar); para llevar al comprador directo a un plan usá Crear checkout con price_id."
          },
          "response": []
        },
        {
          "name": "Listar links",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payment-links?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links"],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "description": "Filtro: active | canceled | archived"
                },
                {
                  "key": "type",
                  "value": "",
                  "description": "Filtro: one_time | recurring"
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Obtener link",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payment-links/{{linkId}}",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links", "{{linkId}}"]
            }
          },
          "response": []
        },
        {
          "name": "Métricas del link",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payment-links/{{linkId}}/stats",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links", "{{linkId}}", "stats"]
            },
            "description": "Métricas netas del link (sin impuestos, comisiones ni reembolsos): pago único (ventas, ticket promedio, reembolsos, disputas, clientes que repiten, países, serie semanal) o recurrente (MRR, en prueba, en riesgo, altas/bajas, churn, conversión de prueba, LTV, serie mensual)."
          },
          "response": []
        },
        {
          "name": "Actualizar link",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 24,\n  \"title\": \"Ebook UX en 30 días (v2)\",\n  \"reference\": \"CATALOGO-UX\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payment-links/{{linkId}}",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links", "{{linkId}}"]
            },
            "description": "Actualiza campos parciales en Polar: title, description, image_file_id, reference, amount (pago único) y, en links recurrentes, amount (0 = gratis), description y trial_period_days de cada plan existente (con su id). El type no es editable. Agregar o quitar planes o cambiar intervalo/asientos responde 400 polar_link_structure_change. status solo acepta active o archived (otro valor: 400 polar_field_not_supported)."
          },
          "response": []
        },
        {
          "name": "Eliminar link",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payment-links/{{linkId}}",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links", "{{linkId}}"]
            },
            "description": "Saca el link de venta, alineado con la acción del dashboard: lo archiva en Polar (productos archivados, checkoutUrl deja de funcionar) y queda status: archived. Las suscripciones vigentes siguen cobrándose en Polar hasta que se cancelen. Si ya fue eliminado o archivado, 409 already_processed; si Polar falla, 502 polar_archive_failed sin cambios. Nunca borra ventas ya realizadas."
          },
          "response": []
        },
        {
          "name": "Crear checkout",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"reference\": \"ORD-1001\",\n  \"customer_email\": \"cliente@ejemplo.com\",\n  \"metadata\": {\n    \"sku\": \"UX-30\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payment-links/{{linkId}}/checkout",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links", "{{linkId}}", "checkout"]
            },
            "description": "Crea una sesión de checkout de Polar sobre un link activo y devuelve { provider: polar, polarCheckoutId, price_id, seats, checkoutUrl, expiresAt }. Cada llamada crea una sesión nueva (sin idempotencia). reference viaja a Polar como vexorReference; metadata solo admite valores planos. En links recurrentes, price_id elige el plan y seats los asientos. Una conexión de Polar anterior al checkout por API responde 409 polar_reconnect_required."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Orders (Polar)",
      "item": [
        {
          "name": "Listar ventas",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/orders?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["orders"],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "description": "paid | partially_refunded | refunded | pending | void"
                },
                {
                  "key": "payment_link_id",
                  "value": "",
                  "description": "Ventas de un link"
                },
                {
                  "key": "reference",
                  "value": "",
                  "description": "Tu referencia (exacta): la de /p/{slug}?reference= o la del checkout por API",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10)"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            },
            "description": "Ventas cobradas por Polar (pagos únicos y renovaciones de suscripción)."
          },
          "response": []
        },
        {
          "name": "Obtener venta",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/orders/{{orderId}}",
              "host": ["{{baseUrl}}"],
              "path": ["orders", "{{orderId}}"]
            },
            "description": "Una venta de Polar, o 404 order_not_found."
          },
          "response": []
        },
        {
          "name": "Reembolsar venta",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Idempotency-Key",
                "value": "",
                "description": "Opcional: un replay devuelve la venta sin volver a reembolsar."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 10,\n  \"reason\": \"customer_request\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/orders/{{orderId}}/refund",
              "host": ["{{baseUrl}}"],
              "path": ["orders", "{{orderId}}", "refund"]
            },
            "description": "Reembolso total o parcial de una venta paid/partially_refunded: sale del saldo de Polar y el impuesto se devuelve en proporción. amount en dólares sin impuesto (default: todo lo reembolsable). Errores: 400 validation_error, 404 order_not_found, 409 polar_reconnect_required, 502 polar_update_failed."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Customers (Polar)",
      "item": [
        {
          "name": "Listar clientes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["customers"],
              "query": [
                {
                  "key": "email",
                  "value": "",
                  "description": "Email exacto (sin distinguir mayúsculas)"
                },
                {
                  "key": "query",
                  "value": "",
                  "description": "Busca en el email o el nombre"
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10)"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            },
            "description": "Clientes (compradores) de Polar, del más nuevo al más viejo, con stats: compras, total pagado neto de reembolsos, reembolsado, suscripciones activas y última compra."
          },
          "response": []
        },
        {
          "name": "Obtener cliente",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/customers/{{customerId}}",
              "host": ["{{baseUrl}}"],
              "path": ["customers", "{{customerId}}"]
            },
            "description": "Un cliente con stats, sus ventas (orders, hasta 100) y sus suscripciones, o 404 customer_not_found."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Disputes",
      "item": [
        {
          "name": "Listar disputas",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/disputes?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["disputes"],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "description": "warning_needs_response | warning_under_review | warning_closed | needs_response | under_review | won | lost | expired | closed"
                },
                {
                  "key": "order_id",
                  "value": "",
                  "description": "Filtro por la venta disputada (id de GET /orders)"
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            },
            "description": "Disputas de las ventas de Polar. Filtros: status (prevented, early_warning, needs_response, under_review, won, lost) y order_id. Polar las defiende: la única acción es aceptarlas."
          },
          "response": []
        },
        {
          "name": "Obtener disputa",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/disputes/{{disputeId}}",
              "host": ["{{baseUrl}}"],
              "path": ["disputes", "{{disputeId}}"]
            },
            "description": "Detalle de una disputa de Polar (mismo objeto que en la lista). Polar la defiende: no recibe evidencia."
          },
          "response": []
        },
        {
          "name": "Aceptar disputa",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/disputes/{{disputeId}}/accept",
              "host": ["{{baseUrl}}"],
              "path": ["disputes", "{{disputeId}}", "accept"]
            },
            "description": "Da la disputa por perdida (irreversible). Es la única acción posible: Polar defiende la disputa y no recibe evidencia. Errores: 400 dispute_not_respondable, 404 dispute_not_found, 409 polar_reconnect_required, 502 polar_update_failed."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Subscriptions",
      "item": [
        {
          "name": "Listar suscripciones",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/subscriptions?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["subscriptions"],
              "query": [
                {
                  "key": "status",
                  "value": "",
                  "description": "active | trialing | past_due | canceled | unpaid | pending | incomplete"
                },
                {
                  "key": "payment_link_id",
                  "value": "",
                  "description": "Filtro por link recurrente"
                },
                {
                  "key": "reference",
                  "value": "",
                  "description": "Tu referencia (exacta): la de /p/{slug}?reference= o la del checkout por API",
                  "disabled": true
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            }
          },
          "response": []
        },
        {
          "name": "Obtener suscripción",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/subscriptions/{{subscriptionId}}",
              "host": ["{{baseUrl}}"],
              "path": ["subscriptions", "{{subscriptionId}}"]
            }
          },
          "response": []
        },
        {
          "name": "Cambiar asientos",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"seats\": 3\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/subscriptions/{{subscriptionId}}",
              "host": ["{{baseUrl}}"],
              "path": ["subscriptions", "{{subscriptionId}}"]
            },
            "description": "Cambia la cantidad de asientos (`seats`) de una suscripción activa con plan per-seat: es el único campo mutable. Devuelve la suscripción con `seats` y `seatTotalCents` adicionales a nivel raíz. También en suscripciones de Polar (active/trialing sin cancelación programada): la diferencia se factura al instante. Errores: 400 invalid_seats, 404 subscription_not_found, 409 polar_reconnect_required, 502 polar_update_failed."
          },
          "response": []
        },
        {
          "name": "Cancelar suscripción",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/subscriptions/{{subscriptionId}}/cancel",
              "host": ["{{baseUrl}}"],
              "path": ["subscriptions", "{{subscriptionId}}", "cancel"]
            },
            "description": "Programa la cancelación al final del período actual (cancel_at_period_end). Idempotente."
          },
          "response": []
        },
        {
          "name": "Abrir portal del cliente",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/subscriptions/{{subscriptionId}}/portal",
              "host": ["{{baseUrl}}"],
              "path": ["subscriptions", "{{subscriptionId}}", "portal"]
            },
            "description": "Devuelve { url } del portal del cliente de Polar para que el suscriptor gestione su método de pago, facturas o cancelación."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Balance",
      "item": [
        {
          "name": "Obtener balance",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/balance",
              "host": ["{{baseUrl}}"],
              "path": ["balance"]
            },
            "description": "Devuelve { connected, polar, sandbox, updatedAt }. En polar, tu saldo de Polar (disponible, retenido 7 días, retirado), polar.financeUrl y polar.localEstimate (el mismo saldo en tu moneda local con la cotización de Stripe que se aplica al retirar). Sin Polar conectado: connected false."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Payouts",
      "item": [
        {
          "name": "Listar retiros",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payouts?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["payouts"],
              "query": [
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            },
            "description": "Lista tus retiros de Polar, hechos desde vexorpay o desde Polar (source dice cuál). Se actualizan al crearlos y cada 10 minutos."
          },
          "response": []
        },
        {
          "name": "Estimar retiro",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/payouts/estimate",
              "host": ["{{baseUrl}}"],
              "path": ["payouts", "estimate"]
            },
            "description": "Lo que llegaría a tu cuenta de cobro si retirás ahora todo el saldo disponible de Polar: bruto, comisiones de retiro de Polar, neto y localEstimate (moneda local con la cotización de Stripe)."
          },
          "response": []
        },
        {
          "name": "Retirar saldo de Polar",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Un reintento con la misma clave devuelve el mismo retiro sin crear otro"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/payouts",
              "host": ["{{baseUrl}}"],
              "path": ["payouts"]
            },
            "description": "Retira TODO el saldo disponible de Polar a tu cuenta de cobro (Polar no acepta un monto parcial). Body vacío. Con OAuth requiere el scope payouts:write."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Events",
      "item": [
        {
          "name": "Listar eventos",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/events?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["events"],
              "query": [
                {
                  "key": "type",
                  "value": "",
                  "description": "payment.completed | payment.refunded | payment.disputed | payout.paid (los subscription.*, payment.failed y dispute.resolved existen como webhook pero no se materializan acá)"
                },
                {
                  "key": "created[gte]",
                  "value": "",
                  "description": "ISO 8601"
                },
                {
                  "key": "created[lte]",
                  "value": "",
                  "description": "ISO 8601"
                },
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor por id de evento"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor por id de evento"
                }
              ]
            },
            "description": "Historial de eventos de negocio (mismos evt_... que se firman en los webhooks) para conciliar."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Connected Accounts",
      "item": [
        {
          "name": "Listar cuentas conectadas",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/connected-accounts?limit=10",
              "host": ["{{baseUrl}}"],
              "path": ["connected-accounts"],
              "query": [
                {
                  "key": "limit",
                  "value": "10",
                  "description": "Entero entre 1 y 100 (default 10); fuera de rango responde 400"
                },
                {
                  "key": "starting_after",
                  "value": "",
                  "description": "Cursor de paginación"
                },
                {
                  "key": "ending_before",
                  "value": "",
                  "description": "Cursor de paginación"
                }
              ]
            },
            "description": "Lista las conexiones activas de la app de marketplace dueña de la credencial. Requiere una credencial de app y el scope account:operate (con tokens OAuth)."
          },
          "response": []
        },
        {
          "name": "Obtener cuenta conectada",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/connected-accounts/{{connectedAccountId}}",
              "host": ["{{baseUrl}}"],
              "path": ["connected-accounts", "{{connectedAccountId}}"]
            },
            "description": "Detalle de una conexión (activa o revocada). 404 not_found si no existe o es de otra app o modo."
          },
          "response": []
        },
        {
          "name": "Revocar cuenta conectada",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/connected-accounts/{{connectedAccountId}}",
              "host": ["{{baseUrl}}"],
              "path": ["connected-accounts", "{{connectedAccountId}}"]
            },
            "description": "Revoca la conexión (idempotente): revoca los tokens OAuth del conectado para esa app, borra el consentimiento y deja la conexión en revoked."
          },
          "response": []
        },
        {
          "name": "Crear link a nombre del conectado",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Vexor-Account",
                "value": "{{connectedUserId}}",
                "description": "ID del usuario conectado en cuyo nombre se crea el link."
              },
              {
                "key": "Idempotency-Key",
                "value": "",
                "description": "Opcional: protege contra duplicados si repetís la misma petición."
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"amount\": 25,\n  \"title\": \"Curso de ejemplo\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": {
              "raw": "{{baseUrl}}/payment-links",
              "host": ["{{baseUrl}}"],
              "path": ["payment-links"]
            },
            "description": "Crea un link de pago a nombre del usuario conectado (header Vexor-Account). El link se crea en la organización de Polar del conectado; no hay comisión de marketplace. Errores: 403 invalid_connected_account / insufficient_scope, 400 account_not_connected si el conectado no tiene Polar."
          },
          "response": []
        }
      ]
    }
  ]
}
