Skip to main content
Webhooks let your server know when audio and video generation finishes, fails, or when a content item is deleted—without polling the API. BeyondWords sends a POST request with a JSON payload to a URL you configure. Use webhooks to trigger downstream workflows: notify a CMS, update a search index, fetch player data for a native app, or sync content across systems. See the Pugpig integration guide for a common app-distribution pattern.
Set a source_id when creating content via the API, WordPress plugin, or RSS Feed Importer. The webhook payload includes source_id, so you can map notifications back to your CMS article ID without storing BeyondWords content_id values.

Webhooks API

Create, update, test, and manage webhooks programmatically.

How it works

  1. Content is created or updated in BeyondWords—via the API, WordPress, Ghost, Magic Embed, RSS Feed Importer, or the dashboard.
  2. BeyondWords processes the content (audio/video generation).
  3. When processing completes, fails, or the content item is deleted, BeyondWords sends a webhook notification to each enabled webhook URL in your project.
  4. Your endpoint receives a JSON payload and responds with a 2xx status code.
BeyondWords retries failed deliveries automatically. If your endpoint returns 4xx or 5xx, or the request times out, BeyondWords will retry with exponential backoff.

Event types

action_typeWhen it fires
audio.updatedGeneration or regeneration completed successfully
audio.errorGeneration failed
audio.deletedContent item deleted
Event names reference audio, but they apply to content items as a whole. A content item may include audio and/or video outputs, and may include article and script variants. Use action_type to determine what happened, then inspect state, media, and published in the payload.

Set up a webhook

1

Create a new webhook

Go to Settings → Webhooks in your project dashboard.Click + Webhook.
2

Enter webhook URL

Enter the HTTPS URL where BeyondWords should send event notifications. This should be an endpoint on your server that accepts POST requests with a JSON body.
3

Set request headers (optional)

For paywalled or protected content, you may need to provide authentication headers to grant BeyondWords servers access to your content:
  1. Add a Header name and Header value
  2. Click + to add additional headers if needed
  3. Click Save changes
Requests will be made with User-Agent: BeyondWords Importer
4

Enable static IP (optional)

If your endpoint requires IP allowlisting, enable static IP so webhook requests originate from a fixed address.
  1. Switch Static IP on
  2. Allowlist the displayed IP addresses in your firewall, CDN, or server configuration
Webhook requests are sent from 20.234.8.180 when static IP is enabled.
5

Enable and save

Toggle Enabled on, then click Save changes.

Test your webhook

Quick preview with Webhook.site

If you want to see what a webhook payload looks like without building an endpoint, use Webhook.site. It gives you a temporary URL that logs any requests sent to it.
  1. Open webhook.site and copy your unique URL
  2. In BeyondWords, go to Settings → Webhooks and paste that URL into Webhook URL
  3. Click Test, or publish content and wait for a real audio.updated event
  4. Return to Webhook.site to inspect the JSON payload, headers, and timestamp
Webhook.site URLs are public and temporary—use them for testing only, not production.

Test from the dashboard

Before going live with your own endpoint:
  1. Configure your Webhook URL and optional headers
  2. Click Test
BeyondWords sends a sample payload to your URL. A successful test means your endpoint returned a 2xx response. You can also test a webhook via the API.

Payload reference

Each notification is a POST request with Content-Type: application/json. The event type is in action_type.

Common fields

FieldDescription
action_typeEvent type: audio.updated, audio.error, or audio.deleted
stateProcessing state at the time of the event—processed or error
idNumeric content ID (legacy)
content_idContent UUID—use with the player API
source_idYour external ID for the content (e.g. CMS article ID)—same value as external_id
external_idSame as source_id
project_idYour BeyondWords project ID
titleContent title
publishedWhether the content is published in BeyondWords
published_atPublish timestamp (ISO 8601)
processing_atProcessing timestamp (ISO 8601)
deletedWhether the content item has been deleted
metadataCustom metadata object
mediaArray of generated media objects (id, content_type, url, duration)
audio_with_intro_outroIntro/outro media variants, when configured
image_urlFeatured image URL, if set
is_copyWhether this content item is a duplicate of another
After receiving a webhook, fetch full player data with the player API using source_id or get player by content ID using content_id.

audio.updated

