DocsDiscoBeat

DiscoBeat Channel API

These docs are for DiscoBeat channel partners integrating with Disco's ad network. They cover authentication, recommendation configuration, channel and publisher management, and upcoming features.

Base URL & Authentication

Base URL

All endpoints are relative to your environment's base URL:

Production

https://api.disconetwork.com

Staging

https://api.disconetwork-staging.com

Authentication

All requests require a secret API key passed in the x-api-key header. Your Disco CS agent will provision a key for each environment you use.

⚠️Warning
Secret key vs. publishable key: The publishable key is safe to embed in client-side code and grants read-only access. The secret key allows writes and must be kept private. Never expose your secret key in client-side code.
ℹ️Info
Keys are environment-specific: Your staging key works only against the staging base URL, and your production key works only against production. Use staging while you're integrating and testing; switch to production once you're ready to go live. Sending a staging key to production (or vice versa) returns a 401 with "API key environment does not match service environment."
Authenticate a request
curl -H "x-api-key: your-secret-api-key" \
    https://api.disconetwork.com/discobeat/channel/details/

An invalid, expired, or missing key returns 401:

401 response
{"detail": "Invalid or expired API key."}

Errors & Validation

The API uses standard HTTP status codes. Here are the formats you'll encounter:

Validation errors. 400

Field-level validation messages:

400 validation
{
  "subcategory_ids": ["At least one subcategory must belong to the selected primary category."]
}

Conflict errors. 409

409 conflict
{"error": "A create request for this brand and domain already exists."}

Not found errors. 404

404 not found
{"error": "Publisher not found."}

Endpoint Reference

Ad Recommendation Management

MethodPathDescriptionDetails
GET/discobeat/adconfig/categories/List all subcategories, grouped by parent category
PUT/discobeat/channel/exclusions/Update channel-wide exclusions
PUT/discobeat/publishers/{id}/exclusions/Update publisher-specific exclusions

Channel & Publisher Management

MethodPathDescriptionDetails
GET/discobeat/channel/details/Get channel name and global exclusions
GET/discobeat/publishers/list/List all publishers, paginated and searchable
GET/discobeat/publishers/details/{id}/Get details for a single publisher
POST/discobeat/publishers/add/Submit a request to add publisher(s)
DELETE/discobeat/publishers/{id}/remove/Remove a publisher from your channel
Recommendations Configuration

List Categories

GET/discobeat/adconfig/categories/

Returns all categories with their subcategories, grouped by parent.

Successful Response

Response: 200
{
  "categories": [
    {
      "remote_id": "c9a1e2b3-4d5f-6789-abcd-ef0123456789",
      "name": "Fashion",
      "subcategories": [
        {"remote_id": "d4e5f6a7-8901-4235-bcde-f67890000001", "name": "Women's Apparel"},
        {"remote_id": "e5f6a7b8-9012-4356-cdef-a78901000002", "name": "Men's Apparel"},
        {"remote_id": "f6a7b8c9-0123-4567-defa-b89012000003", "name": "Footwear"}
      ]
    },
    {
      "remote_id": "a7b8c9d0-1234-4678-efab-c90123000004",
      "name": "Home & Garden",
      "subcategories": [
        {"remote_id": "b8c9d0e1-2345-4789-fabc-d01234000005", "name": "Furniture"},
        {"remote_id": "c9d0e1f2-3456-4890-abcd-e12345000006", "name": "Kitchen"}
      ]
    }
  ]
}

Notes

  • Use this to populate selectors when submitting publisher create requests or managing exclusions.
  • Categories and subcategories are sorted alphabetically.
Example
curl -H "x-api-key: your-management-api-key" \
  https://api.disconetwork.com/discobeat/adconfig/categories/

Update Channel Exclusions

PUT/discobeat/channel/exclusions/

Set subcategory exclusions that apply to all publishers under your channel. This replaces the current exclusion list entirely. Send [] to clear all.

FieldTypeReqDetails
subcategory_idsstring[]Subcategory remote_ids to exclude. Send [] to clear.

Successful Response

Request body
{
  "subcategory_ids": [
    "d4e5f6a7-8901-2345-bcde-f67890123456",
    "e5f6a7b8-9012-3456-cdef-a78901234567"
  ]
}
Response: 200
{"ok": true}

Notes

  • This replaces the current exclusion list entirely. Send [] to clear all.
Example
curl -X PUT \
  -H "x-api-key: your-management-api-key" \
  -H "Content-Type: application/json" \
  -d '{"subcategory_ids": ["d4e5f6a7-8901-2345-bcde-f67890123456"]}' \
  https://api.disconetwork.com/discobeat/channel/exclusions/

Update Publisher Exclusions

PUT/discobeat/publishers/{publisher_remote_id}/exclusions/

