Skip to main content

Email Queue REST API

A single endpoint for polling the status of an email job group. Used by the Migration Wizard status panel, the Broadcasts admin screen and Benecaster’s admin sending banner to show real-time delivery progress. An add-on can put its own job in that banner; see Showing Your Job in the Admin Banner.


GET /benecaster/v1/shows/{id}/email-queue-status

Returns the current delivery status for a job group — a set of email queue rows identified by a shared related_id and type.

Auth: manage_options + X-WP-Nonce

Parameters:

Param Source Type Required Description
{id} Path int Yes Show ID
related_id Query int Yes ID of the entity driving this job group (e.g. migration import ID or broadcast ID)
type Query string Yes Email type string identifying the job group (e.g. migration_invitation, broadcast)

Response:

{
  "total": 89,
  "sent": 71,
  "failed": 2,
  "pending": 16,
  "status": "sending",
  "estimated_completion": "2026-05-17T15:42:00"
}

Response fields:

Field Type Description
total int Total rows in this job group
sent int Rows with status sent
failed int Rows with status failed
pending int Rows with status pending or in_progress
status string queued, sending, complete, or complete_with_failures
estimated_completion string|null ISO 8601 datetime estimated from current pending count and the emails_per_hour setting; null when pending = 0

Status values:

Status Meaning
queued Job exists but processing hasn’t started yet
sending At least one row sent; rows still pending
complete All rows terminal (sent or failed); zero failures
complete_with_failures All rows terminal; one or more failed rows

Errors:

Code HTTP Condition
show_not_found 404 Show ID does not exist
invalid_param 400 related_id or type missing

Polling pattern:

The Broadcasts screen polls this endpoint every 30 seconds while status is queued or sending. Stop polling when status is complete or complete_with_failures. The estimated_completion field gives the UI a target to display — it is recalculated on every poll as the pending count decreases.

Relationship to broadcasts:

For broadcasts specifically, use related_id = the broadcast ID and type = broadcast. The GET /broadcasts/{id}/recipients endpoint gives per-recipient detail; this endpoint gives the aggregate counts needed for a status bar.


Showing Your Job in the Admin Banner

Benecaster’s admin shows a sending banner at the top of every Benecaster screen — “Sending {label}: 47 of 1,203 sent” with a View status → link — for one email job at a time. It follows the job named in the browser’s localStorage under the key benecaster_active_email_job, and polls this endpoint for it. It re-reads the key whenever the podcaster moves to another Benecaster screen, and when another tab writes it, so the banner appears as soon as your job starts.

The banner does not discover jobs from the server. No key, no banner: an add-on that queues email and wants the banner writes the key itself.

localStorage.setItem( 'benecaster_active_email_job', JSON.stringify( {
    show_id:    showId,              // the show the queue rows belong to
    related_id: importId,            // the queue rows' related_id
    type:       'migration_welcome', // the rows' exact email_type: the banner polls with it
    label:      __( 'welcome emails', 'my-addon' ), // lowercase and translated
    view_url:   statusPageUrl,       // optional: adds the View status link
} ) );
Field Required Description
show_id Yes The show the queue rows belong to
related_id Yes The rows’ related_id, as passed to this endpoint
type Yes The rows’ exact email_type. A near match finds no rows, and the banner shows nothing useful
label Yes What is being sent, lowercase and already translated; it is placed mid-sentence
view_url No Where View status → goes. Omit it and the banner has no link
  • Only one job is followed. The broadcast screen writes the same key while a broadcast sends, so the last writer wins.
  • The banner clears the key when the podcaster dismisses its completion notice. If your job ends another way, clear it yourself with localStorage.removeItem( 'benecaster_active_email_job' ).
  • The key name and the field names are a stable contract for add-ons.

See Also

Need this built rather than just documented? See our services →