---
title: "Public Article Play Beacon"
method: POST
path: "/v1/articles/{article_slug}/play-beacon"
---

# Public Article Play Beacon

`POST /v1/articles/{article_slug}/play-beacon`

## Request

- Base URL: `https://api.storyflo.com` (the document declares no server; this is the origin it was published from)
- URL: `https://api.storyflo.com/v1/articles/{article_slug}/play-beacon`
- Auth: none declared

Frontend audio-element beacon fallback.

Listeners on Spotify / Apple Podcasts fetch the audio enclosure
directly from R2, bypassing our /v1/articles/{slug}/audio route —
so we can't observe those plays server-side. The web player
POSTs here on the ``play`` audio event as a near-zero-cost
fallback so the rev-share earnings widget reflects real listens.

Same write semantics as the resolve path: per-day SHA-256 ip_hash
(or hash of X-Listener-Token when present), no PII stored. The
write is wrapped + rollback-safe so a beacon never returns 500.
Returns fast with ``{"ok": true}`` regardless of write outcome —
a beacon is fire-and-forget by design.

Flywheel pull-through (migration 0164): an optional JSON body
``{"source_embedder_slug": "<slug>"}`` (or the ``?via=<slug>`` query
param) attributes the play to the embedder surface it came through.
Both are optional + parsed defensively — a body-less beacon (every
existing caller) still works unchanged.

## Path parameters

- `article_slug` string, required

## Response `200`

Successful Response

- object

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/storyflo/apis/storyflo-inference-router.md) · [All operations](https://skmtc.dev/storyflo/apis/storyflo-inference-router/llms.txt) · [OpenAPI document](https://skmtc.dev/storyflo/apis/storyflo-inference-router/revisions/c3a1a735ac7a?raw)
