Marketplace sleek-design-mobile-apps
Use when the user wants to design a mobile app, create screens, build UI, or interact with their Sleek projects. Covers high-level requests ("design an app that does X") and specific ones ("list my projects", "create a new project", "screenshot that screen").
git clone https://github.com/aiskillstore/marketplace
T=$(mktemp -d) && git clone --depth=1 https://github.com/aiskillstore/marketplace "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/sleekdotdesign/sleek-design-mobile-apps" ~/.claude/skills/aiskillstore-marketplace-sleek-design-mobile-apps && rm -rf "$T"
skills/sleekdotdesign/sleek-design-mobile-apps/SKILL.mdDesigning with Sleek
Overview
Sleek is an AI-powered mobile app design tool. You interact with it via a REST API at
/api/v1/* to create projects, describe what you want built in plain language, and get back rendered screens. All communication is standard HTTP with bearer token auth.
Base URL:
https://sleek.design
Auth: Authorization: Bearer $SLEEK_API_KEY on every /api/v1/* request
Content-Type: application/json (requests and responses)
CORS: Enabled on all /api/v1/* endpoints
Prerequisites: API Key
Create API keys at https://sleek.design/dashboard/api-keys. The full key value is shown only once at creation — store it in the
SLEEK_API_KEY environment variable.
Required plan: Pro+ (API access is gated)
Key scopes
| Scope | What it unlocks |
|---|---|
| List / get projects |
| Create / delete projects |
| List components in a project |
| Get chat run status |
| Send chat messages |
| Render component screenshots |
Create a key with only the scopes needed for the task.
Security & Privacy
- Single host: All requests go exclusively to
. No data is sent to third parties.https://sleek.design - HTTPS only: All communication uses HTTPS. The API key is transmitted only in the
header to Sleek endpoints.Authorization - Minimal scopes: Create API keys with only the scopes required for the task. Prefer short-lived or revocable keys.
- Image URLs: When using
in chat messages, those URLs are fetched by Sleek's servers. Avoid passing URLs that contain sensitive content.imageUrls
Handling high-level requests
When the user says something like "design a fitness tracking app" or "build me a settings screen":
- Create a project if one doesn't exist yet (ask the user for a name, or derive one from the request)
- Send a chat message describing what to build — you can use the user's words directly as
; Sleek's AI interprets natural languagemessage.text - Follow the screenshot delivery rule below to show the result
You do not need to decompose the request into screens first. Send the full intent as a single message and let Sleek decide what screens to create.
Screenshot delivery rule
After every chat run that produces
or screen_created
operations, always take screenshots and show them to the user. Never silently complete a chat run without delivering the visuals.screen_updated
When screens are created for the first time on a project (i.e. the run includes
screen_created operations), deliver:
- One screenshot per newly created screen (individual
)componentIds: [screenId] - One combined screenshot of all screens in the project (
)componentIds: [all screen ids]
When only existing screens are updated, deliver one screenshot per affected screen.
Use
background: "transparent" for all screenshots unless the user explicitly requests otherwise.
Quick Reference — All Endpoints
| Method | Path | Scope | Description |
|---|---|---|---|
| | | List projects |
| | | Create project |
| | | Get project |
| | | Delete project |
| | | List components |
| | | Send chat message |
| | | Poll run status |
| | | Render screenshot |
All IDs are stable string identifiers.
Endpoints
Projects
List projects
GET /api/v1/projects?limit=50&offset=0 Authorization: Bearer $SLEEK_API_KEY
Response
200:
{ "data": [ { "id": "proj_abc", "name": "My App", "slug": "my-app", "createdAt": "2026-01-01T00:00:00Z", "updatedAt": "..." } ], "pagination": { "total": 12, "limit": 50, "offset": 0 } }
Create project
POST /api/v1/projects Authorization: Bearer $SLEEK_API_KEY Content-Type: application/json { "name": "My New App" }
Response
201 — same shape as a single project.
Get / Delete project
GET /api/v1/projects/:projectId DELETE /api/v1/projects/:projectId → 204 No Content
Components
List components
GET /api/v1/projects/:projectId/components?limit=50&offset=0 Authorization: Bearer $SLEEK_API_KEY
Response
200:
{ "data": [ { "id": "cmp_xyz", "name": "Hero Section", "activeVersion": 3, "versions": [{ "id": "ver_001", "version": 1, "createdAt": "..." }], "createdAt": "...", "updatedAt": "..." } ], "pagination": { "total": 5, "limit": 50, "offset": 0 } }
Chat — Send Message
This is the core action: describe what you want in
message.text and the AI creates or modifies screens.
POST /api/v1/projects/:projectId/chat/messages?wait=false Authorization: Bearer $SLEEK_API_KEY Content-Type: application/json idempotency-key: <optional, max 255 chars> { "message": { "text": "Add a pricing section with three tiers" }, "imageUrls": ["https://example.com/ref.png"], "target": { "screenId": "scr_abc" } }
| Field | Required | Notes |
|---|---|---|
| Yes | 1+ chars, trimmed |
| No | HTTPS URLs only; included as visual context |
| No | Edit a specific screen; omit to let AI decide |
| No | Sync wait mode (default: false) |
header | No | Replay-safe re-sends |
Response — async (default, wait=false
)
wait=falseStatus
202 Accepted. result and error are absent until the run reaches a terminal state.
{ "data": { "runId": "run_111", "status": "queued", "statusUrl": "/api/v1/projects/proj_abc/chat/runs/run_111" } }
Response — sync (wait=true
)
wait=trueBlocks up to 300 seconds. Returns
200 when completed, 202 if timed out.
{ "data": { "runId": "run_111", "status": "completed", "statusUrl": "...", "result": { "assistantText": "I added a pricing section with...", "operations": [ { "type": "screen_created", "screenId": "scr_xyz", "screenName": "Pricing" }, { "type": "screen_updated", "screenId": "scr_abc" }, { "type": "theme_updated" } ] } } }
Chat — Poll Run Status
Use this after async send to check progress.
GET /api/v1/projects/:projectId/chat/runs/:runId Authorization: Bearer $SLEEK_API_KEY
Response — same shape as send message
data object:
{ "data": { "runId": "run_111", "status": "queued", "statusUrl": "..." } }
When completed successfully,
result is present:
{ "data": { "runId": "run_111", "status": "completed", "statusUrl": "...", "result": { "assistantText": "...", "operations": [...] } } }
When failed,
error is present:
{ "data": { "runId": "run_111", "status": "failed", "statusUrl": "...", "error": { "code": "execution_failed", "message": "..." } } }
Run status lifecycle:
queued → running → completed | failed
Screenshots
Takes a snapshot of one or more rendered components.
POST /api/screenshots Authorization: Bearer $SLEEK_API_KEY Content-Type: application/json { "componentIds": ["cmp_xyz", "cmp_abc"], "projectId": "proj_abc", "format": "png", "scale": 2, "gap": 40, "padding": 40, "background": "transparent" }
| Field | Default | Notes |
|---|---|---|
| | or |
| | 1–3 (device pixel ratio) |
| | Pixels between components |
| | Uniform padding on all sides |
| (optional) | Horizontal padding; overrides for left/right when provided |
| (optional) | Vertical padding; overrides for top/bottom when provided |
| | Any CSS color (hex, named, ) |
| | Overlay a subtle dot grid on the background |
paddingX and paddingY take precedence over padding for their axis. If neither is set, padding applies to all sides. For example, { "padding": 20, "paddingX": 10 } gives 10px horizontal and 20px vertical padding.
When
showDots is true, a dot pattern is drawn over the background color. The dots automatically adapt to the background: dark backgrounds get light dots, light backgrounds get dark dots. This has no effect when background is "transparent".
Always use
"background": "transparent" unless the user explicitly requests a specific background color.
Response: raw binary
image/png or image/webp with Content-Disposition: attachment.
Error Shapes
{ "code": "UNAUTHORIZED", "message": "..." }
| HTTP | Code | When |
|---|---|---|
| 401 | | Missing/invalid/expired API key |
| 403 | | Valid key, wrong scope or plan |
| 404 | | Resource doesn't exist |
| 400 | | Validation failure |
| 409 | | Another run is active for this project |
| 500 | | Server error |
Chat run-level errors (inside
data.error):
| Code | Meaning |
|---|---|
| Organization has no credits left |
| AI execution error |
Flows
Flow 1: Create project and generate a UI (async + polling)
1. POST /api/v1/projects → get projectId 2. POST /api/v1/projects/:id/chat/messages → get runId (202) 3. Poll GET /api/v1/projects/:id/chat/runs/:runId until status == "completed" or "failed" 4. Collect screenIds from result.operations (screen_created and screen_updated entries) 5. Screenshot each affected screen individually 6. If any screen_created: also screenshot all project screens combined 7. Show all screenshots to the user
Polling recommendation: start at 2s interval, back off to 5s after 10s, give up after 5 minutes.
Flow 2: Sync mode (simple, blocking)
Best for short tasks or when latency is acceptable.
1. POST /api/v1/projects/:id/chat/messages?wait=true → blocks up to 300s → 200 if completed, 202 if timed out 2. If 202, fall back to Flow 1 polling with the returned runId 3. On completion, screenshot and show affected screens (see screenshot delivery rule)
Flow 3: Edit a specific screen
1. GET /api/v1/projects/:id/components → find screenId 2. POST /api/v1/projects/:id/chat/messages body: { message: { text: "..." }, target: { screenId: "scr_xyz" } } 3. Poll or wait as above 4. Screenshot the updated screen and show it to the user
Flow 4: Idempotent message (safe retries)
Add
idempotency-key header on the send request. If the network drops and you retry with the same key, the server returns the existing run rather than creating a duplicate. The key must be ≤255 chars.
POST /api/v1/projects/:id/chat/messages idempotency-key: my-unique-request-id-abc123
Flow 5: One run at a time (conflict handling)
Only one active run is allowed per project. If you send a message while one is running, you get
409 CONFLICT. Wait for the active run to complete before sending the next message.
409 response → poll existing run → completed → send next message
Pagination
All list endpoints accept
limit (1–100, default 50) and offset (≥0). The response always includes pagination.total so you can page through all results.
GET /api/v1/projects?limit=10&offset=20
Common Mistakes
| Mistake | Fix |
|---|---|
Sending to without header | Add to every request |
| Using wrong scope | Check key's scopes match the endpoint (e.g. for sending messages) |
| Sending next message before run completes | Poll until / before next send |
Using on long generations | It blocks 300s max; have a fallback to polling for response |
HTTP URLs in | Only HTTPS URLs are accepted |
Assuming is present on | is absent until status is |