Endpoint autenticado POST /api/catalog/graphql que serve o conteúdo dos ZIPs oficiais (hotéis + destinos) já normalizado, paginado e versionado por release. Use este endpoint para montar e manter o seu catálogo local; chame Hotel.svc/HotelDetail só sob demanda para enriquecer (fotos, amenities, descrições).
wsk_* emitido pela Iterpec após contrato assinado e formuláriocliente preenchido.Retry-After.# GraphQL Schema (read-only)
type Destination {
id: ID!
name: String!
countryCode: String
type: String
nameEn: String
namePt: String
}
type Hotel {
id: ID!
name: String!
destinationId: ID
category: String
address: String
latitude: Float
longitude: Float
lastUpdateSource: String
}
type Release {
id: ID!
version: String!
releasedAt: String!
hotelsCount: Int!
destinationsCount: Int!
hotelsSha256: String
}
type SyncStatus {
workspaceCid: ID!
currentReleaseId: ID
lastFullSyncAt: String
daysSinceSync: Int
isStale: Boolean!
note: String
}
type Query {
currentRelease: Release
destinations(country: String, search: String, limit: Int = 100, offset: Int = 0): [Destination!]!
hotels(destinationId: ID, search: String, limit: Int = 100, offset: Int = 0): [Hotel!]!
hotel(id: ID!): Hotel
syncStatus: SyncStatus!
}X-Catalog-Release-Id — id do release atual; mude o cache local quando mudar.X-Catalog-Version — versão semântica do release.X-RateLimit-Limit / X-RateLimit-Remaining — controle de quota.curl -X POST https://iterpec.com/api/catalog/graphql \
-H "Authorization: Bearer wsk_..." \
-H "Content-Type: application/json" \
-d '{
"query": "query($d:ID!,$l:Int!,$o:Int!){ hotels(destinationId:$d,limit:$l,offset:$o){ id name category latitude longitude } }",
"variables": { "d": "1006065", "l": 500, "o": 0 }
}'Inclua destinations e hotels na mesma operação para o servidor marcar last_full_sync_at do workspace.
// Full sync paginado (destinos + hotéis) — marca last_full_sync_at no workspace
const ENDPOINT = "https://iterpec.com/api/catalog/graphql";
const TOKEN = process.env.ITERPEC_WORKSPACE_TOKEN; // wsk_*
async function gql(query, variables) {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: {
"Authorization": `Bearer ${TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ query, variables }),
});
if (res.status === 429) {
const retry = Number(res.headers.get("Retry-After") ?? 30);
await new Promise(r => setTimeout(r, retry * 1000));
return gql(query, variables);
}
const releaseId = res.headers.get("X-Catalog-Release-Id");
const body = await res.json();
if (body.errors) throw new Error(JSON.stringify(body.errors));
return { data: body.data, releaseId };
}
const LIMIT = 500;
const all = { destinations: [], hotels: [] };
let offset = 0;
while (true) {
const { data, releaseId } = await gql(
`query($l:Int!,$o:Int!){
destinations(limit:$l, offset:$o){ id name countryCode type }
hotels(limit:$l, offset:$o){ id name destinationId category latitude longitude }
}`,
{ l: LIMIT, o: offset },
);
all.destinations.push(...data.destinations);
all.hotels.push(...data.hotels);
console.log(`offset=${offset} release=${releaseId} +${data.hotels.length} hotels`);
if (data.hotels.length < LIMIT && data.destinations.length < LIMIT) break;
offset += LIMIT;
}
console.log("done", all.destinations.length, all.hotels.length);Workspaces que ficam >30 dias sem full sync entram em isStale=true. Após >50 dias, comercial@iterpec.com é notificado automaticamente.
query {
syncStatus {
workspaceCid
currentReleaseId
lastFullSyncAt
daysSinceSync
isStale
}
currentRelease {
id version releasedAt hotelsCount destinationsCount hotelsSha256
}
}release_id. Se mudar → re-sync completo.HotelDetail para todos os hotéis — só para os tops do Search.Cole seu token wsk_* e dispare uma query real contra /api/catalog/graphql. Útil para validar headers de release, paginação e rate-limit antes de codar.
O token fica apenas no seu navegador (não é enviado para nenhum servidor da Iterpec além do GraphQL endpoint).
401 — token ausente, expirado ou não é wsk_* de workspace.429 — quota excedida; respeite Retry-After.422 — query inválida; valide com a aba Playground antes.get_catalog_graphql_recipe e get_catalog_sync_status antes de implementar — elas retornam queries prontas e o estado atual do seu catálogo.