Ir para o conteúdo

Relatórios e oposições

Este guia cobre as leituras focadas em registrabilidade e oposições do contrato da Tarno: o relatório de registrabilidade de uma marca, a linha do tempo de oposições de uma marca, e a listagem de oposições abertas em uma classe de Nice ranqueadas por similaridade. Os três endpoints usam o scope brands:read e têm equivalente MCP.

O esquema completo e sempre atualizado por campo vive na referência OpenAPI interativa em /docs (Scalar). Este guia explica o contrato de relatórios e oposições e aponta para essa referência — não reformula o esquema. Quando um campo não está documentado aqui, /docs é autoritativo.

Ao longo do guia a URL base é escrita como $TARNO_BASE_URL e a chave como $TARNO_API_KEY, e cada chamada leva o cabeçalho X-API-Key — igual ao guia de primeiros passos e ao guia de autenticação.

O que este guia cobre

Três leituras, todas sob /v1 e todas com scope brands:read:

  • Relatório de registrabilidade (GET /v1/brands/:nroSolicitud/report) — o detalhe de uma marca como um superset, com campos extras úteis para avaliar registrabilidade.
  • Linha do tempo de oposições (GET /v1/brands/:nroSolicitud/opposition) — a sequência cronológica dos eventos de oposição de uma marca, mais a janela de oposição derivada (quando aplicável).
  • Oposições abertas (GET /v1/oppositions/open) — marcas com janela de oposição aberta em uma classe de Nice, ranqueadas por similaridade a um portfólio.

Estas rotas são de somente leitura e honestas por design: nunca fabricam datas ou prazos que o corpus não pode sustentar. Quando um dado não existe, o campo é omitido (ver os avisos de honestidade em cada seção).

Relatório de registrabilidade

GET /v1/brands/:nroSolicitud/report — scope brands:read. MCP: get_brand_report.

Retorna um BrandReport, que é um superset do detalhe da marca: inclui tudo que GET /v1/brands/:nroSolicitud retorna (classes, pessoas, anotações do Estado-Diário) mais os campos extras úteis para avaliar registrabilidade. Um número de solicitação desconhecido retorna 404 not_found.

Campos extras sobre o detalhe base:

Campo Tipo Notas
nroRegistro string | omitido Número de registro. É omitido quando a marca não tem registro — nunca chega como null.
estado string Estado atual da marca.
tipoSigno string Tipo de sinal (nominativa, mista, figurativa, …).
fechaPresentacion YYYY-MM-DD Data de apresentação.
fechaVencimiento YYYY-MM-DD | null Data de vencimento do registro.
fechaPublicacion YYYY-MM-DD | null Data de publicação no Estado-Diário.
fechaRegistro YYYY-MM-DD | null Data de registro.
tipoNombre string Nome do tipo de marca.
subtipoNombre string | null Nome do subtipo, se aplicável.
traduccion string | null Tradução declarada do sinal, se aplicável.
descripcionEtiqueta string | null Descrição da etiqueta.
protectionDescription string | null Descrição do escopo de proteção.
imagenUrl string | null URL da imagem do sinal (marcas mistas/figurativas).
renovadaDe string | null Número de solicitação da marca da qual esta é renovação.
renovadaPor string | null Número de solicitação da marca que renova esta.
titulares[] array\<Persona> Titulares, separados por papel. Cada pessoa traz a sua classificação, comuna e region (ver abaixo).
representantes[] array\<Persona> Representantes, separados por papel.
completeness objeto Bloco de honestidade. SEMPRE presente (ver aviso).
coverageThrough objeto | omitido Fronteira de cobertura. Omitido se não há instância enriquecida (ver aviso).
estadoDerivado string | omitido Estado que o corpus realmente pode justificar, do mesmo catálogo controlado que estado. Omitido quando não há nada a derivar.
estadoDesactualizado boolean SEMPRE presente. Verdadeiro quando o corpus já tem a prova da concessão que estado ainda não reflete.

estado não muda: continua sendo o valor EM BRUTO da INAPI. estadoDerivado e estadoDesactualizado são campos adicionados, nunca uma reescrita de estado. Existem porque a INAPI atribui o número e a data de registro antes de virar o estado: medido, ela vira no dia ~4-6 após a data de registro e só chega a 100 % no dia 9, enquanto a anotação de concessão do Estado-Diário entra no mesmo dia em que é declarada. Nessa janela a ficha dizia «em trâmite, sem registro» sobre um processo já titulado. estadoDerivado publica o que a evidência do corpus prova e estadoDesactualizado avisa que os dois não coincidem.

