Official HTTP API for file management and link lifecycle operations.
#API Base URL
https://api.wisylink.com
#Authentication
| Header | Required | Format | Notes |
|---|---|---|---|
x-api-key | Yes (or use Authorization) | <api_key> | Preferred header for server-to-server requests. |
Authorization | Yes (or use x-api-key) | Bearer <api_key> | Same authorization behavior. |
#Request/Response Basics
| Rule | Value |
|---|---|
| JSON endpoints | Content-Type: application/json |
| Chunk upload body | Content-Type: application/octet-stream |
| Timestamp format | Epoch milliseconds (number) |
| File id format | 24-character hex string |
| Link id format | 6-character string of lowercase letters and digits |
| Hosted link URL format | https://<id>.wisylink.com |
#Usage
Builds started through the API count against your account's subscription usage windows (5-hour + daily limits on your plan), the same windows as builds started in the web and mobile apps; chat itself never uses them. When a window is full, requests still answer and builds wait, then start by themselves when it refills. Reference files add no upload fee.
Each API key can also carry a credit limit, an optional secondary throttle: a dollar cap per day, week or month of at most $10. See Credit Limit Exceeded.
#File Constraints
| Rule | Value |
|---|---|
| Max upload size | 25 MB (26214400 bytes) |
| Max chunk size | 4 MB (4194304 bytes) |
| Allowed extensions | jpeg/jpg, png, webp, gif, heic, svg, mp3, mp4, pdf, xlsx, docx, csv, txt, json, html, zip, wasm |
| Type detection | By file content, not by name: a file whose content is not one of these types is rejected |
| Empty uploads | Rejected |
#Endpoints
#Files
#Create File
/filesStarts a new file upload session and returns the file id to use in chunk uploads.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
name | JSON body | string | No | Original file name hint. Extension is replaced with detected real extension before persistence. |
Request example:
curl -X POST "https://api.wisylink.com/files" \
-H "x-api-key: <api_key>" \
-H "Content-Type: application/json" \
-d '{
"name": "my-original-video.mov"
}'Response (201):
| Field | Type | Description |
|---|---|---|
id | string | File identifier (24-char hex). |
created_at | number | Epoch milliseconds. |
{
"id": "67e6f6e6c5a91e4d2d9b0a11",
"created_at": 1762432496000
}#Upload File
/files/chunksUploads raw file chunks to an existing file id. Each request accepts at most 4 MB.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | Query | string | Yes | File id from Create File. |
last | Query | boolean | No | Defaults to false. Set true for the final chunk. |
| (body) | Raw body | binary | Yes | application/octet-stream, max 4194304 bytes. |
Request example:
curl -X POST "https://api.wisylink.com/files/chunks?id=<file_id>&last=true" \
-H "x-api-key: <api_key>" \
-H "Content-Type: application/octet-stream" \
--data-binary "@./chunk-last.bin"Response (200):
| Field | Type | Description |
|---|---|---|
id | string | File identifier. |
ok | boolean | true when chunk write is accepted. |
{
"id": "67e6f6e6c5a91e4d2d9b0a11",
"ok": true
}Notes:
- Upload sessions expire automatically if not completed within
15minutes. - The final chunk must be sent with
last=true; that call finalizes and processes the file. - A file of a type that is not allowed answers
400 bad_requestwith the allowed extensions inmessage. A chunk over4 MB, a file over25 MBor a full storage quota answers413 bad_requestwith amessage.
#Get File
/files/:idReturns metadata for a single uploaded file by id.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | Path | string | Yes | Must be a valid id (24-char hex). |
Request example:
curl "https://api.wisylink.com/files/67e6f6e6c5a91e4d2d9b0a11" \
-H "x-api-key: <api_key>"Response (200):
| Field | Type | Description |
|---|---|---|
id | string | File identifier (24-char hex). |
content_type | string | MIME content type. |
name | string | Persisted display file name (original base name + detected extension). |
size | number | Byte size. |
created_at | number | Epoch milliseconds. |
updated_at | number | Epoch milliseconds. |
{
"id": "67e6f6e6c5a91e4d2d9b0a11",
"content_type": "video/mp4",
"name": "my-original-video.mp4",
"size": 128934,
"created_at": 1762432496000,
"updated_at": 1762432496000
}#Delete File
/files/:idPermanently removes a single uploaded file and its stored object. References to this file id in any link file_ids are removed automatically.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | Path | string | Yes | Must be a valid id (24-char hex). |
Request example:
curl -X DELETE "https://api.wisylink.com/files/67e6f6e6c5a91e4d2d9b0a11" \
-H "x-api-key: <api_key>"Response (200):
{ "ok": true }#Links
#Chat Link
/chatCreates a new link or continues an existing one. The Wisy agent reads the message, builds a hosted page, and reports back. Privacy and page meta are resolved by the agent — no explicit type or settings fields in the request.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | JSON body | string | No | Existing link id. Omit to create a new link; provide to continue an existing one. |
message | JSON body | string | Yes | Your request — describe what to build or change. Max 5000 characters. |
file_ids | JSON body | string[] | No | Max 10, owned by the same API key owner. Duplicates are ignored; ids after the first 10 are dropped without an error. |
Notes:
- Omit
idto start a fresh link; the build begins immediately andstatusisbuildinguntil it settles. - Include
idto continue generation on an existing link. The server tracks conversation history — send only the new message. file_idsreferences uploaded files. Use Create File and Upload File first, then pass the returned id values. Only the first10distinct ids of a message are used, and the ones after them are neither attached nor checked, so send at most10. An id that does not exist or belongs to another account answers400 bad_requestwith the unknown ids inmissing_file_ids.statusisbuildingwhile any build of the link runs. A message sent while the link is building is queued behind the running build;queuedis the status of a link whose next build was accepted and is waiting to start, because the previous build is settling, every build slot of your plan is busy, or your plan's 5-hour or daily usage window is full; in the last case it starts by itself when the window refills.urlis the hosted page URL; it goes live once the build finishes (statusbecomescompleted).
Request example:
# New link
curl -X POST "https://api.wisylink.com/chat" \
-H "x-api-key: <api_key>" \
-H "Content-Type: application/json" \
-d '{
"message": "Build a landing page for Ember Coffee with a menu and a contact form.",
"file_ids": ["67e6f6e6c5a91e4d2d9b0a11"]
}'Response (201 for new link, 200 for continued link):
| Field | Type | Description |
|---|---|---|
id | string | Link identifier (6 lowercase letters or digits). |
url | string | Hosted page URL. |
status | string | building \ |
answer | string | Wisy's reply to the request. |
created_at | number | Epoch milliseconds. |
updated_at | number | Epoch milliseconds. |
{
"id": "k7m2xq",
"url": "https://k7m2xq.wisylink.com",
"status": "building",
"answer": "On it — building your Ember Coffee landing page now.",
"created_at": 1762432496000,
"updated_at": 1762432496000
}#List Links
/linksReturns your links, newest first, with page-based pagination.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
page | Query | number | No | 1-based page number. Defaults to 1. |
limit | Query | number | No | Items per page, 1..100. Defaults to 20. |
Request example:
curl "https://api.wisylink.com/links?page=1&limit=20" \
-H "x-api-key: <api_key>"Response (200):
| Field | Type | Description |
|---|---|---|
items | object[] | Links for this page; each item has the same shape as Get Link. |
page | number | Current page. |
limit | number | Items per page. |
total | number | Total links across all pages. |
total_pages | number | Total page count. |
has_prev | boolean | Whether a previous page exists. |
has_next | boolean | Whether a next page exists. |
{
"items": [
{
"id": "k7m2xq",
"url": "https://k7m2xq.wisylink.com",
"status": "completed",
"file_ids": ["67e6f6e6c5a91e4d2d9b0a11"],
"created_at": 1762432496000,
"updated_at": 1762432596000
}
],
"page": 1,
"limit": 20,
"total": 1,
"total_pages": 1,
"has_prev": false,
"has_next": false
}#Get Link
/links/:idReturns a single link by id with its hosted-page URL and metadata.
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | Path | string | Yes | Link id (6 lowercase letters or digits). |
Notes:
urlis the hosted page URL.file_idslists the reference files attached to the link.
Request example:
curl "https://api.wisylink.com/links/k7m2xq" \
-H "x-api-key: <api_key>"Response (200):
| Field | Type | Description |
|---|---|---|
id | string | Link identifier (6 lowercase letters or digits). |
url | string | Hosted page URL. |
status | string | building \ |
file_ids | string[] | Reference files attached to the link. |
created_at | number | Epoch milliseconds. |
updated_at | number | Epoch milliseconds. |
{
"id": "k7m2xq",
"url": "https://k7m2xq.wisylink.com",
"status": "completed",
"file_ids": ["67e6f6e6c5a91e4d2d9b0a11"],
"created_at": 1762432496000,
"updated_at": 1762432596000
}#Delete Link
/links/:idPermanently removes a single link by id. Files listed in the link file_ids are deleted together (file record + stored object).
Request:
| Field | Where | Type | Required | Rules |
|---|---|---|---|---|
id | Path | string | Yes | Link id (6 lowercase letters or digits). |
Request example:
curl -X DELETE "https://api.wisylink.com/links/k7m2xq" \
-H "x-api-key: <api_key>"Response (200):
{ "ok": true }#Errors
#Unauthorized
unauthorizedReturned when API key is missing or invalid.
{
"error": "unauthorized",
"message": "Missing or invalid API key. Provide `x-api-key` or `Authorization: Bearer <key>`."
}#Limit Reached
limit_reachedNo longer returned for the account's subscription usage windows: when the 5-hour or daily window is full, POST /chat still answers and the build waits with status queued, then starts by itself when the window refills. Code that still handles it can stay as it is (the body below carried reason and reset_at, epoch milliseconds).
{
"error": "limit_reached",
"reason": "5h_limit",
"reset_at": 1762432496000
}#Credit Limit Exceeded
credit_limit_exceededReturned on any endpoint when the API key's spend for the current period reaches its credit limit. The limit is a dollar cap of at most $10 per period (day, week or month, in UTC; weeks start on Monday). limit, used, and remaining are USD; resets_at is epoch milliseconds. A turn is charged after it finishes, so used can end slightly above limit.
{
"error": "credit_limit_exceeded",
"message": "API key credit limit is exceeded for the current period.",
"limit": 10,
"used": 10.04,
"remaining": 0,
"period": "month",
"resets_at": 1762432496000
}#Too Many Builds
build_concurrency_limitReturned by POST /chat when too many builds are already running for the plan. Wait for one to finish, then retry. limit is the concurrent-build allowance.
{
"error": "build_concurrency_limit",
"message": "Too many builds running at once for your plan. Wait for one to finish.",
"limit": 3
}#Rate Limited
rate_limitedReturned when the account sends requests faster than an endpoint's per-minute limit: POST /chat allows 20 requests per minute, and file uploads, file deletes and DELETE /links/:id have limits of their own. Wait a short while, then retry.
{ "error": "rate_limited" }#Bad Request
bad_requestReturned for invalid request shape, invalid types, invalid formats, or missing required values: for example an empty or too long message, file_ids that do not exist (listed in missing_file_ids), or a file of a type that is not allowed.
#Payload Too Large
payload_too_largeReturned by POST /chat when the JSON body is larger than 32 KB. Oversized file chunks and files answer 413 bad_request instead, see Upload File.
{ "error": "payload_too_large" }#Not Found
not_foundReturned when target file or link does not exist for the authenticated owner.
#Chat Unavailable
chat_unavailableReturned by POST /chat when the agent cannot answer the message right now. Try again in a moment.
{
"error": "chat_unavailable",
"message": "Wisy is briefly unavailable — please try again in a moment."
}