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
| Permiso | Permite |
|---|---|
apps:read | Listar y leer apps, descargar códigos QR |
apps:write | Crear, actualizar y eliminar apps, reemplazar enlaces de tienda, importar metadatos de tienda |
analytics:read | Leer las estadísticas de las apps |
webhooks:manage | Listar, 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 porid, 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_storeyweb. - Las claves de plataforma son
ios,android,huawei,windows,macosyother. Las claves de destino son las claves de tienda máslanding.
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.
| Estado | Cuándo |
|---|---|
401 | Falta el token, no es válido o fue revocado. {"message": "Unauthenticated."} |
402 | El plan del espacio de trabajo no incluye acceso a la API. Código plan_required. |
403 | El token no tiene el permiso que necesita este endpoint. {"message": "Invalid ability provided."} |
404 | La app o la suscripción no existe, o pertenece a otro espacio de trabajo. |
422 | La validación falló, o no se pudo completar la solicitud. Por ejemplo, código metadata_unavailable. |
429 | Se superó el límite de solicitudes. Espera el número de segundos indicado en Retry-After. |
5xx | Algo 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 ruta | Permiso | Descripción |
|---|---|---|
GET /workspace | cualquiera | Espacio de trabajo, plan, uso y el token actual |
GET /events | cualquiera | Tipos de eventos de webhook |
GET /apps | apps:read | Listar apps |
POST /apps | apps:write | Crear una app |
GET /apps/{id} | apps:read | Obtener una app |
PATCH /apps/{id} | apps:write | Actualizar una app |
DELETE /apps/{id} | apps:write | Eliminar una app |
PUT /apps/{id}/links | apps:write | Configurar o quitar enlaces de tienda |
POST /apps/{id}/metadata | apps:write | Importar los datos de la ficha de la tienda |
GET /apps/{id}/analytics | analytics:read | Totales, series diarias y desgloses |
GET /apps/{id}/qr | apps:read | Imagen del código QR |
GET /webhooks | webhooks:manage | Listar suscripciones de webhook |
POST /webhooks | webhooks:manage | Crear una suscripción de webhook |
DELETE /webhooks/{id} | webhooks:manage | Eliminar una suscripción de webhook |
El objeto app
| Campo | Tipo | Descripción |
|---|---|---|
id | string | ULID de la app |
name | string | Nombre de la app |
slug | string | La ruta del enlace inteligente: mapps.one/{slug} |
status | string | live, paused o suspended |
tagline, description | string o null | Texto de la página |
category | string o null | Una clave de categoría, como health-fitness o productivity |
page_theme | string | clean, midnight o vivid |
accent_color | string o null | Color hexadecimal, como #16a34a |
developer | object | name, website y email |
social_links | object | Perfiles sociales completados, con la red como clave: x, instagram, tiktok, youtube, facebook, linkedin, threads, github, discord, reddit |
features | array | Elementos de la lista de funciones con icon, title y description |
listed_in_explore | boolean | Si la app aparece en Explorar |
utm_passthrough | boolean | Si las etiquetas UTM se reenvían a las tiendas |
redirect_rules | object | Destino por plataforma, con los valores predeterminados completados |
icon_url | string o null | URL pública del ícono |
rating | object o null | value y count de la tienda |
urls | object | URL públicas: smart_link, landing_page, qr_svg, qr_png, privacy_policy, terms. Las URL legales devuelven 404 hasta que se publica el documento. |
links | object | Enlaces 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. |
screenshots | array | Capturas de pantalla con url, width y height. Se incluye después de una importación de metadatos. |
created_at, updated_at | string | Marcas 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
| Campo | Obligatorio | Descripción |
|---|---|---|
name | Sí | Nombre de la app, de hasta 120 caracteres |
slug | No | De 3 a 40 letras minúsculas, números y guiones simples. Si se omite, se genera un slug libre a partir del nombre. |
links | No | Enlaces 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.
| Campo | Tipo |
|---|---|
name | string |
slug | string. Cambiarlo rompe el enlace anterior de inmediato. |
tagline, description | string o null |
category | clave de categoría o null |
page_theme | clean, midnight o vivid |
accent_color | #rrggbb o null |
utm_passthrough, listed_in_explore | boolean |
redirect_rules | objeto 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.
Configurar enlaces de tienda
PUT /apps/{id}/links recibe un objeto links con la tienda como clave:
- una URL añade o reemplaza el enlace de esa tienda,
nullo 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.
| Campo | Descripción |
|---|---|
overwrite | Opcional, 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ámetro | Descripción |
|---|---|
range | 7d, 30d, 90d, 12m o custom. Predeterminado: 30d. |
from, to | Fechas en formato YYYY-MM-DD, ambas incluidas, para range=custom. to no puede ser posterior a hoy. |
timezone | Una 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 }
}
}
}
fromestá incluido ytoestá excluido. Ambos son instantes en UTC.clamped_to_planestruecuando el rango solicitado se acortó al historial del plan.dailycuenta 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:
| Campo | Obligatorio | Descripción |
|---|---|---|
url | Sí | Una URL https pública que recibe los eventos |
events | Sí | Un array de tipos de eventos, o ["*"] para todos los eventos |
description | No | Hasta 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.