API do DestinoLab Paraty

A API é a ponte entre as cinco soluções do DestinoLab Paraty e o banco central do destino. As soluções mandam para cá o que acontece no território (check-ins, carimbos, pontos de coleta, pesagens) e leem daqui o catálogo único de atrativos. O portal e os dashboards leem do mesmo lugar. Nenhuma solução fala direto com o banco, e nenhuma tem rota privilegiada.

APIhttps://api.destinolabparaty.com.br
Identidade (OAuth)https://auth.destinolabparaty.com.br
FormatoJSON em UTF-8, chaves em snake_case, só HTTPS

Começar em três passos

  1. Peça um token com o client_id e o client_secret que a sua empresa recebeu. Ele vale 15 minutos.
    TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" -d grant_type=client_credentials \
      https://auth.destinolabparaty.com.br/oauth/token | python3 -c 'import json,sys; print(json.load(sys.stdin)["access_token"])')
  2. Confira a conexão. A resposta diz quem é o client e quais escopos ele tem.
    curl -H "Authorization: Bearer $TOKEN" https://api.destinolabparaty.com.br/v1/cliente
  3. Leia os atrativos e mande o primeiro check-in.
    curl -H "Authorization: Bearer $TOKEN" 'https://api.destinolabparaty.com.br/v1/pois?limite=5'
    
    curl -X POST https://api.destinolabparaty.com.br/v1/checkins \
      -H "Authorization: Bearer $TOKEN" -H "Idempotency-Key: $(uuidgen)" \
      -H 'Content-Type: application/json' -d '{"poi":"PTY-POI-0001","origem":"qr"}'

No Postman: importe a collection, preencha client_id e client_secret nas variáveis da collection e chame qualquer requisição. O token é pedido e renovado sozinho.

Convenções

IdentificadoresTodo recurso tem um código estável e público (PTY-POI-0001, PTY-COL-0001, PTY-OPE-0012). Check-ins e coletas têm uuid. O id interno do banco nunca aparece.
QR Code do atrativoCada atrativo tem um qr_uuid (UUID v4) fixo, que vai impresso no QR Code físico. Ele vem na busca e no detalhe do atrativo, e serve para achar o atrativo (GET /v1/pois?qr_uuid=) e para registrar check-in.
DatasISO 8601 com fuso: 2026-12-27T10:30:00-03:00. Hora sem fuso é recusada. A API devolve sempre no fuso de Paraty. Filtros de período usam o dia, AAAA-MM-DD.
Dinheiro e pesoSempre inteiros: dinheiro em centavos, peso em gramas. Número com casa decimal é recusado.
Campo desconhecidoResponde 422, no corpo e na consulta. Nada é ignorado em silêncio.
Dado pessoalNenhuma rota de integração aceita nome, e-mail, telefone ou documento de visitante. Quando o fato é de uma pessoa, ela vai como sub: o identificador que a sua solução recebeu no login dela, diferente em cada solução.
PaginaçãoPor cursor. A resposta traz pagina.proximo e pagina.tem_mais; repita a chamada com depois=<proximo>. limite vai de 1 a 200 (padrão 50).
IdempotênciaTodo POST que cria algo exige o cabeçalho Idempotency-Key (1 a 120 caracteres). Repetir a mesma chave com o mesmo corpo, em até 24 h, devolve a resposta original com Idempotent-Replayed: true e não cria de novo. Mesma chave com outro corpo: 422. Check-ins, pontos e coletas aceitam também referencia_externa (o id no seu sistema), que impede duplicata sem prazo.
ConcorrênciaPATCH /v1/pois/{codigo} exige If-Match com o ETag do último GET: 428 sem o cabeçalho, 412 se alguém alterou antes.
LimitesPor client e por minuto: 600 leituras e 120 escritas. Rotas públicas: 120 por IP. Toda resposta autenticada traz RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset; o 429 traz Retry-After.
RastreioToda resposta traz X-Request-Id. Informe esse valor ao abrir um chamado.
NavegadorA API não responde a CORS: as chamadas partem do servidor da solução, nunca do navegador do visitante (o client_secret não pode ir para o front-end).

Erros

Formato RFC 9457, application/problem+json. Em erro de validação, erros diz o campo e o motivo.

{
    "type": "https://api.destinolabparaty.com.br/erros/validacao",
    "title": "Dados inválidos",
    "status": 422,
    "detail": "Os dados do check-in são inválidos.",
    "instance": "/v1/checkins",
    "request_id": "66f8f763-b272-4d77-b235-c1e692dfe036",
    "erros": [
        {
            "campo": "nome_do_turista",
            "codigo": "campo_desconhecido",
            "mensagem": "Campo não reconhecido."
        }
    ]
}
StatusQuando
400Requisição malformada, ou Idempotency-Key ausente
401Token ausente, vencido ou revogado: peça outro
403O token não tem o escopo, ou o recurso é de outra organização
404Recurso inexistente (ou ainda não publicado)
405Método não aceito neste caminho; veja o cabeçalho Allow
412 / 428If-Match desatualizado / ausente
422Dados inválidos; veja erros
429Limite de taxa; espere Retry-After segundos
503Banco ou segredos indisponíveis; tente de novo

Escopos

O token carrega os escopos do client. Cada rota desta página mostra o escopo que exige.

