
A Laravel package for integrating with the Fal.ai API, providing a fluent interface for AI model interactions with built-in webhook support.
- π Fluent API - Chainable methods for easy request building
- π Webhook Support - Secure webhook handling with ED25519 signature verification
- β‘ Queue & Sync Modes - Support for both immediate and queued requests
- π‘ Real-time Streaming - Server-Sent Events (SSE) support for progressive AI model responses
- π‘οΈ Security - Built-in webhook verification middleware
- π§ͺ Well Tested - Comprehensive test suite
- π Laravel Integration - Native Laravel middleware and service provider
- π£οΈ Built-in Routes - Pre-configured webhook endpoints ready to use
Install the package via Composer:
composer require fal-ai/laravel
Publish the configuration file:
php artisan vendor:publish --provider="FalAi\FalAiServiceProvider"
Add your Fal.ai API key to your .env
file:
FAL_API_KEY=your_fal_api_key_here
use FalAi\FalAi;
$falAi = new FalAi();
$response = $falAi->model('fal-ai/flux/schnell')
->prompt('A beautiful sunset over mountains')
->imageSize('landscape_4_3')
->run();
Tip
Queue mode is the default and recommended for most use cases. It's perfect for complex generations that take time to process.
$response = $falAi->model('fal-ai/flux/dev')
->prompt('A futuristic cityscape')
->queue() // Explicit queue mode (optional, it's the default)
->run();
// Returns: ['request_id' => 'req_123...', 'status' => 'IN_QUEUE']
Use queue mode when:
- Generating high-quality images with many inference steps
- Processing multiple images in batch
- You don't need immediate results
- Working with complex prompts or large image sizes
$response = $falAi->model('fal-ai/flux/schnell')
->prompt('A beautiful landscape')
->sync() // Switch to sync mode
->run();
// Returns the complete result immediately
Use sync mode when:
- You need immediate results
- Generating simple images with few inference steps
- Building interactive applications
- Testing and development
Warning
Sync mode may timeout for complex requests. Use queue mode for production applications.
When you add a webhook URL to your request, it automatically switches to queue mode:
$response = $falAi->model('fal-ai/flux/schnell')
->withWebhook('https://myapp.com/webhooks/fal')
->prompt('A beautiful sunset over mountains')
->imageSize('landscape_4_3')
->run();
// Returns: ['request_id' => 'req_123...', 'status' => 'IN_QUEUE']
- Must be a valid HTTPS URL
- Must be publicly accessible
- Should respond with 2xx status codes
You have two options for handling webhooks: use the built-in route or create your own custom endpoint.
The package includes a pre-configured webhook route at /webhooks/fal
that handles basic webhook processing:
// This route is automatically registered by the package
// POST /webhooks/fal
// Use it in your requests:
$response = $falAi->model('fal-ai/flux/schnell')
->withWebhook(url('/webhooks/fal')) // Uses the built-in route
->prompt('Your prompt here')
->run();
Tip
The built-in route automatically verifies webhooks and returns appropriate responses. Perfect for getting started quickly!
use FalAi\Middleware\VerifyFalWebhook;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/webhooks/fal', function (Request $request) {
$payload = $request->json()->all();
if ($payload['status'] === 'OK') {
$images = $payload['data']['images'];
// Process successful results
foreach ($images as $image) {
// Save image URL: $image['url']
}
} elseif ($payload['status'] === 'ERROR') {
$error = $payload['error'];
// Handle error
}
return response()->json(['status' => 'processed']);
})->middleware(VerifyFalWebhook::class);
For production applications, create a custom webhook endpoint with your own processing logic:
use FalAi\Middleware\VerifyFalWebhook;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
Route::post('/webhooks/fal-custom', function (Request $request) {
$payload = $request->json()->all();
if ($payload['status'] === 'OK') {
$images = $payload['data']['images'];
// Process successful results
foreach ($images as $image) {
// Save image URL: $image['url']
// Custom processing logic here
}
} elseif ($payload['status'] === 'ERROR') {
$error = $payload['error'];
// Handle error with custom logic
}
return response()->json(['status' => 'processed']);
})->middleware(VerifyFalWebhook::class);
For complete control over the verification process:
use FalAi\Services\WebhookVerifier;
use FalAi\Exceptions\WebhookVerificationException;
Route::post('/webhooks/fal-manual', function (Request $request) {
$verifier = new WebhookVerifier();
try {
$verifier->verify($request);
// Webhook is valid, process payload
$payload = $request->json()->all();
return response()->json(['status' => 'verified']);
} catch (WebhookVerificationException $e) {
return response()->json([
'error' => 'Unauthorized',
'message' => 'Webhook verification failed'
], 401);
}
});
{
"request_id": "req_123456789",
"status": "OK",
"data": {
"images": [
{
"url": "https://fal.media/files/generated-image.jpg",
"width": 1024,
"height": 768,
"content_type": "image/jpeg"
}
],
"seed": 12345,
"has_nsfw_concepts": [false],
"prompt": "A beautiful sunset over mountains"
}
}
{
"request_id": "req_123456789",
"status": "ERROR",
"error": {
"type": "ValidationError",
"message": "Invalid prompt provided"
}
}
The Fal.ai Laravel package supports real-time streaming responses using Server-Sent Events (SSE). This is particularly useful for AI models that generate content progressively, such as text generation or image creation with intermediate steps.
To use streaming, call the stream()
method instead of run()
or queue()
:
use Cjmellor\FalAi\Facades\FalAi;
$streamResponse = FalAi::model('fal-ai/flux/schnell')
->prompt('A beautiful sunset over mountains')
->imageSize('landscape_4_3')
->stream();
$streamResponse->getResponse();
}
Feature | Regular Request | Streaming Request |
---|---|---|
Response Time | Wait for completion | Real-time updates |
User Experience | Loading spinner | Progress indicators |
Resource Usage | Lower | Slightly higher |
Complexity | Simple | Moderate |
Best For | Simple workflows | Interactive applications |
- Streaming requests always use the
https://fal.run
endpoint regardless of configuration - Not all Fal.ai models support streaming - check the model documentation
- Streaming responses cannot be cached like regular responses
- Consider implementing proper error handling for network interruptions
- Use streaming for models that benefit from progressive updates (text generation, multi-step image creation)
Note
You can customise the package behaviour by publishing and modifying the configuration file.
The configuration file config/fal-ai.php
contains the following options:
return [
'api_key' => env('FAL_API_KEY'),
'base_url' => 'https://queue.fal.run',
'default_model' => '',
'webhook' => [
// JWKS cache TTL in seconds (max 24 hours)
'jwks_cache_ttl' => env('FAL_WEBHOOK_JWKS_CACHE_TTL', 86400),
// Timestamp tolerance in seconds (prevents replay attacks)
'timestamp_tolerance' => env('FAL_WEBHOOK_TIMESTAMP_TOLERANCE', 300),
// HTTP timeout for JWKS fetching
'verification_timeout' => env('FAL_WEBHOOK_VERIFICATION_TIMEOUT', 10),
],
];
# Required
FAL_API_KEY=your_fal_api_key_here
# Optional webhook configuration
FAL_WEBHOOK_JWKS_CACHE_TTL=86400
FAL_WEBHOOK_TIMESTAMP_TOLERANCE=300
FAL_WEBHOOK_VERIFICATION_TIMEOUT=10
$request = $falAi->model('fal-ai/flux/schnell')
->prompt('Your prompt here') // Set the text prompt
->imageSize('landscape_4_3') // Set image dimensions
->numImages(2) // Number of images to generate
->seed(12345) // Set random seed
->withWebhook('https://...') // Add webhook URL
->queue() // Use queue mode
->sync(); // Use sync mode
Important
Always implement proper error handling in production applications to gracefully handle API failures and webhook verification issues.
use FalAi\Exceptions\WebhookVerificationException;
use InvalidArgumentException;
try {
$response = $falAi->model('fal-ai/flux/schnell')
->withWebhook('https://myapp.com/webhook')
->prompt('Test prompt')
->run();
if (!$response->successful()) {
throw new Exception('API request failed: ' . $response->body());
}
} catch (InvalidArgumentException $e) {
// Invalid webhook URL or other validation errors
echo "Validation error: " . $e->getMessage();
} catch (WebhookVerificationException $e) {
// Webhook verification failed (in webhook endpoints)
echo "Webhook error: " . $e->getMessage();
} catch (Exception $e) {
// Other errors (network, API, etc.)
echo "Error: " . $e->getMessage();
}
Run the test suite:
composer test
Caution
Webhook security is critical for protecting your application from malicious requests. Always use the provided verification mechanisms.
This package implements Fal.ai's webhook verification using:
- ED25519 signature verification using Fal.ai's public keys
- Timestamp validation to prevent replay attacks
- JWKS caching for performance
- Automatic header extraction and validation
Tip
Follow these security practices to ensure your webhook endpoints are secure:
- Always use HTTPS for webhook URLs
- Use the provided middleware for automatic verification
- Validate webhook payloads in your application logic
- Implement proper error handling and logging
- Monitor webhook endpoints for suspicious activity
- Use rate limiting on webhook routes
- Keep your API keys secure and rotate them regularly
Contributions are welcome! Please feel free to submit a Pull Request.
This package is open-sourced software licensed under the MIT license.
For support, please open an issue on GitHub or contact the maintainers.