WisyLink API

Official API reference and integration conventions for WisyLink.

Sections

Official HTTP API for file management and link lifecycle operations.

#API Base URL

  • https://api.wisylink.com

#Authentication

HeaderRequiredFormatNotes
x-api-keyYes (or use Authorization)<api_key>Preferred header for server-to-server requests.
AuthorizationYes (or use x-api-key)Bearer <api_key>Same authorization behavior.

#Request/Response Basics

RuleValue
JSON endpointsContent-Type: application/json
Chunk upload bodyContent-Type: application/octet-stream
Timestamp formatEpoch milliseconds (number)
File id format24-character hex string
Link id format6-character string of lowercase letters and digits
Hosted link URL formathttps://<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

RuleValue
Max upload size25 MB (26214400 bytes)
Max chunk size4 MB (4194304 bytes)
Allowed extensionsjpeg/jpg, png, webp, gif, heic, svg, mp3, mp4, pdf, xlsx, docx, csv, txt, json, html, zip, wasm
Type detectionBy file content, not by name: a file whose content is not one of these types is rejected
Empty uploadsRejected

#Endpoints

#Files

#Create File

POST/files

Starts a new file upload session and returns the file id to use in chunk uploads.

Request:

FieldWhereTypeRequiredRules
nameJSON bodystringNoOriginal file name hint. Extension is replaced with detected real extension before persistence.

Request example:

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"
  }'
bash

Response (201):

FieldTypeDescription
idstringFile identifier (24-char hex).
created_atnumberEpoch milliseconds.
Examplejson
{
  "id": "67e6f6e6c5a91e4d2d9b0a11",
  "created_at": 1762432496000
}

#Upload File

POST/files/chunks

Uploads raw file chunks to an existing file id. Each request accepts at most 4 MB.

Request:

FieldWhereTypeRequiredRules
idQuerystringYesFile id from Create File.
lastQuerybooleanNoDefaults to false. Set true for the final chunk.
(body)Raw bodybinaryYesapplication/octet-stream, max 4194304 bytes.

Request example:

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"
bash

Response (200):

FieldTypeDescription
idstringFile identifier.
okbooleantrue when chunk write is accepted.
Examplejson
{
  "id": "67e6f6e6c5a91e4d2d9b0a11",
  "ok": true
}

Notes:

  • Upload sessions expire automatically if not completed within 15 minutes.
  • 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_request with the allowed extensions in message. A chunk over 4 MB, a file over 25 MB or a full storage quota answers 413 bad_request with a message.

#Get File

GET/files/:id

Returns metadata for a single uploaded file by id.

Request:

FieldWhereTypeRequiredRules
idPathstringYesMust be a valid id (24-char hex).

Request example:

Request example
curl "https://api.wisylink.com/files/67e6f6e6c5a91e4d2d9b0a11" \
  -H "x-api-key: <api_key>"
bash

Response (200):

FieldTypeDescription
idstringFile identifier (24-char hex).
content_typestringMIME content type.
namestringPersisted display file name (original base name + detected extension).
sizenumberByte size.
created_atnumberEpoch milliseconds.
updated_atnumberEpoch milliseconds.
Examplejson
{
  "id": "67e6f6e6c5a91e4d2d9b0a11",
  "content_type": "video/mp4",
  "name": "my-original-video.mp4",
  "size": 128934,
  "created_at": 1762432496000,
  "updated_at": 1762432496000
}

#Delete File

DELETE/files/:id

Permanently removes a single uploaded file and its stored object. References to this file id in any link file_ids are removed automatically.

Request:

FieldWhereTypeRequiredRules
idPathstringYesMust be a valid id (24-char hex).

Request example:

Request example
curl -X DELETE "https://api.wisylink.com/files/67e6f6e6c5a91e4d2d9b0a11" \
  -H "x-api-key: <api_key>"
bash

Response (200):

Examplejson
{ "ok": true }
POST/chat

Creates 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:

FieldWhereTypeRequiredRules
idJSON bodystringNoExisting link id. Omit to create a new link; provide to continue an existing one.
messageJSON bodystringYesYour request — describe what to build or change. Max 5000 characters.
file_idsJSON bodystring[]NoMax 10, owned by the same API key owner. Duplicates are ignored; ids after the first 10 are dropped without an error.