EscopoPermiteQuem recebe
catalogo:lerAtrativos, páginas, agenda, busca e subdomíniosas cinco, portal, Prefeitura
catalogo:escreverCriar e publicar atrativo, agenda e mídia (curadoria)Prefeitura
operadores:lerOperadores homologados e seus equipamentosas cinco, portal, Prefeitura
operadores:escreverCadastrar operador e equipamento; homologar e emitir selo (curadoria)Prefeitura
checkins:escreverRegistrar check-in de visita num atrativoas cinco
checkins:lerListar os check-ins da própria soluçãoas cinco, Prefeitura
residuos:lerPontos de coleta e pesagensas cinco, portal, Prefeitura
residuos:escreverCadastrar ponto de coleta e registrar pesagemReciclo Social, Prefeitura
passaporte:escreverCarimbar o passaporte de um visitante pelo subas cinco
painel:lerIndicadores agregados do destinoportal, Prefeitura
openid, profile, email, passaporte:lerToken de login do visitante (Authorization Code + PKCE)apps com login

O que cada solução usa

As cinco usam a mesma API e as mesmas rotas. O que muda é o que cada uma manda.

Viva

Ordenamento e venda de experiências.

  • Lê atrativos, operadores homologados e selos
  • Check-in no embarque (origem: reserva, com pessoas)
  • Carimbo no passaporte

Diaspora.Black

Roteiros de memória e cultura negra.

  • Lê atrativos e agenda
  • Check-in em cada parada do roteiro
  • Carimbo no passaporte

Interact Place

QR Codes e histórias no local.

  • Lê o qr_uuid de cada atrativo para gerar os QR Codes
  • Resolve o atrativo pelo QR lido (GET /v1/pois?qr_uuid=)
  • Check-in com qr_uuid (origem: qr)

Fubá

Natureza, trilhas e educação ambiental.

  • Lê atrativos por categoria e por proximidade
  • Check-in por localização (origem: geo)
  • Carimbo no passaporte

Reciclo Social

Coleta e economia circular.

  • Cadastra os pontos de coleta de cada atrativo
  • Registra cada pesagem, por material, em gramas
  • Check-in de ações e mutirões (origem: manual)

O que ainda não existe

Estas partes estão previstas no desenho da plataforma e ainda não estão no ar. Chamá-las responde 404. Os escopos eventos:publicar, eventos:consumir e ofertas:ler já vêm no token, mas ainda não abrem nenhuma rota.

Barramento de eventos e webhooks/v1/eventos, /v1/webhooks. Enquanto não existir, a sincronização é por consulta: GET /v1/pois?atualizado_apos=.
Ofertas, saídas e reservas/v1/ofertas, /v1/reservas, /v1/pois/{codigo}/disponibilidade
Registro de saída e ocorrências/v1/saidas, /v1/ocorrencias
Perfil de destino do visitante/v1/visitantes/{sub}/perfil-de-destino

Autenticação

Integração máquina a máquina usa OAuth 2.1 client_credentials: troque o client_id e o client_secret por um access_token (JWT RS256, 15 minutos) e mande-o em Authorization: Bearer. Não há refresh token nesse fluxo: peça outro token quando o atual vencer. O segredo nunca vai em URL nem em corpo JSON.

Obter token (client_credentials)

POST auth./oauth/token Basic: client_id e client_secret

Autentique o client por HTTP Basic (client_id:client_secret). O token sai com todos os escopos do client; para pedir menos, mande scope com os escopos separados por espaço. Até 60 chamadas por minuto por IP; 30 falhas por minuto bloqueiam o client por até 1 minuto.

Exemplo

curl -X POST 'https://auth.destinolabparaty.com.br/oauth/token' \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials

Resposta 200

{
    "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImRscC0yMDI2MTEwNi1iNWI2NmJiZiJ9…",
    "token_type": "Bearer",
    "expires_in": 900,
    "scope": "catalogo:ler checkins:escrever checkins:ler operadores:ler passaporte:escrever residuos:ler"
}

Erros próprios desta rota

  • 401 invalid_client: client_id ou client_secret errado.
  • 429 Muitas tentativas; veja Retry-After.

Quem sou eu (teste de conectividade)

GET /v1/cliente qualquer token

Devolve o client, o parceiro e os escopos do token. É a primeira chamada a fazer depois de receber a credencial.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/cliente' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "client_id": "fuba-maquina",
    "parceiro": "fuba",
    "escopos": [
        "catalogo:ler",
        "checkins:escrever",
        "checkins:ler",
        "operadores:ler",
        "passaporte:escrever",
        "residuos:ler"
    ],
    "token_expira_em": "2026-11-10T14:02:11-03:00"
}

Conferir um token

POST auth./oauth/introspeccao Basic: client_id e client_secret

RFC 7662. Cada client só enxerga os próprios tokens; token de outro client responde active: false.

Exemplo

curl -X POST 'https://auth.destinolabparaty.com.br/oauth/introspeccao' \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d token="$TOKEN"

Resposta 200

{
    "active": true,
    "client_id": "fuba-maquina",
    "scope": "catalogo:ler checkins:escrever",
    "exp": 1794330131,
    "token_type": "Bearer"
}

Revogar um token

POST auth./oauth/revogar Basic: client_id e client_secret

