Saltar al contenido

Desarrolladores

Referencia de la API

La API REST de mapps.one te permite crear y actualizar apps, gestionar enlaces de tienda, importar metadatos de tienda, leer estadísticas, generar códigos QR y suscribirte a webhooks desde tu propio código, tu pipeline de CI o tu integración. La API está disponible en el plan Studio.

URL base

https://mapps.one/api/v1

Todas las solicitudes usan HTTPS. Envía los cuerpos de las solicitudes como JSON con Content-Type: application/json, y envía siempre Accept: application/json para que los errores también se devuelvan como JSON.

Autenticación

Crea un token en el panel, en Desarrolladores. Pueden hacerlo los propietarios y administradores del espacio de trabajo. Dale al token un nombre, como "GitHub Actions", y elige sus permisos. El token solo se muestra una vez, así que guárdalo de inmediato en tu gestor de secretos.

Los tokens pertenecen al espacio de trabajo, no a una persona, así que siguen funcionando cuando alguien deja el equipo. No caducan. Revoca un token desde la misma página cuando ya no lo necesites, o si puede haberse filtrado.

Envía el token como token Bearer:

curl https://mapps.one/api/v1/workspace \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json"

Permisos

PermisoPermite
apps:readListar y leer apps, descargar códigos QR
apps:writeCrear, actualizar y eliminar apps, reemplazar enlaces de tienda, importar metadatos de tienda
analytics:readLeer las estadísticas de las apps
webhooks:manageListar, crear y eliminar suscripciones de webhook

GET /workspace y GET /events funcionan con cualquier token válido. Da a cada integración solo los permisos que necesita.

Convenciones

  • Los ID son ULID de 26 caracteres en minúsculas, como 01j8b2k6r3xq9v7m4n5p0s1t2w. Las apps se identifican por id, no por slug, así que cambiar un slug nunca rompe tu integración.
  • Las marcas de tiempo usan el formato ISO 8601 en UTC, como 2026-09-14T08:12:44+00:00.
  • Las respuestas envuelven el resultado en una clave data.
  • Las claves de tienda son app_store, google_play, app_gallery, microsoft_store y web.
  • Las claves de plataforma son ios, android, huawei, windows, macos y other. Las claves de destino son las claves de tienda más landing.

Límites de solicitudes

Cada espacio de trabajo puede hacer 120 solicitudes por minuto, compartidas entre todos sus tokens. Cada respuesta incluye los encabezados X-RateLimit-Limit y X-RateLimit-Remaining. Cuando superas el límite, la API responde con 429 Too Many Requests y un encabezado Retry-After con el número de segundos que debes esperar.

Errores

Los errores devuelven un cuerpo JSON con un message legible para personas. Algunos errores también incluyen un code legible por máquinas, y los errores de validación enumeran los problemas de cada campo en errors.

EstadoCuándo
401Falta el token, no es válido o fue revocado. {"message": "Unauthenticated."}
402El plan del espacio de trabajo no incluye acceso a la API. Código plan_required.
403El token no tiene el permiso que necesita este endpoint. {"message": "Invalid ability provided."}
404La app o la suscripción no existe, o pertenece a otro espacio de trabajo.
422La validación falló, o no se pudo completar la solicitud. Por ejemplo, código metadata_unavailable.
429Se superó el límite de solicitudes. Espera el número de segundos indicado en Retry-After.
5xxAlgo falló de nuestro lado. Reintenta con un tiempo de espera exponencial.
HTTP/2 402
{
  "message": "API access requires the Studio plan.",
  "code": "plan_required"
}
HTTP/2 422
{
  "message": "This link is already taken.",
  "errors": {
    "slug": ["This link is already taken."]
  }
}

Endpoints

