Desing 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 t...
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 t...
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
sleek.design 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
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)
| 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.
https://sleek.design. No data is sent to third parties.Authorization header to Sleek endpoints.imageUrls in chat messages, those URLs are fetched by Sleek's servers. Avoid passing URLs that contain sensitive content.When the user says something like "design a fitness tracking app" or "build me a settings screen":
message.text; Sleek's AI interprets natural languageYou 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.
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:
componentIds: [screenId])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.
| 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.
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 } }
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 /api/v1/projects/:projectId DELETE /api/v1/projects/:projectId → 204 No Content
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 } }
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 |
wait=false)Status
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" } }
wait=true)Blocks 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" } ] } } }
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
Takes a snapshot of one or more rendered components.
POST /api/v1/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 |
| (optional) | Top padding; overrides when provided |
| (optional) | Right padding; overrides when provided |
| (optional) | Bottom padding; overrides when provided |
| (optional) | Left padding; overrides when provided |
| | Any CSS color (hex, named, ) |
| | Overlay a subtle dot grid on the background |
Padding resolves with a cascade: per-side → axis → uniform. For example,
paddingTop falls back to paddingY, which falls back to padding. So { "padding": 20, "paddingX": 10, "paddingLeft": 5 } gives top/bottom 20px, right 10px, left 5px.
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.
{ "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 |
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.
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)
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
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
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
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
| 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 |
No automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.