RFC 7009. A chamada seguinte com o token revogado já responde 401. Responde 200 mesmo se o token não existir.

Exemplo

curl -X POST 'https://auth.destinolabparaty.com.br/oauth/revogar' \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d token="$TOKEN"

Responde 200.

Descoberta OIDC

GET auth./.well-known/openid-configuration pública

Endereços e capacidades do provedor de identidade.

Exemplo

curl 'https://auth.destinolabparaty.com.br/.well-known/openid-configuration'

Responde 200.

Chaves públicas (JWKS)

GET auth./.well-known/jwks.json pública

Para quem quiser validar a assinatura do JWT por conta própria. A chave roda a cada 90 dias; a anterior segue publicada por 24 h.

Exemplo

curl 'https://auth.destinolabparaty.com.br/.well-known/jwks.json'

Responde 200.

Check-ins

Qualquer das cinco soluções registra que alguém esteve num atrativo. O atrativo vem pelo código ou pelo UUID lido no QR Code. O check-in pode ser anônimo (só conta) ou levar o sub do visitante que fez login na solução. Nome, e-mail, telefone ou documento de visitante nunca entram aqui: campo desconhecido é recusado com 422.

Registrar check-in

POST /v1/checkins checkins:escrever Idempotency-Key obrigatório

Responde 201 com criado: true. Se a referencia_externa já foi usada pela solução, responde 200 com o check-in que já existia e criado: false. O check-in não carimba o passaporte: isso é POST /v1/passaporte/carimbos.

Campos do corpo

poiCódigo do atrativo. Informe poi ou qr_uuid, um dos dois
qr_uuidUUID lido no QR Code do atrativo
origemqr (padrão), geo, reserva ou manual
pessoasTamanho do grupo, de 1 a 500 (padrão 1)
ocorrido_emISO 8601 com fuso; padrão: agora. Não pode estar no futuro
subOpcional. O sub pairwise que a sua solução recebeu no login do visitante
referencia_externaOpcional. O id do check-in no seu sistema (até 80 caracteres); impede duplicata

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/checkins' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"qr_uuid":"0f8fad5b-d9cb-469f-a165-70867728950e","origem":"qr","pessoas":2,"ocorrido_em":"2026-12-27T10:30:00-03:00","referencia_externa":"app-778"}'

Resposta 201

{
    "criado": true,
    "uuid": "b1a7c1de-3f0a-4c55-9d0e-6a1f2c3d4e5f",
    "poi": "PTY-POI-0001",
    "solucao": "fuba",
    "origem": "qr",
    "pessoas": 2,
    "identificado": false,
    "ocorrido_em": "2026-12-27T10:30:00-03:00",
    "referencia_externa": "app-778",
    "registrado_em": "2026-12-27T10:30:04-03:00"
}

Erros próprios desta rota

  • 403 Sem o escopo, ou o visitante do sub revogou o consentimento com a solução.
  • 404 Nenhum visitante com este sub no setor da solução.
  • 422 Atrativo inexistente ou não publicado, data no futuro ou sem fuso, campo desconhecido.

Listar check-ins

GET /v1/checkins checkins:ler

Cada solução vê só os seus; a curadoria vê os de todas. Do mais recente para o mais antigo.

Parâmetros da consulta

poiCódigo do atrativo
deDia inicial, AAAA-MM-DD (fuso de Paraty)
ateDia final, AAAA-MM-DD, incluído
limite1 a 200 (padrão 50)
depoisCursor da página anterior

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/checkins?poi=PTY-POI-0001' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "uuid": "b1a7c1de-3f0a-4c55-9d0e-6a1f2c3d4e5f",
            "poi": "PTY-POI-0001",
            "solucao": "fuba",
            "origem": "qr",
            "pessoas": 2,
            "identificado": false,
            "ocorrido_em": "2026-12-27T10:30:00-03:00",
            "referencia_externa": "app-778",
            "registrado_em": "2026-12-27T10:30:04-03:00"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Resíduos: pontos de coleta e pesagens

Quem opera a coleta cadastra os pontos que mantém dentro de cada atrativo (quantos forem precisos) e depois informa quanto saiu de cada ponto, por material. Peso sempre em gramas, inteiro: 12,4 kg é 12400. Cada ponto só é alterado, e só recebe pesagem, de quem o cadastrou. As outras soluções e o portal leem.

Cadastrar ponto de coleta num atrativo

POST /v1/pois/{codigo}/pontos-de-coleta residuos:escrever Idempotency-Key obrigatório

O código do ponto (PTY-COL-0001) é gerado aqui. Repetir a mesma referencia_externa devolve 200 com o ponto que já existe, sem criar outro.

Campos do corpo

nomeObrigatório, 2 a 160 caracteres
descricaoAté 500 caracteres
tipolixeira (padrão), ecoponto, conteiner, entrega_voluntaria ou outro
materiaisLista: reciclavel, papel, plastico, vidro, metal, organico, rejeito, oleo, eletronico
localizacaolatitude e longitude do ponto
capacidade_litrosInteiro
referencia_externaO id do ponto no seu sistema; impede duplicata
statusativo (padrão) ou inativo
instalado_emAAAA-MM-DD

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/pois/PTY-POI-0001/pontos-de-coleta' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"nome":"Lixeira da entrada da praia","descricao":"Ao lado do quiosque, na chegada dos barcos.","tipo":"lixeira","materiais":["plastico","metal"],"localizacao":{"latitude":-23.19671,"longitude":-44.62951},"capacidade_litros":240,"referencia_externa":"RS-PT-01","instalado_em":"2026-10-20"}'

