Entwickler
API-Referenz
Mit der REST-API von mapps.one kannst du aus deinem eigenen Code, deiner CI-Pipeline oder deiner Integration heraus Apps erstellen und aktualisieren, Store-Links verwalten, Store-Metadaten importieren, Analysen lesen, QR-Codes generieren und Webhooks abonnieren. Die API ist im Studio-Plan verfügbar.
Basis-URL
https://mapps.one/api/v1
Alle Anfragen verwenden HTTPS. Sende Request-Bodys als JSON mit Content-Type: application/json und sende immer Accept: application/json, damit auch Fehler als JSON zurückkommen.
Authentifizierung
Erstelle ein Token im Dashboard unter Entwickler. Workspace-Owner und Admins können das tun. Gib dem Token einen Namen, etwa „GitHub Actions“, und wähle seine Berechtigungen. Das Token wird nur einmal angezeigt. Speichere es daher sofort in deinem Secret-Manager.
Tokens gehören zum Workspace, nicht zu einer Person. Sie funktionieren also weiter, wenn jemand das Team verlässt. Sie laufen nicht ab. Widerrufe ein Token auf derselben Seite, wenn du es nicht mehr brauchst oder wenn es möglicherweise in falsche Hände geraten ist.
Sende das Token als Bearer-Token:
curl https://mapps.one/api/v1/workspace \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
Berechtigungen
| Berechtigung | Erlaubt |
|---|---|
apps:read | Apps auflisten und lesen, QR-Codes herunterladen |
apps:write | Apps erstellen, aktualisieren und löschen, Store-Links ersetzen, Store-Metadaten importieren |
analytics:read | App-Analysen lesen |
webhooks:manage | Webhook-Abos auflisten, erstellen und löschen |
GET /workspace und GET /events funktionieren mit jedem gültigen Token. Gib jeder Integration nur die Berechtigungen, die sie braucht.
Konventionen
- IDs sind 26 Zeichen lange ULIDs in Kleinbuchstaben, etwa
01j8b2k6r3xq9v7m4n5p0s1t2w. Apps werden über ihreidangesprochen, nicht über den Slug. Eine Änderung des Slugs bricht deine Integration also nie. - Zeitstempel sind ISO 8601 in UTC, etwa
2026-09-14T08:12:44+00:00. - Antworten verpacken das Ergebnis in einem
data-Schlüssel. - Store-Schlüssel sind
app_store,google_play,app_gallery,microsoft_storeundweb. - Plattform-Schlüssel sind
ios,android,huawei,windows,macosundother. Ziel-Schlüssel sind die Store-Schlüssel pluslanding.
Rate-Limits
Jeder Workspace kann 120 Anfragen pro Minute stellen, geteilt zwischen all seinen Tokens. Jede Antwort enthält die Header X-RateLimit-Limit und X-RateLimit-Remaining. Überschreitest du das Limit, antwortet die API mit 429 Too Many Requests und einem Retry-After-Header mit der Anzahl der Sekunden, die du warten musst.
Fehler
Fehler liefern einen JSON-Body mit einer menschenlesbaren message. Manche Fehler enthalten zusätzlich einen maschinenlesbaren code, und Validierungsfehler listen Probleme pro Feld in errors auf.
| Status | Wann |
|---|---|
401 | Das Token fehlt, ist ungültig oder wurde widerrufen. {"message": "Unauthenticated."} |
402 | Der Plan des Workspace enthält keinen API-Zugriff. Code plan_required. |
403 | Das Token hat nicht die Berechtigung, die dieser Endpunkt braucht. {"message": "Invalid ability provided."} |
404 | Die App oder das Abo existiert nicht oder gehört zu einem anderen Workspace. |
422 | Die Validierung ist fehlgeschlagen, oder die Anfrage konnte nicht abgeschlossen werden. Zum Beispiel Code metadata_unavailable. |
429 | Rate-Limit überschritten. Warte die Anzahl an Sekunden ab, die in Retry-After steht. |
5xx | Auf unserer Seite ist etwas schiefgelaufen. Versuche es mit exponentiellem Backoff erneut. |
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."]
}
}
Endpunkte
| Methode und Pfad | Berechtigung | Beschreibung |
|---|---|---|
GET /workspace | beliebig | Workspace, Plan, Nutzung und das aktuelle Token |
GET /events | beliebig | Webhook-Ereignistypen |
GET /apps | apps:read | Apps auflisten |
POST /apps | apps:write | App erstellen |
GET /apps/{id} | apps:read | App abrufen |
PATCH /apps/{id} | apps:write | App aktualisieren |
DELETE /apps/{id} | apps:write | App löschen |
PUT /apps/{id}/links | apps:write | Store-Links festlegen oder entfernen |
POST /apps/{id}/metadata | apps:write | Details aus dem Store-Eintrag importieren |
GET /apps/{id}/analytics | analytics:read | Summen, Tagesreihe und Aufschlüsselungen |
GET /apps/{id}/qr | apps:read | QR-Code-Bild |
GET /webhooks | webhooks:manage | Webhook-Abos auflisten |
POST /webhooks | webhooks:manage | Webhook-Abo erstellen |
DELETE /webhooks/{id} | webhooks:manage | Webhook-Abo löschen |
Das App-Objekt
| Feld | Typ | Beschreibung |
|---|---|---|
id | string | ULID der App |
name | string | App-Name |
slug | string | Der Pfad des Smart Links: mapps.one/{slug} |
status | string | live, paused oder suspended |
tagline, description | string oder null | Seitentext |
category | string oder null | Ein Kategorie-Schlüssel, etwa health-fitness oder productivity |
page_theme | string | clean, midnight oder vivid |
accent_color | string oder null | Hex-Farbe, etwa #16a34a |
developer | object | name, website und email |
social_links | object | Ausgefüllte Social-Media-Profile, nach Netzwerk geschlüsselt: x, instagram, tiktok, youtube, facebook, linkedin, threads, github, discord, reddit |
features | array | Funktionseinträge mit icon, title und description |
listed_in_explore | boolean | Ob die App in Entdecken erscheint |
utm_passthrough | boolean | Ob UTM-Tags an die Stores weitergegeben werden |
redirect_rules | object | Ziel pro Plattform, mit ausgefüllten Standardwerten |
icon_url | string oder null | Öffentliche URL des Icons |
rating | object oder null | value und count aus dem Store |
urls | object | Öffentliche URLs: smart_link, landing_page, qr_svg, qr_png, privacy_policy, terms. Die URLs der Rechtstexte liefern 404, bis das Dokument veröffentlicht ist. |
links | object | Store-Links, nach Store geschlüsselt, jeweils mit url, status (unverified, verified oder invalid) und verified_at. In Antworten zu einer einzelnen App enthalten. |
screenshots | array | Screenshots mit url, width und height. Nach einem Metadaten-Import enthalten. |
created_at, updated_at | string | Zeitstempel nach ISO 8601 |
App abrufen
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"
}
}
Apps auflisten
Liefert die Apps im Workspace. Die Ergebnisse sind paginiert: Folge links.next oder übergib ?page=2, bis der Wert null ist.
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
}
}
Die App-Objekte sind in diesem Beispiel gekürzt. Jeder Eintrag enthält alle Felder.
App erstellen
| Feld | Erforderlich | Beschreibung |
|---|---|---|
name | Ja | App-Name, bis zu 120 Zeichen |
slug | Nein | 3 bis 40 Kleinbuchstaben, Ziffern und einzelne Bindestriche. Ohne Angabe wird aus dem Namen ein freier Slug generiert. |
links | Nein | Store-Links, nach Store geschlüsselt, im selben Format wie bei Store-Links festlegen |
Du kannst außerdem alle Felder senden, die unter App aktualisieren aufgeführt sind.
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"
}
}'
Die Antwort ist 201 Created mit dem neuen App-Objekt. Store-Links werden in kanonischer Form mit dem Status unverified gespeichert, bis die Prüfung im Hintergrund abgeschlossen ist. Um Icon, Screenshots und Beschreibung auszufüllen, rufe als Nächstes Store-Metadaten importieren auf.
App aktualisieren
Sende nur die Felder, die du ändern möchtest.
| Feld | Typ |
|---|---|
name | string |
slug | string. Eine Änderung macht den alten Link sofort ungültig. |
tagline, description | string oder null |
category | Kategorie-Schlüssel oder null |
page_theme | clean, midnight oder vivid |
accent_color | #rrggbb oder null |
utm_passthrough, listed_in_explore | boolean |
redirect_rules | object, das Plattform-Schlüssel auf Ziel-Schlüssel abbildet |
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" }
}'
Die Antwort ist das aktualisierte App-Objekt.
App löschen
curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
-X DELETE \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
Die Antwort ist 204 No Content. Das Löschen ist endgültig: Smart Link, Landingpage, Rechtstexte, Medien und Analysen der App werden entfernt.
Store-Links festlegen
PUT /apps/{id}/links erwartet ein links-Objekt, nach Store geschlüsselt:
- eine URL fügt den Link für diesen Store hinzu oder ersetzt ihn,
nulloder ein leerer String entfernt ihn,- Stores, die du weglässt, bleiben unverändert.
Jede URL muss ein gültiger Eintrag im jeweiligen Store sein: ein apps.apple.com-Link mit App-ID, ein play.google.com-Link mit Paket-ID und so weiter. Der web-Link kann jede beliebige http- oder https-Adresse sein. URLs dürfen bis zu 1024 Zeichen lang sein. Links werden in kanonischer Form gespeichert und im Hintergrund geprüft.
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
}
}'
Die Antwort ist das App-Objekt einschließlich links. Ein ungültiger Link liefert 422:
{
"message": "This is not a valid Google Play link.",
"errors": {
"links.google_play": ["This is not a valid Google Play link."]
}
}
Store-Metadaten importieren
POST /apps/{id}/metadata liest den Eintrag im App Store oder, wenn es keinen lesbaren App-Store-Link gibt, den Eintrag bei Google Play und importiert seine Details.
| Feld | Beschreibung |
|---|---|
overwrite | Optional, Standard false. Bei false werden nur leere Felder ausgefüllt, und Screenshots werden nur hinzugefügt, wenn die App noch keine hat. Bei true werden Name, Icon, Texte und Screenshots ersetzt. Bewertung und Preis werden immer aktualisiert. |
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 }'
Die Antwort ist das App-Objekt einschließlich links und screenshots, und ein Webhook vom Typ app.metadata_fetched wird gesendet. Wenn kein Store-Eintrag gelesen werden kann:
HTTP/2 422
{
"message": "The store listing could not be read. Add a valid App Store or Google Play link first.",
"code": "metadata_unavailable"
}
Analysen
GET /apps/{id}/analytics akzeptiert diese Query-Parameter:
| Parameter | Beschreibung |
|---|---|
range | 7d, 30d, 90d, 12m oder custom. Standard 30d. |
from, to | Datumsangaben im Format YYYY-MM-DD, beide einschließlich, für range=custom. to darf nicht später als heute sein. |
timezone | Eine IANA-Zeitzone, etwa Europe/Istanbul, die für die Tagesgrenzen verwendet wird. Standard 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 }
}
}
}
fromist eingeschlossen,toist ausgeschlossen. Beide sind Zeitpunkte in UTC.clamped_to_planisttrue, wenn der angefragte Zeitraum auf den Verlauf des Plans gekürzt wurde.dailyzählt Klicks pro lokalem Datum, einschließlich Tagen ohne Klicks.- Aufschlüsselungen listen bis zu 10 Werte, die häufigsten zuerst. Ein leerer Schlüssel
""bedeutet unbekannt oder nicht gesetzt. - Die Definitionen der Metriken findest du auf der Seite Analysen.
QR-Code
GET /apps/{id}/qr liefert ein Bild. Verwende format=svg (Standard) oder format=png sowie dieselben Optionen wie bei den öffentlichen QR-URLs: fg, bg, margin, ecc, size, logo und download. Siehe QR-Codes und Pressekit.
curl "https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/qr?format=png&size=2048&ecc=Q" \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-o habitly-qr.png
Workspace
GET /workspace liefert den Workspace, die Limits und Funktionen seines Plans, die aktuelle Nutzung und das verwendete Token. Das ist ein guter erster Aufruf, um zu prüfen, ob ein Token funktioniert.
{
"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"] }
}
}
Ein Limit von null bedeutet unbegrenzt.
Ereignistypen
GET /events listet die Webhook-Ereignistypen mit einer kurzen Beschreibung auf. Integrationen können damit eine Ereignisauswahl aufbauen.
{
"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." }
]
}
Webhook-Abos
Erstelle Webhook-Abos per Code, zum Beispiel wenn ein Nutzer deine Integration verbindet, und lösche sie, wenn er die Verbindung trennt. POST /webhooks erwartet:
| Feld | Erforderlich | Beschreibung |
|---|---|---|
url | Ja | Eine öffentliche https-URL, die die Ereignisse empfängt |
events | Ja | Ein Array von Ereignistypen oder ["*"] für alle Ereignisse |
description | Nein | Bis zu 160 Zeichen, wird im Dashboard angezeigt |
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"
}
}
Das secret zum Signieren wird nur beim Erstellen des Abos zurückgegeben. Verwende es, um Signaturen zu verifizieren. Ein Studio-Workspace kann bis zu 10 Webhook-Endpunkte haben. Lösche ein Abo mit DELETE /webhooks/{id}, was 204 No Content liefert.
Beispiel: Beta aus der CI veröffentlichen
Dieses Skript erstellt eine App, fügt ihren Google-Play-Link hinzu, importiert den Store-Eintrag und gibt den Smart Link aus. Es benötigt curl, jq und ein Token mit 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'
Versionierung
Dies ist Version 1 der API. Wir können jederzeit Endpunkte, Felder und Ereignistypen hinzufügen. Ignoriere daher Felder, die du nicht kennst. Inkompatible Änderungen erscheinen als neue Version und werden vorab angekündigt.