Skip to main content

Overview

Instead of polling GET /jobs/{id} repeatedly, you can provide a webhook URL to receive a POST request when your job completes. This is more efficient and reduces unnecessary API calls.

Using Webhooks

Add the X-Webhook-URL header to any generation request. When the job reaches a terminal state (completed, failed, or cancelled), the API will send a POST request to your URL with the full job data.
// npm install @krea-ai/sdk
import { Krea } from "@krea-ai/sdk";

const krea = new Krea({ apiKey: process.env.KREA_API_KEY });

const job = await krea.image(
  "bfl/flux-1-dev",
  {
    prompt: "a serene mountain landscape at sunset",
    width: 1024,
    height: 576
  },
  { webhookUrl: "https://your-server.com/webhook" }
);

console.log(`Job ID: ${job.job_id}`);
// Your webhook will receive the results when complete
curl -X POST https://api.krea.ai/generate/image/bfl/flux-1-dev \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "X-Webhook-URL: https://your-server.com/webhook" \
  -d '{
    "prompt": "a serene mountain landscape at sunset",
    "width": 1024,
    "height": 576
  }'
import requests

API_BASE = "https://api.krea.ai"
API_TOKEN = "your-token-secret"

response = requests.post(
    f"{API_BASE}/generate/image/bfl/flux-1-dev",
    headers={
        "Authorization": f"Bearer {API_TOKEN}",
        "Content-Type": "application/json",
        "X-Webhook-URL": "https://your-server.com/webhook"
    },
    json={
        "prompt": "a serene mountain landscape at sunset",
        "width": 1024,
        "height": 576
    }
)

job = response.json()
print(f"Job ID: {job['job_id']}")
# Your webhook will receive the results when complete
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
)

func main() {
    apiBase := "https://api.krea.ai"
    apiToken := "your-token-secret"

    payload := map[string]interface{}{
        "prompt": "a serene mountain landscape at sunset",
        "width":  1024,
        "height": 576,
    }

    jsonData, _ := json.Marshal(payload)
    req, _ := http.NewRequest("POST", apiBase+"/generate/image/bfl/flux-1-dev", bytes.NewBuffer(jsonData))
    req.Header.Set("Authorization", "Bearer "+apiToken)
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-Webhook-URL", "https://your-server.com/webhook")

    client := &http.Client{}
    resp, _ := client.Do(req)
    defer resp.Body.Close()

    var job map[string]interface{}
    json.NewDecoder(resp.Body).Decode(&job)
    fmt.Printf("Job ID: %s\n", job["job_id"])
    // Your webhook will receive the results when complete
}

Webhook Payload

When the job completes, your webhook URL receives a POST request with the job data:
{
  "job_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "created_at": "2025-01-15T10:30:00.000Z",
  "completed_at": "2025-01-15T10:30:05.000Z",
  "result": {
    "urls": ["https://..."]
  }
}

Best Practices

Respond quickly - Return a 2xx status code promptly. Process the webhook data asynchronously if needed.
Validate the payload - Verify the job_id matches a job you initiated before processing results.
  • Use HTTPS endpoints for security
  • Implement idempotency in case of duplicate deliveries
  • Log webhook receipts for debugging

Webhooks vs Polling

ApproachProsCons
WebhooksReal-time notifications, fewer API callsRequires a public endpoint
PollingWorks anywhere, no server neededMore API calls, slight delay
Use webhooks when you have a server that can receive HTTP requests. Use polling for client-side applications or when you can’t expose a public endpoint.

Next Steps

Job Lifecycle

Learn about job states and status polling

Code Examples

See complete examples with webhook handling