Skip to main content
POST
/
webhook
/
fuga
/
{tenantId}
curl --request POST \ --url https://api.royalti.io/webhook/fuga/{tenantId} \ --header 'Content-Type: application/json' \ --data ' { "type": "product.delivered", "timestamp": "2025-01-22T14:30:00.000Z", "organization_id": 12345, "data": { "product_id": 789012, "delivery_id": "del_abc123", "reference": "ref_xyz789", "status": "delivered", "product": { "id": 789012, "upc": "012345678905" }, "dsp": { "id": 42, "name": "Spotify" } } } '
{ "status": "success", "message": "Webhook processed", "deliveryId": "delivery-uuid-456" }
This endpoint requires authentication. Include your Bearer token in the Authorization header.

Description

This endpoint is called by FUGA, not by API users — configure it as the webhook URL in your FUGA account as https://api.royalti.io/webhook/fuga/{your-tenant-id}. Authentication: Requires x-fuga-signature header containing SHA3-256 hash (not HMAC). Important: FUGA uses simple hash (SHA3-256) of payload + salt, NOT HMAC. Security Features:
  1. SHA3-256 signature verification with tenant-specific salt
  2. Timestamp validation (rejects webhooks older than 5 minutes)
  3. Duplicate message prevention using webhook ID + Redis caching (24-hour TTL)
  4. Replay attack protection
Workflow:
  1. Verifies SHA3-256 signature using tenant-specific salt
  2. Validates webhook timestamp (must be within 5 minutes)
  3. Checks for duplicate webhook ID in Redis cache
  4. Finds DDEX delivery record by FUGA reference (or by product UPC for delivery events)
  5. Updates delivery status based on event type
  6. Updates product metadata with FUGA status
  7. Sends provider-agnostic notifications for status changes
Supported Event Types:
  • product_state - Product acceptance/rejection/processing status (also handles the legacy product.accepted, product.rejected, product.processing, product.delivered, product.failed values)
  • product_change - Metadata updates in FUGA (informational only, no action taken)
  • delivery_completed - Product delivered to a DSP
  • delivery_cancelled - Delivery cancelled by FUGA
  • delivery_rejected - Delivery rejected by a DSP
  • xml_ingestion - Metadata/XML ingestion result
  • delivery.status / delivery.acknowledgment - Legacy acknowledgment events, queued for async processing
Unrecognized type values are acknowledged with 200 and logged, not rejected.

Code Examples

const response = await fetch('https://api.royalti.io/webhook/fuga/123', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    "ref": "#/components/schemas/FugaWebhookPayload"
  })
});

const data = await response.json();
console.log(data);
import requests

response = requests.post(
  'https://api.royalti.io/webhook/fuga/123',
  headers={
    'Authorization': f'Bearer {token}'
  },
  json={"ref":"#/components/schemas/FugaWebhookPayload"}
)

data = response.json()
print(data)
curl -X POST https://api.royalti.io/webhook/fuga/123 \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"ref":"#/components/schemas/FugaWebhookPayload"}'

Headers

x-fuga-webhook-id
string

Unique webhook ID used for duplicate-delivery detection (not required, but recommended)

Path Parameters

tenantId
integer
required

Tenant ID for webhook routing

Body

application/json
type
enum<string>
required

FUGA event type. product_state, product_change, delivery_completed, delivery_cancelled, delivery_rejected, and xml_ingestion are the current event types; the product.* and delivery.* dotted values are legacy types kept for backward compatibility.

Available options:
product_state,
product_change,
delivery_completed,
delivery_cancelled,
delivery_rejected,
xml_ingestion,
product.accepted,
product.rejected,
product.processing,
product.delivered,
product.failed,
delivery.status,
delivery.acknowledgment
Example:

"product_state"

timestamp
string<date-time>
required

Event timestamp (ISO 8601). Webhooks older than 5 minutes are rejected.

Example:

"2024-11-13T14:32:00Z"

organization_id
integer
required

FUGA organization ID

Example:

12345

data
object
required

Event-specific data payload

signature
string

SHA3-256 signature (not used — the signature is sent in the x-fuga-signature header, not the body)

Response

Webhook processed. FUGA webhooks always return 200 (even for internal processing errors and unmatched deliveries) so the platform does not retry — check status in the response body to distinguish outcomes.

status
string
Example:

"success"

message
string
Example:

"Webhook processed"

deliveryId
string

Present when a matching DDEX delivery record was updated

Example:

"delivery-uuid-456"

jobId
string

Present for delivery.status/delivery.acknowledgment events, which are queued for async processing