npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@apicity/fal

v0.1.0

Published

Fal Platform API provider for model management, pricing, usage, and analytics.

Readme

@apicity/fal

npm zero dependencies TypeScript

Fal Platform API provider for model management, pricing, usage, and analytics.

Installation

npm install @apicity/fal
# or
pnpm add @apicity/fal

Quick Start

import { fal as createFal } from "@apicity/fal";

const fal = createFal({ apiKey: process.env.FAL_API_KEY! });

Real-world example: upload a portrait, render a Sora 2 video

fal's signature flow is upload-once, reuse-everywhere — drop bytes onto fal's CDN via a presigned PUT, then thread the resulting https://*.fal.media/ URL through any model endpoint. The two-step snippet below combines tests/integration/fal-storage-upload-initiate.test.ts (POST initiate → PUT bytes) with tests/integration/fal-sora-2-image-to-video.test.ts (image-to-video generation), so every URL, byte count, and asset id below comes from real recorded HARs.

import { readFile } from "node:fs/promises";
import { fal as createFal } from "@apicity/fal";

const fal = createFal({ apiKey: process.env.FAL_API_KEY! });

// 1. Reserve a signed upload slot. `initiate` returns two URLs: a
//    permanent `file_url` you'll feed to downstream models, and a
//    presigned `upload_url` you PUT the bytes to. Both point at the
//    same fal CDN — no third-party hosting needed.
const slot = await fal.storage.upload.initiate({
  file_name: "man.jpg",
  content_type: "image/jpeg",
});
console.log(slot.file_url);
// → "https://v3b.fal.media/files/b/0a96d564/QR9a1l-E0UuoR6zOHUMlX_man.jpg"
//   (the `cat1.jpg` recording shows the same URL shape with a
//    cat1 suffix; the suffix tracks `file_name` you passed in.)

// 2. PUT the bytes to the presigned URL. fal storage is plain HTTP —
//    no SDK call needed, just `fetch` with a matching Content-Type.
//    The signature on `upload_url` expires after a short window;
//    upload promptly. The resulting `file_url` is durable and
//    fetchable by every fal model endpoint.
const bytes = await readFile("./man.jpg");
const put = await fetch(slot.upload_url, {
  method: "PUT",
  headers: { "Content-Type": "image/jpeg" },
  body: bytes,
});
if (!put.ok) throw new Error(`upload failed: ${put.status}`);

// 3. Hand the now-permanent `file_url` to OpenAI's Sora 2 image-to-
//    video model. fal returns a typed bundle: the MP4, a webp
//    thumbnail, and a horizontal spritesheet — all hosted on the
//    same fal CDN. `duration` accepts 4 | 8 | 12 | 16 | 20 (seconds);
//    `aspect_ratio` is "auto" | "9:16" | "16:9".
const result = await fal.sora2.imageToVideo({
  prompt: "the man waves at the camera as the wind blows his hair",
  image_url: slot.file_url,
  aspect_ratio: "16:9",
  duration: 4,
});

console.log(result.video.url);
// → "https://v3b.fal.media/files/b/0a96bf3c/8U5wwkg9EC_eK0Jr3XyiR_Vgq1ZZPm.mp4"
console.log(result.video.file_size);
// → 2009236   // ~2 MB MP4 for a 4-second 720p clip
console.log(result.video_id);
// → "video_69e37804033c8191959194ea8aa8fc6e08bf9f3eb453b1b1"
console.log(result.thumbnail?.url);
// → "https://v3b.fal.media/files/b/0a96bf3c/bsgsaBd5IqdwOuufu_qSx_2yOP4u34.webp"
console.log(result.spritesheet?.url);
// → "https://v3b.fal.media/files/b/0a96bf3c/_9tqG1dEuRCEeegOulGrk_pWsHbiNB.bin"

Notes

  • The recorded sora-2 HAR inlines the image as a data:image/jpeg;base64,… URL — fal accepts both inline data URLs and any https:// URL it can reach. Uploading via fal storage first keeps request bodies tiny (350 KB → <1 KB) and lets you reuse the asset across multiple model calls without re-encoding.
  • The package re-exports a one-call uploadFile(provider, { data, filename, contentType }) helper that wraps the initiate-then-PUT dance and returns the file_url directly — use it when you don't need granular control over the lifecycle or signed URL.
  • Every POST endpoint exposes a Zod schema: call fal.sora2.imageToVideo.schema.safeParse(input) to validate a payload before paying for inference.
  • Long-running calls accept an AbortSignal second argument and compose with the package's middleware, e.g. withRetry(fal.sora2.imageToVideo, { retries: 3 }) from @apicity/fal to ride out transient queue / 429s.
  • Errors throw FalError with status, type, request_id, and the parsed body attached: try { ... } catch (e) { if (e instanceof FalError) console.error(e.status, e.body); }.