Método y rutaPermisoDescripción
GET /workspacecualquieraEspacio de trabajo, plan, uso y el token actual
GET /eventscualquieraTipos de eventos de webhook
GET /appsapps:readListar apps
POST /appsapps:writeCrear una app
GET /apps/{id}apps:readObtener una app
PATCH /apps/{id}apps:writeActualizar una app
DELETE /apps/{id}apps:writeEliminar una app
PUT /apps/{id}/linksapps:writeConfigurar o quitar enlaces de tienda
POST /apps/{id}/metadataapps:writeImportar los datos de la ficha de la tienda
GET /apps/{id}/analyticsanalytics:readTotales, series diarias y desgloses
GET /apps/{id}/qrapps:readImagen del código QR
GET /webhookswebhooks:manageListar suscripciones de webhook
POST /webhookswebhooks:manageCrear una suscripción de webhook
DELETE /webhooks/{id}webhooks:manageEliminar una suscripción de webhook

El objeto app

CampoTipoDescripción
idstringULID de la app
namestringNombre de la app
slugstringLa ruta del enlace inteligente: mapps.one/{slug}
statusstringlive, paused o suspended
tagline, descriptionstring o nullTexto de la página
categorystring o nullUna clave de categoría, como health-fitness o productivity
page_themestringclean, midnight o vivid
accent_colorstring o nullColor hexadecimal, como #16a34a
developerobjectname, website y email
social_linksobjectPerfiles sociales completados, con la red como clave: x, instagram, tiktok, youtube, facebook, linkedin, threads, github, discord, reddit
featuresarrayElementos de la lista de funciones con icon, title y description
listed_in_explorebooleanSi la app aparece en Explorar
utm_passthroughbooleanSi las etiquetas UTM se reenvían a las tiendas
redirect_rulesobjectDestino por plataforma, con los valores predeterminados completados
icon_urlstring o nullURL pública del ícono
ratingobject o nullvalue y count de la tienda
urlsobjectURL públicas: smart_link, landing_page, qr_svg, qr_png, privacy_policy, terms. Las URL legales devuelven 404 hasta que se publica el documento.
linksobjectEnlaces de tienda con la tienda como clave, cada uno con url, status (unverified, verified o invalid) y verified_at. Se incluye en las respuestas de una sola app.
screenshotsarrayCapturas de pantalla con url, width y height. Se incluye después de una importación de metadatos.
created_at, updated_atstringMarcas de tiempo ISO 8601

Obtener una app

curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json"
{
  "data": {
    "id": "01j8b2k6r3xq9v7m4n5p0s1t2w",
    "name": "Habitly",
    "slug": "habitly",
    "status": "live",
    "tagline": "Build habits that stick",
    "description": "Habitly helps you build small daily habits with gentle reminders and streaks.",
    "category": "health-fitness",
    "page_theme": "clean",
    "accent_color": "#16a34a",
    "developer": {
      "name": "Habitly Labs",
      "website": "https://habitly.app",
      "email": "hello@habitly.app"
    },
    "social_links": {
      "instagram": "https://instagram.com/habitly.app"
    },
    "features": [
      { "icon": "bell", "title": "Gentle reminders", "description": "Nudges at the time you choose." }
    ],
    "listed_in_explore": true,
    "utm_passthrough": true,
    "redirect_rules": {
      "ios": "app_store",
      "android": "google_play",
      "huawei": "app_gallery",
      "windows": "microsoft_store",
      "macos": "landing",
      "other": "landing"
    },
    "icon_url": "https://mapps.one/storage/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/icon/icon.png",
    "rating": { "value": 4.8, "count": 12450 },
    "urls": {
      "smart_link": "https://mapps.one/habitly",
      "landing_page": "https://mapps.one/habitly/page",
      "qr_svg": "https://mapps.one/habitly/qr.svg",
      "qr_png": "https://mapps.one/habitly/qr.png",
      "privacy_policy": "https://mapps.one/habitly/privacy",
      "terms": "https://mapps.one/habitly/terms"
    },
    "links": {
      "app_store": {
        "url": "https://apps.apple.com/app/id1612345678",
        "status": "verified",
        "verified_at": "2026-09-14T08:12:44+00:00"
      },
      "google_play": {
        "url": "https://play.google.com/store/apps/details?id=com.habitly.app",
        "status": "verified",
        "verified_at": "2026-09-14T08:12:46+00:00"
      }
    },
    "created_at": "2026-09-01T11:20:03+00:00",
    "updated_at": "2026-09-14T08:12:46+00:00"
  }
}