Resposta 201

{
    "criado": true,
    "coletas": 0,
    "total_coletado_gramas": 0,
    "ultima_coleta_em": null,
    "codigo": "PTY-COL-0001",
    "poi": "PTY-POI-0003",
    "operado_por": "reciclo",
    "nome": "Lixeira da entrada da praia",
    "descricao": "Ao lado do quiosque, na chegada dos barcos.",
    "tipo": "lixeira",
    "materiais": [
        "plastico",
        "metal"
    ],
    "localizacao": {
        "latitude": -23.19671,
        "longitude": -44.62951
    },
    "capacidade_litros": 240,
    "referencia_externa": "RS-PT-01",
    "status": "ativo",
    "instalado_em": "2026-10-20",
    "criado_em": "2026-10-20T09:12:44-03:00",
    "atualizado_em": "2026-10-20T09:12:44-03:00"
}

Erros próprios desta rota

  • 404 Atrativo inexistente ou não publicado.

Pontos de coleta de um atrativo

GET /v1/pois/{codigo}/pontos-de-coleta residuos:ler

Cada ponto vem com o total já coletado nele e a data da última coleta.

Parâmetros da consulta

statusativo ou inativo
limite1 a 200
depoisCursor da página anterior

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/pois/PTY-POI-0001/pontos-de-coleta' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "codigo": "PTY-COL-0001",
            "poi": "PTY-POI-0003",
            "operado_por": "reciclo",
            "nome": "Lixeira da entrada da praia",
            "descricao": "Ao lado do quiosque, na chegada dos barcos.",
            "tipo": "lixeira",
            "materiais": [
                "plastico",
                "metal"
            ],
            "localizacao": {
                "latitude": -23.19671,
                "longitude": -44.62951
            },
            "capacidade_litros": 240,
            "referencia_externa": "RS-PT-01",
            "status": "ativo",
            "instalado_em": "2026-10-20",
            "coletas": 2,
            "total_coletado_gramas": 15500,
            "ultima_coleta_em": "2026-11-02T08:05:00-03:00",
            "criado_em": "2026-10-20T09:12:44-03:00",
            "atualizado_em": "2026-10-20T09:12:44-03:00"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Todos os pontos de coleta

GET /v1/pontos-de-coleta residuos:ler

A mesma lista, sem partir de um atrativo.

Parâmetros da consulta

poiCódigo do atrativo
statusativo ou inativo
limite1 a 200
depoisCursor da página anterior

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/pontos-de-coleta' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "codigo": "PTY-COL-0001",
            "poi": "PTY-POI-0003",
            "operado_por": "reciclo",
            "nome": "Lixeira da entrada da praia",
            "descricao": "Ao lado do quiosque, na chegada dos barcos.",
            "tipo": "lixeira",
            "materiais": [
                "plastico",
                "metal"
            ],
            "localizacao": {
                "latitude": -23.19671,
                "longitude": -44.62951
            },
            "capacidade_litros": 240,
            "referencia_externa": "RS-PT-01",
            "status": "ativo",
            "instalado_em": "2026-10-20",
            "coletas": 2,
            "total_coletado_gramas": 15500,
            "ultima_coleta_em": "2026-11-02T08:05:00-03:00",
            "criado_em": "2026-10-20T09:12:44-03:00",
            "atualizado_em": "2026-10-20T09:12:44-03:00"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Detalhe do ponto de coleta

GET /v1/pontos-de-coleta/{codigo} residuos:ler

Com os totais do ponto.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/pontos-de-coleta/PTY-COL-0001' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "codigo": "PTY-COL-0001",
    "poi": "PTY-POI-0003",
    "operado_por": "reciclo",
    "nome": "Lixeira da entrada da praia",
    "descricao": "Ao lado do quiosque, na chegada dos barcos.",
    "tipo": "lixeira",
    "materiais": [
        "plastico",
        "metal"
    ],
    "localizacao": {
        "latitude": -23.19671,
        "longitude": -44.62951
    },
    "capacidade_litros": 240,
    "referencia_externa": "RS-PT-01",
    "status": "ativo",
    "instalado_em": "2026-10-20",
    "coletas": 2,
    "total_coletado_gramas": 15500,
    "ultima_coleta_em": "2026-11-02T08:05:00-03:00",
    "criado_em": "2026-10-20T09:12:44-03:00",
    "atualizado_em": "2026-10-20T09:12:44-03:00"
}

Alterar ponto de coleta

PATCH /v1/pontos-de-coleta/{codigo} residuos:escrever

Mesmos campos do cadastro, todos opcionais. Para desativar um ponto, mande status: inativo (o histórico de coletas permanece). Só quem cadastrou o ponto altera.

Exemplo

curl -X PATCH 'https://api.destinolabparaty.com.br/v1/pontos-de-coleta/PTY-COL-0001' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"status":"inativo"}'

Responde 200.

Erros próprios desta rota

  • 403 O ponto é operado por outra organização.