Set additional subcategory exclusions for a specific publisher.

FieldTypeReqDetails
subcategory_idsstring[]Full set of subcategory remote_ids to exclude for this publisher.

Successful Response

Request body
{
  "subcategory_ids": [
    "d4e5f6a7-8901-2345-bcde-f67890123456",
    "e5f6a7b8-9012-3456-cdef-a78901234567",
    "f6a7b8c9-0123-4567-defa-b89012345678"
  ]
}
Response: 200
{"ok": true}

Notes

  • These are applied at runtime on top of the publisher's own exclusions and your channel-level exclusions.
  • Send [] to clear.

Error Responses

StatusCondition
404No publisher with that ID found for your channel
Example
curl -X PUT \
  -H "x-api-key: your-management-api-key" \
  -H "Content-Type: application/json" \
  -d '{"subcategory_ids": ["d4e5f6a7-8901-2345-bcde-f67890123456"]}' \
  https://api.disconetwork.com/discobeat/publishers/f47ac10b-58cc-4372-a567-0e02b2c3d479/exclusions/
Channel & Publisher Management

Channel Details

GET/discobeat/channel/details/

Returns your channel name and channel-level exclusions.

Successful Response

Response: 200
{
  "channel": {
    "name": "Narvar",
    "exclusions": {
      "subcategories": {
        "channel": ["d4e5f6a7-8901-2345-bcde-f67890123456"]
      }
    }
  }
}

Notes

  • The exclusions.subcategories.channel array contains subcategory IDs excluded across all your publishers.
Example
curl -H "x-api-key: your-management-api-key" \
  https://api.disconetwork.com/discobeat/channel/details/

Publisher List

GET/discobeat/publishers/list/

Returns a paginated list of all publishers and pending requests, sorted newest first.

Query Parameters

FieldTypeReqDetails
pageintegerPage number: Default: 1
page_sizeintegerResults per page: Max: 200. Default: 50
qstringFilter by name: Words are split and matched independently (OR).

Successful Response

Response: 200
{
  "count": 47,
  "next": "https://api.disconetwork.com/discobeat/publishers/list/?page=2",
  "previous": null,
  "publishers": [
    {
      "pending_publisher_id": null,
      "publisher_remote_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
      "brand_name": "Allbirds",
      "primary_category": "Fashion",
      "status": "APPROVED",
      "created_at": "2026-03-10T09:15:00Z",
      "exclusions": {
        "subcategories": {
          "external": ["d4e5f6a7-8901-4235-bcde-f67890000001"],
          "publisher": ["e5f6a7b8-9012-4356-cdef-a78901000002"]
        }
      }
    },
    {
      "pending_publisher_id": "b2c3d4e5-f678-9012-3456-789012345678",
      "publisher_remote_id": null,
      "brand_name": "New Brand Co",
      "primary_category": "Home & Garden",
      "status": "PENDING",
      "created_at": "2026-04-14T12:00:00Z",
      "exclusions": {
        "subcategories": {"external": [], "publisher": []}
      }
    }
  ]
}

Notes

Status values

PENDINGNEEDS_INFOAPPROVEDREJECTED

Key fields

pending_publisher_id . Present for pending requests. Use as the path parameter for the detail endpoint until approved.

publisher_remote_id . The publisher's adserving UUID. null for pending requests. Use for remove and exclusions endpoints once approved.

exclusions.subcategories.external . Set by the publisher, read-only from your perspective. May change without notice.

exclusions.subcategories.publisher . Set by your channel for this specific publisher via the publisher exclusions endpoint.

Example
curl -H "x-api-key: your-management-api-key" \
  "https://api.disconetwork.com/discobeat/publishers/list/?page=1&page_size=50"

Publisher Detail

GET/discobeat/publishers/details/{id}/

Returns the full record for a single publisher or pending request.

Successful Response

Response: 200 (approved publisher)
{
  "publisher": {
    "pending_publisher_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "publisher_remote_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
    "api_key": "disco_pk_live_...",
    "brand_name": "Allbirds",
    "primary_category": "Fashion",
    "status": "APPROVED",
    "created_at": "2026-03-10T09:15:00Z",
    "exclusions": {
      "subcategories": {
        "external": ["d4e5f6a7-8901-4235-bcde-f67890000001"],
        "publisher": ["e5f6a7b8-9012-4356-cdef-a78901000002"]
      }
    }
  }
}

Notes

  • Pass the remote_id (approved) or pending_publisher_id (pending) from the list.

Error Responses

StatusCondition
404No publisher or pending request with that ID found for your channel
Example
curl -H "x-api-key: your-management-api-key" \
  https://api.disconetwork.com/discobeat/publishers/details/f47ac10b-58cc-4372-a567-0e02b2c3d479/