Triggered when generation or regeneration completes successfully.
audio.updated payload
{
  "id": 12345,
  "title": "My article",
  "project_id": "67890",
  "external_id": "cms-article-001",
  "state": "processed",
  "metadata": {},
  "media": [
    {
      "id": "media-uuid-1",
      "content_type": "mp3",
      "url": "https://example.com/audio.mp3",
      "duration": 281
    },
    {
      "id": "media-uuid-2",
      "content_type": "m3u8",
      "url": "https://example.com/audio.m3u8",
      "duration": 281
    }
  ],
  "audio_with_intro_outro": [],
  "image_url": null,
  "deleted": false,
  "access_key": null,
  "processing_at": "2025-07-02T13:19:39.054Z",
  "published": true,
  "published_at": "2025-07-02T13:19:38.699Z",
  "content_id": "content-uuid",
  "source_id": "cms-article-001",
  "is_copy": false,
  "action_type": "audio.updated"
}

audio.error

Triggered when generation fails.
audio.error payload
{
  "id": 12345,
  "title": "My article",
  "project_id": "67890",
  "external_id": "cms-article-001",
  "state": "error",
  "metadata": {},
  "media": [],
  "audio_with_intro_outro": [],
  "image_url": null,
  "deleted": false,
  "access_key": null,
  "processing_at": "2025-07-02T13:19:39.054Z",
  "published": false,
  "published_at": "2025-07-02T13:19:38.699Z",
  "content_id": "content-uuid",
  "source_id": "cms-article-001",
  "is_copy": false,
  "action_type": "audio.error"
}

audio.deleted

Triggered when a content item is deleted.
audio.deleted payload
{
  "id": 12345,
  "title": null,
  "project_id": "67890",
  "external_id": "cms-article-001",
  "state": "processed",
  "metadata": {},
  "media": [],
  "audio_with_intro_outro": [],
  "image_url": null,
  "deleted": true,
  "access_key": null,
  "processing_at": "2025-07-02T13:19:39.054Z",
  "published": true,
  "published_at": "2025-07-02T13:19:38.699Z",
  "content_id": "content-uuid",
  "source_id": "cms-article-001",
  "is_copy": false,
  "action_type": "audio.deleted"
}

Managing webhooks

You can create multiple webhooks per project—for example, one for your CMS and one for a partner integration. For each webhook you can:
  • Edit the URL, headers, or static IP settings
  • Temporarily disable it with the Enabled toggle
  • Delete it when no longer needed
  • View delivery status and errors in the dashboard
Manage webhooks programmatically via the Webhooks API.

Security and reliability

  • Use HTTPS—webhook URLs must be served over HTTPS.
  • Authenticate requests—configure request headers (such as Authorization) in the webhook settings. Validate these on your server before processing the payload. BeyondWords does not sign payloads with a shared secret—authentication is via the headers you configure.
  • Allowlist static IPs—if your endpoint is behind a firewall, enable static IP and allowlist the BeyondWords egress addresses.
  • Respond quickly—return a 2xx response promptly. Process the payload asynchronously if needed.
  • Handle retries—failed deliveries are retried automatically. Make your handler idempotent so duplicate notifications for the same content_id and action_type do not cause problems.
  • Map content reliably—prefer source_id over title or URLs, which can change.

FAQs

audio.updated fires when audio/video generation or regeneration completes successfully—when the content item reaches the processed state. It does not fire when generation starts, only when it finishes (or fails, in which case audio.error fires instead).
Use source_id in the payload—this is the external ID you set when creating content (your CMS article ID, WordPress post ID, RSS guid, etc.). If you did not set a source_id, use content_id and store the mapping in your system, or look up content in the BeyondWords dashboard.
Return any 2xx HTTP status code to acknowledge receipt. Responses with 4xx or 5xx status codes, or timeouts, are treated as failures and will be retried.
Yes. Although event names reference audio, payloads describe the whole content item. Check the media array for generated assets. For full player configuration including video, use the player API after receiving the webhook.
Yes. Any integration that creates content in BeyondWords can trigger webhooks when processing completes. Set a stable source_id in your embed code or CMS integration so webhook payloads map cleanly to your articles. See Magic Embed and WordPress.
Webhooks push notifications to your server when events occur. Polling requires your server to repeatedly call the content API or player API to check whether processing has finished. Webhooks are more efficient for workflows that need to react promptly when generation completes.

Getting help

If you encounter issues or have questions, contact support.