API Reference

68 endpoints across 18 groups. Each method mirrors an upstream URL path.

bytedance

POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/image-to-video

Upstream docs ↗

const res = await fal.bytedance.seedance2p0.fast.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/reference-to-video

const res = await fal.bytedance.seedance2p0.fast.referenceToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/text-to-video

Upstream docs ↗

const res = await fal.bytedance.seedance2p0.fast.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/bytedance/seedance-2.0/image-to-video

Upstream docs ↗

const res = await fal.bytedance.seedance2p0.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/bytedance/seedance-2.0/reference-to-video

const res = await fal.bytedance.seedance2p0.referenceToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/bytedance/seedance-2.0/text-to-video

Upstream docs ↗

const res = await fal.bytedance.seedance2p0.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/bytedance/seedream/v5/lite/edit

Upstream docs ↗

const res = await fal.bytedance.seedream.v5.lite.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/bytedance/seedream/v5/lite/text-to-image

Upstream docs ↗

const res = await fal.bytedance.seedream.v5.lite.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

falAi

POST https://api.fal.ai/v1/fal-ai/elevenlabs/speech-to-text/scribe-v2

Upstream docs ↗

const res = await fal.falAi.elevenlabs.speechToText.scribeV2({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

gptImage1p5

POST https://api.fal.ai/v1/fal-ai/gpt-image-1.5

Upstream docs ↗

const res = await fal.gptImage1p5({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/gpt-image-1.5/edit

Upstream docs ↗

const res = await fal.gptImage1p5.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

hunyuan

POST https://api.fal.ai/v1/fal-ai/hunyuan-image/v3/instruct/edit

Upstream docs ↗

const res = await fal.hunyuan.v3.instructEdit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

klingVideo

POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/image-to-video

Upstream docs ↗

const res = await fal.klingVideo.o3p4k.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/reference-to-video

Upstream docs ↗

const res = await fal.klingVideo.o3p4k.referenceToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/text-to-video

Upstream docs ↗

const res = await fal.klingVideo.o3p4k.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/v3/pro/image-to-video

Upstream docs ↗

const res = await fal.klingVideo.v3.pro.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/v3/pro/text-to-video

Upstream docs ↗

const res = await fal.klingVideo.v3.pro.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/v3/standard/image-to-video

Upstream docs ↗

const res = await fal.klingVideo.v3.standard.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/kling-video/v3/standard/text-to-video

Upstream docs ↗

const res = await fal.klingVideo.v3.standard.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

models

DELETE https://api.fal.ai/v1/models/requests/{param}/payloads

Upstream docs ↗

const res = await fal.v1.models.requests.payloads({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models

Upstream docs ↗

const res = await fal.v1.models({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models/pricing

Upstream docs ↗

const res = await fal.v1.models.pricing({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models/pricing/estimate

Upstream docs ↗

const res = await fal.v1.models.pricing.estimate({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models/requests/{param}/payloads

Upstream docs ↗

const res = await fal.v1.models.requests.payloads({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/models/pricing/estimate

Upstream docs ↗

const res = await fal.v1.models.pricing.estimate({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models

Upstream docs ↗

const res = await fal.v1.models({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/models/pricing

Upstream docs ↗

const res = await fal.v1.models.pricing({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/models/pricing/estimate

Upstream docs ↗

const res = await fal.v1.models.pricing.estimate({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

DELETE https://api.fal.ai/v1/models/requests/{param}/payloads

Upstream docs ↗

const res = await fal.v1.models.requests.payloads({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

nanoBanana

POST https://api.fal.ai/v1/fal-ai/nano-banana/edit

Upstream docs ↗

const res = await fal.nanoBanana.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/nano-banana

Upstream docs ↗

const res = await fal.nanoBanana.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

nanoBanana2

POST https://api.fal.ai/v1/fal-ai/nano-banana-2/edit

Upstream docs ↗

const res = await fal.nanoBanana2.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/nano-banana-2

Upstream docs ↗

const res = await fal.nanoBanana2.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

nanoBananaPro

POST https://api.fal.ai/v1/fal-ai/nano-banana-pro/edit

Upstream docs ↗

const res = await fal.nanoBananaPro.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/nano-banana-pro

Upstream docs ↗

const res = await fal.nanoBananaPro.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

queue

POST https://api.fal.ai/v1/POST

Upstream docs ↗

const res = await fal.v1.queue.submit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/POST

Upstream docs ↗

const res = await fal.v1.queue.submit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

qwenImage

POST https://api.fal.ai/v1/fal-ai/qwen-image

Upstream docs ↗

const res = await fal.qwenImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/qwen-image-edit

Upstream docs ↗

const res = await fal.qwenImage.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

serverless

POST https://api.fal.ai/v1/serverless/logs/stream

Upstream docs ↗

const res = await fal.v1.serverless.logs({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/serverless/files/file/local/{param}

Upstream docs ↗

const res = await fal.v1.serverless.files.uploadLocal({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/serverless/files/file/url/{param}

Upstream docs ↗

const res = await fal.v1.serverless.files.uploadUrl({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/serverless/files/file/local/{param}

Upstream docs ↗

const res = await fal.v1.serverless.files.uploadLocal({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/serverless/files/file/url/{param}

Upstream docs ↗

const res = await fal.v1.serverless.files.uploadUrl({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/serverless/logs/stream

Upstream docs ↗

const res = await fal.v1.serverless.logs({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

sora2

POST https://api.fal.ai/v1/fal-ai/sora-2/image-to-video

Upstream docs ↗

const res = await fal.sora2.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/sora-2/text-to-video

Upstream docs ↗

const res = await fal.sora2.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

storage

const res = await fal.storage.upload.completeMultipart({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

const res = await fal.storage.upload.initiate({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

const res = await fal.storage.upload.initiateMultipart({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

veo3p1

POST https://api.fal.ai/v1/fal-ai/veo3.1/image-to-video

Upstream docs ↗

const res = await fal.veo3p1.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/veo3.1

Upstream docs ↗

const res = await fal.veo3p1.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

wan

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/edit

Upstream docs ↗

const res = await fal.wan.v2p7.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/edit-video

const res = await fal.wan.v2p7.editVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/image-to-video

Upstream docs ↗

const res = await fal.wan.v2p7.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/pro/edit

Upstream docs ↗

const res = await fal.wan.v2p7.pro.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/pro/text-to-image

Upstream docs ↗

const res = await fal.wan.v2p7.pro.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/reference-to-video

const res = await fal.wan.v2p7.referenceToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/text-to-image

Upstream docs ↗

const res = await fal.wan.v2p7.textToImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/fal-ai/wan/v2.7/text-to-video

Upstream docs ↗

const res = await fal.wan.v2p7.textToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

workflows

GET https://api.fal.ai/v1/workflows

Upstream docs ↗

const res = await fal.v1.workflows({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

GET https://api.fal.ai/v1/workflows

Upstream docs ↗

const res = await fal.v1.workflows({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

xai

POST https://api.fal.ai/v1/xai/grok-imagine-image

Upstream docs ↗

const res = await fal.xai.grokImagineImage({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/xai/grok-imagine-image/edit

Upstream docs ↗

const res = await fal.xai.grokImagineImage.edit({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/xai/grok-imagine-video/edit-video

Upstream docs ↗

const res = await fal.xai.grokImagineVideo.editVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/xai/grok-imagine-video/extend-video

Upstream docs ↗

const res = await fal.xai.grokImagineVideo.extendVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/xai/grok-imagine-video/image-to-video

Upstream docs ↗

const res = await fal.xai.grokImagineVideo.imageToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

POST https://api.fal.ai/v1/xai/grok-imagine-video/reference-to-video

Upstream docs ↗

const res = await fal.xai.grokImagineVideo.referenceToVideo({ /* ... */ });

Source: packages/provider/fal/src/fal.ts

Middleware

import { fal as createFal, withRetry } from "@apicity/fal";

const fal = createFal({ apiKey: process.env.FAL_API_KEY! });
const models = withRetry(fal.get.v1.models, { retries: 3 });

Part of the apicity monorepo.

License

MIT — see LICENSE.