{
  "info": {
    "_postman_id": "8f2c6d1e-3a47-4b9c-a5d0-7e1b4c9a2f36",
    "name": "API pública do BetBackoffice v1.1.0",
    "description": "Coleção gerada da especificação OpenAPI. Defina as variáveis da coleção **operatorKey** e **operatorSecret** com chaves de **sandbox** (`bk_test_…`) — a assinatura HMAC, o timestamp e a Idempotency-Key são calculados automaticamente. Comece por *Metadados › Identidade da credencial* (GET /me).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://backoffice.betfoguete.bet",
      "type": "string"
    },
    {
      "key": "operatorKey",
      "value": "",
      "type": "string"
    },
    {
      "key": "operatorSecret",
      "value": "",
      "type": "secret"
    },
    {
      "key": "playerId",
      "value": "PLU-3f1c9a2e-8d4b-4e6a-9c1d-2b7e5f0a1c34",
      "type": "string"
    },
    {
      "key": "depositId",
      "value": "DEP-7b2e4c10-5a93-4f8e-b1d6-0c9a3e7d2f58",
      "type": "string"
    },
    {
      "key": "withdrawalId",
      "value": "WD-c41d9e07-2b6a-4d35-8f10-7e5b9a3c6d82",
      "type": "string"
    }
  ],
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          "// Assina a requisição com HMAC-SHA256 (veja a documentação: string canônica).",
          "const key = pm.variables.get(\"operatorKey\");",
          "const secret = pm.variables.get(\"operatorSecret\");",
          "if (!key || !secret) {",
          "  throw new Error(\"Defina as variáveis da coleção operatorKey e operatorSecret (chaves de SANDBOX: bk_test_).\");",
          "}",
          "const method = pm.request.method.toUpperCase();",
          "const pathWithQuery = pm.variables.replaceIn(pm.request.url.getPathWithQuery());",
          "const hasBody = pm.request.body && pm.request.body.mode === \"raw\";",
          "const body = hasBody ? pm.variables.replaceIn(pm.request.body.raw || \"\") : \"\";",
          "const timestamp = String(Math.floor(Date.now() / 1000));",
          "const bodyHash = CryptoJS.SHA256(body).toString(CryptoJS.enc.Hex);",
          "const canonical = [method, pathWithQuery, timestamp, bodyHash].join(\"\\n\");",
          "const signature = CryptoJS.HmacSHA256(canonical, secret).toString(CryptoJS.enc.Hex);",
          "pm.request.headers.upsert({ key: \"X-Operator-Key\", value: key });",
          "pm.request.headers.upsert({ key: \"X-Timestamp\", value: timestamp });",
          "pm.request.headers.upsert({ key: \"X-Signature\", value: signature });",
          "if (method === \"POST\") {",
          "  pm.request.headers.upsert({ key: \"Idempotency-Key\", value: pm.variables.replaceIn(\"{{$guid}}\") });",
          "}"
        ]
      }
    }
  ],
  "item": [
    {
      "name": "Metadados",
      "item": [
        {
          "name": "Especificação OpenAPI",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/openapi.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "openapi.json"
              ]
            },
            "description": "Documento OpenAPI 3.1 desta versão da API. Público, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        },
        {
          "name": "Changelog da API",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/changelog",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "changelog"
              ]
            },
            "description": "Histórico de mudanças em Markdown. Público, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        },
        {
          "name": "Identidade da credencial",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/me",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "me"
              ]
            },
            "description": "Devolve o operador e a marca associados à credencial usada. Serve para validar a assinatura HMAC na integração."
          },
          "response": []
        },
        {
          "name": "Coleção Postman",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/postman.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "postman.json"
              ]
            },
            "description": "Coleção Postman v2.1 com todas as operações, corpos de exemplo e um script de pré-requisição que assina cada chamada com HMAC. Importe no Postman, defina `operatorKey` e `operatorSecret` (chaves de sandbox) e envie. Público, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        },
        {
          "name": "Snippets de assinatura",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/signing-snippets.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "signing-snippets.json"
              ]
            },
            "description": "Código para assinar requisições e verificar webhooks em Node.js, Python, PHP, Go, Java, C# e curl/openssl. Público, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        },
        {
          "name": "Vetores de teste da assinatura",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/test-vectors.json",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "test-vectors.json"
              ]
            },
            "description": "Entradas e assinaturas esperadas (requisição e webhook) para você conferir a sua implementação. Público, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        },
        {
          "name": "Página de documentação",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/docs",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "docs"
              ]
            },
            "description": "Página HTML com a referência interativa, primeiros passos, testador assinado (somente sandbox) e downloads. Pública, sem autenticação.",
            "auth": {
              "type": "noauth"
            }
          },
          "response": [],
          "event": [
            {
              "listen": "prerequest",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "// rota pública: sem assinatura"
                ]
              }
            }
          ]
        }
      ]
    },
    {
      "name": "Jogadores",
      "item": [
        {
          "name": "Cadastrar jogador",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"externalId\":\"jogador-123\",\"name\":\"Ana Souza\",\"email\":\"ana.souza@exemplo.com\",\"cpf\":\"52998224725\",\"phone\":\"11999998888\",\"birthDate\":\"1990-05-20\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Cria a conta do jogador na marca do operador, com KYC `nao_iniciado`. O login do jogador é responsabilidade do seu front-end: a API não recebe senha."
          },
          "response": [],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  pm.collectionVariables.set(\"playerId\", pm.response.json().id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Consultar jogador",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}"
              ]
            },
            "description": "Consultar jogador"
          },
          "response": []
        },
        {
          "name": "Buscar jogador por externalId",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players?externalId=jogador-123",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players"
              ],
              "query": [
                {
                  "key": "externalId",
                  "value": "jogador-123"
                }
              ]
            },
            "description": "Devolve o jogador da sua marca com o `externalId` informado (lista vazia se não existir)."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Carteira",
      "item": [
        {
          "name": "Saldo do jogador",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/wallet",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "wallet"
              ]
            },
            "description": "Saldo do jogador"
          },
          "response": []
        },
        {
          "name": "Extrato do jogador",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/transactions?limit=20",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "transactions"
              ],
              "query": [
                {
                  "key": "limit",
                  "value": "20"
                }
              ]
            },
            "description": "Lançamentos da carteira, do mais recente ao mais antigo. Paginação por cursor: envie `nextCursor` como `cursor` para a próxima página; `nextCursor` nulo indica o fim."
          },
          "response": []
        }
      ]
    },
    {
      "name": "KYC",
      "item": [
        {
          "name": "Situação do KYC",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/kyc",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "kyc"
              ]
            },
            "description": "Status da verificação de identidade e caso mais recente. A decisão (aprovar/reprovar) é feita pela equipe de compliance no backoffice."
          },
          "response": []
        },
        {
          "name": "Registrar envio de documento",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/kyc/submissions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "kyc",
                "submissions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"documentType\":\"RG\",\"reference\":\"doc-ana-souza-001\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Registra que o jogador enviou um documento e coloca o KYC `em_analise`. Nesta versão a API **não recebe o arquivo**: guarde-o no seu sistema e informe uma `reference` opaca para a equipe de compliance localizá-lo."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Depósitos",
      "item": [
        {
          "name": "Criar depósito",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/deposits",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "deposits"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"amount\":\"150.00\",\"currency\":\"BRL\",\"method\":\"PIX\",\"externalReference\":\"psp-2026-000123\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Registra a intenção de depósito como `pending`. O meio de pagamento é seu: depois de receber o pagamento, chame `POST /deposits/{depositId}/confirm` para creditar a carteira (ou `/fail` se não se concretizar). Respeita autoexclusão e o limite diário de depósito do jogador."
          },
          "response": [],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  pm.collectionVariables.set(\"depositId\", pm.response.json().id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Consultar depósito",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deposits/{{depositId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deposits",
                "{{depositId}}"
              ]
            },
            "description": "Consultar depósito"
          },
          "response": []
        },
        {
          "name": "Confirmar depósito",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deposits/{{depositId}}/confirm",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deposits",
                "{{depositId}}",
                "confirm"
              ]
            },
            "description": "Confirma que o pagamento foi recebido e credita o valor na carteira real do jogador, uma única vez."
          },
          "response": []
        },
        {
          "name": "Marcar depósito como não concretizado",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/deposits/{{depositId}}/fail",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "deposits",
                "{{depositId}}",
                "fail"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"reason\":\"pagamento expirou no PSP\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Marcar depósito como não concretizado"
          },
          "response": []
        }
      ]
    },
    {
      "name": "Saques",
      "item": [
        {
          "name": "Solicitar saque",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/withdrawals",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "withdrawals"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"amount\":\"50.00\",\"currency\":\"BRL\",\"method\":\"PIX\",\"destination\":\"ana.souza@exemplo.com\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Cria um pedido de saque na fila de análise do backoffice (aprovação e alçadas são da equipe). Exige KYC aprovado e jogador ativo, sem rollover de bônus pendente, e saldo real disponível descontados os saques ainda em aberto. O saldo é debitado no pagamento."
          },
          "response": [],
          "event": [
            {
              "listen": "test",
              "script": {
                "type": "text/javascript",
                "exec": [
                  "if (pm.response.code >= 200 && pm.response.code < 300) {",
                  "  pm.collectionVariables.set(\"withdrawalId\", pm.response.json().id);",
                  "}"
                ]
              }
            }
          ]
        },
        {
          "name": "Consultar saque",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/withdrawals/{{withdrawalId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "withdrawals",
                "{{withdrawalId}}"
              ]
            },
            "description": "Consultar saque"
          },
          "response": []
        },
        {
          "name": "Cancelar saque",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/withdrawals/{{withdrawalId}}/cancel",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "withdrawals",
                "{{withdrawalId}}",
                "cancel"
              ]
            },
            "description": "Só é possível enquanto o saque ainda não foi aprovado pela equipe."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Jogos",
      "item": [
        {
          "name": "Catálogo de jogos",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/games",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "games"
              ]
            },
            "description": "Catálogo de jogos"
          },
          "response": []
        },
        {
          "name": "Criar sessão de jogo",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/players/{{playerId}}/game-sessions",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "players",
                "{{playerId}}",
                "game-sessions"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"gameId\":\"rocket-crash\",\"locale\":\"pt-BR\",\"device\":\"desktop\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Cria uma sessão de jogo com dinheiro real e devolve a `gameUrl`, que o seu front abre (ex.: em um iframe). Exige jogador ativo e KYC aprovado. A URL carrega um token de curta duração (30 minutos): **não a registre em logs nem a repasse a terceiros**. Cada chamada cria uma nova sessão (não usa `Idempotency-Key`)."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Webhooks",
      "item": [
        {
          "name": "Enviar webhook de teste",
          "request": {
            "method": "POST",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/api/v1/webhooks/test",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "webhooks",
                "test"
              ]
            },
            "description": "Enfileira um evento `webhook.test` para a URL de webhook configurada para o seu operador, para validar a URL e a verificação de assinatura. A entrega é assíncrona (poucos segundos). A URL e o segredo são configurados pela equipe no backoffice."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Sandbox",
      "item": [
        {
          "name": "Decidir o KYC (somente sandbox)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sandbox/players/{{playerId}}/kyc/decision",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sandbox",
                "players",
                "{{playerId}}",
                "kyc",
                "decision"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"status\":\"aprovado\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Simula a decisão da equipe de compliance para o KYC do jogador, para você completar o fluxo em teste sem depender de ninguém. Dispara o webhook `kyc.status_changed`. **Em produção esta rota responde `403 SANDBOX_ONLY`**: lá a decisão é da equipe."
          },
          "response": []
        },
        {
          "name": "Decidir um saque (somente sandbox)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/api/v1/sandbox/withdrawals/{{withdrawalId}}/decision",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "api",
                "v1",
                "sandbox",
                "withdrawals",
                "{{withdrawalId}}",
                "decision"
              ]
            },
            "body": {
              "mode": "raw",
              "raw": "{\"decision\":\"approve\"}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "description": "Simula a análise da equipe: `approve` (em análise → aprovado), `reject` (recusa) ou `pay` (aprovado → pago, debitando a carteira). Dispara `withdrawal.status_changed`. **Em produção responde `403 SANDBOX_ONLY`.**"
          },
          "response": []
        }
      ]
    }
  ]
}
