개발자
API 레퍼런스
mapps.one REST API를 사용하면 자체 코드, CI 파이프라인 또는 연동 서비스에서 앱을 만들고 업데이트하고, 스토어 링크를 관리하고, 스토어 메타데이터를 가져오고, 분석을 읽고, QR 코드를 생성하고, 웹훅을 구독할 수 있어요. API는 Studio 플랜에서 사용할 수 있어요.
기본 URL
https://mapps.one/api/v1
모든 요청은 HTTPS를 사용해요. 요청 본문은 Content-Type: application/json 헤더와 함께 JSON으로 보내고, 오류도 JSON으로 반환되도록 항상 Accept: application/json 헤더를 보내세요.
인증
대시보드의 개발자 메뉴에서 토큰을 만드세요. 워크스페이스 소유자와 관리자가 이 작업을 할 수 있어요. 토큰에 "GitHub Actions" 같은 이름을 지정하고 권한을 선택하세요. 토큰은 한 번만 표시되므로 바로 시크릿 관리 도구에 보관하세요.
토큰은 개인이 아닌 워크스페이스에 속하므로, 누군가 팀을 떠나도 계속 작동해요. 토큰은 만료되지 않아요. 더 이상 필요 없거나 유출되었을 가능성이 있다면 같은 페이지에서 토큰을 폐기하세요.
토큰은 Bearer 토큰으로 보내세요.
curl https://mapps.one/api/v1/workspace \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
권한
| 권한 | 허용되는 작업 |
|---|---|
apps:read | 앱 목록 조회 및 읽기, QR 코드 다운로드 |
apps:write | 앱 만들기, 업데이트 및 삭제, 스토어 링크 교체, 스토어 메타데이터 가져오기 |
analytics:read | 앱 분석 읽기 |
webhooks:manage | 웹훅 구독 목록 조회, 만들기 및 삭제 |
GET /workspace 엔드포인트와 GET /events 엔드포인트는 유효한 토큰이라면 어떤 토큰으로도 사용할 수 있어요. 각 연동 서비스에는 필요한 권한만 부여하세요.
규칙
- ID는
01j8b2k6r3xq9v7m4n5p0s1t2w값처럼 26자의 소문자 ULID예요. 앱은 링크 주소(슬러그)가 아닌id값으로 지정하므로, 링크 주소를 바꿔도 연동이 깨지지 않아요. - 타임스탬프는
2026-09-14T08:12:44+00:00값처럼 UTC 기준 ISO 8601 형식이에요. - 응답은 결과를
data키로 감싸요. - 스토어 키는
app_store,google_play,app_gallery,microsoft_store,web값이에요. - 플랫폼 키는
ios,android,huawei,windows,macos,other값이에요. 이동 대상 키는 스토어 키에landing값을 더한 것이에요.
요청 한도
각 워크스페이스는 분당 120개의 요청을 보낼 수 있으며, 이 한도는 워크스페이스의 모든 토큰이 함께 사용해요. 모든 응답에는 X-RateLimit-Limit 헤더와 X-RateLimit-Remaining 헤더가 포함돼요. 한도를 넘으면 API가 429 Too Many Requests 상태와 함께, 기다려야 할 초 수를 담은 Retry-After 헤더로 응답해요.
오류
오류는 사람이 읽을 수 있는 message 필드가 담긴 JSON 본문을 반환해요. 일부 오류에는 기계가 읽을 수 있는 code 필드도 포함되며, 유효성 검사 오류는 errors 필드에 필드별 문제를 나열해요.
| 상태 | 발생 조건 |
|---|---|
401 | 토큰이 없거나, 유효하지 않거나, 폐기되었어요. {"message": "Unauthenticated."} |
402 | 워크스페이스 플랜에 API 접근이 포함되지 않아요. 코드 plan_required. |
403 | 토큰에 이 엔드포인트에 필요한 권한이 없어요. {"message": "Invalid ability provided."} |
404 | 앱이나 구독이 존재하지 않거나 다른 워크스페이스에 속해 있어요. |
422 | 유효성 검사에 실패했거나 요청을 완료할 수 없어요. 예: 코드 metadata_unavailable. |
429 | 요청 한도를 초과했어요. Retry-After 헤더에 표시된 초 수만큼 기다리세요. |
5xx | 저희 쪽에서 문제가 발생했어요. 지수 백오프로 재시도하세요. |
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."]
}
}
엔드포인트
| 메서드 및 경로 | 권한 | 설명 |
|---|---|---|
GET /workspace | 모두 | 워크스페이스, 플랜, 사용량, 현재 토큰 |
GET /events | 모두 | 웹훅 이벤트 유형 |
GET /apps | apps:read | 앱 목록 조회 |
POST /apps | apps:write | 앱 만들기 |
GET /apps/{id} | apps:read | 앱 조회 |
PATCH /apps/{id} | apps:write | 앱 업데이트 |
DELETE /apps/{id} | apps:write | 앱 삭제 |
PUT /apps/{id}/links | apps:write | 스토어 링크 설정 또는 삭제 |
POST /apps/{id}/metadata | apps:write | 스토어 등록 정보에서 정보 가져오기 |
GET /apps/{id}/analytics | analytics:read | 합계, 일별 시계열, 세부 분석 |
GET /apps/{id}/qr | apps:read | QR 코드 이미지 |
GET /webhooks | webhooks:manage | 웹훅 구독 목록 조회 |
POST /webhooks | webhooks:manage | 웹훅 구독 만들기 |
DELETE /webhooks/{id} | webhooks:manage | 웹훅 구독 삭제 |
앱 객체
| 필드 | 유형 | 설명 |
|---|---|---|
id | string | 앱의 ULID |
name | string | 앱 이름 |
slug | string | 스마트 링크의 경로: mapps.one/{slug} |
status | string | live, paused 또는 suspended |
tagline, description | string 또는 null | 페이지 텍스트 |
category | string 또는 null | health-fitness, productivity 같은 카테고리 키 |
page_theme | string | clean, midnight 또는 vivid |
accent_color | string 또는 null | #16a34a 같은 16진수 색상 |
developer | object | name, website, email |
social_links | object | 입력된 소셜 프로필. 네트워크별 키로 구분돼요: x, instagram, tiktok, youtube, facebook, linkedin, threads, github, discord, reddit |
features | array | icon, title, description 값을 가진 기능 항목 |
listed_in_explore | boolean | 앱이 둘러보기에 표시되는지 여부 |
utm_passthrough | boolean | UTM 태그를 스토어로 전달하는지 여부 |
redirect_rules | object | 플랫폼별 이동 대상(기본값이 채워져 있음) |
icon_url | string 또는 null | 아이콘의 공개 URL |
rating | object 또는 null | 스토어에서 가져온 value 및 count 값 |
urls | object | 공개 URL: smart_link, landing_page, qr_svg, qr_png, privacy_policy, terms. 법률 문서 URL은 문서가 게시될 때까지 404를 반환해요. |
links | object | 스토어별 키로 구분된 스토어 링크. 각 링크에는 url, status(unverified, verified 또는 invalid), verified_at 값이 있어요. 단일 앱 응답에 포함돼요. |
screenshots | array | url, width, height 값을 가진 스크린샷. 메타데이터를 가져온 후에 포함돼요. |
created_at, updated_at | string | ISO 8601 타임스탬프 |
앱 조회하기
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"
}
}
앱 목록 조회하기
워크스페이스의 앱을 반환해요. 결과는 페이지로 나뉘어 있어요. links.next 값이 null 값이 될 때까지 해당 링크를 따라가거나 ?page=2 파라미터를 전달하세요.
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
}
}
이 예시에서는 앱 객체를 줄여서 표시했어요. 실제로는 각 항목에 전체 필드가 포함돼요.
앱 만들기
| 필드 | 필수 | 설명 |
|---|---|---|
name | 예 | 앱 이름, 최대 120자 |
slug | 아니요 | 영문 소문자, 숫자, 단일 하이픈으로 된 3~40자. 생략하면 이름을 바탕으로 사용 가능한 링크 주소가 생성돼요. |
links | 아니요 | 스토어별 키로 구분된 스토어 링크. 형식은 스토어 링크 설정하기와 같아요. |
앱 업데이트하기에 나열된 필드도 함께 보낼 수 있어요.
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"
}
}'
응답은 새 앱 객체와 함께 201 Created 상태로 반환돼요. 스토어 링크는 표준 형식으로 저장되며, 백그라운드 확인이 끝날 때까지 상태는 unverified 값이에요. 아이콘, 스크린샷, 설명을 채우려면 이어서 스토어 메타데이터 가져오기를 호출하세요.
앱 업데이트하기
변경할 필드만 보내세요.
| 필드 | 유형 |
|---|---|
name | string |
slug | string. 변경하면 이전 링크가 즉시 작동하지 않아요. |
tagline, description | string 또는 null |
category | 카테고리 키 또는 null |
page_theme | clean, midnight 또는 vivid |
accent_color | #rrggbb 또는 null |
utm_passthrough, listed_in_explore | boolean |
redirect_rules | 플랫폼 키를 이동 대상 키에 매핑한 object |
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" }
}'
응답은 업데이트된 앱 객체예요.
앱 삭제하기
curl https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w \
-X DELETE \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-H "Accept: application/json"
응답은 204 No Content 상태예요. 삭제는 되돌릴 수 없어요. 앱의 스마트 링크, 랜딩 페이지, 법률 문서, 미디어, 분석 데이터가 삭제돼요.
스토어 링크 설정하기
PUT /apps/{id}/links 엔드포인트는 스토어별 키로 구분된 links 객체를 받아요.
- URL을 보내면 해당 스토어의 링크가 추가되거나 교체돼요.
null값이나 빈 문자열을 보내면 링크가 삭제돼요.- 생략한 스토어는 변경되지 않아요.
각 URL은 해당 스토어의 유효한 등록 정보여야 해요. 예를 들어 앱 ID가 포함된 apps.apple.com 링크, 패키지 ID가 포함된 play.google.com 링크 등이에요. web 링크에는 http 또는 https 주소라면 무엇이든 사용할 수 있어요. URL은 최대 1024자까지 가능해요. 링크는 표준 형식으로 저장되고 백그라운드에서 확인돼요.
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
}
}'
응답은 links 필드를 포함한 앱 객체예요. 유효하지 않은 링크는 422 상태를 반환해요.
{
"message": "This is not a valid Google Play link.",
"errors": {
"links.google_play": ["This is not a valid Google Play link."]
}
}
스토어 메타데이터 가져오기
POST /apps/{id}/metadata 엔드포인트는 App Store 등록 정보를 읽고(읽을 수 있는 App Store 링크가 없으면 Google Play 등록 정보를 읽어요) 그 정보를 가져와요.
| 필드 | 설명 |
|---|---|
overwrite | 선택 사항이며 기본값은 false 값이에요. false이면 비어 있는 필드만 채우고, 앱에 스크린샷이 없을 때만 스크린샷을 추가해요. true이면 이름, 아이콘, 텍스트, 스크린샷을 교체해요. 평점과 가격은 항상 업데이트돼요. |
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 }'
응답은 links 필드와 screenshots 필드를 포함한 앱 객체이며, app.metadata_fetched 웹훅이 전송돼요. 읽을 수 있는 등록 정보가 없으면 다음과 같이 응답해요.
HTTP/2 422
{
"message": "The store listing could not be read. Add a valid App Store or Google Play link first.",
"code": "metadata_unavailable"
}
분석
GET /apps/{id}/analytics 엔드포인트는 다음 쿼리 파라미터를 받아요.
| 파라미터 | 설명 |
|---|---|
range | 7d, 30d, 90d, 12m 또는 custom. 기본값은 30d 값이에요. |
from, to | range=custom 값과 함께 사용하는 YYYY-MM-DD 형식의 날짜(양쪽 모두 포함). to 값은 오늘보다 늦을 수 없어요. |
timezone | 일 경계를 정하는 데 사용하는 IANA 시간대(예: Europe/Istanbul). 기본값은 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값은 포함되고to값은 제외돼요. 둘 다 UTC 시점이에요.- 요청한 범위가 플랜의 기록 기간에 맞춰 짧아졌다면
clamped_to_plan값은true값이에요. daily필드는 클릭이 없는 날을 포함해 현지 날짜별 클릭 수를 집계해요.- 세부 분석은 가장 빈도가 높은 값부터 최대 10개까지 나열해요. 빈 키
""값은 알 수 없거나 설정되지 않았다는 뜻이에요. - 지표 정의는 분석 페이지에 있어요.
QR 코드
GET /apps/{id}/qr 엔드포인트는 이미지를 반환해요. format=svg(기본값) 또는 format=png 값을 사용하고, 공개 QR URL과 같은 옵션인 fg, bg, margin, ecc, size, logo, download 값을 함께 사용할 수 있어요. QR 코드 및 프레스 키트를 참고하세요.
curl "https://mapps.one/api/v1/apps/01j8b2k6r3xq9v7m4n5p0s1t2w/qr?format=png&size=2048&ecc=Q" \
-H "Authorization: Bearer $MAPPS_TOKEN" \
-o habitly-qr.png
워크스페이스
GET /workspace 엔드포인트는 워크스페이스, 플랜 한도와 기능, 현재 사용량, 사용 중인 토큰을 반환해요. 토큰이 작동하는지 확인하는 첫 호출로 알맞아요.
{
"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"] }
}
}
한도가 null 값이면 무제한이라는 뜻이에요.
이벤트 유형
GET /events 엔드포인트는 웹훅 이벤트 유형을 짧은 설명과 함께 나열해요. 연동 서비스에서 이벤트 선택 화면을 만드는 데 사용할 수 있어요.
{
"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." }
]
}
웹훅 구독
사용자가 연동 서비스를 연결할 때처럼 코드에서 웹훅 구독을 만들고, 사용자가 연결을 해제하면 구독을 삭제하세요. POST /webhooks 엔드포인트는 다음 필드를 받아요.
| 필드 | 필수 | 설명 |
|---|---|---|
url | 예 | 이벤트를 받을 공개 https URL |
events | 예 | 이벤트 유형 배열 또는 모든 이벤트를 뜻하는 ["*"] 값 |
description | 아니요 | 최대 160자이며 대시보드에 표시돼요 |
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"
}
}
서명 secret 값은 구독을 만들 때만 반환돼요. 이 값으로 서명을 검증하세요. Studio 워크스페이스에는 최대 10개의 웹훅 엔드포인트를 만들 수 있어요. 구독은 DELETE /webhooks/{id} 요청으로 삭제하며, 이 요청은 204 No Content 상태를 반환해요.
예시: CI에서 베타 게시하기
이 스크립트는 앱을 만들고, Google Play 링크를 추가하고, 등록 정보를 가져온 다음 스마트 링크를 출력해요. curl, jq, 그리고 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'
버전 관리
이 문서는 API 버전 1을 다뤄요. 엔드포인트, 필드, 이벤트 유형은 언제든지 추가될 수 있으므로 알 수 없는 필드는 무시하세요. 호환성을 깨는 변경 사항은 사전 공지와 함께 새 버전으로 출시돼요.