flye.win

// sdks

Official SDKs

Official clients for JavaScript/TypeScript and Python. Every endpoint of every API becomes a method with the same parameters as this documentation, and the SDK takes care of the key, errors, timeouts and retries. This page covers everything, from installing to the full reference of every method.

version 0.1.0 no dependencies npm ↗ PyPI ↗ OpenAPI ↗
Examples in

Installation

npm install flyewin
# or: pnpm add flyewin · yarn add flyewin · bun add flyewin
  • —JavaScript/TypeScript: Node 18 or newer, Deno and Bun. Works with import (ESM) and require (CommonJS), and ships with TypeScript types.
  • —Python: 3.8 or newer. Uses only the standard library, no requests or any other dependency.

Use the SDK on your server. A flye_sk_ key in the browser or in a mobile app can be copied by anyone. Your front end calls your back end, and the back end calls flye.win.

// CommonJS (require) also works:
const Flye = require("flyewin");
const { FlyeError } = require("flyewin");

First call

  1. 01

    Create a key

    In Dashboard → Keys. To start, pick Test: it needs no plan and uses no quota.

  2. 02

    Keep the key in an environment variable

    The SDK reads FLYE_API_KEY on its own, so the key stays out of your code and out of git.

    # macOS / Linux
    export FLYE_API_KEY="flye_test_…"
    
    # Windows (PowerShell)
    $env:FLYE_API_KEY = "flye_test_…"
  3. 03

    Call the API

    import Flye from "flyewin";
    
    const flye = new Flye(); // reads FLYE_API_KEY
    
    const data = await flye.utils.uuid({ count: 2 });
    console.log(data.uuids);

    The method returns the response JSON already parsed: an object in JavaScript and a dict in Python. The shape of each response is in the reference at the end of this page.

Configuration

Everything is optional. With nothing set, the client reads the key from FLYE_API_KEY and uses the defaults below. Create a single client and reuse it across your app.

JavaScriptPythondefaultdescription
apiKeyapi_keyFLYE_API_KEYYour key (flye_sk_… or flye_test_…). Without it and without the environment variable, the client isn't created.
baseURLbase_urlhttps://flye.win/v1API address. Only change it for tests or your own proxy.
timeouttimeout30000 ms · 30.0 sMaximum time per request: milliseconds in JS, seconds in Python.
maxRetriesmax_retries2How many times to repeat a call that failed for a temporary reason. 0 turns it off.
fetch—globalThis.fetchJavaScript only: another fetch implementation, for old runtimes or tests.
import Flye from "flyewin";

const flye = new Flye(process.env.FLYE_API_KEY, {
  timeout: 10_000, // ms, per request
  maxRetries: 3,
});

// or pass everything in one object:
const other = new Flye({ apiKey: "flye_test_...", maxRetries: 0 });

Environment variables read by both SDKs: FLYE_API_KEY (the key) and FLYE_BASE_URL (the address). What you pass in code takes precedence.

Test keys

With a flye_test_ key the code is exactly the same: every method returns the documented example response, with no plan and no quota used (30 requests per minute and 1,000 per day). Required parameters and routes are checked as in production, so an integration mistake shows up while testing.

const flye = new Flye("flye_test_...");

const data = await flye.utils.hash({ text: "hello" });
console.log(flye.lastResponse.headers.get("x-flye-mode")); // "test"

Use the test key in development and CI. To go live, just change FLYE_API_KEY to a flye_sk_ key.

Handling errors

Every failure becomes a FlyeError: an API error response, a timeout, a network failure or a missing parameter. Branch on code, which is stable. The message is for people and may change.

fielddescription
codeError code, such as rate_limited or invalid_api_key. It's the same error.code the API returns.
statusHTTP status (401, 429…). Empty when the request never reached the API (network or timeout).
messageHuman-readable explanation, in the account's language.
bodyThe error response body, already parsed from JSON.
headersThe response headers (Retry-After, X-RateLimit-*…).
import Flye, { FlyeError } from "flyewin";

const flye = new Flye();

try {
  const data = await flye.utils.hash({ text: "hello" });
} catch (err) {
  if (!(err instanceof FlyeError)) throw err;

  switch (err.code) {
    case "invalid_api_key":
      // wrong or revoked key
      break;
    case "no_subscription":
      // activate a plan for this API in the dashboard
      break;
    case "rate_limited":
    case "quota_exceeded":
      // slow down / upgrade the plan
      break;
    default:
      console.error(err.status, err.code, err.message);
  }
}

Errors raised by the SDK itself

These don't come from the API: the SDK detects them before or during the call.

