@apicity/fal 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,1168 @@
1
+ # @apicity/fal
2
+
3
+ [![npm](https://img.shields.io/npm/v/@apicity/fal?color=cb0000)](https://www.npmjs.com/package/@apicity/fal)
4
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)](package.json)
5
+ [![TypeScript](https://img.shields.io/badge/TypeScript-strict-blue?logo=typescript&logoColor=white)](tsconfig.json)
6
+
7
+ Fal Platform API provider for model management, pricing, usage, and analytics.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @apicity/fal
13
+ # or
14
+ pnpm add @apicity/fal
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { fal as createFal } from "@apicity/fal";
21
+
22
+ const fal = createFal({ apiKey: process.env.FAL_API_KEY! });
23
+ ```
24
+
25
+ ## Real-world example: upload a portrait, render a Sora 2 video
26
+
27
+ fal's signature flow is upload-once, reuse-everywhere — drop bytes onto
28
+ fal's CDN via a presigned PUT, then thread the resulting
29
+ `https://*.fal.media/` URL through any model endpoint. The two-step
30
+ snippet below combines
31
+ [`tests/integration/fal-storage-upload-initiate.test.ts`](../../../tests/integration/fal-storage-upload-initiate.test.ts)
32
+ (POST initiate → PUT bytes) with
33
+ [`tests/integration/fal-sora-2-image-to-video.test.ts`](../../../tests/integration/fal-sora-2-image-to-video.test.ts)
34
+ (image-to-video generation), so every URL, byte count, and asset id
35
+ below comes from real recorded HARs.
36
+
37
+ ```typescript
38
+ import { readFile } from "node:fs/promises";
39
+ import { fal as createFal } from "@apicity/fal";
40
+
41
+ const fal = createFal({ apiKey: process.env.FAL_API_KEY! });
42
+
43
+ // 1. Reserve a signed upload slot. `initiate` returns two URLs: a
44
+ // permanent `file_url` you'll feed to downstream models, and a
45
+ // presigned `upload_url` you PUT the bytes to. Both point at the
46
+ // same fal CDN — no third-party hosting needed.
47
+ const slot = await fal.storage.upload.initiate({
48
+ file_name: "man.jpg",
49
+ content_type: "image/jpeg",
50
+ });
51
+ console.log(slot.file_url);
52
+ // → "https://v3b.fal.media/files/b/0a96d564/QR9a1l-E0UuoR6zOHUMlX_man.jpg"
53
+ // (the `cat1.jpg` recording shows the same URL shape with a
54
+ // cat1 suffix; the suffix tracks `file_name` you passed in.)
55
+
56
+ // 2. PUT the bytes to the presigned URL. fal storage is plain HTTP —
57
+ // no SDK call needed, just `fetch` with a matching Content-Type.
58
+ // The signature on `upload_url` expires after a short window;
59
+ // upload promptly. The resulting `file_url` is durable and
60
+ // fetchable by every fal model endpoint.
61
+ const bytes = await readFile("./man.jpg");
62
+ const put = await fetch(slot.upload_url, {
63
+ method: "PUT",
64
+ headers: { "Content-Type": "image/jpeg" },
65
+ body: bytes,
66
+ });
67
+ if (!put.ok) throw new Error(`upload failed: ${put.status}`);
68
+
69
+ // 3. Hand the now-permanent `file_url` to OpenAI's Sora 2 image-to-
70
+ // video model. fal returns a typed bundle: the MP4, a webp
71
+ // thumbnail, and a horizontal spritesheet — all hosted on the
72
+ // same fal CDN. `duration` accepts 4 | 8 | 12 | 16 | 20 (seconds);
73
+ // `aspect_ratio` is "auto" | "9:16" | "16:9".
74
+ const result = await fal.sora2.imageToVideo({
75
+ prompt: "the man waves at the camera as the wind blows his hair",
76
+ image_url: slot.file_url,
77
+ aspect_ratio: "16:9",
78
+ duration: 4,
79
+ });
80
+
81
+ console.log(result.video.url);
82
+ // → "https://v3b.fal.media/files/b/0a96bf3c/8U5wwkg9EC_eK0Jr3XyiR_Vgq1ZZPm.mp4"
83
+ console.log(result.video.file_size);
84
+ // → 2009236 // ~2 MB MP4 for a 4-second 720p clip
85
+ console.log(result.video_id);
86
+ // → "video_69e37804033c8191959194ea8aa8fc6e08bf9f3eb453b1b1"
87
+ console.log(result.thumbnail?.url);
88
+ // → "https://v3b.fal.media/files/b/0a96bf3c/bsgsaBd5IqdwOuufu_qSx_2yOP4u34.webp"
89
+ console.log(result.spritesheet?.url);
90
+ // → "https://v3b.fal.media/files/b/0a96bf3c/_9tqG1dEuRCEeegOulGrk_pWsHbiNB.bin"
91
+ ```
92
+
93
+ **Notes**
94
+
95
+ - The recorded sora-2 HAR inlines the image as a
96
+ `data:image/jpeg;base64,…` URL — fal accepts both inline data URLs
97
+ and any `https://` URL it can reach. Uploading via fal storage
98
+ first keeps request bodies tiny (350 KB → <1 KB) and lets you reuse
99
+ the asset across multiple model calls without re-encoding.
100
+ - The package re-exports a one-call `uploadFile(provider, { data,
101
+ filename, contentType })` helper that wraps the initiate-then-PUT
102
+ dance and returns the `file_url` directly — use it when you don't
103
+ need granular control over the lifecycle or signed URL.
104
+ - Every POST endpoint exposes a Zod schema: call
105
+ `fal.sora2.imageToVideo.schema.safeParse(input)` to validate a
106
+ payload before paying for inference.
107
+ - Long-running calls accept an `AbortSignal` second argument and
108
+ compose with the package's middleware, e.g.
109
+ `withRetry(fal.sora2.imageToVideo, { retries: 3 })` from
110
+ `@apicity/fal` to ride out transient queue / 429s.
111
+ - Errors throw `FalError` with `status`, `type`, `request_id`, and the
112
+ parsed `body` attached:
113
+ `try { ... } catch (e) { if (e instanceof FalError) console.error(e.status, e.body); }`.
114
+
115
+ ## API Reference
116
+
117
+ 68 endpoints across 18 groups. Each method mirrors an upstream URL path.
118
+
119
+ ### bytedance
120
+
121
+ <details>
122
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.fast.imageToVideo</code></b></summary>
123
+
124
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/image-to-video</code>
125
+
126
+ [Upstream docs ↗](https://docs.fal.ai)
127
+
128
+ ```typescript
129
+ const res = await fal.bytedance.seedance2p0.fast.imageToVideo({ /* ... */ });
130
+ ```
131
+
132
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
133
+
134
+ </details>
135
+
136
+ <details>
137
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.fast.referenceToVideo</code></b></summary>
138
+
139
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/reference-to-video</code>
140
+
141
+ ```typescript
142
+ const res = await fal.bytedance.seedance2p0.fast.referenceToVideo({ /* ... */ });
143
+ ```
144
+
145
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
146
+
147
+ </details>
148
+
149
+ <details>
150
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.fast.textToVideo</code></b></summary>
151
+
152
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/fast/text-to-video</code>
153
+
154
+ [Upstream docs ↗](https://docs.fal.ai)
155
+
156
+ ```typescript
157
+ const res = await fal.bytedance.seedance2p0.fast.textToVideo({ /* ... */ });
158
+ ```
159
+
160
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
161
+
162
+ </details>
163
+
164
+ <details>
165
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.imageToVideo</code></b></summary>
166
+
167
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/image-to-video</code>
168
+
169
+ [Upstream docs ↗](https://docs.fal.ai)
170
+
171
+ ```typescript
172
+ const res = await fal.bytedance.seedance2p0.imageToVideo({ /* ... */ });
173
+ ```
174
+
175
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
176
+
177
+ </details>
178
+
179
+ <details>
180
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.referenceToVideo</code></b></summary>
181
+
182
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/reference-to-video</code>
183
+
184
+ ```typescript
185
+ const res = await fal.bytedance.seedance2p0.referenceToVideo({ /* ... */ });
186
+ ```
187
+
188
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
189
+
190
+ </details>
191
+
192
+ <details>
193
+ <summary><code>POST</code> <b><code>fal.bytedance.seedance2p0.textToVideo</code></b></summary>
194
+
195
+ <code>POST https://api.fal.ai/v1/bytedance/seedance-2.0/text-to-video</code>
196
+
197
+ [Upstream docs ↗](https://docs.fal.ai)
198
+
199
+ ```typescript
200
+ const res = await fal.bytedance.seedance2p0.textToVideo({ /* ... */ });
201
+ ```
202
+
203
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
204
+
205
+ </details>
206
+
207
+ <details>
208
+ <summary><code>POST</code> <b><code>fal.bytedance.seedream.v5.lite.edit</code></b></summary>
209
+
210
+ <code>POST https://api.fal.ai/v1/fal-ai/bytedance/seedream/v5/lite/edit</code>
211
+
212
+ [Upstream docs ↗](https://docs.fal.ai)
213
+
214
+ ```typescript
215
+ const res = await fal.bytedance.seedream.v5.lite.edit({ /* ... */ });
216
+ ```
217
+
218
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
219
+
220
+ </details>
221
+
222
+ <details>
223
+ <summary><code>POST</code> <b><code>fal.bytedance.seedream.v5.lite.textToImage</code></b></summary>
224
+
225
+ <code>POST https://api.fal.ai/v1/fal-ai/bytedance/seedream/v5/lite/text-to-image</code>
226
+
227
+ [Upstream docs ↗](https://docs.fal.ai)
228
+
229
+ ```typescript
230
+ const res = await fal.bytedance.seedream.v5.lite.textToImage({ /* ... */ });
231
+ ```
232
+
233
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
234
+
235
+ </details>
236
+
237
+ ### falAi
238
+
239
+ <details>
240
+ <summary><code>POST</code> <b><code>fal.falAi.elevenlabs.speechToText.scribeV2</code></b></summary>
241
+
242
+ <code>POST https://api.fal.ai/v1/fal-ai/elevenlabs/speech-to-text/scribe-v2</code>
243
+
244
+ [Upstream docs ↗](https://docs.fal.ai)
245
+
246
+ ```typescript
247
+ const res = await fal.falAi.elevenlabs.speechToText.scribeV2({ /* ... */ });
248
+ ```
249
+
250
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
251
+
252
+ </details>
253
+
254
+ ### gptImage1p5
255
+
256
+ <details>
257
+ <summary><code>POST</code> <b><code>fal.gptImage1p5</code></b></summary>
258
+
259
+ <code>POST https://api.fal.ai/v1/fal-ai/gpt-image-1.5</code>
260
+
261
+ [Upstream docs ↗](https://docs.fal.ai)
262
+
263
+ ```typescript
264
+ const res = await fal.gptImage1p5({ /* ... */ });
265
+ ```
266
+
267
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
268
+
269
+ </details>
270
+
271
+ <details>
272
+ <summary><code>POST</code> <b><code>fal.gptImage1p5.edit</code></b></summary>
273
+
274
+ <code>POST https://api.fal.ai/v1/fal-ai/gpt-image-1.5/edit</code>
275
+
276
+ [Upstream docs ↗](https://docs.fal.ai)
277
+
278
+ ```typescript
279
+ const res = await fal.gptImage1p5.edit({ /* ... */ });
280
+ ```
281
+
282
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
283
+
284
+ </details>
285
+
286
+ ### hunyuan
287
+
288
+ <details>
289
+ <summary><code>POST</code> <b><code>fal.hunyuan.v3.instructEdit</code></b></summary>
290
+
291
+ <code>POST https://api.fal.ai/v1/fal-ai/hunyuan-image/v3/instruct/edit</code>
292
+
293
+ [Upstream docs ↗](https://docs.fal.ai)
294
+
295
+ ```typescript
296
+ const res = await fal.hunyuan.v3.instructEdit({ /* ... */ });
297
+ ```
298
+
299
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
300
+
301
+ </details>
302
+
303
+ ### klingVideo
304
+
305
+ <details>
306
+ <summary><code>POST</code> <b><code>fal.klingVideo.o3p4k.imageToVideo</code></b></summary>
307
+
308
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/image-to-video</code>
309
+
310
+ [Upstream docs ↗](https://docs.fal.ai)
311
+
312
+ ```typescript
313
+ const res = await fal.klingVideo.o3p4k.imageToVideo({ /* ... */ });
314
+ ```
315
+
316
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
317
+
318
+ </details>
319
+
320
+ <details>
321
+ <summary><code>POST</code> <b><code>fal.klingVideo.o3p4k.referenceToVideo</code></b></summary>
322
+
323
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/reference-to-video</code>
324
+
325
+ [Upstream docs ↗](https://docs.fal.ai)
326
+
327
+ ```typescript
328
+ const res = await fal.klingVideo.o3p4k.referenceToVideo({ /* ... */ });
329
+ ```
330
+
331
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
332
+
333
+ </details>
334
+
335
+ <details>
336
+ <summary><code>POST</code> <b><code>fal.klingVideo.o3p4k.textToVideo</code></b></summary>
337
+
338
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/o3/4k/text-to-video</code>
339
+
340
+ [Upstream docs ↗](https://docs.fal.ai)
341
+
342
+ ```typescript
343
+ const res = await fal.klingVideo.o3p4k.textToVideo({ /* ... */ });
344
+ ```
345
+
346
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
347
+
348
+ </details>
349
+
350
+ <details>
351
+ <summary><code>POST</code> <b><code>fal.klingVideo.v3.pro.imageToVideo</code></b></summary>
352
+
353
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/v3/pro/image-to-video</code>
354
+
355
+ [Upstream docs ↗](https://docs.fal.ai)
356
+
357
+ ```typescript
358
+ const res = await fal.klingVideo.v3.pro.imageToVideo({ /* ... */ });
359
+ ```
360
+
361
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
362
+
363
+ </details>
364
+
365
+ <details>
366
+ <summary><code>POST</code> <b><code>fal.klingVideo.v3.pro.textToVideo</code></b></summary>
367
+
368
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/v3/pro/text-to-video</code>
369
+
370
+ [Upstream docs ↗](https://docs.fal.ai)
371
+
372
+ ```typescript
373
+ const res = await fal.klingVideo.v3.pro.textToVideo({ /* ... */ });
374
+ ```
375
+
376
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
377
+
378
+ </details>
379
+
380
+ <details>
381
+ <summary><code>POST</code> <b><code>fal.klingVideo.v3.standard.imageToVideo</code></b></summary>
382
+
383
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/v3/standard/image-to-video</code>
384
+
385
+ [Upstream docs ↗](https://docs.fal.ai)
386
+
387
+ ```typescript
388
+ const res = await fal.klingVideo.v3.standard.imageToVideo({ /* ... */ });
389
+ ```
390
+
391
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
392
+
393
+ </details>
394
+
395
+ <details>
396
+ <summary><code>POST</code> <b><code>fal.klingVideo.v3.standard.textToVideo</code></b></summary>
397
+
398
+ <code>POST https://api.fal.ai/v1/fal-ai/kling-video/v3/standard/text-to-video</code>
399
+
400
+ [Upstream docs ↗](https://docs.fal.ai)
401
+
402
+ ```typescript
403
+ const res = await fal.klingVideo.v3.standard.textToVideo({ /* ... */ });
404
+ ```
405
+
406
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
407
+
408
+ </details>
409
+
410
+ ### models
411
+
412
+ <details>
413
+ <summary><code>DELETE</code> <b><code>fal.v1.models.requests.payloads</code></b></summary>
414
+
415
+ <code>DELETE https://api.fal.ai/v1/models/requests/{param}/payloads</code>
416
+
417
+ [Upstream docs ↗](https://docs.fal.ai)
418
+
419
+ ```typescript
420
+ const res = await fal.v1.models.requests.payloads({ /* ... */ });
421
+ ```
422
+
423
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
424
+
425
+ </details>
426
+
427
+ <details>
428
+ <summary><code>GET</code> <b><code>fal.v1.models</code></b></summary>
429
+
430
+ <code>GET https://api.fal.ai/v1/models</code>
431
+
432
+ [Upstream docs ↗](https://docs.fal.ai)
433
+
434
+ ```typescript
435
+ const res = await fal.v1.models({ /* ... */ });
436
+ ```
437
+
438
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
439
+
440
+ </details>
441
+
442
+ <details>
443
+ <summary><code>GET</code> <b><code>fal.v1.models.pricing</code></b></summary>
444
+
445
+ <code>GET https://api.fal.ai/v1/models/pricing</code>
446
+
447
+ [Upstream docs ↗](https://docs.fal.ai)
448
+
449
+ ```typescript
450
+ const res = await fal.v1.models.pricing({ /* ... */ });
451
+ ```
452
+
453
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
454
+
455
+ </details>
456
+
457
+ <details>
458
+ <summary><code>GET</code> <b><code>fal.v1.models.pricing.estimate</code></b></summary>
459
+
460
+ <code>GET https://api.fal.ai/v1/models/pricing/estimate</code>
461
+
462
+ [Upstream docs ↗](https://docs.fal.ai)
463
+
464
+ ```typescript
465
+ const res = await fal.v1.models.pricing.estimate({ /* ... */ });
466
+ ```
467
+
468
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
469
+
470
+ </details>
471
+
472
+ <details>
473
+ <summary><code>GET</code> <b><code>fal.v1.models.requests.payloads</code></b></summary>
474
+
475
+ <code>GET https://api.fal.ai/v1/models/requests/{param}/payloads</code>
476
+
477
+ [Upstream docs ↗](https://docs.fal.ai)
478
+
479
+ ```typescript
480
+ const res = await fal.v1.models.requests.payloads({ /* ... */ });
481
+ ```
482
+
483
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
484
+
485
+ </details>
486
+
487
+ <details>
488
+ <summary><code>POST</code> <b><code>fal.v1.models.pricing.estimate</code></b></summary>
489
+
490
+ <code>POST https://api.fal.ai/v1/models/pricing/estimate</code>
491
+
492
+ [Upstream docs ↗](https://docs.fal.ai)
493
+
494
+ ```typescript
495
+ const res = await fal.v1.models.pricing.estimate({ /* ... */ });
496
+ ```
497
+
498
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
499
+
500
+ </details>
501
+
502
+ <details>
503
+ <summary><code>GET</code> <b><code>fal.v1.models</code></b></summary>
504
+
505
+ <code>GET https://api.fal.ai/v1/models</code>
506
+
507
+ [Upstream docs ↗](https://docs.fal.ai)
508
+
509
+ ```typescript
510
+ const res = await fal.v1.models({ /* ... */ });
511
+ ```
512
+
513
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
514
+
515
+ </details>
516
+
517
+ <details>
518
+ <summary><code>GET</code> <b><code>fal.v1.models.pricing</code></b></summary>
519
+
520
+ <code>GET https://api.fal.ai/v1/models/pricing</code>
521
+
522
+ [Upstream docs ↗](https://docs.fal.ai)
523
+
524
+ ```typescript
525
+ const res = await fal.v1.models.pricing({ /* ... */ });
526
+ ```
527
+
528
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
529
+
530
+ </details>
531
+
532
+ <details>
533
+ <summary><code>POST</code> <b><code>fal.v1.models.pricing.estimate</code></b></summary>
534
+
535
+ <code>POST https://api.fal.ai/v1/models/pricing/estimate</code>
536
+
537
+ [Upstream docs ↗](https://docs.fal.ai)
538
+
539
+ ```typescript
540
+ const res = await fal.v1.models.pricing.estimate({ /* ... */ });
541
+ ```
542
+
543
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
544
+
545
+ </details>
546
+
547
+ <details>
548
+ <summary><code>DELETE</code> <b><code>fal.v1.models.requests.payloads</code></b></summary>
549
+
550
+ <code>DELETE https://api.fal.ai/v1/models/requests/{param}/payloads</code>
551
+
552
+ [Upstream docs ↗](https://docs.fal.ai)
553
+
554
+ ```typescript
555
+ const res = await fal.v1.models.requests.payloads({ /* ... */ });
556
+ ```
557
+
558
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
559
+
560
+ </details>
561
+
562
+ ### nanoBanana
563
+
564
+ <details>
565
+ <summary><code>POST</code> <b><code>fal.nanoBanana.edit</code></b></summary>
566
+
567
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana/edit</code>
568
+
569
+ [Upstream docs ↗](https://docs.fal.ai)
570
+
571
+ ```typescript
572
+ const res = await fal.nanoBanana.edit({ /* ... */ });
573
+ ```
574
+
575
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
576
+
577
+ </details>
578
+
579
+ <details>
580
+ <summary><code>POST</code> <b><code>fal.nanoBanana.textToImage</code></b></summary>
581
+
582
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana</code>
583
+
584
+ [Upstream docs ↗](https://docs.fal.ai)
585
+
586
+ ```typescript
587
+ const res = await fal.nanoBanana.textToImage({ /* ... */ });
588
+ ```
589
+
590
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
591
+
592
+ </details>
593
+
594
+ ### nanoBanana2
595
+
596
+ <details>
597
+ <summary><code>POST</code> <b><code>fal.nanoBanana2.edit</code></b></summary>
598
+
599
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana-2/edit</code>
600
+
601
+ [Upstream docs ↗](https://docs.fal.ai)
602
+
603
+ ```typescript
604
+ const res = await fal.nanoBanana2.edit({ /* ... */ });
605
+ ```
606
+
607
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
608
+
609
+ </details>
610
+
611
+ <details>
612
+ <summary><code>POST</code> <b><code>fal.nanoBanana2.textToImage</code></b></summary>
613
+
614
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana-2</code>
615
+
616
+ [Upstream docs ↗](https://docs.fal.ai)
617
+
618
+ ```typescript
619
+ const res = await fal.nanoBanana2.textToImage({ /* ... */ });
620
+ ```
621
+
622
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
623
+
624
+ </details>
625
+
626
+ ### nanoBananaPro
627
+
628
+ <details>
629
+ <summary><code>POST</code> <b><code>fal.nanoBananaPro.edit</code></b></summary>
630
+
631
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana-pro/edit</code>
632
+
633
+ [Upstream docs ↗](https://docs.fal.ai)
634
+
635
+ ```typescript
636
+ const res = await fal.nanoBananaPro.edit({ /* ... */ });
637
+ ```
638
+
639
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
640
+
641
+ </details>
642
+
643
+ <details>
644
+ <summary><code>POST</code> <b><code>fal.nanoBananaPro.textToImage</code></b></summary>
645
+
646
+ <code>POST https://api.fal.ai/v1/fal-ai/nano-banana-pro</code>
647
+
648
+ [Upstream docs ↗](https://docs.fal.ai)
649
+
650
+ ```typescript
651
+ const res = await fal.nanoBananaPro.textToImage({ /* ... */ });
652
+ ```
653
+
654
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
655
+
656
+ </details>
657
+
658
+ ### queue
659
+
660
+ <details>
661
+ <summary><code>POST</code> <b><code>fal.v1.queue.submit</code></b></summary>
662
+
663
+ <code>POST https://api.fal.ai/v1/POST</code>
664
+
665
+ [Upstream docs ↗](https://docs.fal.ai)
666
+
667
+ ```typescript
668
+ const res = await fal.v1.queue.submit({ /* ... */ });
669
+ ```
670
+
671
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
672
+
673
+ </details>
674
+
675
+ <details>
676
+ <summary><code>POST</code> <b><code>fal.v1.queue.submit</code></b></summary>
677
+
678
+ <code>POST https://api.fal.ai/v1/POST</code>
679
+
680
+ [Upstream docs ↗](https://docs.fal.ai)
681
+
682
+ ```typescript
683
+ const res = await fal.v1.queue.submit({ /* ... */ });
684
+ ```
685
+
686
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
687
+
688
+ </details>
689
+
690
+ ### qwenImage
691
+
692
+ <details>
693
+ <summary><code>POST</code> <b><code>fal.qwenImage</code></b></summary>
694
+
695
+ <code>POST https://api.fal.ai/v1/fal-ai/qwen-image</code>
696
+
697
+ [Upstream docs ↗](https://docs.fal.ai)
698
+
699
+ ```typescript
700
+ const res = await fal.qwenImage({ /* ... */ });
701
+ ```
702
+
703
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
704
+
705
+ </details>
706
+
707
+ <details>
708
+ <summary><code>POST</code> <b><code>fal.qwenImage.edit</code></b></summary>
709
+
710
+ <code>POST https://api.fal.ai/v1/fal-ai/qwen-image-edit</code>
711
+
712
+ [Upstream docs ↗](https://docs.fal.ai)
713
+
714
+ ```typescript
715
+ const res = await fal.qwenImage.edit({ /* ... */ });
716
+ ```
717
+
718
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
719
+
720
+ </details>
721
+
722
+ ### serverless
723
+
724
+ <details>
725
+ <summary><code>POST</code> <b><code>fal.v1.serverless.logs</code></b></summary>
726
+
727
+ <code>POST https://api.fal.ai/v1/serverless/logs/stream</code>
728
+
729
+ [Upstream docs ↗](https://docs.fal.ai)
730
+
731
+ ```typescript
732
+ const res = await fal.v1.serverless.logs({ /* ... */ });
733
+ ```
734
+
735
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
736
+
737
+ </details>
738
+
739
+ <details>
740
+ <summary><code>POST</code> <b><code>fal.v1.serverless.files.uploadLocal</code></b></summary>
741
+
742
+ <code>POST https://api.fal.ai/v1/serverless/files/file/local/{param}</code>
743
+
744
+ [Upstream docs ↗](https://docs.fal.ai)
745
+
746
+ ```typescript
747
+ const res = await fal.v1.serverless.files.uploadLocal({ /* ... */ });
748
+ ```
749
+
750
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
751
+
752
+ </details>
753
+
754
+ <details>
755
+ <summary><code>POST</code> <b><code>fal.v1.serverless.files.uploadUrl</code></b></summary>
756
+
757
+ <code>POST https://api.fal.ai/v1/serverless/files/file/url/{param}</code>
758
+
759
+ [Upstream docs ↗](https://docs.fal.ai)
760
+
761
+ ```typescript
762
+ const res = await fal.v1.serverless.files.uploadUrl({ /* ... */ });
763
+ ```
764
+
765
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
766
+
767
+ </details>
768
+
769
+ <details>
770
+ <summary><code>POST</code> <b><code>fal.v1.serverless.files.uploadLocal</code></b></summary>
771
+
772
+ <code>POST https://api.fal.ai/v1/serverless/files/file/local/{param}</code>
773
+
774
+ [Upstream docs ↗](https://docs.fal.ai)
775
+
776
+ ```typescript
777
+ const res = await fal.v1.serverless.files.uploadLocal({ /* ... */ });
778
+ ```
779
+
780
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
781
+
782
+ </details>
783
+
784
+ <details>
785
+ <summary><code>POST</code> <b><code>fal.v1.serverless.files.uploadUrl</code></b></summary>
786
+
787
+ <code>POST https://api.fal.ai/v1/serverless/files/file/url/{param}</code>
788
+
789
+ [Upstream docs ↗](https://docs.fal.ai)
790
+
791
+ ```typescript
792
+ const res = await fal.v1.serverless.files.uploadUrl({ /* ... */ });
793
+ ```
794
+
795
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
796
+
797
+ </details>
798
+
799
+ <details>
800
+ <summary><code>POST</code> <b><code>fal.v1.serverless.logs</code></b></summary>
801
+
802
+ <code>POST https://api.fal.ai/v1/serverless/logs/stream</code>
803
+
804
+ [Upstream docs ↗](https://docs.fal.ai)
805
+
806
+ ```typescript
807
+ const res = await fal.v1.serverless.logs({ /* ... */ });
808
+ ```
809
+
810
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
811
+
812
+ </details>
813
+
814
+ ### sora2
815
+
816
+ <details>
817
+ <summary><code>POST</code> <b><code>fal.sora2.imageToVideo</code></b></summary>
818
+
819
+ <code>POST https://api.fal.ai/v1/fal-ai/sora-2/image-to-video</code>
820
+
821
+ [Upstream docs ↗](https://docs.fal.ai)
822
+
823
+ ```typescript
824
+ const res = await fal.sora2.imageToVideo({ /* ... */ });
825
+ ```
826
+
827
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
828
+
829
+ </details>
830
+
831
+ <details>
832
+ <summary><code>POST</code> <b><code>fal.sora2.textToVideo</code></b></summary>
833
+
834
+ <code>POST https://api.fal.ai/v1/fal-ai/sora-2/text-to-video</code>
835
+
836
+ [Upstream docs ↗](https://docs.fal.ai)
837
+
838
+ ```typescript
839
+ const res = await fal.sora2.textToVideo({ /* ... */ });
840
+ ```
841
+
842
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
843
+
844
+ </details>
845
+
846
+ ### storage
847
+
848
+ <details>
849
+ <summary><b><code>fal.storage.upload.completeMultipart</code></b></summary>
850
+
851
+ ```typescript
852
+ const res = await fal.storage.upload.completeMultipart({ /* ... */ });
853
+ ```
854
+
855
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
856
+
857
+ </details>
858
+
859
+ <details>
860
+ <summary><b><code>fal.storage.upload.initiate</code></b></summary>
861
+
862
+ ```typescript
863
+ const res = await fal.storage.upload.initiate({ /* ... */ });
864
+ ```
865
+
866
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
867
+
868
+ </details>
869
+
870
+ <details>
871
+ <summary><b><code>fal.storage.upload.initiateMultipart</code></b></summary>
872
+
873
+ ```typescript
874
+ const res = await fal.storage.upload.initiateMultipart({ /* ... */ });
875
+ ```
876
+
877
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
878
+
879
+ </details>
880
+
881
+ ### veo3p1
882
+
883
+ <details>
884
+ <summary><code>POST</code> <b><code>fal.veo3p1.imageToVideo</code></b></summary>
885
+
886
+ <code>POST https://api.fal.ai/v1/fal-ai/veo3.1/image-to-video</code>
887
+
888
+ [Upstream docs ↗](https://docs.fal.ai)
889
+
890
+ ```typescript
891
+ const res = await fal.veo3p1.imageToVideo({ /* ... */ });
892
+ ```
893
+
894
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
895
+
896
+ </details>
897
+
898
+ <details>
899
+ <summary><code>POST</code> <b><code>fal.veo3p1.textToVideo</code></b></summary>
900
+
901
+ <code>POST https://api.fal.ai/v1/fal-ai/veo3.1</code>
902
+
903
+ [Upstream docs ↗](https://docs.fal.ai)
904
+
905
+ ```typescript
906
+ const res = await fal.veo3p1.textToVideo({ /* ... */ });
907
+ ```
908
+
909
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
910
+
911
+ </details>
912
+
913
+ ### wan
914
+
915
+ <details>
916
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.edit</code></b></summary>
917
+
918
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/edit</code>
919
+
920
+ [Upstream docs ↗](https://docs.fal.ai)
921
+
922
+ ```typescript
923
+ const res = await fal.wan.v2p7.edit({ /* ... */ });
924
+ ```
925
+
926
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
927
+
928
+ </details>
929
+
930
+ <details>
931
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.editVideo</code></b></summary>
932
+
933
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/edit-video</code>
934
+
935
+ ```typescript
936
+ const res = await fal.wan.v2p7.editVideo({ /* ... */ });
937
+ ```
938
+
939
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
940
+
941
+ </details>
942
+
943
+ <details>
944
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.imageToVideo</code></b></summary>
945
+
946
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/image-to-video</code>
947
+
948
+ [Upstream docs ↗](https://docs.fal.ai)
949
+
950
+ ```typescript
951
+ const res = await fal.wan.v2p7.imageToVideo({ /* ... */ });
952
+ ```
953
+
954
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
955
+
956
+ </details>
957
+
958
+ <details>
959
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.pro.edit</code></b></summary>
960
+
961
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/pro/edit</code>
962
+
963
+ [Upstream docs ↗](https://docs.fal.ai)
964
+
965
+ ```typescript
966
+ const res = await fal.wan.v2p7.pro.edit({ /* ... */ });
967
+ ```
968
+
969
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
970
+
971
+ </details>
972
+
973
+ <details>
974
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.pro.textToImage</code></b></summary>
975
+
976
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/pro/text-to-image</code>
977
+
978
+ [Upstream docs ↗](https://docs.fal.ai)
979
+
980
+ ```typescript
981
+ const res = await fal.wan.v2p7.pro.textToImage({ /* ... */ });
982
+ ```
983
+
984
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
985
+
986
+ </details>
987
+
988
+ <details>
989
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.referenceToVideo</code></b></summary>
990
+
991
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/reference-to-video</code>
992
+
993
+ ```typescript
994
+ const res = await fal.wan.v2p7.referenceToVideo({ /* ... */ });
995
+ ```
996
+
997
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
998
+
999
+ </details>
1000
+
1001
+ <details>
1002
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.textToImage</code></b></summary>
1003
+
1004
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/text-to-image</code>
1005
+
1006
+ [Upstream docs ↗](https://docs.fal.ai)
1007
+
1008
+ ```typescript
1009
+ const res = await fal.wan.v2p7.textToImage({ /* ... */ });
1010
+ ```
1011
+
1012
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1013
+
1014
+ </details>
1015
+
1016
+ <details>
1017
+ <summary><code>POST</code> <b><code>fal.wan.v2p7.textToVideo</code></b></summary>
1018
+
1019
+ <code>POST https://api.fal.ai/v1/fal-ai/wan/v2.7/text-to-video</code>
1020
+
1021
+ [Upstream docs ↗](https://docs.fal.ai)
1022
+
1023
+ ```typescript
1024
+ const res = await fal.wan.v2p7.textToVideo({ /* ... */ });
1025
+ ```
1026
+
1027
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1028
+
1029
+ </details>
1030
+
1031
+ ### workflows
1032
+
1033
+ <details>
1034
+ <summary><code>GET</code> <b><code>fal.v1.workflows</code></b></summary>
1035
+
1036
+ <code>GET https://api.fal.ai/v1/workflows</code>
1037
+
1038
+ [Upstream docs ↗](https://docs.fal.ai)
1039
+
1040
+ ```typescript
1041
+ const res = await fal.v1.workflows({ /* ... */ });
1042
+ ```
1043
+
1044
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1045
+
1046
+ </details>
1047
+
1048
+ <details>
1049
+ <summary><code>GET</code> <b><code>fal.v1.workflows</code></b></summary>
1050
+
1051
+ <code>GET https://api.fal.ai/v1/workflows</code>
1052
+
1053
+ [Upstream docs ↗](https://docs.fal.ai)
1054
+
1055
+ ```typescript
1056
+ const res = await fal.v1.workflows({ /* ... */ });
1057
+ ```
1058
+
1059
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1060
+
1061
+ </details>
1062
+
1063
+ ### xai
1064
+
1065
+ <details>
1066
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineImage</code></b></summary>
1067
+
1068
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-image</code>
1069
+
1070
+ [Upstream docs ↗](https://docs.fal.ai)
1071
+
1072
+ ```typescript
1073
+ const res = await fal.xai.grokImagineImage({ /* ... */ });
1074
+ ```
1075
+
1076
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1077
+
1078
+ </details>
1079
+
1080
+ <details>
1081
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineImage.edit</code></b></summary>
1082
+
1083
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-image/edit</code>
1084
+
1085
+ [Upstream docs ↗](https://docs.fal.ai)
1086
+
1087
+ ```typescript
1088
+ const res = await fal.xai.grokImagineImage.edit({ /* ... */ });
1089
+ ```
1090
+
1091
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1092
+
1093
+ </details>
1094
+
1095
+ <details>
1096
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineVideo.editVideo</code></b></summary>
1097
+
1098
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-video/edit-video</code>
1099
+
1100
+ [Upstream docs ↗](https://docs.fal.ai)
1101
+
1102
+ ```typescript
1103
+ const res = await fal.xai.grokImagineVideo.editVideo({ /* ... */ });
1104
+ ```
1105
+
1106
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1107
+
1108
+ </details>
1109
+
1110
+ <details>
1111
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineVideo.extendVideo</code></b></summary>
1112
+
1113
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-video/extend-video</code>
1114
+
1115
+ [Upstream docs ↗](https://docs.fal.ai)
1116
+
1117
+ ```typescript
1118
+ const res = await fal.xai.grokImagineVideo.extendVideo({ /* ... */ });
1119
+ ```
1120
+
1121
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1122
+
1123
+ </details>
1124
+
1125
+ <details>
1126
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineVideo.imageToVideo</code></b></summary>
1127
+
1128
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-video/image-to-video</code>
1129
+
1130
+ [Upstream docs ↗](https://docs.fal.ai)
1131
+
1132
+ ```typescript
1133
+ const res = await fal.xai.grokImagineVideo.imageToVideo({ /* ... */ });
1134
+ ```
1135
+
1136
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1137
+
1138
+ </details>
1139
+
1140
+ <details>
1141
+ <summary><code>POST</code> <b><code>fal.xai.grokImagineVideo.referenceToVideo</code></b></summary>
1142
+
1143
+ <code>POST https://api.fal.ai/v1/xai/grok-imagine-video/reference-to-video</code>
1144
+
1145
+ [Upstream docs ↗](https://docs.fal.ai)
1146
+
1147
+ ```typescript
1148
+ const res = await fal.xai.grokImagineVideo.referenceToVideo({ /* ... */ });
1149
+ ```
1150
+
1151
+ Source: [`packages/provider/fal/src/fal.ts`](src/fal.ts)
1152
+
1153
+ </details>
1154
+
1155
+ ## Middleware
1156
+
1157
+ ```typescript
1158
+ import { fal as createFal, withRetry } from "@apicity/fal";
1159
+
1160
+ const fal = createFal({ apiKey: process.env.FAL_API_KEY! });
1161
+ const models = withRetry(fal.get.v1.models, { retries: 3 });
1162
+ ```
1163
+
1164
+ Part of the [apicity](https://github.com/justintanner/apicity) monorepo.
1165
+
1166
+ ## License
1167
+
1168
+ MIT — see [LICENSE](LICENSE).