nroRegistro também é omitido quando a INAPI envia o seu sentinela de zero. A INAPI publica «sem número de registro» como um zero (0 numérico no detalhe do Buscador, o texto "0" no CSV de open-data). Um zero não é um número de registro, portanto o relatório trata-o como ausência: omite o campo. Antes emitia nroRegistro: "0", o que quebrava a própria promessa de omissão do contrato e podia aparecer junto de estadoDerivado: "registrada" na mesma resposta. Um consumidor que já verificava a presença do campo não precisa mudar nada: apenas deixa de receber o zero. O identificador do processo é nroSolicitud, um campo distinto e sempre presente, que isto não altera.

titulares[] e representantes[] estão separados por papel. Uma pessoa cujo papel é 'ambas' (titular e representante) aparece em ambos os arrays.

Dois blocos de honestidade. completeness está sempre presente e declara quão completo está o registro retornado. coverageThrough é a fronteira de cobertura dos dados e é omitido quando a marca não tem uma instância enriquecida — sua ausência significa "sem fronteira conhecida", nunca um valor inventado.

Titularidade atual, e histórico

personas[], titulares[] e representantes[] trazem apenas quem o é hoje. Uma marca que mudou de mãos já não nomeia o dono anterior entre os atuais — antes nomeava, e eram dois titulares igualmente vigentes com um deles falso.

Os anteriores vivem em personasHistoricas[], com mais dois campos:

campo o que é
retiradoEn a data em que o INAPI diz que a titularidade se moveu, não quando a processámos
retiradoPor a anotação que o prova: A07T transferência total, A07P parcial, MSO08 cessão, A01 mudança de nome

Está sempre presente e quase sempre vazio. Não estar é o sinal de que a marca mudou de mãos.

Copropriedade não é histórico. Dois titulares simultâneos são legítimos e ambos ficam em personas[]: só se retira alguém quando existe uma anotação que nomeia o adquirente.

Classes que cobrem a marca, e as que já não cobrem

Uma marca regista-se em classes, e elas não vivem nem morrem juntas. clases[] traz apenas as que a cobrem hoje; as restantes passam para clasesHistoricas[], com o motivo que o INAPI dá em estado.

Medido: 10.232 marcas têm classes em estados misturados, e 8.220 delas constam registrada — a marca está viva enquanto parte das suas classes foi recusada ou não foi renovada. FARMACIAS AHUMADA (pedido 1113943) consta registada com 34 classes: 7 cobrem-na e 27 não foram renovadas. Antes listavam-se as 34 por igual.

cobre hoje já não cobre
(C) Concedida · (X) En Trámite · (1) Para conceder · (2) Para rechazar (N) Rechazada · (A) Abandonada · (D) Desistida · (V) Vencida · (3) No renovada · (O) Cancelada voluntariamente · (U) Anulada · (I) Dividida · (T) Transferida · (P) Transferida Parcialmente

(2) Para rechazar continua a cobrir. É uma decisão proposta, não firme: dá-la por caída seria antecipar um desfecho que não ocorreu.

(T), (P) e (I) não morreram: MUDARAM. A classe foi transferida ou dividida e continua a proteger alguém, mas já não sob esta marca — que é o que aqui se responde.

Sem estado ⇒ fica em clases[]. Não saber não prova que tenha caído. O estado viaja tal como o INAPI o publica, para poderdes julgar por vós.

Ónus sobre a marca

gravamenes[] responde que ónus continuam ali, não se alguma vez houve algum. Isso já estava em anotaciones[], mas para o ler era preciso saber que A05I inscreve um penhor e A05A o levanta. Aqui cada inscrição já vem emparelhada com o levantamento que a encerrou.

campo o que é
tipo prenda, precautoria, embargo, prohibicion ou otros
estado activo (inscrito e por levantar) ou alzado
inscritoEn / alzadoEn as duas datas do INAPI
aFavorDe o credor, retirado apenas da inscrição
seccionInscripcion / seccionAlzamiento os códigos que o provam
alzamientoObservable se o INAPI publica algum código capaz de levantar este tipo de ónus

Os activos vêm primeiro, e dentro deles os mais recentes.

aFavorDe é o credor, nunca o titular. A expressão "A Favor de:" muda de sentido entre os dois lados: na inscrição nomeia quem recebe a garantia e no levantamento quem recupera a marca livre. Por isso só se lê do lado da inscrição. Medido: nos penhores, o "A Favor de:" do levantamento é um titular da própria marca em 81,6 % dos casos, e o da inscrição apenas em 0,7 %.

