Seal on Chain API
API REST para registro de copyright con validez legal en blockchain NEAR. Genera evidencia inmutable, certificados PDF y archivos CWR para PROs.
https://api.sealonchain.com
🔐 Autenticación
La API utiliza API Keys para autenticar requests de terceros (PROs como SGAE, ASCAP, Unison, etc.).
Los siguientes endpoints NO requieren autenticación: /health, /docs, /api/cwr/supported-pros
Obtener una API Key
Para obtener una API Key, contacta con Spleet proporcionando:
- Nombre de tu organización
- Email de contacto técnico
- Casos de uso previstos
Usar la API Key
Incluye tu API Key en el header X-API-Key de cada request:
cURLcurl -H "X-API-Key: sk_live_tu_api_key_aqui" \
https://api.spleet.ai/api/cwr/{masterHash}
JavaScriptfetch('https://api.spleet.ai/api/cwr/{masterHash}', {
headers: {
'X-API-Key': 'sk_live_tu_api_key_aqui'
}
})
Formato de API Key
| Prefijo | Entorno | Ejemplo |
|---|---|---|
sk_live_ | Producción | sk_live_Abc123xyz... |
sk_test_ | Desarrollo | sk_test_Abc123xyz... |
Scopes (Permisos)
Cada API Key tiene permisos específicos:
| Scope | Descripción | Endpoints |
|---|---|---|
cwr:read | Generar y validar CWR | /api/cwr/* |
verify:read | Verificar hashes | /api/verify/* |
register:write | Registrar copyrights | /api/register |
Rate Limits
Los límites por defecto son:
| Límite | Valor |
|---|---|
| Por minuto | 60 requests |
| Por día | 10,000 requests |
Las respuestas incluyen headers X-RateLimit-Limit-Minute y X-RateLimit-Limit-Day con tus límites.
Errores de Autenticación
| Código | Error | Descripción |
|---|---|---|
| 401 | API key requerida | No se incluyó el header X-API-Key |
| 401 | API key inválida | La key no existe o está desactivada |
| 403 | Permisos insuficientes | La key no tiene el scope necesario |
| 429 | Rate limit excedido | Demasiadas requests, espera antes de reintentar |
Ejemplo de error 401:
JSON{
"success": false,
"error": "API key requerida",
"hint": "Incluye el header X-API-Key con tu API key",
"docs": "/docs#authentication"
}
Health Check
Verifica el estado del servicio, configuración de NEAR y conexión a base de datos.
Response 200
JSON{
"status": "ok",
"service": "seal-on-chain",
"version": "1.1.0",
"near": {
"networkId": "testnet",
"contractName": "seal-on-chain.testnet"
},
"database": {
"configured": true,
"connected": true
}
}
Register Copyright
Además del anclaje en NEAR blockchain, la evidencia JSON completa se almacena permanentemente en Arweave, garantizando que los datos del registro sean inmutables y accesibles para siempre a través de su URI único.
Registra un copyright en blockchain NEAR. Genera evidencia JSON, calcula hash maestro, ancla en blockchain, almacena en Arweave y genera certificado PDF.
Request Body
JSON{
"audioHash": "a1b2c3d4...64chars",
"signedPdfHash": "b2c3d4e5...64chars",
"authors": [
{
"party_id": "uuid",
"name": "Juan Pérez",
"roles": ["COMPOSER", "PRODUCER"],
"split_percentage": 50,
"ipi_number": "1234567890",
"pro_name": "SGAE"
}
],
"metadata": {
"external_work_id": "work_001",
"work_title": "Mi Canción",
"isrc": "ESXXX2400001"
}
}
Response 201
JSON{
"success": true,
"data": {
"evidence_id": "evid_1705312200000_550e8400",
"master_hash": "c3d4e5f6...64chars",
"near_transaction_hash": "ABC123...",
"certificate_url": "https://...",
"arweave_uri": "arweave://bafyexample"
}
}
Status Codes
| 201 | Registro creado exitosamente |
| 400 | Datos de entrada inválidos |
| 409 | Hash ya registrado |
| 500 | Error interno |
Verify Hash
Verifica si un hash está registrado en blockchain NEAR y retorna información del registro.
Path Parameters
| Parámetro | Tipo | Descripción |
|---|---|---|
hash | string | Hash SHA-256 (64 caracteres hexadecimales) |
Response 200
JSON{
"success": true,
"data": {
"master_hash": "c3d4e5f6...",
"exists": true,
"registered_at": "2024-01-15T10:30:00Z",
"near_transaction_hash": "ABC123...",
"authors": [...],
"certificate_url": "https://..."
}
}
Regenerate Certificate
Regenera el certificado PDF para un registro existente. Útil cuando se necesita actualizar el certificado con nueva información o formato.
Request Body
JSON{
"masterHash": "c3d4e5f6789012345678901234567890abcdef1234567890abcdef1234567890"
}
Response 200
JSON{
"success": true,
"data": {
"certificate_url": "https://storage.supabase.co/.../certificate.pdf",
"certificate_hash": "d4e5f6789012345678901234567890abcdef...",
"regenerated_at": "2024-01-15T10:30:00.000Z"
}
}
Status Codes
| 200 | Certificado regenerado exitosamente |
| 400 | Hash inválido |
| 404 | Registro no encontrado |
| 500 | Error interno |
🎵 Audio Fingerprinting
El fingerprinting acústico permite detectar si un archivo de audio ya ha sido registrado, incluso si ha sido recodificado o ligeramente modificado. Usa tecnología Chromaprint/AcoustID para generar una "huella digital" única del audio.
Verifica si el servicio de fingerprinting está disponible (requiere fpcalc instalado en el servidor).
Este endpoint NO requiere autenticación.
Response 200
JSON{
"success": true,
"data": {
"available": true,
"fpcalc_installed": true,
"version": "1.5.1"
}
}
Check Duplicate
Verifica si un archivo de audio ya existe en la base de datos antes de iniciar el proceso de registro. Usa tanto hash SHA-256 como fingerprint acústico para detectar duplicados.
Request Body
JSON{
"audioFile": "base64_encoded_audio_file...",
"audioHash": "abc123...64chars", // Opcional si se envía audioFile
"audioMimeType": "audio/wav", // Opcional, default: audio/wav
"excludeWorkId": "uuid" // Opcional, para excluir una obra de la búsqueda
}
Response 200 (No duplicado)
JSON{
"success": true,
"data": {
"isDuplicate": false,
"audioHash": "abc123...64chars",
"fingerprintAvailable": true,
"message": "No se encontraron duplicados"
}
}
Response 200 (Duplicado encontrado)
JSON{
"success": true,
"data": {
"isDuplicate": true,
"audioHash": "abc123...64chars",
"matchType": "exact_hash", // o "fingerprint"
"existingRegistration": {
"masterHash": "existing_master_hash...",
"workTitle": "Mi Canción Original",
"registeredAt": "2024-01-15T10:30:00Z",
"certificateUrl": "https://..."
}
}
}
Tipos de Match
| Tipo | Descripción |
|---|---|
exact_hash | El archivo es idéntico (mismo SHA-256) |
fingerprint | Audio similar detectado por fingerprint acústico |
Find Similar
Busca obras con audio similar al proporcionado usando fingerprint acústico. Retorna una lista de posibles coincidencias ordenadas por similitud.
Request Body
JSON{
"audioFile": "base64_encoded_audio_file...",
"audioMimeType": "audio/wav",
"threshold": 0.8, // Opcional, 0-1, default: 0.8
"limit": 10 // Opcional, máximo resultados
}
Response 200
JSON{
"success": true,
"data": {
"query": {
"fingerprint": "AQAEHZG...",
"duration": 180
},
"matches": [
{
"masterHash": "abc123...",
"workTitle": "Canción Similar",
"similarity": 0.95,
"registeredAt": "2024-01-15T10:30:00Z",
"authors": ["Juan Pérez"]
}
],
"totalMatches": 1
}
}
El fingerprinting requiere que fpcalc esté instalado en el servidor. Verifica el estado con GET /api/fingerprint/status.
🎵 Generate CWR
CWR (Common Works Registration) es el estándar de la industria musical para comunicar obras entre editores y PROs como SGAE, ASCAP, BMI, etc.
Genera un archivo CWR 2.1 a partir del master hash de un registro. Compatible con SGAE, ASCAP, BMI y otras PROs.
Path Parameters
| Parámetro | Tipo | Descripción |
|---|---|---|
masterHash | string | Hash SHA-256 del registro |
Query Parameters
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
receiverId | string | - | Código PRO: SGAE, ASCAP, BMI... |
format | string | file | file (descarga) o json |
validate | string | true | Incluir warnings de validación |
Ejemplo
cURLcurl -O "https://api.sealonchain.com/api/cwr/32a981bee1d6b...?receiverId=SGAE"
Response (format=json)
JSON{
"success": true,
"data": {
"filename": "CW20241115_MI_CANCION_550E84.V21",
"stats": {
"totalRecords": 14,
"totalWriters": 2
},
"cwr_content": "HDRSPLEET...",
"receiver": {
"id": "SGAE",
"name": "Sociedad General de Autores y Editores"
}
}
}
Tipos de Registro CWR
Validate for CWR
Valida si un registro tiene los datos necesarios para generar un CWR, sin generarlo.
Response 200
JSON{
"success": true,
"data": {
"can_generate_cwr": true,
"validation": {
"errors": [],
"warnings": [
"Autor \"Juan Pérez\" no tiene IPI Number - requerido para registro en PROs",
"Autor \"Juan Pérez\" no tiene PRO asignada (SGAE, ASCAP, etc.)"
]
},
"work_info": {
"title": "Mi Canción",
"authors_count": 2,
"has_isrc": true
}
}
}
Validate CWR File
Valida un archivo CWR 2.1 subido directamente. Útil para verificar archivos CWR generados externamente antes de enviarlos a una PRO.
Request Body
JSON{
"cwrContent": "HDRSPLEET Spleet Technologies SL...",
"filename": "CW20241115_MI_CANCION.V21" // Opcional
}
Response 200
JSON{
"success": true,
"data": {
"valid": true,
"cwr_version": "2.1",
"stats": {
"totalRecords": 14,
"totalTransactions": 1,
"totalWriters": 2
},
"validation": {
"errors": [],
"warnings": [
"Línea 5: IPI Number '123456' tiene longitud incorrecta (esperado 9-11 dígitos)"
]
},
"sender": {
"id": "SPLEET",
"name": "Spleet Technologies SL"
},
"receiver": {
"id": "SGAE"
}
}
}
Status Codes
| 200 | Archivo validado (puede tener warnings) |
| 400 | Contenido CWR inválido o vacío |
| 422 | Archivo CWR con errores críticos |
Supported PROs
Lista todas las PROs (Performing Rights Organizations) soportadas.
PROs Disponibles
📤 CWR Batch / SFTP
¿Cansado de registrar obras una a una en SGAE, Unison o tu PRO?
Con Spleet, cada vez que se firma un contrato, la obra se puede registrar automáticamente
en tu PRO mediante archivos CWR. Solo configura tu servidor SFTP una vez y Spleet enviará
los registros semanalmente o bajo demanda.
Cada editorial configura su propio destino (SGAE, ASCAP, BMI, etc.)
de forma independiente.
Genera archivos CWR 2.1 para las obras pendientes de un team y los envía automáticamente al servidor SFTP de su PRO (SGAE, ASCAP, BMI, etc.). Procesa todos los registros que aún no han sido enviados.
Headers
| Header | Valor | Descripción |
|---|---|---|
Content-Type | application/json | Tipo de contenido |
X-API-Key | string | API Key de autenticación |
Request Body
JSON{
"teamId": "uuid-del-team",
"receiverId": "SGAE",
"sftpConfig": {
"host": "sftp.empresa.com",
"port": 22,
"username": "spleet_cwr",
"password": "secreto",
"remotePath": "/incoming/cwr"
},
"batchSize": 100,
"fromDate": "2025-01-01T00:00:00Z"
}
Response 200
JSON{
"success": true,
"data": {
"batchId": "batch_uuid",
"status": "success",
"totalProcessed": 15,
"successfulUploads": 14,
"failedUploads": 0,
"skippedRecords": 1,
"details": [
{
"masterHash": "abc123...",
"filename": "CW20251127_CANCION_550E84.V21",
"status": "success"
}
],
"startedAt": "2025-11-27T03:00:00Z",
"completedAt": "2025-11-27T03:05:00Z"
}
}
Test SFTP Connection
Prueba la conexión SFTP con las credenciales proporcionadas. Útil para validar la configuración antes de guardarla.
Request Body
JSON{
"host": "sftp.empresa.com",
"port": 22,
"username": "spleet_cwr",
"password": "secreto",
"remotePath": "/incoming/cwr"
}
Response 200 (Éxito)
JSON{
"success": true,
"message": "Conexión SFTP exitosa",
"details": {
"connected": true,
"canWrite": true,
"remotePath": "/incoming/cwr"
}
}
Response 500 (Error)
JSON{
"success": false,
"error": "ECONNREFUSED: Connection refused"
}
Batch Status
Obtiene el estado de un batch de CWR específico, incluyendo detalles de cada archivo procesado.
Path Parameters
| Parámetro | Tipo | Descripción |
|---|---|---|
batchId | string | UUID del batch |
Response 200
JSON{
"success": true,
"data": {
"id": "batch_uuid",
"teamId": "team_uuid",
"status": "success",
"totalRecords": 15,
"successfulUploads": 14,
"failedUploads": 0,
"skippedRecords": 1,
"receiverId": "SGAE",
"startedAt": "2025-11-27T03:00:00Z",
"completedAt": "2025-11-27T03:05:00Z",
"triggeredBy": "cron",
"details": [
{
"masterHash": "abc123...",
"filename": "CW20251127_CANCION_550E84.V21",
"status": "success"
},
{
"masterHash": "def456...",
"status": "skipped",
"error": "No tiene autores válidos"
}
]
}
}
Batch History
Obtiene el historial de batches de CWR enviados por un team, ordenados por fecha descendente.
Path Parameters
| Parámetro | Tipo | Descripción |
|---|---|---|
teamId | string | UUID del team |
Query Parameters
| Parámetro | Tipo | Default | Descripción |
|---|---|---|---|
limit | number | 10 | Número máximo de batches |
offset | number | 0 | Offset para paginación |
Response 200
JSON{
"success": true,
"data": {
"batches": [
{
"id": "batch_uuid_1",
"status": "success",
"totalRecords": 15,
"successfulUploads": 15,
"failedUploads": 0,
"receiverId": "SGAE",
"startedAt": "2025-11-27T03:00:00Z",
"triggeredBy": "cron"
},
{
"id": "batch_uuid_2",
"status": "partial",
"totalRecords": 10,
"successfulUploads": 8,
"failedUploads": 2,
"receiverId": "SGAE",
"startedAt": "2025-11-20T03:00:00Z",
"triggeredBy": "manual"
}
],
"total": 25,
"limit": 10,
"offset": 0
}
}
Para más información sobre la configuración multi-tenant de CWR/SFTP, consulta:
Códigos de Error
Códigos HTTP
| Código | Descripción |
|---|---|
| 200 | Solicitud exitosa |
| 201 | Recurso creado |
| 400 | Datos de entrada inválidos |
| 404 | Recurso no encontrado |
| 409 | Conflicto (hash ya registrado) |
| 422 | Datos insuficientes |
| 500 | Error interno del servidor |
Tipos de Error
| Tipo | Descripción |
|---|---|
validation_error | Datos de entrada inválidos |
blockchain_error | Error con NEAR blockchain |
database_error | Error de base de datos |
cwr_error | Error generando CWR |
Validaciones
Hash SHA-256
- Exactamente 64 caracteres
- Solo caracteres hexadecimales (0-9, a-f)
Autores
| Campo | Requerido | Descripción |
|---|---|---|
party_id | ✅ | UUID del autor |
name | ✅ | Nombre completo |
roles | ✅ | Array de roles |
split_percentage | ✅ | 0-100 (suma = 100%) |
ipi_number | ⚠️ | Recomendado para CWR |
pro_name | ⚠️ | Código PRO |
Para que el CWR sea aceptado por SGAE/ASCAP, cada autor debe tener IPI Number válido (9-11 dígitos).
Roles Válidos
Códigos CWR según CISAC CWR 2.1:
| Rol Spleet | Código CWR | Descripción |
|---|---|---|
COMPOSER | C | Compositor |
LYRICIST | A | Letrista |
ARRANGER | AR | Arreglista |
ADAPTER | AD | Adaptador |
TRANSLATOR | TR | Traductor |
SUB_ARRANGER | SR | Sub-Arreglista |
SUB_AUTHOR | SA | Sub-Autor |
PRODUCER | C | Productor |
MIXING_ENGINEER | C | Ingeniero de Mezcla |
MASTERING_ENGINEER | C | Ingeniero de Masterización |
PERFORMER | - | Intérprete |