Documentación de la API
Toda la documentación está generada directamente a partir de las definiciones que ejecuta el motor de procesamiento.
Especificación OpenAPI para integración automática: /api/v1/openapi.json
Autenticación
Envía tu clave de API en cualquiera de las dos cabeceras aceptadas. Ambas son equivalentes.
Authorization: Bearer nmd_live_xxxxxxxxxxxxxxxx X-API-Key: nmd_live_xxxxxxxxxxxxxxxx
Las claves se generan en tu panel de control. Cada clave se muestra una sola vez y se almacena únicamente en formato hash.
POST /api/v1/analyze
Lee cada campo de metadatos en el archivo y devuelve el modelo normalizado.
curl -X POST https://your-domain/api/v1/analyze \ -H "Authorization: Bearer $NMD_KEY" \ -F "file=@photo.jpg"
La respuesta agrupa los campos por categoría y conserva los valores originales sin traducir bajo raw:
{
"file": { "name": "photo.jpg", "format": "jpeg", "size": 4821904 },
"counts": { "total": 31, "removable": 26, "sensitive": 16 },
"blocks": { "exif": { "present": true, "count": 29 }, "gps": { "present": true } },
"metadata": {
"camera": {
"camera.make": { "label": "Make", "value": "Apple", "sensitive": true, "removable": true }
}
}
}POST /api/v1/clean
Elimina metadatos y reexamina los bytes generados para verificar el resultado. Devuelve el archivo limpio o el informe en JSON con <code>response=json</code>.
| Parámetro | Valores | Por defecto |
|---|---|---|
| mode | quick, full | quick |
| keepCopyright | 0, 1 | 0 |
| keepColorProfile | 0, 1 | quick: 1, full: 0 |
| keepOrientation | 0, 1 | quick: 1, full: 0 |
| removeC2pa | 0, 1 | 0 |
| response | file, json | file |
curl -X POST https://your-domain/api/v1/clean \ -H "Authorization: Bearer $NMD_KEY" \ -F "file=@video.mp4" -F "mode=full" -OJ
removeC2pa está desactivado por defecto. La limpieza normal de metadatos nunca suprime las credenciales C2PA salvo petición explícita.
Al descargar el archivo, en la cabecera X-NoMoreData-Result viaja codificado en URL un resumen del informe de verificación: los valores escalares literales — verified es true solo cuando el reanálisis no encontró restos inesperados — y cada lista como un recuento, removedCount, residualCount, etc. Siempre se decodifica y se analiza. Para las listas, pide response=json.
POST /api/v1/edit
Aplica modificaciones a campos concretos. Enviar <code>value: null</code> elimina el campo seleccionado.
| Parámetro | Valores | Por defecto |
|---|---|---|
| edits | JSON array of {key, value} | required |
| replaceAll | 0, 1 | 0 |
| removeC2pa | 0, 1 | 0 |
| response | file, json | file |
replaceAll suprime los bloques de metadatos existentes pero no afecta a Content Credentials C2PA a menos que se especifique.
curl -X POST https://your-domain/api/v1/edit \
-H "Authorization: Bearer $NMD_KEY" \
-F "file=@photo.jpg" \
-F 'edits=[{"key":"camera.make","value":"Canon"},{"key":"location.latitude","value":null}]' \
-F "response=json"POST /api/v1/apply-profile
Aplica un conjunto coherente de campos característicos de un modelo de dispositivo.
curl -X POST https://your-domain/api/v1/apply-profile \ -H "Authorization: Bearer $NMD_KEY" \ -F "file=@photo.jpg" -F "profile=canon-eos-r5" -F "iso=400"
La aplicación de un perfil escribe metadatos típicos de un dispositivo pero no constituye prueba legal de que el archivo fue capturado por dicho equipo.
Ejemplos en otros lenguajes
JavaScript
const body = new FormData();
body.append('file', file); // a File or Blob
body.append('mode', 'full');
body.append('response', 'json');
const res = await fetch('https://your-domain/api/v1/clean', {
method: 'POST',
headers: { Authorization: `Bearer ${process.env.NMD_KEY}` },
body,
});
const report = await res.json();
console.log(report.verified, report.removed.length);Python
import os, requests
with open("photo.jpg", "rb") as fh:
response = requests.post(
"https://your-domain/api/v1/clean",
headers={"Authorization": f"Bearer {os.environ['NMD_KEY']}"},
files={"file": fh},
data={"mode": "full", "response": "json"},
)
report = response.json()
print(report["verified"], len(report["removed"]))Gestión de errores
Todos los errores comparten una estructura estándar y predecible.
{ "error": { "code": "unsupported_format", "message": "GIF is not supported.", "hint": "..." } }| Código | Estado HTTP | Significado |
|---|---|---|
| missing_api_key | 401 | No se facilitó ninguna clave de API. |
| invalid_api_key | 401 | La clave es desconocida, ha sido revocada o es inválida. |
| plan_required | 403 | Tu plan actual no incluye acceso a la API. |
| missing_file | 400 | No se adjuntó ningún archivo en la petición multipart. |
| invalid_request | 400 | Parámetro ausente o con formato incorrecto. |
| file_too_large | 413 | El archivo supera el tamaño máximo permitido por tu plan. |
| unsupported_format | 415 | El formato de archivo no es compatible. |
| corrupt_file | 422 | No se pudo procesar el archivo: datos corruptos o ilegibles. |
| unsupported_operation | 422 | Archivo válido, pero la operación no está disponible para este formato. |
| rate_limited | 429 | Demasiadas peticiones en un corto periodo de tiempo. |
| quota_exceeded | 429 | Has agotado la cuota mensual de llamadas de tu plan. |
Límites de velocidad y cuotas
Se aplican dos controles: un límite por IP para proteger el servicio y la cuota mensual contratada en tu suscripción.
X-RateLimit-Limit: 2000 X-RateLimit-Remaining: 1834 X-RateLimit-Reset: 1767225600
Superar la cuota devuelve HTTP 429 con código quota_exceeded y cabecera Retry-After.
Formatos compatibles
| Formato | Analizar | Limpiar | Editar |
|---|---|---|---|
| JPEG | sí | sí | sí |
| PNG | sí | sí | sí |
| WebP | sí | sí | sí |
| HEIC/HEIF | sí | sí | sí |
| AVIF | sí | sí | sí |
| MP4 | sí | sí | sí |
| QuickTime MOV | sí | sí | sí |
| WebM | sí | sí | no |
| sí | sí | sí | |
| MP3 | sí | sí | sí |
| WAV | sí | sí | sí |
| M4A | sí | sí | sí |
Solicitar una acción no admitida devuelve 422 unsupported_operation.
Campos editables (28)
Claves aceptadas por /api/v1/edit.
| Clave | Campo |
|---|---|
| camera.make | Make |
| camera.model | Model |
| camera.lensMake | Lens make |
| camera.lensModel | Lens model |
| camera.serialNumber | Body serial number |
| camera.lensSerialNumber | Lens serial number |
| capture.iso | ISO |
| capture.exposureTime | Exposure time |
| capture.fNumber | Aperture (f-number) |
| capture.focalLength | Focal length |
| capture.focalLength35mm | Focal length (35 mm equiv.) |
| capture.exposureBias | Exposure compensation |
| capture.exposureProgram | Exposure program |
| capture.meteringMode | Metering mode |
| capture.whiteBalance | White balance |
| capture.flash | Flash |
| capture.colorSpace | Colour space |
| capture.orientation | Orientation |
| date.original | Date taken |
| date.digitized | Date digitised |
| date.modified | File change date |
| general.software | Software |
| general.artist | Artist |
| general.copyright | Copyright |
| general.description | Image description |
| location.latitude | Latitude |
| location.longitude | Longitude |
| location.altitude | Altitude |
Tratamiento de archivos en la API
Los archivos enviados a la API se procesan únicamente en memoria volátil durante la solicitud y se descartan inmediatamente tras devolver la respuesta.
Para máxima confidencialidad, el procesamiento directo en el navegador web sigue siendo la vía recomendada.