alzamientoObservable: false significa que esse activo não é afirmável. Para prohibición e otros, o INAPI não publica qualquer código que os levante: constam por levantar porque não temos como saber, não porque continuem vivos. Não os useis para afirmar que uma marca está onerada hoje.

Um levantamento pode vir sem a sua inscrição (inscritoEn: null): o ónus foi levantado e a sua inscrição é anterior ao que o histórico alcança. Conta como alzado, nunca como activo.

Está sempre presente e quase sempre vazio: em todo o corpus, 2.790 marcas têm algum ónus registado e 2.048 algum activo.

Uma licença não é um ónus. A03I/A03A formam um par idêntico na forma e ficam de fora de propósito: é um direito concedido sobre a marca, não um gravame contra ela.

Âmbito territorial das pessoas

Cada pessoa de personas[], titulares[] e representantes[] traz mais dois campos:

Campo Tipo Notas
comuna string | null Código CUT da comuna, sem zero à esquerda: '13114' (Las Condes), '5109' (Viña del Mar)
region string | null Código CUT da região, sem zero à esquerda: '13', '5'
comunaNombre string | null O nome dessa comuna ('Las Condes'), resolvido do catálogo
regionNombre string | null O nome dessa região ('Región Metropolitana')

Desde 2026-08-25 os códigos viajam com o seu nome. Continuam não sendo o endereço — esse não é exposto. Os nomes são os que a INAPI publica, com as suas próprias grafias (Valparaiso sem acento); null quando o código não está no catálogo, nunca inventados. Cobertura: 100 % das regiões e 99,82 % das comunas.

  • A província sai do próprio código. Complete a comuna com zeros até 5 dígitos e fique com os 3 primeiros: 05109051 (província de Valparaíso), 03301033 (Huasco). Nenhuma tabela é necessária para filtrar por província.
  • 99 / 99999 / 999 é a sentinela de desconhecido ou estrangeiro, não uma região real.
  • Viajam sempre juntas: ou as duas nulas, ou as duas com valor.
  • Cobertura medida (2026-08-24): 70,0 % dos titulares e 96,4 % dos representantes.

Que tipo de parte é cada pessoa

Desde 2026-09-08 cada pessoa de personas[], titulares[] e representantes[] traz mais cinco campos, idênticos aos que devolvem o detalhe da marca e a busca de pessoas. São aditivos: nenhum campo anterior foi removido, renomeado ou re-tipado, e nenhum scope mudou —são lidos sob o mesmo brands:read—, portanto um consumidor existente continua a parsear o relatório sem tocar em nada.

Campo Tipo Notas
tipo natural | juridica | desconocido Que tipo de parte é. desconocido é um valor, não um buraco: um terço do corpus não tem RUT nem sufixo societário, e o contrato di-lo em vez de o deduzir.
tipoOrigen rut | sufijo | manual | omitido Que sinal produziu tipo. Sem sinal a chave desaparece — nunca chega como null.
observacion string | null A cláusula de jurisdição que a INAPI escreve colada ao nome («…, SOCIEDAD ORGANIZADA BAJO LAS LEYES DE…»), retirada de nombre. É prosa da INAPI, com 681 grafias distintas da mesma cláusula: não é vocabulário controlado.
nombrePublicado string | null A grafia tal como a INAPI a publicou.
revision boolean O corpus marcou a linha para que uma pessoa a veja. O motivo não é publicado.
  • Um filtro tipo = 'natural' não serve para «tudo o que não é uma empresa». Traria umas 130.000 partes que ninguém classificou. Se precisa de certeza, exija tipoOrigen: 'rut'.
  • nombre é o campo com que se BUSCA; nombrePublicado é o que se MOSTRA no relatório, ou o que se CONFRONTA com o documento da INAPI. nombre é a forma canónica (MAIÚSCULAS com acentos); comparar contra nombrePublicado reintroduz o ruído de maiúsculas e acentos que a canónica remove.
  • O corpus de pessoas foi reescrito a 2026-09-08: 396.444 nomes passaram à forma canónica (~240.000 mudaram de grafia) e foram fundidos 179 grupos de duplicados sem que nenhuma marca mudasse de dono. Comparar um relatório em cache de antes com um de hoje mostrará diferenças de maiúsculas e acentos que não são mudanças de dado.