Registrar quanto foi coletado

POST /v1/pontos-de-coleta/{codigo}/coletas residuos:escrever Idempotency-Key obrigatório

Uma chamada por material pesado. Repetir a mesma referencia_externa devolve 200 com a coleta que já existe.

Campos do corpo

materialObrigatório: reciclavel, papel, plastico, vidro, metal, organico, rejeito, oleo ou eletronico
peso_gramasObrigatório. Inteiro, em gramas (1 a 50000000). Número com vírgula é recusado
coletado_emObrigatório. ISO 8601 com fuso; não pode estar no futuro
observacaoAté 255 caracteres
referencia_externaO id da pesagem no seu sistema; impede duplicata

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/pontos-de-coleta/PTY-COL-0001/coletas' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"material":"plastico","peso_gramas":12400,"coletado_em":"2026-11-02T08:00:00-03:00","referencia_externa":"pes-2026-11-02-01"}'

Resposta 201

{
    "criado": true,
    "uuid": "c2d3e4f5-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
    "ponto_de_coleta": "PTY-COL-0001",
    "poi": "PTY-POI-0003",
    "material": "plastico",
    "peso_gramas": 12400,
    "coletado_em": "2026-11-02T08:00:00-03:00",
    "observacao": null,
    "referencia_externa": "pes-2026-11-02-01",
    "registrado_em": "2026-11-02T08:01:10-03:00"
}

Coletas de um ponto

GET /v1/pontos-de-coleta/{codigo}/coletas residuos:ler

Da mais recente para a mais antiga.

Parâmetros da consulta

deDia inicial, AAAA-MM-DD
ateDia final, AAAA-MM-DD, incluído
limite1 a 200
depoisCursor da página anterior

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/pontos-de-coleta/PTY-COL-0001/coletas' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "uuid": "c2d3e4f5-0a1b-4c2d-8e3f-4a5b6c7d8e9f",
            "ponto_de_coleta": "PTY-COL-0001",
            "poi": "PTY-POI-0003",
            "material": "plastico",
            "peso_gramas": 12400,
            "coletado_em": "2026-11-02T08:00:00-03:00",
            "observacao": null,
            "referencia_externa": "pes-2026-11-02-01",
            "registrado_em": "2026-11-02T08:01:10-03:00"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Passaporte

Carimbos por atrativo visitado, emitidos pelas cinco soluções na conta única do visitante. A solução fala em sub; o centro resolve a pessoa. Exige que o visitante tenha autorizado a solução a carimbar.

Carimbar o passaporte

POST /v1/passaporte/carimbos passaporte:escrever

201 com criado: true e as conquistas novas; 200 se o carimbo já existia (um por visitante, atrativo e solução).

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/passaporte/carimbos' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"sub":"VGhpcyBpcyBhIHBhaXJ3aXNlIHN1YmplY3QgaWQ","poi":"PTY-POI-0001","origem":"qr"}'

Resposta 201

{
    "criado": true,
    "conquistas": [
        "primeiro_carimbo"
    ]
}

Erros próprios desta rota

  • 403 O visitante não autorizou esta solução a carimbar.
  • 404 Nenhum visitante com este sub no setor da solução.

Catálogo de conquistas

GET /v1/passaporte/conquistas pública

Pública. As conquistas e as regras que as liberam.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/passaporte/conquistas'

Resposta 200

{
    "dados": [
        {
            "codigo": "primeiro_carimbo",
            "nome": "Primeiro carimbo",
            "descricao": "Você começou o seu Passaporte Destino Paraty.",
            "regra": {
                "tipo": "total",
                "minimo": 1
            }
        }
    ]
}

Operadores, equipamentos e selos

Prestadores de serviço turístico e suas embarcações e veículos. As soluções veem só os homologados. O documento (CPF ou CNPJ) é cifrado e só volta mascarado.

Listar operadores

GET /v1/operadores operadores:ler

Só os homologados (a curadoria vê todos).

Parâmetros da consulta

categorianautico_escuna, nautico_barco, nautico_lancha, jipe, guia, receptivo, hospedagem, alimentacao, outro
buscaTexto no nome
statusSó a curadoria
limite1 a 200
depoisCursor da página anterior

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/operadores' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "codigo": "PTY-OPE-0012",
            "nome_fantasia": "Escuna Vitória",
            "razao_social": "Vitória Passeios Náuticos LTDA",
            "tipo_pessoa": "juridica",
            "documento": "**.***.***/0001-**",
            "categoria": "nautico_escuna",
            "contato": {
                "email": "contato@exemplo.org",
                "telefone": "+55 24 99999-0000",
                "whatsapp": null
            },
            "cadastur": {
                "numero": "12.345678.90.0001-2",
                "situacao": "regular",
                "validade": "2027-03-01"
            },
            "homologacao": {
                "status": "homologado",
                "homologado_em": "2026-10-01T09:00:00-03:00",
                "homologado_por": "prefeitura-maquina",
                "motivo_recusa": null
            },
            "comunidade_tradicional": false,
            "fora_eixo_centro": false,
            "origem_cadastro": "oficina",
            "criado_em": "2026-09-20T14:00:00-03:00",
            "atualizado_em": "2026-10-01T09:00:00-03:00"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Detalhe do operador

GET /v1/operadores/{codigo} operadores:ler