codewhen it happens
missing_api_keyNo key in code nor in FLYE_API_KEY. Happens when creating the client.
missing_paramA parameter that goes in the path is missing, like the id in getPack. The call isn't sent.
invalid_fileThe value given to an upload isn't an accepted file (see Uploads).
timeoutThe response didn't arrive within the timeout.
network_errorNo connection, DNS failed or the connection dropped, after the retries.

The full list of API error codes is in Documentation → Errors.

Retries

The SDK only repeats what is safe to repeat:

  • —Network failures and 5xx errors, only on GET calls. A POST (like an upload) is never repeated on its own, so nothing gets duplicated.
  • —429 with a Retry-After of up to 60 seconds (per-minute limit), on any method: the SDK waits as asked and tries again.
  • —Never repeated: monthly quota used up, invalid key, no plan or a wrong parameter. Trying again wouldn't help.
  • —Up to maxRetries times (default 2), with growing waits: about 0.5 s, 1 s, 2 s…
// Whole client:
const flye = new Flye(undefined, { maxRetries: 4 });

// Only this call (0 = never retry):
await flye.cdn.upload({ image, project: "shop" }, { maxRetries: 0 });

In JavaScript you can change it per call, in the second argument. In Python the setting applies to the client: create another client if you need different behavior.

Timeouts and cancelling

The default timeout is 30 seconds per request, including downloading the response. Change it for the whole client or a single call. In JavaScript you can also cancel with an AbortSignal. When time runs out, the error code is timeout.

// Per call, in milliseconds:
await flye.stickers.search({ q: "cat" }, { timeout: 5_000 });

// Cancel with an AbortController (e.g. the user left the page):
const controller = new AbortController();
const pending = flye.stickers.search({ q: "cat" }, { signal: controller.signal });
controller.abort();

Limits and quota

The limit headers of the last response stay on the client: lastResponse in JavaScript and last_response in Python. Use them to show quota to your users or to slow down before hitting the limit.

const data = await flye.utils.uuid();
const h = flye.lastResponse.headers;

console.log(h.get("x-ratelimit-remaining")); // left in this minute
console.log(h.get("x-quota-remaining"));     // left this month

With several calls at once, lastResponse holds the one that finished last. Read it right after the await or use one client per task.

File uploads

Parameters of type file (like image in cdn.upload) accept several forms. The SDK builds the multipart/form-data body and guesses the file type from its name.

  • —JavaScript: Blob or File, Buffer/Uint8Array/ArrayBuffer, or { data, filename, contentType } to name the bytes.
  • —Python: a file opened in binary mode, a path (str or Path), bytes, or the tuple (name, bytes, type).
import { openAsBlob } from "node:fs";
import { readFile } from "node:fs/promises";

// Node 20+: a Blob straight from disk
await flye.cdn.upload({ image: await openAsBlob("photo.jpg"), project: "shop" });

// Any Node: bytes + a file name
await flye.cdn.upload({
  image: { data: await readFile("photo.jpg"), filename: "photo.jpg" },
  project: "shop",
  folder: "products",
});

// A File received by your server (Next.js, Hono, Remix...)
const form = await request.formData();
await flye.cdn.upload({ image: form.get("image"), project: "shop" });

Per end-user limits

On plans with per end-user limits (like Scale), pass endUserId / end_user_id with a stable identifier for each user of your platform, preferably a hash. The SDK sends it in the X-End-User-Id header, and the per-minute limit then applies to each user. The parameter only exists on methods that accept the header.

// Scale plan: the per-minute limit applies to each of your users
const data = await flye.stickers.search({
  q: "cat",
  endUserId: hash(user.id), // sent as the X-End-User-Id header
});

TypeScript and types

The npm package ships index.d.ts: every method and parameter has a type and a description in your editor. Parameter types are named <Api><Method>Params, like StickersSearchParams. Responses are any: the shape of each one is in the reference below. In Python, the package has type hints (py.typed) for mypy, pyright and your editor.

import Flye, { FlyeError, type StickersSearchParams } from "flyewin";

const flye = new Flye();

const params: StickersSearchParams = { q: "cat", limit: 10 };
const data = await flye.stickers.search(params);

Newer parameters

When an API gains a parameter before you update the SDK, pass it anyway: anything the SDK doesn't know goes to the API unchanged (in the query for GET and DELETE, in the JSON body otherwise). In Python, flye.request calls any path directly.

// Parameters newer than your SDK version are sent as-is:
await flye.utils.uuid({ count: 2, someNewOption: true });

Using it on a server