Identidade de cada anotação

Cada elemento de anotaciones[] traz um id (string opaca). É estável: a escrita do corpus é somente-anexação, então uma anotação conserva seu id enquanto existir.

!!! warning "O que o id NÃO resolve" A chave que decide se uma anotação chega a ser escrita é (nro_solicitud, tipo, fecha, md5(observacion)) e não inclui a seção. Para um código fora de M1..M14 sem observação, isso permite no máximo uma anotação por marca e por dia: uma segunda seção do mesmo dia nunca é escrita e portanto não tem id. Medido: 5,37 % do que a fonte oferece. Ver o esquema.

!!! danger "historyIncomplete: false não garante que não falte nenhuma anotação" É um negativo estreito: significa "não há diff de Sheets pendente de confirmação pelo Buscador". Não é levantado por um movimento que não muda estado, nem pelo atraso do Buscador em relação ao Estado Diario, nem pela colisão de chave acima. coverageTier (denso/residual) é a era do corpus, não uma afirmação sobre a marca. Para delimitar o que se pode afirmar, use dataAsOf, coverageThrough e enrichmentPending.

curl

curl -sS "$TARNO_BASE_URL/v1/brands/123456/report" \
  -H "X-API-Key: $TARNO_API_KEY"

TypeScript (fetch)