Listar apps

Devuelve las apps del espacio de trabajo. Los resultados están paginados: sigue links.next, o pasa ?page=2, hasta que sea null.

curl "https://mapps.one/api/v1/apps?page=1" \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json"
{
  "data": [
    { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "name": "Habitly", "slug": "habitly", "status": "live" },
    { "id": "01j8d5r2w9y6a3c0e7g4j1m8p5", "name": "Habitly Focus", "slug": "habitly-focus", "status": "paused" }
  ],
  "links": {
    "first": "https://mapps.one/api/v1/apps?page=1",
    "last": "https://mapps.one/api/v1/apps?page=1",
    "prev": null,
    "next": null
  },
  "meta": {
    "current_page": 1,
    "last_page": 1,
    "per_page": 25,
    "total": 2
  }
}

Los objetos app están abreviados en este ejemplo. Cada elemento tiene el conjunto completo de campos.

Crear una app

CampoObligatorioDescripción
nameSíNombre de la app, de hasta 120 caracteres
slugNoDe 3 a 40 letras minúsculas, números y guiones simples. Si se omite, se genera un slug libre a partir del nombre.
linksNoEnlaces de tienda con la tienda como clave, en el mismo formato que en Configurar enlaces de tienda

También puedes enviar cualquiera de los campos que se indican en Actualizar una app.

curl https://mapps.one/api/v1/apps \
  -X POST \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Habitly",
    "slug": "habitly",
    "links": {
      "app_store": "https://apps.apple.com/us/app/habitly/id1612345678",
      "google_play": "https://play.google.com/store/apps/details?id=com.habitly.app"
    }
  }'

La respuesta es 201 Created con el nuevo objeto app. Los enlaces de tienda se guardan en forma canónica con el estado unverified hasta que termina la comprobación en segundo plano. Para completar el ícono, las capturas de pantalla y la descripción, llama a continuación a Importar metadatos de tienda.

Actualizar una app

Envía solo los campos que quieras cambiar.

CampoTipo
namestring
slugstring. Cambiarlo rompe el enlace anterior de inmediato.
tagline, descriptionstring o null
categoryclave de categoría o null
page_themeclean, midnight o vivid
accent_color#rrggbb o null
utm_passthrough, listed_in_exploreboolean
redirect_rulesobjeto que asigna a cada clave de plataforma una clave de destino
curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
  -X PATCH \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "tagline": "Tiny habits, big changes",
    "redirect_rules": { "macos": "landing" }
  }'

La respuesta es el objeto app actualizado.

Eliminar una app

curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
  -X DELETE \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json"

La respuesta es 204 No Content. La eliminación es permanente: se eliminan el enlace inteligente, la página de destino, los documentos legales, los archivos multimedia y las estadísticas de la app.

PUT /apps/{id}/links recibe un objeto links con la tienda como clave:

  • una URL añade o reemplaza el enlace de esa tienda,
  • null o una cadena vacía lo elimina,
  • las tiendas que no incluyas no se modifican.

Cada URL debe ser una ficha válida de su tienda: un enlace de apps.apple.com con un ID de app, un enlace de play.google.com con un ID de paquete, etc. El enlace web puede ser cualquier dirección http o https. Las URL pueden tener hasta 1024 caracteres. Los enlaces se guardan en forma canónica y se comprueban en segundo plano.

curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/links \
  -X PUT \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "links": {
      "app_gallery": "https://appgallery.huawei.com/app/C109876543",
      "web": null
    }
  }'

La respuesta es el objeto app, incluido links. Un enlace no válido devuelve 422:

{
  "message": "This is not a valid Google Play link.",
  "errors": {
    "links.google_play": ["This is not a valid Google Play link."]
  }
}

Importar metadatos de tienda

POST /apps/{id}/metadata lee la ficha del App Store, o la ficha de Google Play cuando no hay un enlace del App Store legible, e importa sus datos.