Operador não homologado responde 404 para quem não é da curadoria.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/operadores/PTY-OPE-0012' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "codigo": "PTY-OPE-0012",
    "nome_fantasia": "Escuna Vitória",
    "razao_social": "Vitória Passeios Náuticos LTDA",
    "tipo_pessoa": "juridica",
    "documento": "**.***.***/0001-**",
    "categoria": "nautico_escuna",
    "contato": {
        "email": "contato@exemplo.org",
        "telefone": "+55 24 99999-0000",
        "whatsapp": null
    },
    "cadastur": {
        "numero": "12.345678.90.0001-2",
        "situacao": "regular",
        "validade": "2027-03-01"
    },
    "homologacao": {
        "status": "homologado",
        "homologado_em": "2026-10-01T09:00:00-03:00",
        "homologado_por": "prefeitura-maquina",
        "motivo_recusa": null
    },
    "comunidade_tradicional": false,
    "fora_eixo_centro": false,
    "origem_cadastro": "oficina",
    "criado_em": "2026-09-20T14:00:00-03:00",
    "atualizado_em": "2026-10-01T09:00:00-03:00"
}

Cadastrar operador

POST /v1/operadores operadores:escrever Idempotency-Key obrigatório

Nasce pendente. O documento é validado, cifrado e não se repete na base.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/operadores' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"nome_fantasia":"Escuna Vitória","tipo_pessoa":"juridica","documento":"11.222.333/0001-81","categoria":"nautico_escuna","email":"contato@exemplo.org","telefone":"+55 24 99999-0000","cadastur":"12.345678.90.0001-2","cadastur_validade":"2027-03-01","origem_cadastro":"oficina"}'

Responde 201.

Mudar o status de homologação

POST /v1/operadores/{codigo}/homologacao operadores:escrever

pendente → em_analise → homologado → suspenso. homologado, recusado e suspenso são atos da curadoria; recusado e suspenso exigem motivo.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/operadores/PTY-OPE-0012/homologacao' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"status":"homologado","cadastur_situacao":"regular"}'

Responde 200.

Equipamentos do operador

GET /v1/operadores/{codigo}/equipamentos operadores:ler

Com o selo de cada um, quando emitido.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/operadores/PTY-OPE-0012/equipamentos' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "codigo": "PTY-EQP-0034",
            "tipo": "escuna",
            "nome": "Vitória V",
            "registro_capitania": "3811000001",
            "placa": null,
            "capacidade_passageiros": 80,
            "ano_fabricacao": 2012,
            "status": "ativo",
            "selo": {
                "codigo": "PTY-SEL-7K3M9X2QBD",
                "emitido_em": "2026-11-07T10:00:00-03:00",
                "validade": "2027-11-07"
            }
        }
    ]
}

Cadastrar equipamento

POST /v1/operadores/{codigo}/equipamentos operadores:escrever Idempotency-Key obrigatório

Tipos: escuna, lancha, barco, jipe, van, bicicleta, outro.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/operadores/PTY-OPE-0012/equipamentos' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"tipo":"escuna","nome":"Vitória V","registro_capitania":"3811000001","capacidade_passageiros":80,"ano_fabricacao":2012}'

Responde 201.

Emitir ou trocar o selo (curadoria)

POST /v1/equipamentos/{codigo}/selo operadores:escrever

O código novo invalida o anterior na hora.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/equipamentos/PTY-EQP-0034/selo' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"validade":"2027-11-07"}'

Responde 200.

Verificar selo

GET /v1/selos/{selo_codigo} pública

Pública: é o que o turista confere ao apontar a câmera para o adesivo. situacao: homologado, vencido, suspenso, nao_homologado ou equipamento_inativo. Código desconhecido responde 404.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/selos/PTY-SEL-7K3M9X2QBD'

Resposta 200

{
    "selo": "PTY-SEL-7K3M9X2QBD",
    "situacao": "homologado",
    "verificado_em": "2026-11-07T10:30:00-03:00",
    "operador": {
        "codigo": "PTY-OPE-0012",
        "nome": "Escuna Vitória",
        "categoria": "nautico_escuna"
    },
    "equipamento": {
        "codigo": "PTY-EQP-0034",
        "tipo": "escuna",
        "nome": "Vitória V",
        "capacidade_passageiros": 80
    },
    "selo_validade": "2027-11-07"
}

Painel (dashboards)

O que as cinco soluções mandaram para o centro, somado. É de onde o portal e os dashboards leem. Só agregados: nenhuma informação de pessoa. Período padrão: os últimos 30 dias; máximo de 366 dias.

Indicadores do destino

GET /v1/painel/indicadores painel:ler

Check-ins (total, pessoas, por solução, por origem e por dia), carimbos, resíduos por material, atrativos publicados, operadores homologados e contas de visitante.

Parâmetros da consulta