const res = await fetch(`${process.env.TARNO_BASE_URL}/v1/brands/123456/report`, {
  headers: { "X-API-Key": process.env.TARNO_API_KEY! },
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${res.status} ${error.code}: ${error.message} (requestId=${error.requestId})`);
}

const report = await res.json(); // BrandReport — superset do detalhe da marca
console.log(report.estado, report.completeness);
// coverageThrough pode vir omitido se não há instância enriquecida.

Linha do tempo de oposições de uma marca

GET /v1/brands/:nroSolicitud/opposition — scope brands:read. MCP: get_brand_opposition.

Retorna uma OppositionTimeline: uma lista plana e cronológica (fecha ascendente) das anotações do Estado-Diário cujo tipo de seção é 'oposicion', mais a janela de oposição derivada quando a marca tem data de publicação. Um número de solicitação desconhecido retorna 404 not_found.

Campo Tipo Notas
nroSolicitud string Número de solicitação da marca.
estado string | omitido Estado bruto (raw). Omitido se for NULL.
eventos[] array\<Evento> Anotações de seção 'oposicion', em ordem cronológica (fecha ASC).
ventanaOposicion objeto | omitido A única data derivada. Presente só se há data de publicação (ver aviso).
freshnessNote string SEMPRE presente. Declara honestamente o gap de frescor do Estado-Diário.
dataAsOf string | omitido Marca temporal dos dados, se aplicável.
coverageThrough objeto | omitido Fronteira de cobertura.

Cada elemento de eventos[]:

Subcampo Tipo Notas
fecha YYYY-MM-DD Data da anotação.
seccion string Código da seção do Estado-Diário.
seccionNombre string Nome legível da seção.
seccionTipo 'oposicion' Tipo de seção — sempre 'oposicion' nesta linha do tempo.
observacion string Texto da anotação.

E ventanaOposicion (quando presente):

Subcampo Tipo Notas
fechaPublicacion YYYY-MM-DD Data de publicação a partir da qual a janela é contada.
fechaLimite YYYY-MM-DD Data limite = publicação + 30 dias úteis.
diasHabilesRestantes integer Dias úteis restantes até a data limite.
vencida bool true se a janela já venceu.

Honestidade — prazos. Os eventos não levam um prazo por-evento: correm a partir de datas de notificação que o corpus não captura com precisão, então nenhuma data limite por evento é calculada. A única data derivada segura é ventanaOposicion = data de publicação + 30 dias úteis, e está presente se a marca tem data de publicação — nunca é fabricada. Além disso, freshnessNote está sempre presente e declara o gap de frescor do Estado-Diário, para que você saiba o quanto a linha do tempo pode estar atrasada em relação à realidade.

curl

curl -sS "$TARNO_BASE_URL/v1/brands/123456/opposition" \
  -H "X-API-Key: $TARNO_API_KEY"

TypeScript (fetch)

const res = await fetch(`${process.env.TARNO_BASE_URL}/v1/brands/123456/opposition`, {
  headers: { "X-API-Key": process.env.TARNO_API_KEY! },
});

if (!res.ok) {
  const { error } = await res.json();
  throw new Error(`${res.status} ${error.code}: ${error.message} (requestId=${error.requestId})`);
}

const timeline = await res.json(); // OppositionTimeline
console.log(timeline.freshnessNote); // sempre presente
for (const ev of timeline.eventos) {
  console.log(ev.fecha, ev.seccionNombre, ev.observacion);
}
// ventanaOposicion só existe se a marca tem fechaPublicacion.
if (timeline.ventanaOposicion) {
  console.log("Vence:", timeline.ventanaOposicion.fechaLimite, "vencida:", timeline.ventanaOposicion.vencida);
}

Oposições abertas em uma classe

GET /v1/oppositions/open?clase=X&(q=…|nroSolicitud=…) — scope brands:read. MCP: get_open_oppositions.

Lista marcas com janela de oposição aberta em uma classe de Nice, ranqueadas por similaridade a um portfólio. O caso de uso: vigiar ameaças de registro na sua classe — marcas recém-publicadas cuja janela de oposição segue aberta e que se parecem com algo que você quer proteger. O ranking usa o mesmo modelo de similaridade que search / find-similar (fonético + léxico + semântico).

Query:

Param Tipo Notas
clase integer OBRIGATÓRIO. Classe de Nice, inteiro 145.
q string Texto livre. Exatamente um de q ou nroSolicitud (ver aviso).
nroSolicitud string Uma marca existente como referência. Exatamente um de q ou nroSolicitud (ver aviso).

O xor q / nroSolicitud. Você deve enviar clase e exatamente um de q (texto livre) ou nroSolicitud (uma marca existente que atua como referência de similaridade). Enviar ambos ou nenhum retorna 400 validation_error.

Resposta: BrandSummaryPage = { items: BrandSummary[], nextCursor: string | null, dataAsOf? }. A paginação é por keyset: para a próxima página, reenvie nextCursor sem alterações como cursor; nextCursor: null = fim — mesma semântica de keyset que primeiros passos. Cada elemento de items é a mesma forma BrandSummary documentada em primeiros passos e em /docs.

curl

curl -sS "$TARNO_BASE_URL/v1/oppositions/open?clase=43&q=cafe%20example" \
  -H "X-API-Key: $TARNO_API_KEY"

TypeScript (fetch) — paginando

const baseUrl = process.env.TARNO_BASE_URL!;
const apiKey = process.env.TARNO_API_KEY!;

let cursor: string | null = null;
do {
  const url = new URL(`${baseUrl}/v1/oppositions/open`);
  url.searchParams.set("clase", "43");
  url.searchParams.set("q", "cafe example"); // exatamente um de q | nroSolicitud
  if (cursor) url.searchParams.set("cursor", cursor);

  const res = await fetch(url, { headers: { "X-API-Key": apiKey } });
  if (!res.ok) {
    const { error } = await res.json();
    throw new Error(`${res.status} ${error.code}: ${error.message} (requestId=${error.requestId})`);
  }

  const page = await res.json(); // BrandSummaryPage
  for (const brand of page.items) console.log(brand.nroSolicitud, brand.denominacion, brand.score);
  cursor = page.nextCursor; // null = fim
} while (cursor);

Scopes

Os três endpoints requerem o scope brands:read.

Um array de scopes vazio não tem restrição (mesma regra que no resto do contrato): uma chave sem scopes recebe todos os scopes de leitura, incluindo brands:read. Uma chave com scopes não vazios recebe os listados; chamar uma destas rotas sem brands:read é rejeitado com 403 forbidden nomeando o scope faltante.

Consulte o guia de autenticação para o ciclo de vida da chave e a semântica de scopes.

MCP

REST é equivalente a MCP: mesma chave, mesmos scopes, mesmos esquemas Zod. O servidor MCP expõe estas ferramentas:

Ferramenta MCP Equivalente REST
get_brand_report GET /v1/brands/:nroSolicitud/report
get_brand_opposition GET /v1/brands/:nroSolicitud/opposition
get_open_oppositions GET /v1/oppositions/open

Consulte o guia de MCP para o endpoint, o transporte e a autenticação.

Erros

Todos os erros usam o envelope uniforme { error: { code, message, requestId } } — descrito em primeiros passos.

HTTP code Quando
401 unauthorized Chave ausente, malformada, desconhecida ou revogada.
403 forbidden Falta o scope brands:read requerido.
404 not_found Marca inexistente (em report e opposition).
400 validation_error Em oppositions/open: falta clase, ou o xor q / nroSolicitud não é cumprido (ambos ou nenhum).

Ver também