Skip to main content
Configure your webhook URL in the Developer dashboard. Your webhook secret starts with whsec_ and is used to sign all payloads. Webhooks allow you to receive HTTP POST notifications when image generations complete or fail, eliminating the need for polling. Best practices:
  • Verify signatures. Always verify webhook signatures before processing events to ensure authenticity
  • Respond quickly. Return a 2xx status code within 10 seconds to acknowledge receipt
  • Use HTTPS. Always use HTTPS endpoints in production for secure communication
  • Secure secrets. Store webhook secrets in environment variables, never in code
  • Implement idempotency. Use the webhook id field to prevent duplicate processing of the same event
  • Handle retries. Failed webhooks will be retried with exponential backoff. Ensure your endpoint is idempotent

Events

generation.completed
string
Triggered when a generation finishes successfully.
generation.failed
string
Triggered when a generation fails with an error.

Request headers

All webhook requests include the following headers:
X-Webhook-Signature
string
HMAC-SHA256 signature for payload verification.
X-Webhook-Timestamp
string
Unix timestamp of when the webhook was sent.
X-Webhook-Version
string
Webhook payload format version.
User-Agent
string
Always set to BabySea-Webhook/1.0.

Response headers

All API responses include these headers for monitoring and debugging:
X-Request-ID
string
Unique identifier for the request (UUID v4). Include this when contacting support for faster debugging.
X-API-Version
string
Current API version being used.
X-RateLimit-Limit
integer
Maximum number of requests allowed per minute for this endpoint.
X-RateLimit-Remaining
integer
Number of requests remaining in the current rate limit window.
X-RateLimit-Reset
integer
Unix timestamp indicating when the rate limit window resets.

Payload structure

Webhook events are sent as POST requests with a JSON body:
{
  "id": "bb7fbf57-1209-4d4e-88d4-0af285a96047",
  "event": "generation.completed",
  "created_at": "2026-01-22T16:07:08.044Z",
  "api_version": "2026-01-05",
  "data": {
    "generation_id": "f53f23ab-c8b6-4e4e-acd5-310a552821d7",
    "status": "succeeded",
    "name": "Room Design",
    "prompt": "Make the sheets in the style of the logo. Make the scene natural",
    "model": "google/nano-banana",
    "credit_cost": 2,
    "output_images": [
      "https://app.babysea.ai/storage/v1/object/public/image_generation/output/f53f23ab-c8b6-4e4e-acd5-310a552821d7/tmpscku3dnk.jpeg"
    ],
    "output_success": 1,
    "output_failed": 0,
    "failure_reason": null,
    "predict_time": 9.043826488,
    "total_time": 9.452142989,
    "created_at": "2026-01-22T16:06:55.588566",
    "completed_at": "2026-01-22T16:07:08.044Z"
  }
}

Payload schema

id
string
Unique identifier for this webhook delivery. Use for idempotency.
event
string
Event type that triggered the webhook. Values: generation.completed, generation.failed.
created_at
string
ISO 8601 timestamp of when the webhook was created.
api_version
string
API version used for this webhook.
data
object
Container object for generation data.

Signature verification

Always verify webhook signatures to ensure requests are from BabySea and prevent unauthorized access.
const crypto = require('crypto');

function verifyWebhookSignature(req) {
  const signature = req.headers['x-webhook-signature'];
  const timestamp = req.headers['x-webhook-timestamp'];
  const payload = JSON.stringify(req.body);
  
  // Parse signature header: t=timestamp,v1=signature
  const [, v1Part] = signature.split(',');
  const receivedSig = v1Part.split('=')[1];
  
  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSig = crypto
    .createHmac('sha256', process.env.BABYSEA_WEBHOOK_SECRET)
    .update(signedPayload)
    .digest('hex');
  
  // Verify timestamp is recent (prevent replay attacks)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    return false; // Reject if older than 5 minutes
  }
  
  return receivedSig === expectedSig;
}

Rate limits

API requests are rate limited per account to ensure system stability.

Generation

You can create up to 10 generations per 60 seconds, with only 1 concurrent generation allowed.

Endpoint

GET /v1/status
string
60 requests per minute
GET /v1/data/account
string
60 requests per minute
GET /v1/data/list/image
string
30 requests per minute
GET /v1/image-generation/:id
string
10 requests per minute
POST /v1/image-generation/:modelIdentifier
string
1 concurrent request maximum

Handling

  • Monitor remaining requests: Check the X-RateLimit-Remaining header to track your usage
  • Implement exponential backoff: When rate limited (429 status), wait before retrying with increasing delays
  • Use reset timestamp: Check X-RateLimit-Reset to know exactly when to retry
  • Queue requests: Implement client-side queuing to stay within rate limits
  • Log request IDs: Always log X-Request-ID for debugging failed or rate-limited request