Certifica y publica el badge sin pasos manuales Certify and publish the badge without manual steps
El navegador no interviene en ningún momento. Todo ocurre en tu script o pipeline: The browser is never involved. Everything happens in your script or pipeline:
Hash
SHA3-512 del archivo, calculado en tu máquina. El archivo nunca sale. SHA3-512 of the file, computed on your machine. The file never leaves.
CertificarCertify
POST al API con el hash y tu API key. Sygnet devuelve confirmación. POST to the API with the hash and your API key. Sygnet returns confirmation.
Badge
La URL del widget es determinista. La construyes tú, sin llamada extra. The widget URL is deterministic. You build it yourself, no extra call needed.
Sygnet usa SHA3-512: 128 caracteres hexadecimales, algoritmo estándar NIST. A diferencia del SHA2 más común, SHA3 tiene una construcción diferente (Keccak) que lo hace resistente a ataques de extensión de longitud. Esto es importante: el mismo archivo siempre produce el mismo hash, así que puedes verificar más tarde sin guardar el archivo. Sygnet uses SHA3-512: 128 hexadecimal characters, NIST standard algorithm. Unlike the more common SHA2, SHA3 has a different construction (Keccak) that makes it resistant to length-extension attacks. Key point: the same file always produces the same hash, so you can verify later without keeping the file.
Python 3.6+
import hashlib
def hash_file(path: str) -> str:
"""SHA3-512 of a file, memory-efficient (64 KB chunks)."""
h = hashlib.sha3_512()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(65536), b''):
h.update(chunk)
return h.hexdigest()
# Usage
print(hash_file("my-article.pdf"))
# → "a1b2c3d4e5f6..." (128 chars)
No necesita dependencias externas. hashlib es librería estándar de Python.
No external dependencies. hashlib is Python's standard library.
Node.js
// Option A — js-sha3 (compatible with all Node versions)
// npm install js-sha3
const { sha3_512 } = require('js-sha3');
const fs = require('fs');
function hashFile(path) {
return sha3_512(fs.readFileSync(path));
}
// Option B — native crypto (Node 21+ / OpenSSL 3+)
const crypto = require('crypto');
const fs = require('fs');
function hashFile(path) {
return crypto.createHash('sha3-512')
.update(fs.readFileSync(path))
.digest('hex');
}
Usa la opción A si necesitas compatibilidad amplia. La opción B no requiere dependencias pero solo funciona en Node.js 21+. Use option A for broad compatibility. Option B requires no dependencies but only works on Node.js 21+.
Línea de comandosCommand line
# Python — works on any system with Python 3.6+
python3 -c "
import hashlib, sys
h = hashlib.sha3_512()
[h.update(c) for c in iter(lambda: open(sys.argv[1],'rb').read(65536), b'')]
print(h.hexdigest())
" my-file.pdf
# OpenSSL 3+ (Linux / macOS Ventura+)
openssl dgst -sha3-512 my-file.pdf | awk '{print $2}'
Primero necesitas una API key: Dashboard → Claves API → + Nueva clave. Guarda la clave al generarla (no se puede recuperar después). First you need an API key: Dashboard → API Keys → + New key. Save the key when you generate it (it cannot be recovered later).
/api/certificados
Cabecera requeridaRequired header
Authorization: Bearer apikey_your_key_here
Body JSON
{
"hash": "a1b2c3d4...", // SHA3-512, 128 chars — required
"algorithm": "SHA3-512", // exact string, case-sensitive — SHA3-512 (default) | SHA256
"sia_level": 1, // 1–5, required
"description": "My video: AI in 2026", // visible label, optional
"published_url": "https://youtube.com/watch?v=..." // publication URL, optional
}
RespuestaResponse
// Success — always HTTP 200, whether newly created or already existing
{ "ok": true, "hash": "a1b2c3d4...", "new": true }
// If a certificate with this hash was already active:
{ "ok": true, "hash": "a1b2c3d4...", "new": false, "own": true }
// Error (400/401/404/429)
{ "ok": false, "error": "Hash inválido (se esperaba SHA3-512 hex de 128 chars)", "error_code": "invalid_hash_format" }
Python — requests
import requests
def certificar(hash_: str, titulo: str, sia: int = 1, published_url: str = None) -> dict:
payload = {
"hash": hash_,
"algorithm": "SHA3-512",
"sia_level": sia,
"description": titulo,
}
if published_url:
payload["published_url"] = published_url
r = requests.post(
"https://mysygnet.com/api/certificados",
headers={"Authorization": "Bearer apikey_YOUR_KEY"},
json=payload,
timeout=15
)
r.raise_for_status()
return r.json()
Node.js — native fetch
async function certificar(hash, titulo, sia = 1, publishedUrl = null) {
const payload = { hash, algorithm: 'SHA3-512', sia_level: sia, description: titulo };
if (publishedUrl) payload.published_url = publishedUrl;
const r = await fetch('https://mysygnet.com/api/certificados', {
method: 'POST',
headers: {
'Authorization': 'Bearer apikey_YOUR_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!r.ok) throw new Error(await r.text());
return r.json();
}
Idempotente: si el mismo hash ya está certificado y activo, Sygnet devuelve ok: true, new: false sin crear un duplicado. Puedes llamar a este endpoint varias veces sin miedo — usa el campo new de la respuesta si necesitas saber si se creó o ya existía.
Idempotent: if the same hash is already certified and active, Sygnet returns ok: true, new: false without creating a duplicate. You can call this endpoint multiple times safely — use the response's new field if you need to know whether it was just created.
Rate limit: 20 certificaciones por hora por IP de origen (no por cuenta). Si tu pipeline corre en un servidor con IP fija y necesitas más volumen, contacta a soporte — crear varias cuentas no evita el límite porque se aplica por IP. Rate limit: 20 certifications per hour per source IP (not per account). If your pipeline runs on a fixed-IP server and you need higher volume, contact support — creating multiple accounts won't bypass the limit since it's applied per IP.
Esta es la ventaja clave frente a otros sistemas: no necesitas una llamada extra al API para obtener el badge. Conoces el hash porque tú lo calculaste — con eso ya tienes todas las URLs: This is the key advantage over other systems: you don't need an extra API call to get the badge. You know the hash because you computed it — from that you already have all the URLs:
Todas las URLs, a partir del hash All URLs, from the hash
HASH = "a1b2c3d4..." # 128 chars you computed
# Badge SVG (embeddable as <img>, updates in real time)
badge_url = f"https://mysygnet.com/api/certificados/{HASH}/badge"
# Interactive widget (iframe, dark card 300×100px, click → verify)
widget_url = f"https://mysygnet.com/pages/widget.html?hash={HASH}"
# OBS Browser Source (transparent background, auto-refresh 60s)
overlay_url = f"https://mysygnet.com/pages/overlay.html?hash={HASH}"
# Raw JSON API — for scripts/monitoring, NOT for sharing with humans
api_url = f"https://mysygnet.com/api/certificados/{HASH}"
# Certificate PDF (downloadable)
pdf_url = f"https://mysygnet.com/api/certificados/{HASH}/pdf"
# Iframe snippet ready to paste on your site
iframe = (
f'<iframe src="{widget_url}" width="300" height="100" '
f'frameborder="0" scrolling="no" '
f'style="border:none;overflow:hidden;border-radius:12px"></iframe>'
)
La página de verificación para humanos (no el JSON de la API) The human verification page (not the API's JSON)
/api/certificados/{HASH} de arriba devuelve JSON crudo —
perfecto para tu script, pero si un desconocido hace clic en él desde YouTube o un badge, solo ve texto técnico.
Para compartir con tu audiencia usa mysygnet.com/?cert=...,
que muestra una página legible con el nombre del creador, la declaración y un CTA — este es el link que hay que pegar en descripciones, bios y posts.
The /api/certificados/{HASH} URL above returns raw JSON —
perfect for your script, but if a stranger clicks it from YouTube or a badge, all they see is technical text.
To share with your audience use mysygnet.com/?cert=...,
which renders a readable page with the creator's name, the declaration, and a CTA — this is the link to paste in descriptions, bios, and posts.
# Python — build the human-readable verification link
import json, base64
def build_share_url(hash_: str, sia_level: int, caduca_at=None, description: str = None) -> str:
payload = {"h": hash_, "s": sia_level}
if caduca_at:
payload["e"] = int(caduca_at.timestamp()) # unix timestamp
if description:
payload["l"] = description
b64 = base64.b64encode(json.dumps(payload, separators=(",", ":")).encode()).decode()
return f"https://mysygnet.com/?cert={b64}"
# share_url = build_share_url(HASH, sia_level=1, description="My video: AI in 2026")
# → https://mysygnet.com/?cert=eyJoIjoi...
Badge SVG vs. Widget iframe
Parámetro ?lang=?lang= parameter
Añade ?hash=...&lang=en para el widget y overlay en inglés.
Por defecto el idioma es español. Úsalo si tu audiencia es internacional.
Add ?hash=...&lang=en for the widget and overlay in English.
Default language is Spanish. Use this for international audiences.
Tienes un script que procesa tus vídeos o artículos antes de publicarlos. Añade estas dos funciones y ya tienes certificación SIA + badge automáticos: You have a script that processes your videos or articles before publishing. Add these two functions and you get automatic SIA certification + badge:
Python — pipeline completo Python — full pipeline
Certifica un archivo y devuelve todas las URLs listas para usar. Certify a file and return all ready-to-use URLs.
import hashlib
import json
import base64
import requests
SYGNET_API_KEY = "apikey_YOUR_KEY"
BASE = "https://mysygnet.com"
def hash_file(path: str) -> str:
h = hashlib.sha3_512()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(65536), b''):
h.update(chunk)
return h.hexdigest()
def certificar_y_badge(
file_path: str,
titulo: str,
sia: int = 1,
published_url: str = None,
lang: str = "en"
) -> dict:
"""
Certify a file and return hash + all useful URLs.
sia: 1=100% human 2=human+AI 3=co-authored 4=mainly AI 5=100% AI
"""
hash_ = hash_file(file_path)
payload = {
"hash": hash_,
"algorithm": "SHA3-512",
"sia_level": sia,
"description": titulo,
}
if published_url:
payload["published_url"] = published_url
r = requests.post(
f"{BASE}/api/certificados",
headers={"Authorization": f"Bearer {SYGNET_API_KEY}"},
json=payload,
timeout=15
)
r.raise_for_status()
widget_url = f"{BASE}/pages/widget.html?hash={hash_}&lang={lang}"
overlay_url = f"{BASE}/pages/overlay.html?hash={hash_}&lang={lang}"
iframe = (
f'<iframe src="{widget_url}" width="300" height="100" '
f'frameborder="0" scrolling="no" '
f'style="border:none;overflow:hidden;border-radius:12px"></iframe>'
)
badge_img = f'<img src="{BASE}/api/certificados/{hash_}/badge" alt="Sygnet SIA certificate">'
# Human-readable page to share with your audience (YouTube description, bio, post)
share_payload = {"h": hash_, "s": sia, "l": titulo}
share_b64 = base64.b64encode(json.dumps(share_payload, separators=(",", ":")).encode()).decode()
share_url = f"{BASE}/?cert={share_b64}"
return {
"hash": hash_,
"widget_url": widget_url,
"overlay_url": overlay_url,
"iframe": iframe,
"badge_img": badge_img,
"share_url": share_url, # for humans — paste this on YouTube/bio/posts
"api_url": f"{BASE}/api/certificados/{hash_}", # raw JSON — for scripts/monitoring only
"pdf_url": f"{BASE}/api/certificados/{hash_}/pdf",
}
# ── Example usage ─────────────────────────────────────────────────────────────
cert = certificar_y_badge(
file_path = "episode-42.mp4",
titulo = "Episode 42: The future of AI",
sia = 1, # 100% human
published_url = "https://www.youtube.com/watch?v=XXXX",
lang = "en"
)
print(f"Hash: {cert['hash'][:16]}…")
print(f"Share with your audience: {cert['share_url']}")
print()
print("Paste this on your site:")
print(cert['iframe'])
print()
print("For GitHub README (no iframes allowed):")
print(cert['badge_img'])
Node.js — mismo pipelinesame pipeline
const { sha3_512 } = require('js-sha3'); // npm install js-sha3
const fs = require('fs');
const SYGNET_API_KEY = 'apikey_YOUR_KEY';
const BASE = 'https://mysygnet.com';
async function certificarYBadge(filePath, titulo, sia = 1, publishedUrl = null, lang = 'en') {
const hash = sha3_512(fs.readFileSync(filePath));
const payload = { hash, algorithm: 'SHA3-512', sia_level: sia, description: titulo };
if (publishedUrl) payload.published_url = publishedUrl;
const r = await fetch(`${BASE}/api/certificados`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${SYGNET_API_KEY}`, 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!r.ok) throw new Error(await r.text());
const widgetUrl = `${BASE}/pages/widget.html?hash=${hash}&lang=${lang}`;
const overlayUrl = `${BASE}/pages/overlay.html?hash=${hash}&lang=${lang}`;
const iframe = `<iframe src="${widgetUrl}" width="300" height="100" frameborder="0" scrolling="no" style="border:none;overflow:hidden;border-radius:12px"></iframe>`;
// Human-readable page to share with your audience (YouTube description, bio, post)
const sharePayload = { h: hash, s: sia, l: titulo };
const shareB64 = Buffer.from(JSON.stringify(sharePayload)).toString('base64');
const shareUrl = `${BASE}/?cert=${shareB64}`;
return { hash, widgetUrl, overlayUrl, iframe,
shareUrl, // for humans — paste this on YouTube/bio/posts
apiUrl: `${BASE}/api/certificados/${hash}`, // raw JSON — for scripts/monitoring only
pdfUrl: `${BASE}/api/certificados/${hash}/pdf` };
}
// Usage
certificarYBadge('episode-42.mp4', 'Episode 42: AI', 1, 'https://youtu.be/XXXX')
.then(cert => {
console.log('Share with your audience:', cert.shareUrl);
console.log('Iframe:\n', cert.iframe);
});
Si tu pipeline usa una herramienta de automatización visual, el flujo es el mismo — solo que con nodos en lugar de líneas de código. If your pipeline uses a visual automation tool, the flow is the same — just with nodes instead of lines of code.
Flujo en Make / n8n / Zapier Flow in Make / n8n / Zapier
Trigger: tu evento de publicación Trigger: your publish event
Nuevo archivo en Google Drive, nuevo post en Ghost, nuevo episodio en RSS, etc. New file in Google Drive, new post in Ghost, new episode in RSS, etc.
HTTP Request → tu endpoint de hashing HTTP Request → your hashing endpoint
Un script o Cloud Function que recibe el archivo (o su URL) y devuelve el SHA3-512. Puedes usar la función Python del paso 2 desplegada en Railway, Render o Google Cloud Functions. A script or Cloud Function that receives the file (or its URL) and returns the SHA3-512. You can deploy the Python function from step 2 on Railway, Render, or Google Cloud Functions.
HTTP Request → POST https://mysygnet.com/api/certificados
Cabecera: Authorization: Bearer apikey_YOUR_KEY · Body JSON con hash, algorithm, sia_level, description.
Header: Authorization: Bearer apikey_YOUR_KEY · JSON body with hash, algorithm, sia_level, description.
Set variable: construir la URL del widget Set variable: build the widget URL
En Make: usa el módulo "Set variable" con el valor https://mysygnet.com/pages/widget.html?hash={{hash}} donde hash es la variable del paso anterior.
In Make: use the "Set variable" module with value https://mysygnet.com/pages/widget.html?hash={{hash}} where hash is the variable from the previous step.
Actualizar tu CMS / plataforma con el widget Update your CMS / platform with the widget
HTTP Request a la API de Ghost, WordPress, Webflow, etc., con el snippet iframe ya construido. HTTP Request to the Ghost, WordPress, Webflow API, etc., with the already-built iframe snippet.
El pipeline anterior es síncrono: tu script espera la respuesta del POST para continuar. Si tu arquitectura es asíncrona (cola de mensajes, worker), el webhook es más natural: certificas, Sygnet te avisa cuando está listo, tu worker incrusta el badge. The previous pipeline is synchronous: your script waits for the POST response to continue. If your architecture is asynchronous (message queue, worker), the webhook is more natural: you certify, Sygnet notifies you when it's ready, your worker embeds the badge.
Pipeline síncrono (POST → esperar respuesta) Synchronous pipeline (POST → wait for response)
Mejor para: scripts simples, pipelines lineales, Make/Zapier. Best for: simple scripts, linear pipelines, Make/Zapier.
El hash lo construyes tú → la URL del widget es inmediata. You build the hash → the widget URL is immediate.
Flujo event-driven (webhook) Event-driven flow (webhook)
Mejor para: workers asíncronos, sistemas de cola, arquitecturas desacopladas. Best for: async workers, queue systems, decoupled architectures.
El webhook dispara tu worker con el hash — mismo resultado. The webhook triggers your worker with the hash — same result.
Ejemplo: worker que recibe el webhook y actualiza el CMS Example: worker that receives the webhook and updates the CMS
Flask. Para más detalle sobre la verificación HMAC, ver laFor more on HMAC verification, see the Guía de webhooksWebhooks Guide .
import hmac, hashlib, json
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = "your_webhook_secret"
BASE = "https://mysygnet.com"
@app.route("/sygnet-webhook", methods=["POST"])
def recibir():
body = request.get_data()
firma = request.headers.get("X-Sygnet-Signature", "")
esp = "sha256=" + hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
if not hmac.compare_digest(esp, firma):
abort(401)
evento = json.loads(body)
hash_ = evento["hash"]
# Widget URL is deterministic — no extra API call needed
widget_url = f"{BASE}/pages/widget.html?hash={hash_}"
overlay_url = f"{BASE}/pages/overlay.html?hash={hash_}"
iframe = (
f'<iframe src="{widget_url}" width="300" height="100" '
f'frameborder="0" scrolling="no" '
f'style="border:none;overflow:hidden;border-radius:12px"></iframe>'
)
# Update your CMS / database with the iframe
actualizar_cms(evento["description"], iframe)
return "", 200
def actualizar_cms(titulo, iframe_html):
# Your logic: Ghost API, WordPress API, Webflow CMS, etc.
print(f"Updating '{titulo}' with badge:\n{iframe_html}")
if __name__ == "__main__":
app.run(port=5000)
Cada plataforma tiene sus propias restricciones con los iframes: Each platform has its own iframe restrictions:
YouTube
Las descripciones no admiten HTML. Pega el link para humanos (mysygnet.com/?cert=..., ver sección 4) — no el endpoint /api/certificados/HASH, que devuelve JSON crudo, no una página legible.
Los usuarios hacen clic y ven una página con el nombre del creador y la declaración.
Descriptions don't support HTML. Paste the human-facing link (mysygnet.com/?cert=..., see section 4) — not the /api/certificados/HASH endpoint, which returns raw JSON, not a readable page.
Users click it and see a page with the creator's name and declaration.
GitHub README
GitHub no permite iframes en Markdown. Usa el badge SVG enlazado:
GitHub doesn't allow iframes in Markdown. Use the linked SVG badge:
[](https://mysygnet.com/api/certificados/HASH)
Ghost
Inserta un bloque HTML y pega el snippet <iframe>. Funciona en todos los temas.
Insert an HTML block and paste the <iframe> snippet. Works in all themes.
WordPress
En el editor Gutenberg, añade un bloque "HTML personalizado" y pega el <iframe>. En el editor clásico, cambia a vista HTML y pégalo donde quieras.
In the Gutenberg editor, add a "Custom HTML" block and paste the <iframe>. In the classic editor, switch to HTML view and paste it where you want.
Newsletter / EmailNewsletter / Email
La mayoría de clientes de email bloquean iframes. Usa el badge SVG como <img> enlazado al link para humanos (mysygnet.com/?cert=...), o simplemente esa URL en texto plano.
Most email clients block iframes. Use the SVG badge as an <img> linked to the human-facing page (mysygnet.com/?cert=...), or simply that URL as plain text.
OBS (streaming en vivolive streaming)
Añade un Browser Source con la URL del overlay: https://mysygnet.com/pages/overlay.html?hash=HASH. Tamaño recomendado: 400×72 px. Background transparente activado.
Add a Browser Source with the overlay URL: https://mysygnet.com/pages/overlay.html?hash=HASH. Recommended size: 400×72 px. Enable transparent background.
No. Sygnet nunca ve tu archivo. Solo recibes el hash de 128 caracteres. El hash es matemáticamente unidireccional: no es posible reconstruir el archivo a partir de él. Eso significa que puedes certificar contenido privado o confidencial sin exponerlo. No. Sygnet never sees your file. Only the 128-character hash is sent. The hash is mathematically one-way: it is impossible to reconstruct the file from it. This means you can certify private or confidential content without exposing it.
El endpoint es idempotente. Si ya existe un certificado activo con el mismo hash,
Sygnet devuelve ok: true sin crear un duplicado.
Puedes llamarlo múltiples veces sin riesgo — útil si tu pipeline no lleva registro de qué ya está certificado.
The endpoint is idempotent. If an active certificate with the same hash already exists,
Sygnet returns ok: true without creating a duplicate.
You can call it multiple times safely — useful if your pipeline doesn't track what's already been certified.
Sí. El widget y el overlay hacen un refresco automático cada 60 segundos. Si el estado del certificado cambia (expira, es revocado o disputado), el color y el texto se actualizan solos en el siguiente ciclo. No tienes que cambiar el snippet — la URL es siempre la misma. Yes. The widget and overlay auto-refresh every 60 seconds. If the certificate status changes (expires, is revoked, or disputed), the colour and text update automatically on the next cycle. You don't need to change the snippet — the URL is always the same.
Sí — y ya hay una Action reusable que hace todo esto en un solo paso de YAML: fralopgom/Sygnet/.github/actions/sygnet-certify. Guarda tu API key como secret del repositorio y úsala así:
Yes — there's already a reusable Action that does all of this in a single step of YAML: fralopgom/Sygnet/.github/actions/sygnet-certify. Store your API key as a repository secret and use it like this:
- name: Certify artifact / Certificar artefacto
id: sygnet
uses: fralopgom/Sygnet/.github/actions/sygnet-certify@main
with:
file: dist/app.zip
sia_level: 1
description: 'Release ${{ github.ref_name }}'
api_key: ${{ secrets.SYGNET_API_KEY }}
- name: Share the verification link / Compartir el link de verificación
run: echo "${{ steps.sygnet.outputs.share_url }}"
Documentación completa (inputs, outputs, ejemplo con GitHub Releases) en el README de la Action. Si prefieres no depender de una Action de terceros, el equivalente en curl puro es: Full docs (inputs, outputs, GitHub Releases example) in the Action's README. If you'd rather not depend on a third-party Action, the plain-curl equivalent is:
- name: Certify artifact / Certificar artefacto
run: |
HASH=$(python3 -c "
import hashlib, sys
h = hashlib.sha3_512()
[h.update(c) for c in iter(lambda: open(sys.argv[1],'rb').read(65536), b'')]
print(h.hexdigest())
" dist/app.zip)
curl -s -X POST https://mysygnet.com/api/certificados \
-H "Authorization: Bearer ${{ secrets.SYGNET_API_KEY }}" \
-H "Content-Type: application/json" \
-d "{\"hash\":\"$HASH\",\"algorithm\":\"SHA3-512\",\"sia_level\":1,\"description\":\"Release v${{ github.ref_name }}\"}"
Hashea el contenido como bytes. En Python: Hash the content as bytes. In Python:
import hashlib
text = "This is the content of my article..."
hash_ = hashlib.sha3_512(text.encode('utf-8')).hexdigest()
# → Use this hash exactly as you would with a file
Importante: usa siempre la misma codificación (UTF-8) para que el hash sea reproducible. Un espacio extra o un salto de línea diferente produce un hash distinto. Important: always use the same encoding (UTF-8) so the hash is reproducible. An extra space or a different line ending produces a different hash.