OTL ShoesAPI
Exemplos em
Menu da documentação

Primeiros passos

Do token à primeira resposta em cinco minutos.

1. Tenha um token em mãos

Quem cria o token é o parceiro, no painel dele, em Integrações → Nova integração. Ele escolhe o nome, as permissões e a validade, e recebe o token uma única vez. O passo a passo com as telas está em Para o parceiro: criar uma integração.

O token começa com otl_prod_…otl_sbx_…. Use o seletor Produção / Sandbox no topo desta página para ver os exemplos no ambiente em que você está trabalhando.

Para começar, peça ao parceiro um token de sandbox. O catálogo é o mesmo, e você pode errar à vontade.

2. Confirme que o token funciona

A primeira chamada de toda integração é o /v1/eu: ela não exige permissão nenhuma e mostra o que o seu token pode fazer.

curl "https://api.otlshoes.com.br/v1/eu" \
  -H "Authorization: Bearer otl_prod_SEU_TOKEN"
curl "https://api-sandbox.otlshoes.com.br/v1/eu" \
  -H "Authorization: Bearer otl_sbx_SEU_TOKEN"
const resposta = await fetch('https://api.otlshoes.com.br/v1/eu', {
  headers: {
    Authorization: 'Bearer otl_prod_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
const resposta = await fetch('https://api-sandbox.otlshoes.com.br/v1/eu', {
  headers: {
    Authorization: 'Bearer otl_sbx_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
<?php
$ch = curl_init('https://api.otlshoes.com.br/v1/eu');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_prod_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
<?php
$ch = curl_init('https://api-sandbox.otlshoes.com.br/v1/eu');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_sbx_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
import requests

resposta = requests.get(
    "https://api.otlshoes.com.br/v1/eu",
    headers={
        "Authorization": "Bearer otl_prod_SEU_TOKEN",
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
import requests

resposta = requests.get(
    "https://api-sandbox.otlshoes.com.br/v1/eu",
    headers={
        "Authorization": "Bearer otl_sbx_SEU_TOKEN",
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
Testar agora no ambiente de testes

A chamada é feita de verdade, do seu navegador para a API de testes (https://api-sandbox.otlshoes.com.br/v1). Use um token otl_sbx_…: ele fica só nesta aba, e some ao fechá-la. Token de produção não é aceito aqui.

Resposta:

{
  "parceiro": {
    "nome": "Loja do João",
    "loja": "João Calçados"
  },
  "integracao": {
    "id": "cmuq5txm9000510arvq62c497",
    "nome": "Bling – João Dev",
    "criadaEm": "2026-10-01T20:23:15-03:00",
    "expiraEm": "2026-10-31T20:23:15-03:00"
  },
  "permissoes": [
    "conta:ler",
    "produtos:ler"
  ],
  "limite": {
    "porMinuto": 60,
    "restante": 59
  },
  "ambiente": "producao"
}

Confira três coisas:

  • ambiente é o que você esperava;
  • permissoes tem o que a sua integração vai usar — se faltar algo, o parceiro edita a integração;
  • integracao.expiraEm — se houver data, anote: depois dela o token para de funcionar.
curl "https://api.otlshoes.com.br/v1/produtos?limite=50" \
  -H "Authorization: Bearer otl_prod_SEU_TOKEN"
curl "https://api-sandbox.otlshoes.com.br/v1/produtos?limite=50" \
  -H "Authorization: Bearer otl_sbx_SEU_TOKEN"
const resposta = await fetch('https://api.otlshoes.com.br/v1/produtos?limite=50', {
  headers: {
    Authorization: 'Bearer otl_prod_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
const resposta = await fetch('https://api-sandbox.otlshoes.com.br/v1/produtos?limite=50', {
  headers: {
    Authorization: 'Bearer otl_sbx_SEU_TOKEN',
  },
});

if (!resposta.ok) {
  const { erro } = await resposta.json();
  throw new Error(`${erro.codigo}: ${erro.mensagem} (${erro.requestId})`);
}
const dados = await resposta.json();
<?php
$ch = curl_init('https://api.otlshoes.com.br/v1/produtos?limite=50');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_prod_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
<?php
$ch = curl_init('https://api-sandbox.otlshoes.com.br/v1/produtos?limite=50');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Authorization: Bearer otl_sbx_SEU_TOKEN',
]);

$corpo = json_decode(curl_exec($ch), true);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);

if ($status >= 400) {
    throw new Exception($corpo['erro']['codigo'] . ': ' . $corpo['erro']['mensagem']);
}
import requests

resposta = requests.get(
    "https://api.otlshoes.com.br/v1/produtos",
    headers={
        "Authorization": "Bearer otl_prod_SEU_TOKEN",
    },
    params={
        "limite": 50
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
import requests

resposta = requests.get(
    "https://api-sandbox.otlshoes.com.br/v1/produtos",
    headers={
        "Authorization": "Bearer otl_sbx_SEU_TOKEN",
    },
    params={
        "limite": 50
    },
    timeout=30,
)

if not resposta.ok:
    erro = resposta.json()["erro"]
    raise RuntimeError(f'{erro["codigo"]}: {erro["mensagem"]} ({erro["requestId"]})')
dados = resposta.json()
Testar agora no ambiente de testes

A chamada é feita de verdade, do seu navegador para a API de testes (https://api-sandbox.otlshoes.com.br/v1). Use um token otl_sbx_…: ele fica só nesta aba, e some ao fechá-la. Token de produção não é aceito aqui.

A resposta traz até 50 produtos em dados e, em paginacao.proximoCursor, o que mandar na próxima chamada para continuar. Quando temMais for false, você chegou ao fim. O detalhe está em Listar produtos, e a receita completa em Sincronizar catálogo e estoque.

4. Trate os erros pelo código

Toda resposta de erro tem o mesmo formato:

{
  "erro": {
    "codigo": "ESCOPO_INSUFICIENTE",
    "mensagem": "Esta integração não tem a permissão pedidos:ler.",
    "escopoNecessario": "pedidos:ler",
    "detalhes": [],
    "requestId": "req_87da1622e9de4dd9b63e6cb2",
    "doc": "https://docs.otlshoes.com.br/erros#ESCOPO_INSUFICIENTE"
  }
}

O seu sistema deve decidir o que fazer pelo campo codigo, que é estável — a mensagem pode mudar. A lista está em Erros. Guarde o requestId no seu log: é com ele que a equipe OTL localiza a chamada.

Próximos passos