Développeurs
Référence de l'API
L'API REST de mapps.one vous permet de créer et de mettre à jour des applications, de gérer les liens de store, d'importer les métadonnées des stores, de consulter les statistiques, de générer des codes QR et de vous abonner à des webhooks depuis votre propre code, votre pipeline de CI ou votre intégration. L'API est disponible avec le forfait Studio.
URL de base
https://mapps.one/api/v1
Toutes les requêtes utilisent HTTPS. Envoyez les corps de requête en JSON avec Content-Type: application/json, et envoyez toujours Accept: application/json pour que les erreurs soient elles aussi renvoyées en JSON.
Authentification
Créez un jeton dans le tableau de bord, sous Développeurs. Les propriétaires et les administrateurs de l'espace de travail peuvent le faire. Donnez un nom au jeton, comme « GitHub Actions », et choisissez ses permissions. Le jeton n'est affiché qu'une seule fois, conservez-le donc immédiatement dans votre gestionnaire de secrets.
Les jetons appartiennent à l'espace de travail, et non à une personne : ils continuent donc de fonctionner lorsque quelqu'un quitte l'équipe. Ils n'expirent pas. Révoquez un jeton depuis la même page lorsque vous n'en avez plus besoin, ou s'il a pu fuiter.
Envoyez le jeton comme jeton Bearer :
curl https://mapps.one/api/v1/workspace \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
Permissions
| Permission | Autorise |
|---|---|
apps:read | Lister et lire les applications, télécharger les codes QR |
apps:write | Créer, mettre à jour et supprimer des applications, remplacer les liens de store, importer les métadonnées des stores |
analytics:read | Lire les statistiques des applications |
webhooks:manage | Lister, créer et supprimer des abonnements webhook |
GET /workspace et GET /events fonctionnent avec n'importe quel jeton valide. N'accordez à chaque intégration que les permissions dont elle a besoin.
Conventions
- Les identifiants sont des ULID de 26 caractères en minuscules, comme
01j8b2k6r3xq9v7m4n5p0s1t2w. Les applications sont désignées par leurid, et non par leur slug : renommer un slug ne casse donc jamais votre intégration. - Les horodatages sont au format ISO 8601 en UTC, comme
2026-09-14T08:12:44+00:00. - Les réponses encapsulent le résultat dans une clé
data. - Les clés de store sont
app_store,google_play,app_gallery,microsoft_storeetweb. - Les clés de plateforme sont
ios,android,huawei,windows,macosetother. Les clés de destination sont les clés de store, pluslanding.
Limites de débit
Chaque espace de travail peut effectuer 120 requêtes par minute, partagées entre tous ses jetons. Chaque réponse inclut les en-têtes X-RateLimit-Limit et X-RateLimit-Remaining. Lorsque vous dépassez la limite, l'API répond 429 Too Many Requests avec un en-tête Retry-After qui indique le nombre de secondes à attendre.
Erreurs
Les erreurs renvoient un corps JSON avec un message lisible par un humain. Certaines erreurs incluent aussi un code lisible par une machine, et les erreurs de validation listent les problèmes par champ dans errors.
| Statut | Quand |
|---|---|
401 | Le jeton est absent, non valide ou révoqué. {"message": "Unauthenticated."} |
402 | Le forfait de l'espace de travail n'inclut pas l'accès à l'API. Code plan_required. |
403 | Le jeton n'a pas la permission requise par ce point de terminaison. {"message": "Invalid ability provided."} |
404 | L'application ou l'abonnement n'existe pas, ou appartient à un autre espace de travail. |
422 | La validation a échoué, ou la requête n'a pas pu aboutir. Par exemple, code metadata_unavailable. |
429 | Limite de débit dépassée. Attendez le nombre de secondes indiqué dans Retry-After. |
5xx | Un problème est survenu de notre côté. Réessayez avec un backoff exponentiel. |
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."]
}
}
Points de terminaison
| Méthode et chemin | Permission | Description |
|---|---|---|
GET /workspace | n'importe laquelle | Espace de travail, forfait, utilisation et jeton actuel |
GET /events | n'importe laquelle | Types d'événements webhook |
GET /apps | apps:read | Lister les applications |
POST /apps | apps:write | Créer une application |
GET /apps/{id} | apps:read | Récupérer une application |
PATCH /apps/{id} | apps:write | Mettre à jour une application |
DELETE /apps/{id} | apps:write | Supprimer une application |
PUT /apps/{id}/links | apps:write | Définir ou supprimer des liens de store |
POST /apps/{id}/metadata | apps:write | Importer les détails depuis la fiche store |
GET /apps/{id}/analytics | analytics:read | Totaux, série quotidienne et répartitions |
GET /apps/{id}/qr | apps:read | Image du code QR |
GET /webhooks | webhooks:manage | Lister les abonnements webhook |
POST /webhooks | webhooks:manage | Créer un abonnement webhook |
DELETE /webhooks/{id} | webhooks:manage | Supprimer un abonnement webhook |
L'objet application
| Champ | Type | Description |
|---|---|---|
id | chaîne | ULID de l'application |
name | chaîne | Nom de l'application |
slug | chaîne | Le chemin du lien intelligent : mapps.one/{slug} |
status | chaîne | live, paused ou suspended |
tagline, description | chaîne ou null | Textes de la page |
category | chaîne ou null | Une clé de catégorie, comme health-fitness ou productivity |
page_theme | chaîne | clean, midnight ou vivid |
accent_color | chaîne ou null | Couleur hexadécimale, comme #16a34a |
developer | objet | name, website et email |
social_links | objet | Profils sociaux renseignés, indexés par réseau : x, instagram, tiktok, youtube, facebook, linkedin, threads, github, discord, reddit |
features | tableau | Éléments de la liste de fonctionnalités, avec icon, title et description |
listed_in_explore | booléen | Indique si l'application apparaît dans Explorer |
utm_passthrough | booléen | Indique si les balises UTM sont transmises aux stores |
redirect_rules | objet | Destination par plateforme, avec les valeurs par défaut renseignées |
icon_url | chaîne ou null | URL publique de l'icône |
rating | objet ou null | value et count issus du store |
urls | objet | URL publiques : smart_link, landing_page, qr_svg, qr_png, privacy_policy, terms. Les URL légales renvoient 404 tant que le document n'est pas publié. |
links | objet | Liens de store indexés par store, chacun avec url, status (unverified, verified ou invalid) et verified_at. Inclus dans les réponses qui portent sur une seule application. |
screenshots | tableau | Captures d'écran avec url, width et height. Incluses après une importation des métadonnées. |
created_at, updated_at | chaîne | Horodatages ISO 8601 |
Récupérer une application
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"
}
}
Lister les applications
Renvoie les applications de l'espace de travail. Les résultats sont paginés : suivez links.next, ou passez ?page=2, jusqu'à ce qu'il vaille 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
}
}
Les objets application sont abrégés dans cet exemple. Chaque élément contient l'ensemble des champs.
Créer une application
| Champ | Obligatoire | Description |
|---|---|---|
name | Oui | Nom de l'application, jusqu'à 120 caractères |
slug | Non | De 3 à 40 lettres minuscules, chiffres et tirets simples. S'il est omis, un slug disponible est généré à partir du nom. |
links | Non | Liens de store indexés par store, au même format que dans Définir les liens de store |
Vous pouvez aussi envoyer n'importe lequel des champs listés dans Mettre à jour une application.
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 réponse est 201 Created, avec le nouvel objet application. Les liens de store sont enregistrés sous forme canonique, avec le statut unverified jusqu'à la fin de la vérification en arrière-plan. Pour renseigner l'icône, les captures d'écran et la description, appelez ensuite Importer les métadonnées du store.
Mettre à jour une application
Envoyez uniquement les champs que vous souhaitez modifier.
| Champ | Type |
|---|---|
name | chaîne |
slug | chaîne. Le modifier casse immédiatement l'ancien lien. |
tagline, description | chaîne ou null |
category | clé de catégorie ou null |
page_theme | clean, midnight ou vivid |
accent_color | #rrggbb ou null |
utm_passthrough, listed_in_explore | booléen |
redirect_rules | objet associant une clé de plateforme à une clé de destination |
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 réponse est l'objet application mis à jour.
Supprimer une application
curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
-X DELETE \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
La réponse est 204 No Content. La suppression est définitive : le lien intelligent, la page de destination, les documents légaux, les médias et les statistiques de l'application sont supprimés.
Définir les liens de store
PUT /apps/{id}/links accepte un objet links indexé par store :
- une URL ajoute ou remplace le lien de ce store,
nullou une chaîne vide le supprime,- les stores que vous omettez ne sont pas modifiés.
Chaque URL doit correspondre à une fiche valide de son store : un lien apps.apple.com avec un identifiant d'application, un lien play.google.com avec un identifiant de package, etc. Le lien web peut être n'importe quelle adresse http ou https. Les URL peuvent comporter jusqu'à 1024 caractères. Les liens sont enregistrés sous forme canonique et vérifiés en arrière-plan.
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 réponse est l'objet application, links compris. Un lien non valide renvoie 422 :
{
"message": "This is not a valid Google Play link.",
"errors": {
"links.google_play": ["This is not a valid Google Play link."]
}
}
Importer les métadonnées du store
POST /apps/{id}/metadata lit la fiche App Store, ou la fiche Google Play s'il n'existe aucun lien App Store lisible, et importe ses détails.
| Champ | Description |
|---|---|
overwrite | Facultatif, false par défaut. Avec la valeur false, seuls les champs vides sont remplis, et les captures d'écran ne sont ajoutées que si l'application n'en a aucune. Avec la valeur true, le nom, l'icône, les textes et les captures d'écran sont remplacés. La note et le prix sont toujours mis à jour. |
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 réponse est l'objet application, links et screenshots compris, et un webhook app.metadata_fetched est envoyé. Si aucune fiche ne peut être lue :
HTTP/2 422
{
"message": "The store listing could not be read. Add a valid App Store or Google Play link first.",
"code": "metadata_unavailable"
}
Statistiques
GET /apps/{id}/analytics accepte ces paramètres de requête :
| Paramètre | Description |
|---|---|
range | 7d, 30d, 90d, 12m ou custom. Valeur par défaut : 30d. |
from, to | Dates au format YYYY-MM-DD, toutes deux incluses, pour range=custom. to ne peut pas être postérieure à aujourd'hui. |
timezone | Un fuseau horaire IANA, comme Europe/Istanbul, utilisé pour délimiter les jours. Valeur par défaut : 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 inclus ettoest exclu. Ce sont tous deux des instants UTC.clamped_to_planvauttruelorsque la plage demandée a été raccourcie à l'historique du forfait.dailycompte les clics par date locale, y compris les jours sans clic.- Les répartitions listent jusqu'à 10 valeurs, de la plus fréquente à la moins fréquente. Une clé vide
""signifie inconnue ou non définie. - Les définitions des métriques figurent sur la page Statistiques.
Code QR
GET /apps/{id}/qr renvoie une image. Utilisez format=svg (par défaut) ou format=png, ainsi que les mêmes options que pour les URL QR publiques : fg, bg, margin, ecc, size, logo et download. Consultez Codes QR et kit de presse.
curl "https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/qr?format=png&size=2048&ecc=Q" \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-o habitly-qr.png
Espace de travail
GET /workspace renvoie l'espace de travail, les limites et les fonctionnalités de son forfait, l'utilisation actuelle et le jeton utilisé. C'est un bon premier appel pour vérifier qu'un jeton fonctionne.
{
"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"] }
}
}
Une limite null signifie illimité.
Types d'événements
GET /events liste les types d'événements webhook avec une courte description. Les intégrations peuvent l'utiliser pour créer un sélecteur d'événements.
{
"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." }
]
}
Abonnements webhook
Créez des abonnements webhook depuis votre code, par exemple lorsqu'un utilisateur connecte votre intégration, et supprimez-les lorsqu'il la déconnecte. POST /webhooks accepte :
| Champ | Obligatoire | Description |
|---|---|---|
url | Oui | Une URL https publique qui reçoit les événements |
events | Oui | Un tableau de types d'événements, ou ["*"] pour tous les événements |
description | Non | Jusqu'à 160 caractères, affichée dans le tableau de bord |
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"
}
}
Le secret de signature n'est renvoyé qu'à la création de l'abonnement. Utilisez-le pour vérifier les signatures. Un espace de travail Studio peut avoir jusqu'à 10 points de terminaison de webhook. Supprimez un abonnement avec DELETE /webhooks/{id}, qui renvoie 204 No Content.
Exemple : publier une bêta depuis la CI
Ce script crée une application, ajoute son lien Google Play, importe la fiche et affiche le lien intelligent. Il nécessite curl, jq et un jeton disposant de la permission 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'
Gestion des versions
Il s'agit de la version 1 de l'API. Nous pouvons ajouter des points de terminaison, des champs et des types d'événements à tout moment, ignorez donc les champs que vous ne reconnaissez pas. Les changements incompatibles seront publiés dans une nouvelle version, avec un préavis.