# Wslh (وصلة) > Wslh at wslh.app makes short links (wslh.app/), profile pages (wslh.app/@handle) with menus that take orders, and shows who opened them. It has a JSON REST API and an MCP server, both used with an API key. Human-readable docs: https://wslh.app/docs ## What Wslh is Wslh (Arabic: وصلة) is an Arabic-first web app at https://wslh.app for people and small businesses. It works in Arabic and English. - Short links: wslh.app/ with a custom name or a generated one, a destination the owner can change at any time, an optional end date, and a QR code. Anyone can shorten a link from the home page without an account and gets a private manage link for it. - Pages: one page per name at wslh.app/@handle. Used as a link page, a front door for a business, or a CV. Parts include links, a countdown, opening hours, products with prices, a contact form, a background image and sound, ready-made styles or custom colors, and six display languages. - Menus and orders: a page can carry a menu that takes orders, which the owner manages in the dashboard. - Numbers: visits and clicks over time, where visitors came from and their devices. Visitor addresses are scrambled before anything is saved. - AI assistants: an MCP server and a REST API let an assistant create links, design pages, edit menus, handle orders and read the numbers for the owner. - Sign up: https://wslh.app/register ## Basics - Base URL: https://wslh.app/api - Auth: send `Authorization: Bearer wslh_…` with every request. The account owner makes keys in the dashboard under Wslh AI → Connect assistants (https://wslh.app/dashboard/connect). A key is shown once; keep it on a server, never in a web page. - A key can use every endpoint below. It cannot change the account's email, password or keys, or delete the account. - JSON in and out. Times are ISO 8601 in UTC. Money is text with two decimals, such as "18.50". - Errors: an HTTP status and `{"status": 409, "field": "code", "message": "…"}`. `field` is present when one input is wrong. 403 with `"code": "email_not_verified"` means the owner must confirm their email first. 429 means slow down. - Limits: 3 custom link codes per account (generated codes are unlimited); 5 pages per account, 40 blocks per page; files up to 5 MB, 200 files or 200 MB per account. ## Links - `GET /v1/links`: the account's links, newest first. Each: `id, code, shortUrl, destination, title, active, expiresAt, createdAt, clicks`. - `POST /v1/links` `{"destination": "https://…", "code": "optional-custom", "title": "optional"}` → 201 with the link. Leave out `code` for a generated one. A taken code is 409 with `field: "code"`. - `PATCH /v1/links/{id}` with any of `destination, title, active, expiresAt` → the link. `active: false` pauses it. - `DELETE /v1/links/{id}` → 204. - `GET /v1/links/quota` → `{"customUsed": 1, "customLimit": 3}`. Example: ``` curl -X POST https://wslh.app/api/v1/links \ -H "Authorization: Bearer $WSLH_KEY" \ -H "Content-Type: application/json" \ -d '{"destination":"https://example.com","title":"My first link"}' ``` ## Analytics - `GET /v1/analytics/summary?days=30` (1 to 365) → `days, totalClicks, totalLinks, clicksByDay[{date, clicks}], topLinks[{id, code, destination, clicks}], referrers[{name, clicks}], devices[{name, clicks}], countries[{name, clicks}]`. ## Pages A page lives at wslh.app/@handle. Saving replaces the whole page: read it, change it, send every field back. - `GET /v1/profiles`: the account's pages: `id, handle, url, name, published, views, newOrders`. - `POST /v1/profiles` with a page → 201. `GET /v1/profiles/{id}`, `PUT /v1/profiles/{id}` (replace), `DELETE /v1/profiles/{id}`. - `GET /v1/profiles/available?handle=…` (no key needed) → `{"handle", "available"}`. - `GET /v1/pages/{handle}` (no key needed): a published page as visitors see it. Page fields: - `handle`: 3 to 30 English letters, digits, dots, dashes or underscores. - `name` (required, up to 80), `bio` (up to 300). - `theme`: forest, night, sand, mint, paper, or custom with `colors: {background, text, button, buttonText}` as #rrggbb. - `layout`: column or wide. `linkStyle`: pill or card. `status`: live, open or null. `published`: true or false. - `avatar`, `banner`: a file address (`/api/v1/files/…`) or an https:// picture, or empty. - `socials`: up to 12 `{platform, url}`; platforms: instagram, x, tiktok, snapchat, youtube, twitch, kick, discord, whatsapp, telegram, github, facebook, threads, spotify, steam. - `qr`: `{style: square|rounded|dots, eyes: square|rounded, foreground, background, logo: none|wslh|initial, caption: bool}`. - `blocks` (up to 40, in order): - `{"type":"link","label":"…","url":"https://…","icon":"map","subtitle":"optional"}`; icons: link, coffee, map, calendar, phone, mail, briefcase, cart, clipboard, star, play, music, gift, book, or a platform name. - `{"type":"heading","text":"…"}`, `{"type":"text","text":"…"}` - `{"type":"timeline","title":"Experience","items":[{"title":"…","meta":"…"}]}` - `{"type":"tags","title":"Skills","items":["…"]}` - `{"type":"menu"}` shows the page's menu. - `{"type":"image","url":"…","caption":"","link":""}`, `{"type":"gallery","title":"…","items":[{"url":"…","caption":""}]}` (up to 12) - `{"type":"file","url":"/api/v1/files/…","label":"Download my CV","name":"cv.pdf"}` offers a PDF. ## Menus and orders - `GET /v1/profiles/{id}/menu`, `PUT /v1/profiles/{id}/menu` (replace). Menu: `enabled, ordering, paused, currency (SAR|AED|KWD|BHD|QAR|OMR|EGP|USD), orderTypes [pickup|delivery|dinein], minimumOrder, deliveryFee, whatsapp, note, categories[{name, items[{name, description, price, image, available}]}]`. - `GET /v1/profiles/{id}/orders`: newest first: `id, number, status, createdAt, type, customer{name, phone}, note, currency, lines[{name, quantity, price, total}], subtotal, deliveryFee, total`. - `PATCH /v1/orders/{id}` `{"status": "new|done|cancelled"}`. ## Files - `POST /v1/files` as multipart/form-data with a field named `file` → 201 `{id, url, kind (image|document), contentType, name, size, createdAt}`. JPG, PNG, WebP, GIF or PDF, checked by content. Put `url` in a page. - `GET /v1/files`, `DELETE /v1/files/{id}`. `GET /v1/files/{id}` is public. ## MCP server - URL: https://wslh.app/api/mcp (Streamable HTTP, JSON answers), with `Authorization: Bearer wslh_…`. - Apps that cannot send headers (Claude, ChatGPT and Gemini connectors) use the personal link `https://wslh.app/api/mcp/wslh_…` from the dashboard. - Tools: list_links, create_link, update_link, delete_link, get_analytics, get_page_guide, list_pages, get_page, create_page, save_page, list_files, upload_file, create_upload_link, get_menu, save_menu, list_orders, update_order. - Call get_page_guide before designing a page; it lists every field and template recipe. - To add a CV or a photo: call upload_file with base64 `data` and a `name` when you have the file's bytes. Otherwise call create_upload_link, give the owner the link (it works for 30 minutes on any device, no sign-in, up to 10 files), wait until they say they are done, then call list_files for the addresses. Config for tools with a config file: ``` { "mcpServers": { "wslh": { "url": "https://wslh.app/api/mcp", "headers": { "Authorization": "Bearer wslh_…" } } } } ```