Patterns
Cross-episode ad pattern management
GET /patterns
Section titled “GET /patterns”List ad patterns
Returns all ad patterns from the cross-episode pattern database. Patterns are organized by scope (global, network, podcast) and can be filtered to show only active patterns.
Parameters
Section titled “Parameters”scope(query, string, one ofall,global,network,podcast): Filter by pattern scopeactive_only(query, boolean): Only return active patterns. Accepts the legacyactivequery param as an alias.podcast_id(query, string): Filter to patterns scoped to this podcast slugnetwork_id(query, string): Filter to patterns scoped to this network idsource(query, string, one oflocal,community,imported): Filter by pattern source
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | List of patterns | object |
200 response body
Section titled “200 response body”patterns(array of Pattern)
GET /patterns/corrections/unresolved
Section titled “GET /patterns/corrections/unresolved”List unassigned legacy corrections
Candidates are current feed episodes or durable processing-history entries for an active feed. History candidates include their entry count and latest processing timestamp. They do not imply a current episode, transcript, or media file exists.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Unassigned corrections and safe feed candidates | object |
200 response body
Section titled “200 response body”count(integer): Total unassigned corrections, which may exceed the page returnedcorrections(array of object)corrections[].id(integer)corrections[].episode_id(string)corrections[].podcast_title(string or null)corrections[].episode_title(string or null)corrections[].correction_type(string)corrections[].original_bounds(any): Parsed JSON when valid, otherwise the stored stringcorrections[].corrected_bounds(any): Parsed JSON when valid, otherwise the stored stringcorrections[].created_at(string or null)corrections[].candidates(array of object)corrections[].candidates[].slug(string)corrections[].candidates[].podcast_title(string or null)corrections[].candidates[].episode_title(string or null)corrections[].candidates[].episode_available(boolean)corrections[].candidates[].source(string, one ofcurrent,history)corrections[].candidates[].history_run_count(integer or null)corrections[].candidates[].history_latest_processed_at(string or null)
POST /patterns/corrections/unresolved/bulk
Section titled “POST /patterns/corrections/unresolved/bulk”Assign or delete selected unassigned corrections
Updates up to 500 unique correction IDs in one transaction. Assignment requires one feed with current episode or processing-history evidence for every selected correction. Any stale or invalid row rejects the whole request without changes.
Request body (application/json, required)
Section titled “Request body (application/json, required)”action(string, one ofassign,delete, required)correctionIds(array of integer, required)slug(string): Required when action is assign.confirm(boolean, one oftrue, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | All selected corrections updated | object |
| 400 | Invalid action, confirmation, feed, or correction IDs | Error |
| 409 | A selected correction changed or lacks feed evidence | Error |
200 response body
Section titled “200 response body”action(string, one ofassign,delete, required)correctionIds(array of integer, required)
POST /patterns/corrections/{correction_id}/assign
Section titled “POST /patterns/corrections/{correction_id}/assign”Assign an unassigned correction to a feed
Parameters
Section titled “Parameters”correction_id(path, integer, required)
Request body (application/json, required)
Section titled “Request body (application/json, required)”slug(string, required)confirm(constanttrue, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Correction assigned after explicit confirmation | object |
| 400 | Bad request - invalid input | Error |
| 404 | Resource not found | Error |
| 409 | Correction was already assigned |
200 response body
Section titled “200 response body”assigned(constanttrue, required)correctionId(integer, required)slug(string, required)
DELETE /patterns/corrections/{correction_id}
Section titled “DELETE /patterns/corrections/{correction_id}”Delete one unassigned correction
Deletes only a correction whose feed is still unassigned. It never changes patterns, processing history, media, or feed records.
Parameters
Section titled “Parameters”correction_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Unassigned correction deleted | object |
| 404 | Correction not found | |
| 409 | Correction is already assigned |
200 response body
Section titled “200 response body”deleted(constanttrue, required)correctionId(integer, required)
GET /patterns/{pattern_id}
Section titled “GET /patterns/{pattern_id}”Get a single pattern
Returns details for a specific ad pattern
Parameters
Section titled “Parameters”pattern_id(path, integer, required): Pattern identifier (integer)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern details | Pattern |
| 404 | Resource not found | Error |
PUT /patterns/{pattern_id}
Section titled “PUT /patterns/{pattern_id}”Update a pattern
Update pattern properties like active status, sponsor, category, or disabled reason
Parameters
Section titled “Parameters”pattern_id(path, integer, required): Pattern identifier (integer)
Request body (application/json, required)
Section titled “Request body (application/json, required)”is_active(boolean): Whether the pattern is active. False stamps disabled_at (an already disabled pattern keeps its original time); true clears disabled_at, and disabled_reason too unless the request sends one.sponsor(string): Sponsor name for this patterndisabled_reason(string): Reason for disabling the patterncategory(string or null, one ofsponsor,cross_promo,self_promo,interaction,intro,outro,recap,null): Segment category for this pattern’s matches; each feed’s segment actions map the category to remove, beep, keep, or mark. Null clears the category, and an uncategorized pattern resolves as sponsor. An unrecognized value is rejected with 400.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern updated | object |
| 400 | Bad request - invalid input | Error |
| 404 | Resource not found | Error |
200 response body
Section titled “200 response body”message(string)pattern(Pattern)
DELETE /patterns/{pattern_id}
Section titled “DELETE /patterns/{pattern_id}”Delete a pattern
Permanently delete an ad pattern from the database
Parameters
Section titled “Parameters”pattern_id(path, integer, required): Pattern identifier (integer)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern deleted successfully | object |
| 404 | Resource not found | Error |
200 response body
Section titled “200 response body”message(string)
POST /patterns/backfill-false-positives
Section titled “POST /patterns/backfill-false-positives”Backfill false positive texts
Backfill transcript text for existing false positive corrections that were created before cross-episode matching was enabled. This extracts the transcript text from each correction’s original boundaries and stores it for future cross-episode matching.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Backfill completed | object |
| 500 | Internal server error | Error |
200 response body
Section titled “200 response body”message(string)updated(integer): Number of corrections updated with transcript textskipped(integer): Number of corrections skipped (missing transcript, too short)
POST /patterns/deduplicate
Section titled “POST /patterns/deduplicate”Deduplicate patterns
Manually trigger deduplication of similar patterns in the database
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Deduplication completed | object |
| 500 | Internal server error | Error |
200 response body
Section titled “200 response body”message(string)removed_count(integer): Number of duplicate patterns removed
GET /patterns/export
Section titled “GET /patterns/export”Export patterns
Export all patterns as JSON for backup or transfer
Parameters
Section titled “Parameters”include_corrections(query, boolean): Attach each pattern’s pattern_corrections rows ascorrections. Rows are exported whole, includingorigin(user or auto_pass2).
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Exported patterns | object |
200 response body
Section titled “200 response body”exportedAt(string (date-time))version(string)patterns(array of Pattern)
POST /patterns/import
Section titled “POST /patterns/import”Import patterns
Import patterns from a JSON export file
Request body (application/json, required)
Section titled “Request body (application/json, required)”patterns(array of Pattern, required)merge(boolean): Merge with existing patterns (true) or replace all (false) Defaulttrue.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Patterns imported | object |
200 response body
Section titled “200 response body”message(string)imported(integer)skipped(integer)
GET /patterns/stats
Section titled “GET /patterns/stats”Get pattern statistics
Returns aggregate statistics about the pattern database including counts by scope, stale patterns, patterns without sponsors, and patterns with high false positive rates.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern statistics | object |
200 response body
Section titled “200 response body”total(integer)active(integer)inactive(integer)by_scope(object)by_scope.global(integer)by_scope.network(integer)by_scope.podcast(integer)no_sponsor(integer): Patterns without a sponsor namenever_matched(integer): Patterns that have never been confirmedstale_count(integer): Patterns not matched in 30+ dayshigh_false_positive_count(integer): Patterns with more false positives than confirmationsstale_patterns(array of object)stale_patterns[].id(integer)stale_patterns[].sponsor(string)stale_patterns[].last_matched_at(string)stale_patterns[].confirmation_count(integer)no_sponsor_patterns(array of object)no_sponsor_patterns[].id(integer)no_sponsor_patterns[].scope(string)no_sponsor_patterns[].podcast_name(string or null)no_sponsor_patterns[].created_at(string)no_sponsor_patterns[].text_preview(string)high_false_positive_patterns(array of object)high_false_positive_patterns[].id(integer)high_false_positive_patterns[].sponsor(string)high_false_positive_patterns[].confirmation_count(integer)high_false_positive_patterns[].false_positive_count(integer)
GET /patterns/health
Section titled “GET /patterns/health”Check pattern health
Identify oversized patterns that are too large to match effectively. Returns patterns exceeding character thresholds, likely containing multiple merged ads.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern health report | object |
200 response body
Section titled “200 response body”total_patterns(integer)healthy(integer)issues_count(integer)critical_count(integer): Patterns over 3500 charswarning_count(integer): Patterns over 2500 charsissues(array of object)issues[].id(integer)issues[].sponsor(string)issues[].podcast_id(string or null)issues[].podcast_name(string or null)issues[].template_len(integer)issues[].confirmation_count(integer)issues[].severity(string, one ofwarning,critical)issues[].issue(string)issues[].recommendation(string, one ofreview,delete)
GET /patterns/contaminated
Section titled “GET /patterns/contaminated”Find contaminated patterns
Scan all active patterns for those containing multiple ad transition phrases, indicating they may contain merged multi-sponsor ads that should be split.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | List of contaminated patterns | object |
200 response body
Section titled “200 response body”count(integer): Number of contaminated patterns foundpatterns(array of object)patterns[].id(integer)patterns[].sponsor(string)patterns[].podcast_id(string)patterns[].text_length(integer)patterns[].transition_count(integer)patterns[].scope(string)
POST /patterns/{pattern_id}/split
Section titled “POST /patterns/{pattern_id}/split”Split a contaminated pattern
Split a pattern containing multiple ad transition phrases into separate single-sponsor patterns. The original pattern is disabled and new patterns are created for each detected sponsor segment.
Parameters
Section titled “Parameters”pattern_id(path, integer, required): ID of the pattern to split
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern successfully split | object |
| 400 | Pattern does not need splitting or not found | Error |
200 response body
Section titled “200 response body”success(boolean)original_pattern_id(integer)new_pattern_ids(array of integer)message(string)
GET /patterns/merge-suggestions
Section titled “GET /patterns/merge-suggestions”Suggested pattern merges
Same-sponsor near-duplicate pattern clusters that could fold into one row. Clusters are precomputed and cached server-side (keyed on each sponsor group’s text signature). Patterns without a sponsor are never clustered.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Cluster suggestions | object |
| 500 | Internal server error | Error |
200 response body
Section titled “200 response body”suggestions(array of object)suggestions[].sponsor_id(integer or null)suggestions[].sponsor(string or null)suggestions[].suggested_keep_id(integer): Keep-target chosen by the tiebreakersuggestions[].pattern_ids(array of integer)suggestions[].count(integer)suggestions[].result_intro_variant_count(integer)suggestions[].result_outro_variant_count(integer)
POST /patterns/merge
Section titled “POST /patterns/merge”Merge patterns
Fold patterns into a single kept pattern. The kept pattern keeps its own
text_template (so its audio fingerprint stays valid) and receives the
combined confirmation and false-positive counts plus the unioned
intro/outro variants (deduped, capped at five per side). Corrections are
reassigned, and the merged rows and their audio fingerprints are deleted.
All patterns must share the kept pattern’s sponsor (cross-sponsor merges
are rejected). Merging reads below 75% similarity is allowed but returns
an advisory warning.
Request body (application/json, required)
Section titled “Request body (application/json, required)”keep_id(integer, required): ID of the pattern to keepmerge_ids(array of integer, required): IDs of patterns to merge into the kept pattern
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Patterns merged successfully | object |
| 400 | Bad request - invalid input | Error |
| 404 | Resource not found | Error |
| 500 | Internal server error | Error |
200 response body
Section titled “200 response body”message(string)kept_pattern_id(integer)merged_count(integer)total_confirmations(integer)total_false_positives(integer)intro_variant_count(integer)outro_variant_count(integer)warning(string): Present when a merged pair is below 75% similar
GET /patterns/cleanup
Section titled “GET /patterns/cleanup”Get pattern cleanup status and settings
Scheduled LLM review of learned ad patterns (Experiments). Combines the six configurable settings with live state: whether a run currently holds the lock, the last run’s timestamp/error/summary, and the pending suggestion counts by kind.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Pattern cleanup status | PatternCleanupStatus |
POST /patterns/cleanup/run
Section titled “POST /patterns/cleanup/run”Run pattern cleanup now
Starts a cleanup run on a background thread and returns immediately with the new run’s id. Each run processes a configured batch. force resets review history used for eligibility and replaces pending suggestions for every active learned pattern; approved and rejected decision records remain. Later normal runs continue the remaining batches. Calling force again restarts this process. A missing body means force=false. A supplied body must be a JSON object and force must be a JSON boolean. Rate limited to 6/hour.
Request body (application/json)
Section titled “Request body (application/json)”force(boolean): Defaultfalse.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 202 | Run started | object |
| 400 | Malformed JSON, non-object request body, or non-boolean force | Error |
| 409 | A cleanup run is already in progress (error: cleanup_in_progress) | Error |
| 429 | Rate limit exceeded | Error |
202 response body
Section titled “202 response body”runId(integer)
GET /patterns/cleanup/runs
Section titled “GET /patterns/cleanup/runs”List recent pattern cleanup runs
Parameters
Section titled “Parameters”limit(query, integer)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Recent runs, newest first | object |
200 response body
Section titled “200 response body”runs(array of PatternCleanupRun)
GET /patterns/cleanup/suggestions
Section titled “GET /patterns/cleanup/suggestions”List pattern cleanup suggestions
Each suggestion carries the current pattern summary (sponsor, scope, podcast title, counts), the proposed payload, and an immutable before snapshot from review time. Prefer before_id (the smallest id already seen) over offset to page to older decisions, including approved suggestions available for undo: a keyset cursor is not disturbed by rows that leave the result set between pages, where offset can skip or repeat rows. before_id takes precedence over offset when both are given.
Parameters
Section titled “Parameters”status(query, string, one ofpending,approved,rejected,undone)kind(query, string, one oftrim,split,rename,retire,flag,category)limit(query, integer)offset(query, integer)before_id(query, integer): Keyset cursor; only suggestions with id below this are returned.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Suggestions, newest first | object |
| 400 | Unknown status or kind filter | Error |
200 response body
Section titled “200 response body”suggestions(array of PatternCleanupSuggestion)
POST /patterns/cleanup/suggestions/{suggestion_id}/approve
Section titled “POST /patterns/cleanup/suggestions/{suggestion_id}/approve”Approve a pattern cleanup suggestion
Applies the change in place; the pattern keeps a before snapshot so it can be undone.
Parameters
Section titled “Parameters”suggestion_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Updated suggestion | PatternCleanupSuggestion |
| 404 | Suggestion not found | Error |
| 409 | The suggestion or its pattern does not allow this action (error: invalid_transition) | Error |
POST /patterns/cleanup/suggestions/{suggestion_id}/reject
Section titled “POST /patterns/cleanup/suggestions/{suggestion_id}/reject”Reject a pattern cleanup suggestion
Leaves the pattern alone and acknowledges the reviewed version and statistical evidence. Returns a conflict when the pattern changed after the suggestion was made; unseen newer text is not marked reviewed.
Parameters
Section titled “Parameters”suggestion_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Updated suggestion | PatternCleanupSuggestion |
| 404 | Suggestion not found | Error |
| 409 | The suggestion does not allow this action (error: invalid_transition) | Error |
POST /patterns/cleanup/suggestions/{suggestion_id}/undo
Section titled “POST /patterns/cleanup/suggestions/{suggestion_id}/undo”Undo an approved pattern cleanup suggestion
Restores only fields owned by the approval, using its before and post-approval snapshots. Split undo restores the original pattern and disables its unchanged children.
Parameters
Section titled “Parameters”suggestion_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Updated suggestion | PatternCleanupSuggestion |
| 404 | Suggestion not found | Error |
| 409 | Refused when the suggestion is not approved, a later approval on the same pattern has not been undone, owned fields or split children changed afterward, or an older approval lacks enough saved state for safe undo (error: invalid_transition) | Error |
POST /patterns/cleanup/suggestions/bulk
Section titled “POST /patterns/cleanup/suggestions/bulk”Approve or reject several pattern cleanup suggestions
Request body (application/json, required)
Section titled “Request body (application/json, required)”ids(array of integer, required)action(string, one ofapprove,reject, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Per-id results; a failed id carries an error instead of status |
object |
| 400 | Malformed ids or action | Error |
200 response body
Section titled “200 response body”results(array of object)results[].id(integer)results[].status(string, one ofapproved,rejected)results[].error(string, one ofnot_found,invalid_transition)
GET /detections
Section titled “GET /detections”List ad detections across all feeds
Flattens every episode’s ad markers into one list for the Ad Review tab, with a computed status and resolution per detection. Detections are resolved by POSTing to the existing per-episode corrections endpoint.
Parameters
Section titled “Parameters”page(query, integer)limit(query, integer)status(query, string, one ofneeds_review,pending,rejected,accepted,all): needs_review returns pending-review and rejected detections that have no matching correction yet.feed(query, string): Filter to a single feed by slugq(query, string): Case-insensitive match against sponsor and reasonsort(query, string, one ofdate,confidence,podcast)order(query, string, one ofasc,desc)category(query, string, one ofsponsor,cross_promo,self_promo,interaction,intro,outro,recap,none): Filter by segment category. Usenonefor markers no detection stage classified. Omit for every category.reviewer(query, string, one ofadjusted,unadjusted): Filter by whether the span was moved (see ReviewDetection.reviewerMoved). adjusted keeps moved rows; unadjusted keeps everything else. Omit for no filter. Applies to the cutSummary totals as well.holdReason(query, string, one ofmax_duration,no_cue_evidence,uncorroborated_tail,reviewer_contradiction,reviewer_boundary_conflict,reviewer_inconclusive_bounds,estimated_pattern_bounds,reviewer_reject_conflict,reviewer_failed,no_splice_evidence,verification_miss,verification_kept_conflict,differential_uncorroborated,large_vad_gap_extension,cue_template_unproven,cue_low_confidence,no_transcript_evidence,transcript_differential_unreviewed): Keep only pending-review detections held for this reason. Omit for no filter.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Paginated detection list | object |
| 400 | Bad request - invalid input | Error |
200 response body
Section titled “200 response body”detections(array of ReviewDetection)total(integer)page(integer)totalPages(integer)limit(integer)counts(object): Pre-filter overview counts across all detectionscounts.total(integer)counts.needsReview(integer)counts.pending(integer)counts.rejected(integer)counts.accepted(integer)counts.confirmed(integer)counts.dismissed(integer)counts.pendingByHoldReason(map of integer): Pending-review detections per hold reason. Counts follow only the feed and status filters; the q, reviewer, holdReason and category filters do not narrow them. Holds with no recorded reason are not counted.cutSummary(object): Totals over detections that were cut. Reflects the status, feed, and q filters but not the category filter, so the byCategory breakdown stays complete while the podcast selector still narrows it.cutSummary.count(integer)cutSummary.durationSeconds(number)cutSummary.byCategory(map of integer): Count per segment category, plus anonekey for markers with no category set.cutSummary.distinctSponsors(integer)cutSummary.distinctPodcasts(integer)
POST /patterns/bulk-delete
Section titled “POST /patterns/bulk-delete”Bulk-delete patterns
Hard-delete patterns by id or by source filter. Both confirm: true
and expected_count: N are required; the call is rejected if the
actual matched count does not equal expected_count.
Request body (application/json, required)
Section titled “Request body (application/json, required)”ids(array of integer)source(string, one oflocal,community,imported)confirm(boolean, required)expected_count(integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Deletion summary | object |
| 400 | Validation failure |
200 response body
Section titled “200 response body”deleted(integer)ids(array of integer)
POST /patterns/bulk-disable
Section titled “POST /patterns/bulk-disable”Bulk-disable patterns
Same shape as bulk-delete; sets is_active=0 instead.
Request body (application/json, required)
Section titled “Request body (application/json, required)”Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Disable summary | |
| 400 | Validation failure |
POST /patterns/preview-export
Section titled “POST /patterns/preview-export”Dry-run the community export pipeline for a list of pattern ids
Returns which patterns would pass the quality gates and which would be rejected, with per-id reasons. Used by the UI to show a preview before the user builds the actual submission bundle.
Request body (application/json, required)
Section titled “Request body (application/json, required)”ids(array of integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Preview result | object |
| 400 | ids list missing or empty |
200 response body
Section titled “200 response body”ready(array of integer)rejected(array of object)rejected[].id(integer)rejected[].sponsor(string or null)rejected[].reasons(array of string)ready_count(integer)rejected_count(integer)pattern_count(integer)
POST /patterns/submit-bundle
Section titled “POST /patterns/submit-bundle”Build a downloadable community-submission bundle
Runs the export pipeline on each id and returns a single JSON file
(Content-Disposition: attachment) containing every pattern that
passed quality gates. The file is the artifact the contributor
commits into patterns/community/ to open one PR for all the
selected patterns. The PR-side validator and the manifest builder
both handle the bundle format natively, so the maintainer does
not need to split it after merge.
Request body (application/json, required)
Section titled “Request body (application/json, required)”ids(array of integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Bundle JSON file (downloaded as attachment) | object |
| 400 | ids missing, or every pattern failed quality gates |
200 response body
Section titled “200 response body”format(string)bundle_version(integer)submitted_at(string (date-time))submitted_app_version(string)pattern_count(integer)patterns(array of object)
POST /patterns/{pattern_id}/submit-to-community
Section titled “POST /patterns/{pattern_id}/submit-to-community”Submit a local pattern to the community repository
Runs the community export pipeline: quality gates, tag validation,
PII strip, metadata strip, sponsor classification, and returns a
prefilled GitHub PR URL plus the JSON payload. When too_large is
true the URL exceeds GitHub’s limit and the client should offer
the JSON file as a download instead.
Parameters
Section titled “Parameters”pattern_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Export result | object |
| 400 | Pattern failed export gates |
200 response body
Section titled “200 response body”payload(object)filename(string)pr_url(string)too_large(boolean)sponsor_match(string, one ofexact,alias,fuzzy,unknown)
POST /patterns/{pattern_id}/protect
Section titled “POST /patterns/{pattern_id}/protect”Mark a community pattern as protected from sync
Parameters
Section titled “Parameters”pattern_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Updated protection state | |
| 400 | Pattern is not source=community |
DELETE /patterns/{pattern_id}/protect
Section titled “DELETE /patterns/{pattern_id}/protect”Clear the protected_from_sync flag on a community pattern
Parameters
Section titled “Parameters”pattern_id(path, integer, required)
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Updated protection state |
GET /tags/vocabulary
Section titled “GET /tags/vocabulary”Get the canonical community-pattern tag vocabulary
Returns the fixed tag vocabulary used by the pattern and sponsor tag pickers: the full tag list plus the podcast-genre, sponsor-industry, and special-tag groupings. The vocabulary ships with the app image and only changes when vocabulary_version is bumped.
Responses
Section titled “Responses”| Status | Description | Body |
|---|---|---|
| 200 | Tag vocabulary | object |
200 response body
Section titled “200 response body”vocabulary_version(integer)all_tags(array of string)podcast_genres(array of object)podcast_genres[].tag(string)podcast_genres[].description(string)sponsor_industries(array of object)sponsor_industries[].tag(string)sponsor_industries[].description(string)special_tags(array of object)special_tags[].tag(string)special_tags[].description(string)