Documentação da API
A API GeoLoc recebe CEP + número e devolve latitude, longitude, endereço completo e o nível de precisão. Com vários endereços, também devolve a ordem de visita e os links do Google Maps. Todas as respostas são JSON em UTF-8.
O mesmo serviço responde também em https://api.orderfly.com.br/geocep.
| Rota | Para quê |
|---|---|
GET /health | Confere se a API está no ar (não pede chave). |
GET /localizar | Um endereço, ou uma lista curta na própria URL. |
POST /localizar | Até 1.000 endereços em JSON, com rota opcional. |
POST /rota | Replaneja a rota a partir da posição atual (GPS do app). |
Autenticação
Toda chamada (exceto /health) leva a chave no cabeçalho X-Api-Key.
Sem a chave, ou com uma chave errada, a resposta é 401.
X-Api-Key: SUA_CHAVE
Guarde a chave no servidor. Não coloque a chave em código JavaScript de página nem dentro do aplicativo publicado: quem abrir o código leva a chave. O app chama o seu servidor, e o seu servidor chama a API.
Verificar se está no ar
{"lOk": true}Localizar um endereço
| Parâmetro | Tipo | Descrição |
|---|---|---|
sCep | texto | CEP com ou sem traço: 13216-340 ou 13216340. Obrigatório. |
sNum | texto | Número da porta. 120A, 120-B e 120 fundos usam o 120; vazio, S/N ou KM viram "sem número". |
sLogr | texto | Opcional. Nome da rua, só para desempatar CEP que cobre várias ruas. Aceita abreviações: R. Dr. Bento Goncalves. |
curl -H "X-Api-Key: SUA_CHAVE" \
"https://api.qtux.com.br/geocep/localizar?sCep=13216340&sNum=161"
{
"lOk": true, "iQtd": 1, "iAchou": 1,
"aRet": [{
"iSeq": 0,
"sCep": "13216340", "sNum": "161",
"lOk": true,
"nLat": -23.17516, "nLon": -46.87214,
"sPrec": "numero",
"sLogr": "RUA HERMENEGILDO MARTINELI",
"sLocal": "JARDIM DA FONTE",
"iCodMun": 3525904, "sMun": "Jundiaí", "sUf": "SP",
"lAmbig": false,
"sEnd": "RUA HERMENEGILDO MARTINELI, 161, JARDIM DA FONTE, Jundiaí - SP, 13216-340",
"sMapa": "https://www.google.com/maps/search/?api=1&query=-23.17516,-46.87214",
"iOrdem": 1
}]
}
Vários endereços na URL
Para testar no navegador ou mandar poucos endereços sem POST. Cada endereço é
cep|numero (ou cep|numero|rua), separados por ; ou ,.
Lista no corpo (recomendado)
Até 1.000 endereços por chamada. A resposta mantém a mesma ordem do envio
(iSeq = posição na lista enviada).
{
"aEnd": [
{"sCep": "13216-340", "sNum": "161"},
{"sCep": "13213073", "sNum": "177"},
{"sCep": "90010150", "sNum": "1200", "sLogr": "opcional"}
]
}A lista também pode ir direto no corpo, sem o aEnd: [{"sCep": "...", "sNum": "..."}].
Ordem de visita e ida e volta
No /localizar, o primeiro endereço da lista é sempre a saída. Duas opções,
no corpo do POST ou na URL (&lOtim=1&lVolta=1):
| Opção | Padrão | O que faz |
|---|---|---|
lOtim | false | Reordena as demais paradas pelo menor percurso total. Até 9 paradas testa todas as ordens; acima disso usa otimização (em média 0,25% acima da melhor ordem possível). |
lVolta | false | Volta para a saída no fim (ida e volta). A otimização já conta o trecho de volta. |
{
"lOtim": true, "lVolta": true,
"aEnd": [
{"sCep": "13216340", "sNum": "161"}, // base: saida e chegada
{"sCep": "13202020", "sNum": "235"},
{"sCep": "13203000", "sNum": "221"},
{"sCep": "13206010", "sNum": "2641"},
{"sCep": "13208050", "sNum": "318"},
{"sCep": "13209000", "sNum": "873"},
{"sCep": "13211000", "sNum": "575"},
{"sCep": "13213073", "sNum": "177"},
{"sCep": "13215003", "sNum": "193"}
]
}
{
"lOk": true, "iQtd": 9, "iAchou": 9,
"lOtim": true, "lVolta": true,
"sCusto": "rua",
"nKm": 31.8, "nMin": 58.4,
"aOrdem": [0, 7, 6, 5, 4, 3, 2, 1, 8, 0],
"aMapa": ["https://www.google.com/maps/dir/?api=1&travelmode=driving&origin=...&waypoints=..."],
"aRet": [ /* um item por endereco enviado, com iOrdem */ ]
}
aOrdem lista as posições da lista enviada (iSeq) na ordem de visita; com
lVolta a saída aparece de novo no fim. Endereço não encontrado fica fora da rota.
Os valores de nKm e nMin acima são ilustrativos.
Pelas ruas ou em linha reta: sCusto: "rua" significa que a ordem e os totais
usam o tempo de carro pelas ruas (mão única, rios, rodovias), com nMin.
Se o serviço de rotas estiver fora do ar, a API não falha: responde sCusto: "reta",
com a distância em linha reta e sem nMin.
Replanejar a partir do GPS
Feita para o app de visitas: a cada parada concluída, o app manda a posição atual e o que falta, e recebe a nova ordem e o link das próximas paradas. A API não guarda estado.
| Campo | Tipo | Descrição |
|---|---|---|
oOrig | {nLat, nLon} | Posição atual. Obrigatório. (0, 0) de GPS sem sinal é recusado. |
oFim | {nLat, nLon} | Ponto final fixo, por exemplo a base. Opcional. |
aPar | lista | Paradas: com nLat/nLon (já localizadas) ou com sCep/sNum (a API localiza). sId é livre e volta igual. Até 1.000. |
iParLink | 1 a 10 | Paradas por link do Maps. Padrão 4: o navegador do celular aceita só 3 paradas intermediárias + destino. |
lOtim | true | Reordena pelo menor percurso. false mantém a ordem enviada. |
lComOrig | false | Sem origem no link: o Google usa a posição do aparelho na hora do toque e já abre a navegação. |
{
"oOrig": {"nLat": -23.18989, "nLon": -46.88723},
"oFim": {"nLat": -23.17516, "nLon": -46.87214},
"aPar": [
{"sId": "CLI-102", "nLat": -23.22103, "nLon": -46.87383, "sPrec": "numero", "sEnd": "..."},
{"sId": "CLI-205", "sCep": "13203000", "sNum": "221"}
],
"iParLink": 4
}
{
"lOk": true, "iQtd": 2, "iAchou": 2,
"sCusto": "rua", "nKm": 9.4, "nMin": 21.0,
"aOrdem": [0, 1],
"sMapa": "https://www.google.com/maps/dir/?api=1&travelmode=driving&dir_action=navigate&...",
"aMapa": ["..."],
"aPar": [
{"iSeq": 0, "sId": "CLI-102", "lOk": true, "iOrdem": 1, ...},
{"iSeq": 1, "sId": "CLI-205", "lOk": true, "iOrdem": 2, ...}
]
}
No /rota, iOrdem = 1 é a próxima parada a fazer
(no /localizar, 1 é a saída). sMapa é o link das próximas paradas;
aMapa traz a rota inteira em links encadeados.
Fluxo recomendado no app
Montar o dia
Envie todas as paradas com sCep/sNum. Guarde no app o nLat, nLon, sPrec e sEnd que voltarem.
A cada visita feita
Mande o GPS atual em oOrig e só as paradas que faltam, já com as coordenadas (não precisa localizar de novo).
Seguir o link
Abra o sMapa: o Google já navega até as próximas paradas, na ordem calculada.
Campos da resposta
No topo
| Campo | Tipo | Descrição |
|---|---|---|
lOk | bool | A chamada foi processada. |
iQtd / iAchou | int | Endereços enviados / encontrados. |
sCusto | texto | rua (tempo de carro pelas ruas) ou reta (linha reta). |
nKm | número | Distância total da rota. Em linha reta, o caminho real é maior. |
nMin | número | Tempo de carro estimado, só com sCusto: "rua". |
aOrdem | lista | Posições (iSeq) na ordem de visita. |
aMapa | lista | Links do Google Maps com a rota, já na ordem. |
aRet / aPar | lista | Um item por endereço enviado, na mesma ordem (aPar no /rota). |
Em cada endereço
| Campo | Tipo | Descrição |
|---|---|---|
iSeq | int | Posição na lista enviada (começa em 0). |
lOk | bool | false = CEP inválido ou inexistente; sErro explica. |
nLat / nLon | número | Coordenada em graus decimais (WGS84), 6 casas. |
sPrec | texto | De onde veio a coordenada (ver Precisão). |
iNumRef | int | Só com sPrec: "vizinho": o número usado como referência. |
sLogr / sLocal | texto | Logradouro e bairro/localidade. |
iCodMun / sMun / sUf | int / texto | Código IBGE do município, nome e UF. |
sEnd | texto | Endereço escrito: rua, número, bairro, cidade - UF, CEP. |
sMapa | texto | Link do Google Maps com o alfinete no ponto. |
iOrdem | int | Posição na rota calculada. |
lAmbig / aOpc | bool / lista | CEP com várias ruas possíveis (ver abaixo). |
Precisão (sPrec)
Do melhor para o pior. A API para no primeiro nível que encontrar.
| Valor | Significado |
|---|---|
| numero | Ponto do próprio número predial. |
| interpolado | Calculado entre os dois vizinhos do mesmo lado da rua (mesma paridade). |
| vizinho | Só há número de um lado: usa o mais próximo (iNumRef). |
| logradouro | Sem número válido: centro da rua. |
| cep | Centro do CEP (CEP genérico com várias ruas e sem sLogr). |
| cep_base | CEP fora do Censo: ponto da base de CEPs complementar (qualidade menor). |
Em Brasília (DF) quase não há número predial (endereços por quadra e bloco): lá a resposta
costuma ser logradouro ou cep.
CEP com várias ruas
Em cidades pequenas, um CEP pode cobrir várias ruas. Se o número existir em mais de uma delas, a API
devolve o centro do CEP com lAmbig: true e as ruas candidatas em aOpc. Reenvie com
sLogr para desempatar.
{
"lOk": true, "sPrec": "cep", "lAmbig": true,
"aOpc": [
{"sLogr": "RUA DAS FLORES", "sLocal": "CENTRO", "nLat": -27.1, "nLon": -52.6},
{"sLogr": "AVENIDA BRASIL", "sLocal": "CENTRO", "nLat": -27.1, "nLon": -52.6}
]
}Links do Google Maps
- Formato oficial (
api=1): origem, até 9 paradas intermediárias e destino. Rotas maiores são divididas em vários links encadeados: cada um começa na última parada do anterior. - O Maps calcula o caminho entre paradas seguidas, mas não muda a ordem: a ordem é a da API.
- Pontos com precisão fraca (
logradouro,cep,cep_base) vão no link como endereço escrito, para o Google achar o número; os demais vão por coordenada. - Um endereço só vira um alfinete (busca), não uma rota.
Erros e limites
| Código | Quando |
|---|---|
| 200 | Processado. Endereços não encontrados vêm com lOk: false e sErro no próprio item. |
| 400 | Corpo inválido, lista vazia, oOrig/oFim inválidos. |
| 401 | Chave ausente ou errada. |
| 413 | Mais de 1.000 endereços ou corpo acima de 1 MB. |
| 500 | Falha interna na consulta. Tente de novo; o detalhe fica só no registro do servidor. |
Erros sempre no formato {"lOk": false, "sErro": "..."}. Mensagens por item:
CEP invalido (8 digitos), CEP nao encontrado.
Exemplos completos
Localizar dois endereços e montar a rota com volta para a base.
curl -s https://api.qtux.com.br/geocep/localizar \
-H "X-Api-Key: SUA_CHAVE" \
-H "Content-Type: application/json" \
-d '{"lOtim": true, "lVolta": true,
"aEnd": [{"sCep": "13216340", "sNum": "161"},
{"sCep": "13213073", "sNum": "177"},
{"sCep": "13211000", "sNum": "575"}]}'
<?php
// A chave fica no servidor (variavel de ambiente ou arquivo de configuracao)
$sChave = getenv('GEOLOC_CHAVE');
$aCorpo = [
'lOtim' => true,
'lVolta' => true,
'aEnd' => [
['sCep' => '13216340', 'sNum' => '161'],
['sCep' => '13213073', 'sNum' => '177'],
['sCep' => '13211000', 'sNum' => '575'],
],
];
$hCurl = curl_init('https://api.qtux.com.br/geocep/localizar');
curl_setopt_array($hCurl, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($aCorpo),
CURLOPT_HTTPHEADER => ['Content-Type: application/json', 'X-Api-Key: ' . $sChave],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$aResp = json_decode((string)curl_exec($hCurl), true);
foreach ($aResp['aRet'] ?? [] as $aEnd) {
echo $aEnd['iOrdem'] ?? '-', ' ', $aEnd['sEnd'] ?? $aEnd['sErro'], "\n";
}
echo $aResp['aMapa'][0] ?? '', "\n";
// No servidor (Node 18+): a chave nunca vai para o navegador
const oResp = await fetch('https://api.qtux.com.br/geocep/localizar', {
method: 'POST',
headers: { 'Content-Type': 'application/json', 'X-Api-Key': process.env.GEOLOC_CHAVE },
body: JSON.stringify({
lOtim: true, lVolta: true,
aEnd: [
{ sCep: '13216340', sNum: '161' },
{ sCep: '13213073', sNum: '177' },
{ sCep: '13211000', sNum: '575' }
]
})
});
const oJson = await oResp.json();
oJson.aRet.forEach(o => console.log(o.iOrdem, o.sEnd, o.nLat, o.nLon));
console.log(oJson.aMapa[0]);
import os, requests
oResp = requests.post(
'https://api.qtux.com.br/geocep/localizar',
headers={'X-Api-Key': os.environ['GEOLOC_CHAVE']},
json={'lOtim': True, 'lVolta': True,
'aEnd': [{'sCep': '13216340', 'sNum': '161'},
{'sCep': '13213073', 'sNum': '177'},
{'sCep': '13211000', 'sNum': '575'}]},
timeout=60)
oJson = oResp.json()
for oEnd in oJson['aRet']:
print(oEnd.get('iOrdem'), oEnd.get('sEnd') or oEnd.get('sErro'))
print(oJson['aMapa'][0])
Boas práticas
Mande em lote
Um POST com 300 endereços é muito mais rápido que 300 chamadas de um endereço.
Guarde a coordenada
Endereço de cliente muda pouco: salve nLat, nLon e sPrec no seu cadastro e localize de novo só quando o endereço mudar.
Olhe o sPrec
Para cep e cep_base, peça confirmação ao usuário ou complete o cadastro com o nome da rua.