CampoDescripción
overwriteOpcional, false de forma predeterminada. Si es false, solo se completan los campos vacíos, y las capturas de pantalla solo se añaden si la app no tiene ninguna. Si es true, se reemplazan el nombre, el ícono, los textos y las capturas de pantalla. La valoración y el precio siempre se actualizan.
curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/metadata \
  -X POST \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{ "overwrite": true }'

La respuesta es el objeto app, incluidos links y screenshots, y se envía un webhook app.metadata_fetched. Si no se puede leer ninguna ficha:

HTTP/2 422
{
  "message": "The store listing could not be read. Add a valid App Store or Google Play link first.",
  "code": "metadata_unavailable"
}

Estadísticas

GET /apps/{id}/analytics acepta estos parámetros de consulta:

ParámetroDescripción
range7d, 30d, 90d, 12m o custom. Predeterminado: 30d.
from, toFechas en formato YYYY-MM-DD, ambas incluidas, para range=custom. to no puede ser posterior a hoy.
timezoneUna zona horaria IANA, como Europe/Istanbul, que se usa para los límites de los días. Predeterminado: UTC.
curl "https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/analytics?range=7d&timezone=Europe/Istanbul" \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json"
{
  "data": {
    "app": { "id": "01j8b2k6r3xq9v7m4n5p0s1t2w", "slug": "habitly" },
    "range": {
      "key": "7d",
      "from": "2026-09-07T21:00:00+00:00",
      "to": "2026-09-14T21:00:00+00:00",
      "timezone": "Europe/Istanbul",
      "clamped_to_plan": false
    },
    "summary": {
      "clicks": 1284,
      "visitors": 902,
      "page_views": 356,
      "store_clicks": 141
    },
    "daily": {
      "2026-09-08": 152,
      "2026-09-09": 171,
      "2026-09-10": 168,
      "2026-09-11": 205,
      "2026-09-12": 214,
      "2026-09-13": 190,
      "2026-09-14": 184
    },
    "breakdowns": {
      "os": { "iOS": 702, "Android": 431, "Windows": 88, "macOS": 63 },
      "country": { "TR": 512, "US": 298, "": 236, "DE": 141, "GB": 97 },
      "source": { "instagram": 488, "direct": 402, "qr": 190, "google": 121, "x": 83 },
      "destination": { "app_store": 640, "google_play": 399, "landing": 214, "deep_link": 31 },
      "utm_campaign": { "": 796, "launch": 402, "newsletter-sep": 86 }
    }
  }
}
  • from está incluido y to está excluido. Ambos son instantes en UTC.
  • clamped_to_plan es true cuando el rango solicitado se acortó al historial del plan.
  • daily cuenta los clics por fecha local, incluidos los días sin clics.
  • Los desgloses muestran hasta 10 valores, del más frecuente al menos frecuente. Una clave vacía "" significa desconocido o sin definir.
  • Las definiciones de las métricas están en la página Estadísticas.

Código QR

GET /apps/{id}/qr devuelve una imagen. Usa format=svg (predeterminado) o format=png, además de las mismas opciones que las URL públicas del QR: fg, bg, margin, ecc, size, logo y download. Consulta Códigos QR y kit de prensa.

curl "https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/qr?format=png&size=2048&ecc=Q" \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -o habitly-qr.png

Espacio de trabajo

GET /workspace devuelve el espacio de trabajo, los límites y las funciones de su plan, el uso actual y el token que se está usando. Es una buena primera llamada para comprobar que un token funciona.

{
  "data": {
    "id": "01j8a0f4c7d2e9h6k3m5n8q1r4",
    "name": "Habitly Labs",
    "plan": {
      "key": "studio",
      "name": "Studio",
      "limits": {
        "apps": null,
        "analytics_days": 730,
        "members": 10,
        "custom_domains": 25,
        "legal_locales": null,
        "screenshots": 10,
        "webhooks": 10
      },
      "features": ["remove_badge", "all_themes", "accent_color", "qr_logo", "legal_full", "deep_links", "press_kit", "analytics_export", "custom_domains", "team", "folders", "ab_testing", "api", "webhooks", "white_label"]
    },
    "usage": { "apps": 12, "custom_domains": 3, "members": 4 },
    "token": { "name": "GitHub Actions", "abilities": ["apps:read", "apps:write"] }
  }
}

