---
title: Podcast Integrations API
menu_order: 45
menu_group: Podcasts
requires_podcasts: true
---

# Podcast Integrations API

Provider-neutral extension contract for distribution add-ons. MediaBlaster core owns shows, episodes, validation, RSS, and entitlements. Add-ons own provider auth, mappings, jobs, uploads, and provider UI.

**Required core version:** 3.2.0+

## Security rules

- Never assume public media is available for premium/gated episodes.
- Public REST and RSS must not expose protected audio, video, transcripts, chapters, or full show notes.
- Filesystem paths are never returned from public helpers or REST.
- Use `edit` / `distribution` contexts only with appropriate capabilities.

## Functions

```php
mediablaster_get_podcast_show( $show_id, $context = 'edit' );
mediablaster_get_podcast_episode( $episode_id, $context = 'edit', $user_id = 0 );
mediablaster_get_podcast_episode_guid( $episode_id );
mediablaster_get_podcast_episode_media( $episode_id, $media_type = 'audio' );
mediablaster_validate_podcast_show( $show_id, $context = 'distribution' );
mediablaster_validate_podcast_episode( $episode_id, $context = 'distribution' );
mediablaster_register_podcast_integration( $slug, $args );
mediablaster_get_podcast_integrations();
```

Invalid or forbidden operations return `WP_Error` where appropriate.

### Media payload example

```json
{
  "attachment_id": 12,
  "source_type": "attachment",
  "url": "https://example.com/audio.mp3",
  "mime_type": "audio/mpeg",
  "byte_size": 1234567,
  "duration": "12:34",
  "fingerprint": "sha256..."
}
```

### Validation result schema

```json
{
  "valid": false,
  "errors": [{ "code": "missing_audio", "field": "audio", "message": "..." }],
  "warnings": [{ "code": "artwork_too_small", "field": "featured_media", "message": "..." }],
  "data": {}
}
```

## Hooks

| Hook | Type | Arguments |
|------|------|-----------|
| `mediablaster_register_podcast_integrations` | action | (none) |
| `mediablaster_podcast_show_payload` | filter | `$item, $show_id, $context, $user_id` |
| `mediablaster_podcast_episode_payload` | filter | `$item, $episode_id, $context, $user_id` |
| `mediablaster_podcast_episode_media` | filter | `$payload, $episode_id, $media_type` |
| `mediablaster_podcast_show_validation` | filter | `$result, $show_id, $context` |
| `mediablaster_podcast_episode_validation` | filter | `$result, $episode_id, $context` |
| `mediablaster_podcast_show_saved` | action | `$show_id` |
| `mediablaster_podcast_episode_saved` | action | `$episode_id` |
| `mediablaster_podcast_episode_guid_assigned` | action | `$episode_id, $guid` |
| `mediablaster_podcast_distribution_actions` | filter | `$actions, $post_id, $object_type` (`show`\|`episode`) — applied from the Distribution side metabox on show/episode editors |

## Integrations admin

When Podcasts are enabled, **Podcasts → Integrations** (`manage_podcast_integrations`) lists registered integrations and links to each add-on’s `settings_url` (top-level arg or `callbacks.settings_url`).

## Minimal fictional registration

```php
add_action( 'mediablaster_register_podcast_integrations', function () {
	mediablaster_register_podcast_integration( 'example-distributor', array(
		'label'         => 'Example Distributor',
		'version'       => '1.0.0',
		'required_core' => '3.2.0',
		'capability'    => 'manage_podcast_integrations',
		'supports'      => array( 'publish' ),
		'callbacks'     => array(
			// Add-on owns HTTP; do not call real services from this example.
		),
	) );
} );
```

The registry is inert when no add-on is installed. Core does not create provider job tables.