Add Publishers

POST/discobeat/publishers/add/

Submit one or more create requests for new publishers (max 50 per call).

Request Body

FieldTypeReqDetails
itemsarrayList of publisher entries (max 50)
items[].brand_namestringBrand name of the publisher
items[].domainstringBrand's website domain
items[].primary_category_idstringPrimary category remote_id
items[].subcategory_idsstring[]Subcategory remote_ids: At least one must belong to primary category.
Request body
{
  "items": [
    {
      "brand_name": "Allbirds",
      "domain": "allbirds.com",
      "primary_category_id": "c9a1e2b3-4d5f-6789-abcd-ef0123456789",
      "subcategory_ids": [
        "d4e5f6a7-8901-2345-bcde-f67890123456",
        "e5f6a7b8-9012-3456-cdef-a78901234567"
      ]
    },
    {
      "brand_name": "Casper",
      "domain": "casper.com",
      "primary_category_id": "a7b8c9d0-1234-5678-efab-c90123456789",
      "subcategory_ids": ["b8c9d0e1-2345-6789-fabc-d01234567890"]
    }
  ]
}

Successful Response

Response: 201
{
  "results": [
    {
      "brand_name": "Allbirds",
      "domain": "allbirds.com",
      "status": "created",
      "create_request": {
        "pending_publisher_id": "b2c3d4e5-f678-9012-3456-789012345678",
        "status": "PENDING",
        "brand_name": "Allbirds",
        "domain": "allbirds.com",
        "primary_category": {
          "remote_id": "c9a1e2b3-4d5f-4789-abcd-ef0123456789",
          "name": "Fashion"
        },
        "subcategory_ids": ["d4e5f6a7-8901-4235-bcde-f67890000001", "e5f6a7b8-9012-4356-cdef-a78901000002"],
        "staff_notes": "",
        "created_at": "2026-04-14T12:00:00Z",
        "updated_at": "2026-04-14T12:00:00Z"
      }
    },
    {
      "brand_name": "Casper",
      "domain": "casper.com",
      "status": "duplicate",
      "error": "A create request for this brand and domain already exists."
    }
  ]
}

Notes

ℹ️Info
Each item in the batch reports its result independently. Duplicates are flagged but do not fail the batch.
  • Each request triggers a matching process against existing publishers. Staff will review and approve matches.

Error Responses

StatusCondition
400Missing required fields, invalid category/subcategory IDs, or empty subcategory list
400items is empty or exceeds 50 entries
Example
curl -X POST \
  -H "x-api-key: your-management-api-key" \
  -H "Content-Type: application/json" \
  -d '{"items": [{"brand_name": "Allbirds", "domain": "allbirds.com", "primary_category_id": "c9a1e2b3-4d5f-4789-abcd-ef0123456789", "subcategory_ids": ["d4e5f6a7-8901-4235-bcde-f67890000001"]}]}' \
  https://api.disconetwork.com/discobeat/publishers/add/

Remove Publisher

DELETE/discobeat/publishers/{publisher_remote_id}/remove/

Remove an approved publisher from your channel.

Successful Response

Returns 204 No Content on success.

Error Responses

StatusCondition
404No publisher with that ID found for your channel
Example
curl -X DELETE \
  -H "x-api-key: your-management-api-key" \
  https://api.disconetwork.com/discobeat/publishers/f47ac10b-58cc-4372-a567-0e02b2c3d479/remove/
Roadmap

What's Next

Here's a preview of upcoming changes so you can plan ahead. Dates aren't firm yet. Reach out to your Disco contact with questions.

Soon

Richer channel onboarding

Self-serve flow with a primary admin user, team invitations with channel-scoped access, and a master API key generated at channel creation.

Soon

Surface configuration defaults

Define channel-level surface defaults once, page type, widget type/mode/version, placement ID conventions, and policy config, automatically applied to every new publisher.

Soon

Smarter publisher linking

The API will match against existing publishers (exact domain, fuzzy name) and return: new publisher, existing publisher (auto-linked), or needs review (ambiguous match with candidates).

Soon

Multi-channel publishers

A single merchant can live across multiple channels. One Publisher record per merchant, independent channel relationships with isolated surfaces, exclusions, and reporting.

Soon

Exclusions at the right level

Channel-level defaults that cascade, per-surface overrides, and publisher-managed exclusions respected across all surfaces.

Soon

Reporting dashboards

Channel-scoped reporting with impressions, clicks, conversions, and revenue. Filterable by publisher, surface, and date range. Fully isolated between channels.

Soon

Platform dashboard experience

A visual dashboard for logged-in channel users: view publishers and surfaces, add new publishers, manage exclusions, and access reporting.

Need help integrating?

Our engineering team is here to support your DiscoBeat integration.