Notes:

  • Omit id to start a fresh link; the build begins immediately and status is building until it settles.
  • Include id to continue generation on an existing link. The server tracks conversation history — send only the new message.
  • file_ids references uploaded files. Use Create File and Upload File first, then pass the returned id values. Only the first 10 distinct ids of a message are used, and the ones after them are neither attached nor checked, so send at most 10. An id that does not exist or belongs to another account answers 400 bad_request with the unknown ids in missing_file_ids.
  • status is building while any build of the link runs. A message sent while the link is building is queued behind the running build; queued is 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.
  • url is the hosted page URL; it goes live once the build finishes (status becomes completed).

Request example:

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"]
  }'
bash

Response (201 for new link, 200 for continued link):

FieldTypeDescription
idstringLink identifier (6 lowercase letters or digits).
urlstringHosted page URL.
statusstringbuilding \
answerstringWisy's reply to the request.
created_atnumberEpoch milliseconds.
updated_atnumberEpoch milliseconds.
Examplejson
{
  "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
}
GET/links

Returns your links, newest first, with page-based pagination.

Request:

FieldWhereTypeRequiredRules
pageQuerynumberNo1-based page number. Defaults to 1.
limitQuerynumberNoItems per page, 1..100. Defaults to 20.

Request example:

Request example
curl "https://api.wisylink.com/links?page=1&limit=20" \
  -H "x-api-key: <api_key>"
bash

Response (200):

FieldTypeDescription
itemsobject[]Links for this page; each item has the same shape as Get Link.
pagenumberCurrent page.
limitnumberItems per page.
totalnumberTotal links across all pages.
total_pagesnumberTotal page count.
has_prevbooleanWhether a previous page exists.
has_nextbooleanWhether a next page exists.
Examplejson
{
  "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/links/:id

Returns a single link by id with its hosted-page URL and metadata.

Request:

FieldWhereTypeRequiredRules
idPathstringYesLink id (6 lowercase letters or digits).

Notes:

  • url is the hosted page URL.
  • file_ids lists the reference files attached to the link.

Request example:

Request example
curl "https://api.wisylink.com/links/k7m2xq" \
  -H "x-api-key: <api_key>"
bash

Response (200):

FieldTypeDescription
idstringLink identifier (6 lowercase letters or digits).
urlstringHosted page URL.
statusstringbuilding \
file_idsstring[]Reference files attached to the link.
created_atnumberEpoch milliseconds.
updated_atnumberEpoch milliseconds.
Examplejson
{
  "id": "k7m2xq",
  "url": "https://k7m2xq.wisylink.com",
  "status": "completed",
  "file_ids": ["67e6f6e6c5a91e4d2d9b0a11"],
  "created_at": 1762432496000,
  "updated_at": 1762432596000
}
DELETE/links/:id

Permanently removes a single link by id. Files listed in the link file_ids are deleted together (file record + stored object).

Request:

FieldWhereTypeRequiredRules
idPathstringYesLink id (6 lowercase letters or digits).

Request example:

Request example
curl -X DELETE "https://api.wisylink.com/links/k7m2xq" \
  -H "x-api-key: <api_key>"
bash

Response (200):

Examplejson
{ "ok": true }

#Errors

#Unauthorized

401unauthorized

Returned when API key is missing or invalid.

Examplejson
{
  "error": "unauthorized",
  "message": "Missing or invalid API key. Provide `x-api-key` or `Authorization: Bearer <key>`."
}

#Limit Reached

429limit_reached

No 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).

Examplejson
{
  "error": "limit_reached",
  "reason": "5h_limit",
  "reset_at": 1762432496000
}

#Credit Limit Exceeded

429credit_limit_exceeded

Returned 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.

Examplejson
{
  "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

429build_concurrency_limit

Returned 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.

Examplejson
{
  "error": "build_concurrency_limit",
  "message": "Too many builds running at once for your plan. Wait for one to finish.",
  "limit": 3
}

#Rate Limited

429rate_limited

Returned 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.

Examplejson
{ "error": "rate_limited" }

#Bad Request

400bad_request

Returned 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

413payload_too_large

Returned 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.

Examplejson
{ "error": "payload_too_large" }

#Not Found

404not_found

Returned when target file or link does not exist for the authenticated owner.

#Chat Unavailable

500chat_unavailable

Returned by POST /chat when the agent cannot answer the message right now. Try again in a moment.

Examplejson
{
  "error": "chat_unavailable",
  "message": "Wisy is briefly unavailable — please try again in a moment."
}