{
  "info": {
    "_postman_id": "48954502-987d-4e28-bcfc-3a86990e926a",
    "name": "Only For Gamer - API B2B v1",
    "description": "Colección oficial para integrar la API B2B de Only For Gamer.\n\nURL base de producción:\nhttps://b2b.onlyforgamer.com/api/v1\n\nImportante:\n- Configurá api_token antes de ejecutar solicitudes.\n- POST /orders reserva saldo real.\n- No reutilices Idempotency-Key para pedidos diferentes.\n- La colección guarda automáticamente order_number después de crear un pedido.\n\nEntrega digital:\n- Los pedidos Gift Card completados pueden incluir un objeto delivery al consultar GET /orders/{order_number}.\n- Tratá códigos y PIN como información sensible y no los registres en logs.\n\nValidación de cuenta:\n- GET /products devuelve required_fields y account_validation_available.\n- Si account_validation_available=true, ejecutá POST /products/{sku}/validate-account antes de crear el pedido.\n- POST /orders admite account_validation_token, expected_price, expected_currency y player_ip.\n",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{api_token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "base_url",
      "value": "https://b2b.onlyforgamer.com/api/v1",
      "type": "string"
    },
    {
      "key": "api_token",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Cuenta",
      "description": "Consultas relacionadas con el perfil, saldo y fondos disponibles.",
      "item": [
        {
          "name": "Consultar perfil y saldo",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{base_url}}/me",
            "description": "Consultar perfil y saldo. Requiere profile:read."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('La solicitud fue procesada', function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Productos",
      "description": "Consulta del catálogo, precio B2B y disponibilidad.",
      "item": [
        {
          "name": "Listar productos",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{base_url}}/products?search={{product_search}}&brand={{brand}}&category={{category}}&region={{region}}&product_type={{product_type}}&per_page={{per_page}}&page={{page}}",
            "description": "Listar productos actualmente vendibles para la cuenta. Incluye precio B2B y disponibilidad. Requiere products:read. Admite paginación mediante page y per_page."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('La solicitud fue procesada', function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                  "});",
                  "// OFG_API_ACCOUNT_VALIDATION_POSTMAN_V1",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "    const body = pm.response.json();",
                  "    const items = Array.isArray(body?.data) ? body.data : [];",
                  "    const wanted = String(pm.environment.get('sku') || '').trim().toUpperCase();",
                  "    const product = items.find(item => String(item?.sku || '').trim().toUpperCase() === wanted);",
                  "",
                  "    if (product) {",
                  "        pm.environment.set('expected_price', String(product.price ?? ''));",
                  "        pm.environment.set('expected_currency', String(product.currency ?? ''));",
                  "        pm.environment.set('account_validation_available', product.account_validation_available ? 'true' : 'false');",
                  "        pm.environment.unset('account_validation_token');",
                  "    }",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Validar cuenta",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json"
              },
              {
                "key": "Content-Type",
                "value": "application/json"
              },
              {
                "key": "Authorization",
                "value": "Bearer {{api_token}}",
                "type": "text"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"target_data\": {\n    \"player_id\": \"{{player_id}}\",\n    \"server_id\": \"{{server_id}}\",\n    \"player_ip\": \"{{player_ip}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{base_url}}/products/{{sku}}/validate-account",
            "description": "Ejecutar solamente cuando GET /products devuelve account_validation_available=true. El token devuelto es temporal y debe enviarse luego en POST /orders."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// OFG_API_ACCOUNT_VALIDATION_POSTMAN_V1",
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "    const body = pm.response.json();",
                  "    const token = String(body?.data?.account_validation_token || '');",
                  "",
                  "    if (token) {",
                  "        pm.environment.set('account_validation_token', token);",
                  "    }",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Pedidos",
      "description": "Creación y consulta de pedidos B2B.",
      "item": [
        {
          "name": "Crear pedido",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Content-Type",
                "value": "application/json",
                "type": "text"
              },
              {
                "key": "Idempotency-Key",
                "value": "{{idempotency_key}}",
                "type": "text",
                "description": "Clave única de entre 8 y 100 caracteres."
              }
            ],
            "url": "{{base_url}}/orders",
            "description": "Crear pedido. Requiere orders:create. Esta solicitud reserva saldo real.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"sku\": \"{{sku}}\",\n  \"quantity\": 1,\n  \"external_reference\": \"{{external_reference}}\",\n  \"expected_price\": \"{{expected_price}}\",\n  \"expected_currency\": \"{{expected_currency}}\",\n  \"account_validation_token\": \"{{account_validation_token}}\",\n  \"target_data\": {\n    \"player_id\": \"{{player_id}}\",\n    \"server_id\": \"{{server_id}}\",\n    \"player_ip\": \"{{player_ip}}\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "const currentKey = pm.environment.get('idempotency_key');",
                  "",
                  "if (!currentKey || currentKey.trim() === '') {",
                  "    const random = Math.random()",
                  "        .toString(36)",
                  "        .substring(2, 10);",
                  "",
                  "    const generatedKey =",
                  "        `order-${Date.now()}-${random}`;",
                  "",
                  "    pm.environment.set(",
                  "        'idempotency_key',",
                  "        generatedKey",
                  "    );",
                  "}",
                  "// OFG_API_ACCOUNT_VALIDATION_POSTMAN_V1",
                  "const expectedPrice = String(pm.environment.get('expected_price') || '').trim();",
                  "const expectedCurrency = String(pm.environment.get('expected_currency') || '').trim();",
                  "const validationAvailable = String(pm.environment.get('account_validation_available') || '').trim().toLowerCase();",
                  "const validationToken = String(pm.environment.get('account_validation_token') || '').trim();",
                  "",
                  "if (!expectedPrice || !expectedCurrency) {",
                  "    throw new Error('Ejecutá primero Listar productos para cargar expected_price y expected_currency del SKU.');",
                  "}",
                  "",
                  "if (validationAvailable === 'true' && !validationToken) {",
                  "    throw new Error('Este producto requiere validación previa. Ejecutá Validar cuenta antes de Crear pedido.');",
                  "}"
                ]
              }
            },
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('Respuesta de creación válida', function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                  "});",
                  "",
                  "let response = {};",
                  "",
                  "try {",
                  "    response = pm.response.json();",
                  "} catch (error) {",
                  "    console.warn('No se pudo interpretar la respuesta JSON.');",
                  "}",
                  "",
                  "if (response?.data?.order_number) {",
                  "    pm.environment.set(",
                  "        'order_number',",
                  "        response.data.order_number",
                  "    );",
                  "}",
                  "",
                  "if (response?.data?.external_reference) {",
                  "    pm.environment.set(",
                  "        'external_reference',",
                  "        response.data.external_reference",
                  "    );",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Listar pedidos",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{base_url}}/orders?search={{order_search}}&per_page={{per_page}}",
            "description": "Listar pedidos. Requiere orders:read."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('La solicitud fue procesada', function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                  "});"
                ]
              }
            }
          ]
        },
        {
          "name": "Consultar pedido por número",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{base_url}}/orders/{{order_number}}",
            "description": "Consultar el detalle de un pedido. Requiere orders:read. Cuando un pedido Gift Card está completado y tiene entrega digital disponible, la respuesta puede incluir delivery con card_count, delivered_at y cards. Los códigos y PIN deben tratarse como información sensible."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('La consulta responde HTTP 200', function () {",
                  "    pm.response.to.have.status(200);",
                  "});",
                  "",
                  "const response = pm.response.json();",
                  "",
                  "if (response?.data?.delivery) {",
                  "    pm.test('La entrega digital tiene estructura pública válida', function () {",
                  "        pm.expect(response.data.status).to.eql('completed');",
                  "        pm.expect(response.data.product_type).to.eql('gift_card');",
                  "        pm.expect(response.data.delivery.status).to.eql('delivered');",
                  "        pm.expect(response.data.delivery.card_count).to.be.a('number');",
                  "        pm.expect(response.data.delivery.cards).to.be.an('array');",
                  "    });",
                  "",
                  "    pm.test('La respuesta sensible no debe almacenarse en caché', function () {",
                  "        const cacheControl = pm.response.headers.get('Cache-Control') || '';",
                  "        pm.expect(cacheControl.toLowerCase()).to.include('no-store');",
                  "    });",
                  "}"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Movimientos de saldo",
      "description": "Historial financiero del revendedor.",
      "item": [
        {
          "name": "Consultar movimientos de saldo",
          "request": {
            "method": "GET",
            "header": [
              {
                "key": "Accept",
                "value": "application/json",
                "type": "text"
              }
            ],
            "url": "{{base_url}}/wallet-transactions?type={{wallet_type}}&direction={{wallet_direction}}&order_number={{wallet_order_number}}&date_from={{date_from}}&date_to={{date_to}}&per_page={{wallet_per_page}}&page={{page}}",
            "description": "Consultar movimientos de saldo. Requiere wallet:read o balance:read."
          },
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "pm.test('La respuesta es JSON', function () {",
                  "    pm.expect(pm.response.headers.get('Content-Type')).to.include('application/json');",
                  "});",
                  "",
                  "pm.test('La solicitud fue procesada', function () {",
                  "    pm.expect(pm.response.code).to.be.oneOf([200, 201]);",
                  "});"
                ]
              }
            }
          ]
        }
      ]
    }
  ]
}