Create the client once, when your app starts, and use it in every route. Pass the error on to your front end with the right status, and never send the key back. The Python client is synchronous: in async frameworks, run the call in a thread.

// server.js (Express). One client for the whole app.
import express from "express";
import Flye, { FlyeError } from "flyewin";

const app = express();
const flye = new Flye();

app.get("/stickers", async (req, res) => {
  try {
    res.json(await flye.stickers.search({ q: String(req.query.q ?? "") }));
  } catch (err) {
    const status = err instanceof FlyeError && err.status ? err.status : 502;
    res.status(status).json({ error: err.code ?? "upstream_error" });
  }
});

app.listen(3000);

Versions and updates

Current version: 0.1.0. The SDKs follow the /v1 API: new versions only add methods and parameters, without breaking existing code.

npm install flyewin@latest
pip install --upgrade flyewin

Using another language? The OpenAPI spec generates clients for Go, PHP, Java, C#, Ruby and more. And each API page has ready-made examples in curl, Go and PHP.

// reference

Method reference

Every API and every method, with parameters in both SDKs, an example to copy and the response shape. In JavaScript parameters go in one object; in Python, as keyword arguments. Those that go in the URL path can also be passed by position in Python.

Stickers

Search stickers and animated GIFs, with ready-to-use links.

flye.stickers · flye.stickers

API page
methodHTTPdescription
search GET /stickers/search Search stickers
listPackslist_packs GET /stickers/packs List packs
getPackget_pack GET /stickers/packs/{id} Stickers in a pack
GET /v1/stickers/packs

List packs

flye.stickers.listPacks() · flye.stickers.list_packs()

Lists the packs found for the term, with a cover sticker, so you can build a picker.

parameters

JS · Pythontypein the APIdescription
q required string qquery Search term, 2 to 80 characters. E.g.: gato
endUserIdend_user_id optional string X-End-User-Idheader Scale plan: identifies the user on your platform, so the limit applies per user and not to the account. Use a stable id, preferably a hash.
maxWaitMsmax_wait_ms optional integer max_wait_msquery Longest wait for a term never searched before, 0 to 15000 ms. Past that, the response returns right away with pending=true and the search continues: repeat the call shortly. Without it, waits for the result. E.g.: 300
limit optional integer limitquery Packs per page, 1 to 20. Defaults to 10. E.g.: 5
page optional integer pagequery Page, starting at 1.
type optional string typequery all, animated or static. Defaults to all.
example