deDia inicial, AAAA-MM-DD (fuso de Paraty)
ateDia final, AAAA-MM-DD, incluído

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/painel/indicadores?de=2026-12-01&ate=2026-12-31' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "periodo": {
        "de": "2026-12-01",
        "ate": "2026-12-31"
    },
    "catalogo": {
        "pois_publicados": 48
    },
    "operadores": {
        "homologados": 165
    },
    "visitantes": {
        "contas_ativas": 1240,
        "contas_novas_no_periodo": 310
    },
    "checkins": {
        "total": 5120,
        "pessoas": 11870,
        "visitantes_identificados": 640,
        "pois_com_checkin": 41,
        "por_solucao": [
            {
                "solucao": "fuba",
                "total": 1300,
                "pessoas": 2100
            }
        ],
        "por_origem": [
            {
                "origem": "qr",
                "total": 3900,
                "pessoas": 8200
            }
        ],
        "por_dia": [
            {
                "dia": "2026-12-27",
                "total": 412,
                "pessoas": 980
            }
        ]
    },
    "passaporte": {
        "carimbos_no_periodo": 2210
    },
    "residuos": {
        "pontos_de_coleta_ativos": 36,
        "coletas": 420,
        "peso_gramas": 1845300,
        "por_material": [
            {
                "material": "plastico",
                "coletas": 140,
                "peso_gramas": 612400
            }
        ]
    }
}

Indicadores por atrativo

GET /v1/painel/pois painel:ler

Todos os atrativos publicados, do mais visitado para o menos, com check-ins, pessoas, carimbos, pontos de coleta ativos e gramas coletados no período.

Parâmetros da consulta

deDia inicial, AAAA-MM-DD
ateDia final, AAAA-MM-DD, incluído

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/painel/pois' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "periodo": {
        "de": "2026-12-01",
        "ate": "2026-12-31"
    },
    "dados": [
        {
            "poi": "PTY-POI-0001",
            "nome": "Centro Histórico de Paraty",
            "checkins": 820,
            "pessoas": 1910,
            "carimbos": 300,
            "pontos_de_coleta": 4,
            "residuos_coletados_gramas": 210500
        }
    ]
}

Agenda, busca e conteúdo

O que o portal mostra além dos atrativos: a agenda da cidade, a busca unificada, as páginas editoriais e os subdomínios das soluções.

Agenda do destino

GET /v1/agenda catalogo:ler

Eventos publicados que ainda não acabaram, do mais próximo ao mais distante.

Parâmetros da consulta

deISO 8601 com fuso
ateISO 8601 com fuso
poiCódigo do atrativo
limite1 a 200
depoisCursor

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/agenda' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "codigo": "PTY-AGD-0012",
            "slug": "festa-do-divino",
            "titulo": "Festa do Divino",
            "resumo": "Procissão e música no Centro Histórico.",
            "descricao": null,
            "poi": "PTY-POI-0001",
            "local": "Igreja Matriz",
            "inicio_em": "2027-07-28T19:00:00-03:00",
            "fim_em": "2027-07-28T23:00:00-03:00",
            "organizador": "Secretaria de Cultura",
            "gratuito": true,
            "url_ingressos": null,
            "imagem_capa": null,
            "status": "publicado"
        }
    ],
    "pagina": {
        "limite": 50,
        "proximo": null,
        "tem_mais": false
    }
}

Detalhe do evento

GET /v1/agenda/{codigo} catalogo:ler

Aceita o código (PTY-AGD-0012) ou o slug.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/agenda/PTY-AGD-0012' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "codigo": "PTY-AGD-0012",
    "slug": "festa-do-divino",
    "titulo": "Festa do Divino",
    "resumo": "Procissão e música no Centro Histórico.",
    "descricao": null,
    "poi": "PTY-POI-0001",
    "local": "Igreja Matriz",
    "inicio_em": "2027-07-28T19:00:00-03:00",
    "fim_em": "2027-07-28T23:00:00-03:00",
    "organizador": "Secretaria de Cultura",
    "gratuito": true,
    "url_ingressos": null,
    "imagem_capa": null,
    "status": "publicado"
}

Criar evento (curadoria)

POST /v1/agenda catalogo:escrever Idempotency-Key obrigatório

inicio_em e fim_em exigem fuso. url_ingressos e imagem_capa precisam ser https.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/agenda' \
  -H "Authorization: Bearer $TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H 'Content-Type: application/json' \
  -d '{"titulo":"Festa do Divino","resumo":"Procissão e música no Centro Histórico.","poi":"PTY-POI-0001","local":"Igreja Matriz","inicio_em":"2027-07-28T19:00:00-03:00","fim_em":"2027-07-28T23:00:00-03:00","gratuito":true,"status":"publicado"}'

Responde 201.

Alterar evento (curadoria)

PATCH /v1/agenda/{codigo} catalogo:escrever

Mesmos campos, todos opcionais. status: rascunho, publicado ou cancelado.

Exemplo

curl -X PATCH 'https://api.destinolabparaty.com.br/v1/agenda/PTY-AGD-0012' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"status":"cancelado"}'

Responde 200.

Busca unificada

GET /v1/busca catalogo:ler

Atrativos, páginas e agenda, até 8 de cada. Ignora acento e caixa e conhece sinônimos locais.

Parâmetros da consulta