Un límite null significa ilimitado.

Tipos de eventos

GET /events enumera los tipos de eventos de webhook con una breve descripción. Las integraciones pueden usarlo para crear un selector de eventos.

{
  "data": [
    { "type": "app.created", "description": "An app was added to the workspace." },
    { "type": "app.updated", "description": "App details, links or page settings changed." },
    { "type": "app.deleted", "description": "An app was deleted." },
    { "type": "app.status_changed", "description": "An app went live, was paused or was suspended." },
    { "type": "app.metadata_fetched", "description": "Store metadata was imported for an app." },
    { "type": "legal.published", "description": "A privacy policy or terms document was published." },
    { "type": "domain.verified", "description": "A custom domain was verified." },
    { "type": "link.clicked", "description": "Every smart link click. High volume." },
    { "type": "analytics.daily_summary", "description": "Yesterday's click totals for each app, sent once a day." }
  ]
}

Suscripciones de webhook

Crea suscripciones de webhook desde el código, por ejemplo cuando un usuario conecta tu integración, y elimínalas cuando se desconecte. POST /webhooks recibe:

CampoObligatorioDescripción
urlSíUna URL https pública que recibe los eventos
eventsSíUn array de tipos de eventos, o ["*"] para todos los eventos
descriptionNoHasta 160 caracteres; se muestra en el panel
curl https://mapps.one/api/v1/webhooks \
  -X POST \
  -H "Authorization: Bearer $MAPPS_TOKEN" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.zapier.com/hooks/catch/1234567/abcde12/",
    "events": ["link.clicked"],
    "description": "Zapier: clicks to Google Sheets"
  }'
HTTP/2 201
{
  "data": {
    "id": "01j8c1p4s7v0y3b6e9h2k5n8q1",
    "url": "https://hooks.zapier.com/hooks/catch/1234567/abcde12/",
    "events": ["link.clicked"],
    "description": "Zapier: clicks to Google Sheets",
    "is_active": true,
    "secret": "9f2c4e7a1b8d3f6e0a5c2b9d7e4f1a3c6b8d0e2f4a6c8e0b2d4f6a8c0e2b4d61",
    "created_at": "2026-09-14T10:05:12+00:00"
  }
}

El secret de firma solo se devuelve cuando se crea la suscripción. Úsalo para verificar las firmas. Un espacio de trabajo Studio puede tener hasta 10 endpoints de webhook. Elimina una suscripción con DELETE /webhooks/{id}, que devuelve 204 No Content.

Ejemplo: publicar una beta desde CI

Este script crea una app, añade su enlace de Google Play, importa la ficha e imprime el enlace inteligente. Necesita curl, jq y un token con apps:write.

#!/usr/bin/env bash
set -euo pipefail

API="https://mapps.one/api/v1"
HEADERS=(-H "Authorization: Bearer $MAPPS_TOKEN" -H "Accept: application/json" -H "Content-Type: application/json")

APP_ID=$(curl -sf "${HEADERS[@]}" -X POST "$API/apps" \
  -d '{"name": "Habitly Beta", "slug": "habitly-beta"}' | jq -r '.data.id')

curl -sf "${HEADERS[@]}" -X PUT "$API/apps/$APP_ID/links" \
  -d '{"links": {"google_play": "https://play.google.com/store/apps/details?id=com.habitly.beta"}}' > /dev/null

curl -sf "${HEADERS[@]}" -X POST "$API/apps/$APP_ID/metadata" \
  -d '{"overwrite": true}' | jq -r '.data.urls.smart_link'

Versiones

Esta es la versión 1 de la API. Podemos añadir endpoints, campos y tipos de eventos en cualquier momento, así que ignora los campos que no reconozcas. Los cambios incompatibles se publicarán como una nueva versión, con aviso previo.