flye.stickers.listPacks(params: StickersListPacksParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.stickers.listPacks({
  q: "gato",
  maxWaitMs: 300,
  limit: 5,
});
console.log(data);

response (example)

{
  "query": "gato",
  "total": 12,
  "page": 1,
  "packs": [
    {
      "id": "pk_3f9a1c7e2b8d4a60c1e5",
      "name": "Gatos engraçados",
      "author": "Ana",
      "animated": true,
      "count": 30,
      "cover": "https://flye.win/media/stickers/8e1f0c3ab94d27f6a5c1e08d7b3f4a12.webp"
    }
  ]
}
GET /v1/stickers/packs/{id}

Stickers in a pack

flye.stickers.getPack() · flye.stickers.get_pack()

Returns every sticker in a pack by its id.

parameters

JS · Pythontypein the APIdescription
id required string idpath · positional in Python Pack id, from /search or /packs.
example

flye.stickers.getPack(params: StickersGetPackParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.stickers.getPack({ id: "<id>" });
console.log(data);

response (example)

{
  "pack": {
    "id": "pk_3f9a1c7e2b8d4a60c1e5",
    "name": "Gatos engraçados",
    "author": "Ana",
    "animated": true,
    "count": 30
  },
  "stickers": [
    {
      "id": "8e1f0c3ab94d27f6a5c1e08d7b3f4a12",
      "url": "https://flye.win/media/stickers/8e1f0c3ab94d27f6a5c1e08d7b3f4a12.webp",
      "format": "webp",
      "animated": true
    }
  ]
}

CDN

Image hosting with public links, organized in projects and folders.

flye.cdn · flye.cdn

API page
methodHTTPdescription
upload POST /cdn/upload Upload an image
listProjectslist_projects GET /cdn/projects List projects
createProjectcreate_project POST /cdn/projects Create a project
getProjectget_project GET /cdn/projects/{project} List images
getImageget_image GET /cdn/images/{id} Image details
deleteImagedelete_image DELETE /cdn/images/{id} Delete an image
deleteProjectdelete_project DELETE /cdn/projects/{project} Delete a project
getUsageget_usage GET /cdn/usage Storage and limits
POST /v1/cdn/upload

Upload an image

flye.cdn.upload() · flye.cdn.upload()

Uploads one image as multipart/form-data. The project is created the first time you use it. Accepts jpg, jpeg, png, gif, webp, svg, up to your plan's per-file limit. The type is checked from the file's content, and SVG with scripts or external links is rejected.

parameters

JS · Pythontypein the APIdescription
image required file imagefile The file. Also accepted under the name file.
project required string projectform Project name: letters, numbers, - and _, up to 48 characters. Uppercase becomes lowercase.
folder optional string folderform Folder inside the project, optional, with the same rules as the name.
example

flye.cdn.upload(params: CdnUploadParams, options?: RequestOptions): Promise<any>

import { openAsBlob } from "node:fs";
import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.upload({
  image: await openAsBlob("photo.jpg"),
  project: "<project>",
});
console.log(data);

response (example)

{
  "id": "6f1c2a9e-4b7d-4e1a-9c3f-2d8b7a6e5f40",
  "project": "loja",
  "folder": "produtos",
  "filename": "1743580800000000000.jpg",
  "original_name": "tenis-azul.jpg",
  "url": "https://cdn.flye.win/images/fw_9c41d2e07ab3f5168e2d/produtos/1743580800000000000.jpg",
  "size": 204800,
  "content_type": "image/jpeg",
  "created_at": "2026-11-02T13:30:00Z"
}
GET /v1/cdn/projects

List projects

flye.cdn.listProjects() · flye.cdn.list_projects()

Lists your account's projects, with the image count and storage used by each.

parameters

No parameters.

example

flye.cdn.listProjects(params?: CdnListProjectsParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.listProjects();
console.log(data);

response (example)

{
  "projects": [
    { "name": "loja", "images": 128, "bytes": 52428800, "created_at": "2026-10-01T12:00:00Z" }
  ]
}
POST /v1/cdn/projects

Create a project

flye.cdn.createProject() · flye.cdn.create_project()

Creates an empty project. Optional: uploading already creates the project when it doesn't exist.

parameters

JS · Pythontypein the APIdescription
name required string namebody Project name.
example

flye.cdn.createProject(params: CdnCreateProjectParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.createProject({ name: "<name>" });
console.log(data);

response (example)

{ "name": "loja", "images": 0, "bytes": 0, "created_at": "2026-11-02T13:30:00Z" }
GET /v1/cdn/projects/{project}

List images

flye.cdn.getProject() · flye.cdn.get_project()

Lists the project's images, newest first, and the folders it has.

parameters

JS · Pythontypein the APIdescription
project required string projectpath · positional in Python Project name.
folder optional string folderquery Only this folder's images. Without it, every image in the project. Use / for only those outside folders.
page optional integer pagequery Page, starting at 1.
perPageper_page optional integer per_pagequery Items per page, 1 to 100. Defaults to 20.
example

flye.cdn.getProject(params: CdnGetProjectParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.getProject({ project: "<project>" });
console.log(data);

response (example)

{
  "project": "loja",
  "folders": [{ "name": "produtos", "images": 96 }],
  "images": [{
    "id": "6f1c2a9e-4b7d-4e1a-9c3f-2d8b7a6e5f40",
    "project": "loja",
    "folder": "produtos",
    "filename": "1743580800000000000.jpg",
    "original_name": "tenis-azul.jpg",
    "url": "https://cdn.flye.win/images/fw_9c41d2e07ab3f5168e2d/produtos/1743580800000000000.jpg",
    "size": 204800,
    "content_type": "image/jpeg",
    "created_at": "2026-11-02T13:30:00Z"
  }],
  "pagination": { "page": 1, "per_page": 20, "total": 96, "total_pages": 5 }
}
GET /v1/cdn/images/{id}

Image details

flye.cdn.getImage() · flye.cdn.get_image()

Returns one of your images by the id returned on upload.

parameters

JS · Pythontypein the APIdescription
id required string idpath · positional in Python Image id.
example

flye.cdn.getImage(params: CdnGetImageParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.getImage({ id: "<id>" });
console.log(data);

response (example)

{
  "id": "6f1c2a9e-4b7d-4e1a-9c3f-2d8b7a6e5f40",
  "project": "loja",
  "folder": "produtos",
  "filename": "1743580800000000000.jpg",
  "original_name": "tenis-azul.jpg",
  "url": "https://cdn.flye.win/images/fw_9c41d2e07ab3f5168e2d/produtos/1743580800000000000.jpg",
  "size": 204800,
  "content_type": "image/jpeg",
  "created_at": "2026-11-02T13:30:00Z"
}
DELETE /v1/cdn/images/{id}

Delete an image

flye.cdn.deleteImage() · flye.cdn.delete_image()

Deletes the image and frees the space right away. The link stops working within moments.

parameters

JS · Pythontypein the APIdescription
id required string idpath · positional in Python Image id.
example

flye.cdn.deleteImage(params: CdnDeleteImageParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.deleteImage({ id: "<id>" });
console.log(data);

response (example)

{ "deleted": true, "id": "6f1c2a9e-4b7d-4e1a-9c3f-2d8b7a6e5f40" }
DELETE /v1/cdn/projects/{project}

Delete a project

flye.cdn.deleteProject() · flye.cdn.delete_project()

Deletes the project with all its images and frees the space right away. This can't be undone.

parameters

JS · Pythontypein the APIdescription
project required string projectpath · positional in Python Project name.
example

flye.cdn.deleteProject(params: CdnDeleteProjectParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.deleteProject({ project: "<project>" });
console.log(data);

response (example)

{ "deleted": true, "project": "loja", "images": 128 }
GET /v1/cdn/usage

Storage and limits

flye.cdn.getUsage() · flye.cdn.get_usage()

Shows the storage used, your plan's limits and the largest file accepted. A null limit means unlimited.

parameters

No parameters.

example

flye.cdn.getUsage(params?: CdnGetUsageParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.cdn.getUsage();
console.log(data);

response (example)

{
  "storage": { "used_bytes": 52428800, "limit_bytes": 5368709120 },
  "max_file_bytes": 20971520,
  "images": 128,
  "projects": { "used": 1, "limit": 5 }
}

Utils

UUIDs, hashes, base64 and IP inspection in one call.

flye.utils · flye.utils

API page
methodHTTPdescription
uuid GET /utils/uuid Generate UUIDs
hash GET /utils/hash Compute a hash
base64 POST /utils/base64 Encode / decode base64
ip GET /utils/ip Source IP
GET /v1/utils/uuid

Generate UUIDs

flye.utils.uuid() · flye.utils.uuid()

Generates 1 to 100 UUIDs. Version 7 sorts by time, which suits primary keys.

parameters

JS · Pythontypein the APIdescription
count optional integer countquery How many, from 1 to 100. Defaults to 1. E.g.: 2
version optional integer versionquery 4 (random) or 7 (time-ordered). Defaults to 4. E.g.: 7
example

flye.utils.uuid(params?: UtilsUuidParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.utils.uuid({ count: 2, version: 7 });
console.log(data);

response (example)

{
  "version": 7,
  "uuids": [
    "019a3c1e-7b2d-7c41-9f0e-5d8a21c4b6e3",
    "019a3c1e-7b2d-7f88-a1c2-0e93b7d45f12"
  ]
}
GET /v1/utils/hash

Compute a hash

flye.utils.hash() · flye.utils.hash()

Hashes the given text and returns it as hex.

parameters

JS · Pythontypein the APIdescription
text required string textquery Input text (up to 64 KB). E.g.: flye
algo optional string algoquery md5, sha1, sha256 or sha512. Defaults to sha256. E.g.: sha256
example

flye.utils.hash(params: UtilsHashParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.utils.hash({ text: "flye", algo: "sha256" });
console.log(data);

response (example)

{
  "algo": "sha256",
  "hex": "9a5c3b4f1f8e0d6c…"
}
POST /v1/utils/base64

Encode / decode base64

flye.utils.base64() · flye.utils.base64()

Converts text to and from standard base64 (RFC 4648).

parameters

JS · Pythontypein the APIdescription
text required string textbody Content to convert.
mode optional string modebody encode or decode. Defaults to encode.
example

flye.utils.base64(params: UtilsBase64Params, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.utils.base64({ text: "<text>" });
console.log(data);

response (example)

{
  "mode": "encode",
  "result": "aGVsbG8sIHdvcmxk"
}
GET /v1/utils/ip

Source IP

flye.utils.ip() · flye.utils.ip()

Returns the IP and user agent your request reached the platform with.

parameters

No parameters.

example

flye.utils.ip(params?: UtilsIpParams, options?: RequestOptions): Promise<any>

import Flye from "flyewin";

const flye = new Flye(); // reads FLYE_API_KEY

const data = await flye.utils.ip();
console.log(data);

response (example)

{
  "ip": "203.0.113.24",
  "user_agent": "curl/8.7.1"
}

Are you sure?