qTexto da busca
idiomapt-BR, en-US, es-ES ou fr-FR
limite1 a 8

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/busca?q=praia' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "consulta": "praia",
    "vazia": false,
    "pois": [
        {
            "codigo": "PTY-POI-0024",
            "slug": "praia-brava-de-trindade",
            "nome": "Praia Brava de Trindade",
            "resumo": "Praia do conjunto de Trindade, afastada da vila.",
            "categoria": "praia",
            "imagem": "https://img.destinolabparaty.com.br/attractions/brava-beach-trindade/exemplo.jpg"
        }
    ],
    "paginas": [
        {
            "slug": "caminho-natureza-que-ensina",
            "tipo": "guia",
            "titulo": "Natureza que Ensina",
            "resumo": "Trilhas, rios e praias com quem sabe ler a floresta e o mar."
        }
    ],
    "agenda": []
}

Páginas editoriais

GET /v1/paginas catalogo:ler

Tipos: institucional, guia, noticia, ajuda, legal.

Parâmetros da consulta

tipoTipo da página
idiomapt-BR, en-US, es-ES ou fr-FR

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/paginas?tipo=guia' \
  -H "Authorization: Bearer $TOKEN"

Responde 200.

Uma página editorial

GET /v1/paginas/{slug} catalogo:ler

O corpo (conteudo) é Markdown. Sem tradução no idioma pedido vem o português, com fallback: true.

Parâmetros da consulta

idiomapt-BR, en-US, es-ES ou fr-FR

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/paginas/sobre' \
  -H "Authorization: Bearer $TOKEN"

Responde 200.

Subdomínios das soluções

GET /v1/subdominios catalogo:ler

Para onde cada subdomínio do destino leva (experiencias., cultura., historias., natureza., circular.).

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/subdominios' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "dados": [
        {
            "host": "cultura.destinolabparaty.com.br",
            "titulo": "Diaspora.Black",
            "descricao": "Curadoria da cultura negra",
            "icone": "cultura",
            "destino_url": "https://destinolabparaty.com.br/solucoes/diaspora-black",
            "modo": "redirect",
            "exibir_no_menu": true,
            "parceiro": "diaspora"
        }
    ]
}

Conta do visitante (token de login)

Estas rotas só aceitam o token que o visitante obtém ao fazer login (Authorization Code + PKCE em auth.destinolabparaty.com.br/oauth/autorizar). Token de máquina recebe 403. Há uma única base de visitantes: cada solução recebe um sub diferente para a mesma pessoa e nunca coleta senha.

Dados do visitante

GET /v1/me openid

sub; com profile: nome, idioma e email_verificado; com email: o e-mail.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/me' \
  -H "Authorization: Bearer $TOKEN"

Resposta 200

{
    "sub": "VGhpcyBpcyBhIHBhaXJ3aXNlIHN1YmplY3QgaWQ",
    "nome": "Joana",
    "idioma": "pt-BR",
    "email_verificado": true
}

Alterar nome e idioma

PATCH /v1/me openid + profile

Campos: nome e idioma.

Exemplo

curl -X PATCH 'https://api.destinolabparaty.com.br/v1/me' \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"nome":"Joana M.","idioma":"fr-FR"}'

Responde 200.

Eliminar a conta (LGPD, art. 18, VI)

DELETE /v1/me openid

Anonimiza na hora e revoga todos os tokens. Carimbos e check-ins ficam, sem dono, para a estatística.

Exemplo

curl -X DELETE 'https://api.destinolabparaty.com.br/v1/me' \
  -H "Authorization: Bearer $TOKEN"

Responde 204.

Reenviar a confirmação de e-mail

POST /v1/me/email/verificacao openid

202 com situacao: enviado ou ja_verificado. Até 3 por hora.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/me/email/verificacao' \
  -H "Authorization: Bearer $TOKEN"

Responde 202.

Passaporte do visitante

GET /v1/me/passaporte passaporte:ler

Carimbos e conquistas, com o progresso de cada uma.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/me/passaporte' \
  -H "Authorization: Bearer $TOKEN"

Responde 200.

Consentimentos dados

GET /v1/me/consentimentos openid

O que o visitante autorizou, por aplicação.

Exemplo

curl 'https://api.destinolabparaty.com.br/v1/me/consentimentos' \
  -H "Authorization: Bearer $TOKEN"

Responde 200.

Revogar um consentimento

DELETE /v1/me/consentimentos/{client_id} openid

Encerra também os tokens daquela aplicação.

Exemplo

curl -X DELETE 'https://api.destinolabparaty.com.br/v1/me/consentimentos/app-da-solucao' \
  -H "Authorization: Bearer $TOKEN"

Responde 204.

Exportar os dados (LGPD, art. 18, V)

POST /v1/me/exportacao openid

JSON com tudo o que o centro guarda sobre o visitante.

Exemplo

curl -X POST 'https://api.destinolabparaty.com.br/v1/me/exportacao' \
  -H "Authorization: Bearer $TOKEN"

Responde 200.

Saúde

Para monitoramento. Sem autenticação.

Processo vivo

GET /saude pública

Não toca no banco.

Exemplo

curl 'https://api.destinolabparaty.com.br/saude'

Responde 200.

Pronto para atender

GET /saude/pronto pública

Confere banco e segredos. 503 se algum falhar.

Exemplo

curl 'https://api.destinolabparaty.com.br/saude/pronto'

Resposta 200

{
    "status": "ok",
    "verificacoes": {
        "segredos": {
            "ok": true,
            "ms": 0
        },
        "banco": {
            "ok": true,
            "ms": 22
        }
    },
    "horario": "2026-11-10T13:58:00-03:00"
}