Guía para publicadores
Publica tus productos
Publicar en prodid significa poner dos archivos en la web y un registro en el DNS. En tu propio dominio no hay que registrarse ni guardar ninguna clave: el dominio es la credencial, y cambias o retiras lo que publicas cambiando los archivos.
¿Cómo vas a publicar?
Identidad y alojamiento van por separado. Tu identidad es un dominio que controlas; dónde se sirven los documentos es un detalle que puedes cambiar más adelante sin cambiar tu identidad ni ningún identificador que prodid haya asignado a tus productos. Tres vías, y todas producen exactamente los mismos registros.
Vía 1
Puedes servir archivos en tu propio dominio.
Sirve el documento de descubrimiento en el dominio y publica un registro TXT que nombre al propio dominio.
- Identidad
- el dominio
- Confianza
- verified
Vía 2
Tienes un dominio pero no puedes servir archivos en él.
Publica en un slug alojado y apunta un registro TXT de tu dominio a ese host.
- Identidad
- el dominio, probado por DNS
- Confianza
- verified
Vía 3
No tienes ningún dominio.
Publica en un slug alojado. Añade un dominio más adelante sin perder nada.
- Identidad
- el host del slug
- Confianza
- unverified
Las vías 2 y 3 usan el servicio de publicación alojado en <slug>.prodid.org. Entra en publish.prodid.org con un enlace que te llega por correo, crea un sitio, sube tu archivo y conecta un dominio si tienes uno. Puedes exportarlo todo o borrar el sitio en cualquier momento.
Vía 1
Publica en tu propio dominio
Dos archivos y un registro DNS. Una plataforma que publica en nombre de comercios hace lo mismo en el dominio de cada uno, así que cada comercio conserva su identidad y su nivel de confianza.
Sirve el documento de descubrimiento
Un archivo, en una ruta fija, que indica dónde están tus feeds de producto:
https://acme.example/.well-known/prodid.json.well-known/prodid.jsonapplication/json{ "$type": "org.prodid.feed", "version": 1, "publisher": { "name": "Acme Tekstil", "contact": "data@acme.example" }, "license": "CC0-1.0", "feeds": ["https://acme.example/prodid/items.ndjson"] }El ejemplo de spec/fixtures/v1/examples/prodid.json, generado a partir del propio archivo. $typeObligatorio: sí- Siempre org.prodid.feed.
versionObligatorio: sí- 1. Un documento con 0 se acepta en los rastreos que empiezan antes del 2027-01-26 00:00 UTC y después se rechaza, como negativo definitivo.
publisher.nameObligatorio: sí- El nombre que una persona debe ver junto a tus afirmaciones.
publisher.contactObligatorio: no- Una dirección de correo que alguien lea de verdad. Es donde escribe el índice cuando tu fuente entra en lapse, y es el único aviso que recibirás.
licenseObligatorio: sí- Identificador SPDX que cubre los datos de tus feeds, por ejemplo CC0-1.0.
feedsObligatorio: sí- Hasta 100 URL https, todas en el mismo host que este documento.
domainObligatorio: al delegar- El dominio por el que habla este documento. Obligatorio siempre que se llegue al documento a través de un registro TXT que nombre otro host, y entonces debe ser igual a ese dominio. Opcional cuando el dominio sirve el documento él mismo, y si está presente debe coincidir igualmente.
Sírvelo por HTTPS en el puerto por defecto, con un certificado válido, como
application/json, o cualquierapplication/…+json. No lo redirijas a otro host: la única redirección que sigue el rastreador es deacme.exampleawww.acme.example.Sirve el feed
Un feed es NDJSON: un objeto JSON completo por línea, UTF-8, separado por saltos de línea. Sin un array alrededor ni comas entre líneas. Así un feed de dos millones de productos se lee línea a línea, y una línea mala te cuesta esa línea y no el resto.
prodid/items.ndjsonapplication/x-ndjson{"$type":"org.prodid.item","key":"TJ-2041-NVY-M","brand":"Acme","name":"Trail Jacket","lang":"en","group":"TJ-2041","variant":{"color":"navy","size":"M"},"identifiers":[{"scheme":"gtin","value":"09506000134352"},{"scheme":"mpn","value":"TJ-2041-NVY-M"}],"markets":["TR","DE"],"properties":{"material":"100% recycled polyester","madeIn":"TR","weight":{"value":480,"unit":"g"}},"media":[{"url":"https://acme.example/img/tj2041-navy.webp","license":"CC-BY-4.0","kind":"image"}]} {"$type":"org.prodid.item","key":"TJ-2041-NVY-L","brand":"Acme","name":"Trail Jacket","lang":"en","group":"TJ-2041","variant":{"color":"navy","size":"L"},"identifiers":[{"scheme":"gtin","value":"09506000134406"},{"scheme":"mpn","value":"TJ-2041-NVY-L"}],"markets":["TR","DE"],"properties":{"material":"100% recycled polyester","madeIn":"TR","weight":{"value":505,"unit":"g"}},"media":[{"url":"https://acme.example/img/tj2041-navy.webp","license":"CC-BY-4.0","kind":"image"}]} {"$type":"org.prodid.item","key":"TJ-2041-OLV-M","brand":"Acme","name":"Trail Jacket","lang":"en","group":"TJ-2041","variant":{"color":"olive","size":"M"},"identifiers":[{"scheme":"gtin","value":"09506000134413"},{"scheme":"mpn","value":"TJ-2041-OLV-M"}],"markets":["TR"],"properties":{"material":"100% recycled polyester","madeIn":"TR","weight":{"value":480,"unit":"g"}},"media":[{"url":"https://acme.example/img/tj2041-olive.webp","license":"CC-BY-4.0","kind":"image"}]}Tres variantes de un producto, de spec/fixtures/v1/examples/items.ndjson. Comparten un group, así que el índice construye con ellas una familia de tres variantes. Los feeds viven en el mismo host que el documento que los lista. Un documento de descubrimiento que nombra un feed en otro host se rechaza entero, no en parte: pierdes toda la fuente, no un feed, y cuenta como negativo definitivo, así que pone en marcha el reloj del lapse que se explica abajo. Servir el JSON desde tu web y el NDJSON desde otro host de CDN es algo normal de querer y no está admitido en v1. Pon ambos en un solo host.
La primera de esas líneas, formateada para leerla:
un registro org.prodid.item{ "$type": "org.prodid.item", "key": "TJ-2041-NVY-M", "brand": "Acme", "name": "Trail Jacket", "lang": "en", "group": "TJ-2041", "variant": { "color": "navy", "size": "M" }, "identifiers": [ { "scheme": "gtin", "value": "09506000134352" }, { "scheme": "mpn", "value": "TJ-2041-NVY-M" } ], "markets": ["TR", "DE"], "properties": { "material": "100% recycled polyester", "madeIn": "TR", "weight": { "value": 480, "unit": "g" } }, "media": [{ "url": "https://acme.example/img/tj2041-navy.webp", "license": "CC-BY-4.0", "kind": "image" }] }$typeObligatorio: sí- Siempre org.prodid.item.
keyObligatorio: sí- Tu nombre estable para este registro dentro del feed. Volver a publicar la misma key sustituye al anterior.
brandObligatorio: sí- La marca tal como aparece en el producto. Se normaliza antes de acotar un mpn, así que ARÇELİK y Arçelik son una marca, no dos.
nameObligatorio: sí- El nombre del producto, sin los ejes de variante.
identifiersObligatorio: sí- Al menos un { scheme, value }, y al menos uno que el índice pueda guardar. Los valores no llevan espacios en los extremos y no están vacíos. Un gtin debe tener 8, 12, 13 o 14 dígitos con un dígito de control correcto y no ser todo ceros; un mpn necesita una brand que se normalice a algo, porque ese es el ámbito en el que es único; un gtin de circulación restringida se conserva, pero solo como tu propio rcn. Un registro que se queda sin nada guardable no identifica nada y se omite.
langObligatorio: no- Etiqueta BCP 47 del texto legible de este registro.
groupObligatorio: no- Tu propia clave de agrupación. Los items que la comparten son variantes de una misma familia.
variantObligatorio: no- Los ejes que distinguen este item dentro del grupo: color, talla, capacidad.
categoryObligatorio: no- Código de brick GS1 GPC, escrito gpc: seguido de ocho dígitos.
marketsObligatorio: no- Códigos ISO 3166-1 alfa-2 de los mercados donde se vende este item.
propertiesObligatorio: no- Cadenas, números, booleanos, listas o { value, unit } para una medida.
mediaObligatorio: no- Hasta 20 URL https, cada una con un kind y una licencia SPDX de la lista admitida. A diferencia de los feeds, pueden estar en cualquier host.
Envía items planos. Nunca construyes familias ni variantes tú mismo y nunca envías un
opid: el índice deduce lo primero degroupy asigna lo segundo. Si ya generas un feed de Google Merchant,groupes tuitem_group_id.Dos cosas sobre los códigos de barras que conviene saber antes de exportar. Un
gtintodo ceros no es un código de barras, es un marcador de catálogo, y un registro que lo lleve se rechaza igual que uno con dígito de control erróneo. Un número de circulación restringida, los rangos de uso en tienda, se guarda y se te atribuye, pero no identifica nada a nivel global, así que nunca fusiona tu producto con el de otro y/01/no lo resuelve.Reclama la identidad en el DNS
Con los archivos ya publicados, publica un registro que nombre tu propio dominio como host.
_prodid.acme.example TXT_prodid.acme.example. IN TXT "v=prodid0; host=acme.example"Apunta exactamente a lo que el descubrimiento habría encontrado de todos modos, así que nada cambia en tus datos. Lo que cambia es lo que puede hacer alguien con acceso de solo añadir a tu DNS. Sin registro, uno que añada esa persona se queda con tu identidad sin hacer ruido, porque el DNS gana al archivo. Con tu registro ya puesto, un segundo hace que el descubrimiento falle con más de un registro: un lapse visible, notificado y recuperable.
Nunca delegues
_prodiden un proveedor. El acceso de escritura a_prodid.<domain>es el control de tu identidad, igual que para DKIM o un desafío ACME DNS-01. Un dominio con DNS compartido es una identidad compartida. Dale a una agencia el feed, no el registro.Sube los archivos antes que el registro, no después: un registro que apunta a un documento que aún no existe es un descubrimiento fallido. Los valores se leen sin distinguir mayúsculas y un punto final está bien, así que
ACME.Example.yacme.exampleson el mismo host.Avisa al índice del cambio
Opcional. Cada dominio conocido se vuelve a rastrear según un calendario; un ping solo adelanta el siguiente rastreo.
pedir al índice que ejecute el descubrimiento ahoracurl -X POST https://prodid.org/ping \ -H 'content-type: application/json' \ -d '{"domain": "acme.example"}' HTTP/1.1 202 Accepted Content-Type: application/json {"status":"accepted"}{"domains": [...]}admite hasta 1000 a la vez; así es como una plataforma presenta cada comercio que aloja. No hay clave que enviar, porque el ping no da a quien llama ningún poder sobre el contenido, y202es lo único que responde. No dice si el dominio era conocido, si se encontró algo ni si otra persona lo pingueó hace un minuto. Un429solo significa que tú has superado tu propio presupuesto de peticiones, y los errores llegan comoapplication/problem+json. Lo que le pasó a tu dominio aparece en el estado de tu fuente, no en el ping.
Vía 2
Delega el alojamiento, conserva la identidad
Muchos fabricantes tienen un dominio y no pueden poner un archivo en él. El feed se aloja en otro sitio y el dominio se prueba con DNS, así que la identidad de la fuente sigue siendo el dominio y el nivel de confianza sigue siendo verified. Crea un sitio en publish.prodid.org, escribe tu dominio y te muestra el registro exacto que debes añadir y lo comprueba por ti.
Cómo queda
Un catálogo subido a un slug alojado
, por ejemplo
acme.prodid.org, que sirve tanto el documento de descubrimiento como el feed.Un registro TXT en el dominio que tienes
, que nombra ese host. Un host, nunca una URL, así que un registro nunca puede dirigir al rastreador a una dirección cualquiera.
_prodid.acme.example TXT_prodid.acme.example. IN TXT "v=prodid0; host=acme.prodid.org"Un documento que nombra tu dominio de vuelta.
El DNS dice mi documento está allí; el documento dice hablo por ese dominio. Un documento delegado sin
domainse rechaza: la ausencia nunca se toma como consentimiento, y eso impide que alguien apunte un registro al feed de otro.acme.prodid.org/.well-known/prodid.jsonapplication/json{ "$type": "org.prodid.feed", "version": 1, "domain": "acme.example", "publisher": { "name": "Acme Tekstil", "contact": "data@acme.example" }, "license": "CC0-1.0", "feeds": ["https://acme.prodid.org/feeds/items.ndjson"] }De spec/fixtures/v1/examples/prodid.delegated.json. La única diferencia con la vía 1 es el campo domain, y aquí es obligatorio. Crea tu sitio
El publicador alojado escribe
domainen el documento solo después de ver tu registro TXT él mismo, así que no hay ningún momento en que un documento reclame un dominio que no lo ha pedido.
Vía 3
Publica sin dominio
Crea tu sitio
Un productor sin ningún dominio publica en un slug alojado,
<slug>.prodid.org, con su propio nombre. Reserva uno en publish.prodid.org. La identidad de la fuente es el host del slug y el nivel de confianzaunverified, porque no se ha probado nada sobre un dominio. Los registros son registros de verdad: identificadores, resolución, atribución.Casi todos los publicadores en esta situación ya tienen un archivo de producto de Google Merchant, así que la correspondencia de ese archivo a registros
org.prodid.itemestá escrita en la especificación, columna por columna, junto con lo que descarta a propósito: precio, disponibilidad, envío y estado pertenecen a un vendedor en un día concreto, no al producto. Vale la pena leer Importar un feed de Merchant antes de exportar: publish.prodid.org convierte el CSV o TSV que subes con exactamente esa correspondencia. Cuatro cosas de ahí deciden cómo tiene que ser tu hoja de cálculo:- Cuatro columnas se convierten en ejes de variante:
color,size,materialypattern, entre las que elige un comprador dentro de un mismoitem_group_id.gender,age_group,size_typeysize_systemsiguen siendo propiedades normales: describen todo el grupo, y como ejes partirían un producto en varios la primera vez que alguien escribiera uno de ellos de dos maneras. - Un atributo repetido va separado por comas o con cabecera repetida, por archivo, no por celda. Una celda se divide por comas solo cuando su cabecera aparece una vez en todo el archivo; si repites la cabecera, cada celda bajo ella se toma entera. Es la única forma de llevar un valor con una coma dentro, y es una decisión que tomas una vez para el archivo. Se aplica a
additional_image_link,product_type,product_highlight,product_detailycertification; todo lo demás, incluida unadescriptionllena de comas, se toma entero en cualquier caso. - Un
product_detailnunca sobrescribe nada. Su subatributo central pasa a ser la clave de la propiedad, el nombre de sección se descarta y gana el primer valor de cada clave. Un detail posterior con la misma clave, o uno que cae en una clave que la correspondencia ya produjo, se descarta y se informa con su fila, así que una columna de detail nunca puede redefinir en silencio lo que decía el resto de la fila. - Hay que declarar una licencia para los medios. El formato Merchant no tiene columna para ello y nada se ingiere sin licencia, así que una importación declara un único identificador SPDX admitido que cubre cada imagen y documento del archivo. Una columna
licensepropia lo sustituye fila a fila, y un archivo cuya licencia declarada no es admitida produce registros sin medios, no registros que fallan.
Una fila que no puede convertirse en registro (sin identificador útil, con un GTIN cuyo dígito de control falla) se omite y se informa por su número de fila en la hoja, contando la cabecera como fila 1, así que una fila mala cuesta esa fila y no la importación. Hay un archivo resuelto con el que comprobarte en /spec/fixtures/merchant: un CSV, los registros que debe producir y la fila que debe omitirse.
Lo que importa de una decisión de hoy es lo que pasa después. Añadir un registro TXT en un dominio que adquieras, nombrando ese mismo host, convierte el slug en el dominio en el siguiente rastreo: la misma fuente, los mismos registros, cada
opidconservado, con la confianza subiendo deunverifiedaverified. Tus identificadoresskudependen de la propia fuente y no de su nombre, así que sobreviven al cambio. En publish.prodid.org es el mismo campo de dominio que usa la vía 2.- Cuatro columnas se convierten en ejes de variante:
Comprueba tu dominio
¿Has terminado de publicar? Introduce tu dominio. Se le pide al índice que lo revise ahora y llegas a su página de estado en vivo.
Antes de salir en vivo
Comprueba tus archivos antes del ping
prodid-batch check valida tu documento de descubrimiento y cada feed exactamente como lo haría el índice, sin token y sin preguntarle nada al índice. Se ejecuta desde un clon del repositorio con Bun 1.4.4. Dale los archivos en sí: una ruta que termina en .json se lee como un documento, cualquier otra como un feed NDJSON.
git clone https://github.com/productdevbook/prodid
cd prodid
bun install --frozen-lockfile
curl -fsSo prodid.json https://acme.example/.well-known/prodid.json
curl -fsSo items.ndjson https://acme.example/prodid/items.ndjson
bun apps/batch/src/cli.ts check prodid.json items.ndjson
prodid.json: ok, 1 record
items.ndjson: ok, 3 recordsUn archivo sin problemas imprime ok y el número de registros que el índice tomaría de él. Si no, imprime una línea por problema, como items.ndjson:12: message con la línea del feed en la que está, y sale con un código distinto de cero. Lee los archivos, no tu DNS ni tu servidor, así que el registro TXT, el tipo de contenido y las cabeceras de caché de la lista de arriba siguen siendo cosa tuya.
Las reglas con las que se valida un registro están en la especificación, los esquemas se sirven en /spec/schemas/v1, y /spec/fixtures/v1 tiene vectores legibles por máquina con los que probar tu exportador antes de que nadie lo rastree.
La especificación se publica solo en inglés, y el texto en inglés es el normativo.
Estado: Spec v1. El índice y el publicador alojado funcionan en prodid.org. Cualquiera puede publicar, en su propio dominio o alojado. Los formatos de archivo de esta página son los que lee el índice cuando le haces ping.
Referencia
Conviene saberlo antes que nada, porque decide cuál de las tres vías de abajo es la tuya. El descubrimiento empieza de cero en cada rastreo, primero por DNS, y entre rastreos no se recuerda nada del camino hasta tus datos.
Primero
Un registro DNS TXT en
_prodid.acme.exampleSi hay un registro
v=prodid0, se sigue en exclusiva, aunque nombre tu propio dominio. El registro nombra un host; el documento siempre está enhttps://<host>/.well-known/prodid.json.Solo si no hay tal registro
https://acme.example/.well-known/prodid.jsonEl documento en el propio dominio. Quien sirve el dominio por HTTPS habla por él.
El DNS va primero porque es la prueba más fuerte: quien puede poner un archivo en un host no siempre es el dueño del dominio, y el dueño tiene que poder imponerse. Por eso conviene escribir el registro aunque sirvas el archivo tú mismo; vía 1, paso 3 explica qué ganas.
Exactamente un registro, y nada detrás. Más de un registro v=prodid0 con ese nombre es un error, no una elección entre ellos, y uno solo mal formado o demasiado largo también es un error. No hay alternativa: si existe un registro y no funciona, el descubrimiento termina ahí en lugar de mandar al rastreador a mirar tu dominio. Si cambias de host, sustituye el registro; nunca añadas un segundo. La gramática, con vectores de prueba, está en la especificación.
Qué cuenta como respuesta. HTTP 200 tras como mucho una redirección, un tipo de contenido JSON, un cuerpo que valida contra el esquema del feed y un domain que nombra el dominio que se descubre. Un sitio que responde a rutas desconocidas con una página HTML y un 200 no está respondiendo, como tampoco un documento servido como text/html.
La confianza es una propiedad de la fuente, no de una afirmación. Dice qué se ha probado sobre quién habla, y nada sobre si un dato concreto es correcto. Quien usa los datos decide qué hacer con eso.
| Nivel | Significado |
|---|---|
| authoritative | Control del dominio probado y titularidad de la marca confirmada. |
| verified | Control del dominio probado, por el registro TXT o porque el dominio sirve el documento. |
| unverified | Un slug alojado sin dominio, una importación de datos o una contribución de la comunidad. |
Solo una fuente cuya identidad es un dominio puede ser más que unverified. verified sale del rastreo. authoritative no, porque ningún rastreo puede probar quién es dueño de una marca: lo concede el operador del índice, y solo con pruebas.
La prueba es tu prefijo de empresa GS1.
El prefijo de empresa GS1 de los GTIN que tu fuente publica bajo la marca debe estar licenciado a la organización que controla tu dominio, según la consulta pública «Verified by GS1». La URL de esa consulta se guarda con la concesión como prueba.
Una concesión nombra una marca, y cada una puede revocarse.
La marca se guarda en su forma normalizada. Una fuente puede tener concesiones para varias marcas, y el operador revoca cada una por separado.
Una concesión no sobrevive a la prueba que la sostiene.
Tu fuente es
authoritativeexactamente mientras el control de su dominio esté probado, no esté lapsed y tenga al menos una concesión sin revocar. Si pierdes la prueba de dominio o entras en lapse, baja al instante a lo que permita la prueba que quede (verifieddurante el lapse, menos si también falta la prueba de dominio) sin que nadie intervenga. Vuelve a serauthoritativeen cuanto se cumplan otra vez las tres.Cubre la fuente, no la marca.
La confianza sigue siendo una propiedad de la fuente: una concesión para una marca hace
authoritativecada afirmación de tu fuente, también las de marcas para las que no tiene concesión.
Para pedirla, publica primero en tu propio dominio y luego solicítala con el formulario, indicando tu dominio, la marca y una consulta Verified by GS1 de uno de sus GTIN. El operador comprueba en Verified by GS1 los GTIN que tu fuente publica bajo esa marca. La solicitud es pública.
Publicar un registro con una key que ya existe sustituye al anterior. No hay endpoint de actualización, porque el feed es el estado.
Una key que desaparece de un feed que el rastreador obtuvo entero marca tus afirmaciones sobre ella como retiradas. La entidad y su identificador se quedan: los enlaces de otros siguen funcionando, igual que las afirmaciones de otras fuentes.
Cuando un rastreo lee un documento que ya no nombra una de tus URL de feed, cada registro activo de ese feed se retira al momento, como si hubieran desaparecido todas sus keys, y la URL no se vuelve a pedir. El margen de siete días de abajo no se aplica: quitar una URL es decir que el archivo ya no existe, y el índice te toma la palabra. Volver a listarla más tarde la recupera, leída desde cero. Sirve el documento con un ETag si puedes: un 304 significa que la lista no ha cambiado, así que no retira nada.
Una línea de más de 64 KiB, imposible de analizar o no válida se omite y se cuenta. Como la key de una línea omitida es desconocida, un feed con líneas omitidas no retira nada durante siete días. Después, las keys ausentes se retiran como siempre. El recuento es público, así que un feed que pierde líneas en silencio no pasa desapercibido.
Un rastreo solo tiene éxito cuando se ha leído todo lo que lista el documento: un documento aceptable, y cada feed de él respondiendo 200 o 304. Que un feed agote el tiempo no te hace perder los demás (los que respondieron se ingieren y en un rastreo fallido no se retira nada), pero el rastreo cuenta como fallo de transporte y feeds_failed lo indica en tu estado. Un documento perfectamente sano con una URL de feed muerta para siempre entra por tanto en lapse con el mismo reloj de siete días que un dominio que dejó de responder del todo, y pierde el catálogo treinta días después. Una URL de feed que ya no sirves debe quitarse del documento, no dejarse pudrir.
Un negativo definitivo, es decir, un descubrimiento que termina sin documento aceptable (ni registro ni documento; un registro mal formado, demasiado largo o duplicado; o un documento que no es 200, no es JSON, no es válido, ya no coincide en domain o lista un feed fuera de su host), pone la fuente en lapse al instante. Un fallo de transporte (un timeout de DNS, un 5xx, un 429, un límite alcanzado, en el documento o en cualquier feed) no cambia nada por sí solo, pero siete días seguidos en los que cada intento termina así también te ponen en lapse, así que servir errores para siempre no es una forma de congelar tus afirmaciones.
Ese beneficio de la duda pertenece a un host, no a ti. Solo se aplica en un host en el que tu fuente ya se verificó. En un host donde nunca se ha verificado (un slug nuevo, un host al que acabas de apuntar _prodid, todo lo de las vías 2 y 3), cualquier fallo, timeouts y 5xx incluidos, es un negativo definitivo y te pone en lapse al instante. Es deliberado: si no, una fuente verificada podría apuntar su registro a un host que no controla y deducir, según su lapse empiece hoy o dentro de una semana, si ese host está activo. Cambiar de host no te cuesta nada por ello. El primer rastreo con éxito en el nuevo host lo limpia todo, y un lapse sigue siendo recuperable durante los 30 días anteriores a cualquier retirada.
Una fuente en lapse no acepta afirmaciones nuevas, se muestra como lapsed a los lectores y se avisa a su publisher.contact. Un rastreo de una fuente en lapse no escribe nada hasta que tiene éxito completo; solo entonces se levanta el lapse. Tras 30 días seguidos de lapse, tus registros y sus afirmaciones activas se retiran juntos y quedan como historial. Esos 30 días son tu ventana de recuperación, y por eso la dirección de contacto tiene que leerla alguien.
Volver no exige cambiar nada. Sirve el mismo documento y el mismo feed de siempre y todo lo que publicas se vuelve a afirmar en cuanto el descubrimiento tiene éxito, se haya movido un byte o no: mientras no tiene nada activo tuyo, el índice deja de usar peticiones condicionales, así que un archivo sin cambios nunca es motivo para seguir retirado.
Cada afirmación que ve un lector lleva seen_at: no cuándo se publicó el dato por primera vez en ningún sitio, sino desde cuándo esta fuente afirma este valor sin interrupción. Sobrevive a cada nuevo rastreo que encuentra el mismo valor, que es su razón de ser. No sobrevive a una retirada. Deja tu fuente en lapse más de 30 días y la fecha de cada dato que publicas vuelve a empezar el día que regreses, porque durante el hueco nadie verificable los respaldaba. Las filas retiradas se quedan, así que ?history=1 muestra el hueco en vez de ocultarlo; lo que ve un lector está en la especificación.
/source/acme.example es donde ves que algo va mal: el resultado del último rastreo, qué camino siguió el descubrimiento, cuántos registros cambiaron, cuántas líneas se omitieron, cuántos feeds no se pudieron leer y si estás en lapse y desde cuándo. Solo informa de lo que publica tu dominio y de cuándo miró el índice, nunca de quién pidió un rastreo.
{
"$type": "org.prodid.source",
"version": 1,
"name": "acme.example",
"kind": "domain",
"trust": "verified",
"verified_by": "dns-txt",
"verified_at": "2026-09-14T09:12:03Z",
"lapsed": false,
"license": "CC0-1.0",
"last_crawl": {
"at": "2026-09-19T06:00:11Z",
"via": "dns-txt",
"document_url": "https://acme.prodid.org/.well-known/prodid.json",
"outcome": "success",
"http_status": 200,
"records_seen": 3,
"records_changed": 1,
"lines_skipped": 0,
"feeds_failed": 0,
"media_failed": 0
}
}El tipo se decide leyendo los bytes; tu Content-Type es una pista. Se guardan seis tipos y nada más: JPEG, PNG, GIF, WebP y AVIF como image, PDF como document. Sin SVG, sin HTML, sin archivos comprimidos, sin archivos de Office: una ficha técnica va en PDF. El tipo detectado y el kind de la entrada tienen que coincidir, o la entrada se omite.
| Qué | Límite |
|---|---|
| Una imagen | 20 MiB |
| Un documento | 50 MiB |
| Una descarga de medio | 60 s |
| Entradas de medios en un registro | 20 |
La licencia se comprueba como texto antes de descargar nada, y debe ser exactamente uno de siete identificadores SPDX: los que permiten a cualquiera redistribuir el archivo tal cual, que es lo que hace el índice con él:
CC0-1.0 CC-BY-4.0 CC-BY-SA-4.0 CC-BY-ND-4.0
CC-BY-3.0 CC-BY-SA-3.0 CC-BY-ND-3.0Aquí todo va por entrada. Una entrada rechazada, demasiado grande o inaccesible cuesta esa entrada y nada más: tu registro nunca es inválido por sus medios, sus demás afirmaciones se mantienen y ningún fallo de medios te pone en lapse. Se cuenta en media_failed y se reintenta en el siguiente rastreo de ese registro. Una cosa funciona al revés que en los feeds: la regla del mismo host no se aplica aquí, así que tus imágenes pueden estar en una CDN. Qué se ingiere y la lista de licencias explican el porqué.
Minoristas, registros, conjuntos de datos abiertos y colaboradores son fuentes como cualquier otra. Sus afirmaciones se les atribuyen y nunca sobrescriben las tuyas; donde no coincidís, ambas afirmaciones se ven juntas con sus fuentes.