Reseller API (v1)

API for resellers to programmatically register sites with us

Last updated 18 days ago

The Consent Studio Reseller API

The Reseller API allows approved partners to manage customer sites, assign plans, and automate onboarding.

All endpoints are authenticated using a reseller API token and scoped to the reseller that owns the token.

You’ll need a reseller API token (request one via your account manager or support team).


Authentication

You can authenticate via a Bearer Token in the HTTP header or a token parameter in the query string.

Example (HTTP header)

Authorization: Bearer YOUR_RESELLER_TOKEN

Example (query)

?token=YOUR_RESELLER_TOKEN

If the token is missing or invalid, the API will return a 401 Unauthorized error.


Workflow examples

Create + Invite + Link (Reseller Sends Invoices Externally and Manually)

  1. Make sure that your reseller holds at least one site that has a manually activated subscription for a specific type plan.

  2. POST /sites β€” register the new domain with Consent Studio

  3. PATCH /sites/{domain_or_uuid}/link β€” link it to the a top level site with an active subscription

  4. POST /users/invite/{domain_or_uuid} β€” invite the customer to manage their site

Recommended: Create + Invite (Automatic Payouts to Reseller)

  1. Make sure that you have completed your Reseller Onboarding to be eligible to get automatic payouts to your bank account (!)

  2. POST /sites β€” register the new domain with Consent Studio

  3. POST /users/invite/{domain_or_uuid} β€” invite the customer to manage their site and set-up billing

Cancelling a site

Either...

  • Unlink it from a parent subscription (API) and contact Consent Studio support (manually) to detach it from the reseller account

  • Delete the site completely using the API


Endpoint: Get Reseller Info & Available Plans

Returns metadata about the reseller and a list of subscription plans the reseller can assign to sites.

Endpoint

GET /api/v1/reseller/about

Response (200 OK)

{
  "name": "string",
  "country_code": "string",
  "prices": [
    {
      "uuid": "string",
      "plan": "string",
      "price": "string",
      "amount_customer": "integer",
      "amount_reseller": "integer",
      "cycle": "string"
    }
  ]
}

Remarks

  • A plan can have various prices for end customers. These are listed in the prices array.

  • Prices vary based on how much the customer is charged, how much the reseller earns and the invoicing cycle.

  • Price amounts (amount_customer, amount_reseller) are returned in eurocents.


Endpoint: List All Sites

Returns all sites linked to your reseller account.

Endpoint

GET /api/v1/reseller/sites

Request

{
  "page": int,
  "per_page": null|int
}

Response (200 OK)

{
  "items": [
    {
      "uuid": "string",
      "domain": "string",
      "parent_site": "string|null",
      "is_active": "boolean",
      "is_trialing": "boolean",
      "is_subscribed": "boolean",
      "subscribed_plan": "string|null",
      "subscribed_price": "string|null",
      "access_to_prices": "array",
      "is_top_level_domain": "boolean",
      "is_subdomain": "boolean",
      "has_http_consent_cookies_enabled": "boolean",
      "has_http_consent_cookies_enabled_via_dns_record": "boolean",
      "has_http_consent_cookies_enabled_via_worker": "boolean"
    }
  ],
  "meta": {
    "current_page": "integer",
    "last_page": "integer",
    "per_page": "integer",
    "total": "integer"
  }
}

Endpoint: Create A Site

Creates a new site under your reseller account. If it is not linked to a parent site with an active subscription, the site starts on a trial.

Endpoint

POST /api/v1/reseller/sites

Request

{
  "domain": "string (required)",
  "languages": "array",
  "aliases": "array",
  "plan_uuid": "string|null",
  "access_to_prices": "array|null",
  "link_to_domain": "string|null",
  "link_to_uuid": "string|null",
  "primary_color": "string|null",
  "banner_position": "string|null",
  "dark_mode": "boolean|null",
  "overlay_mode": "boolean|null",
  "enable_brand_icon": "boolean|null",
  "toggle_position": "string|null",
  "enable_toggle_on_desktop": "boolean|null",
  "enable_toggle_on_mobile": "boolean|null",
  "enable_reject_all_button": "boolean|null",
  "enable_close_icon": "boolean|null",
  "enable_google_consent_mode": "boolean|null",
  "enable_uet_consent_mode": "boolean|null",
  "enable_implicit_consent": "boolean|null",
  "highlight_accept_all_button": "boolean|null",
  "hide_inactive_categories": "boolean|null",
  "enable_analytics_reprompting": "boolean|null",
  "enable_marketing_reprompting": "boolean|null",
  "enable_http_cookies_via_worker": "boolean|null",
  "enable_http_cookies_via_cname": "boolean|null",
  "detect_appearance": "boolean|null"
}

Remarks

  • link_to_domain and link_to_uuid are used to link this site to another domain for simplified/combined invoicing.

  • link_to_domain and link_to_uuid cannot both be present at the same time.

  • primary_color must be a color hex when present.

  • access_to_prices is a single-dimensional array of strings. Each string represents the UUID of a price. A price is a rate that the end customer pays and by which the reseller earns.

  • When access_to_prices is empty, the customer can subscribe to Consent Studio pricing directly at rates advertised on https://consent.studio/pricing.

  • When detect_appearance is true, Martin AI will analyse your website to determine the best color scheme that matches your website. Please note: when detect_appearance is true, Martin AI will overwrite your current color scheme.

Response (200 OK)

{
  "uuid": "string",
  "domain": "string",
  "parent_site": "string|null",
  "aliases": "array",
  "languages": "array",
  "last_health_check_at": "string|null",
  "is_active": "boolean",
  "is_trialing": "boolean",
  "is_subscribed": "boolean",
  "subscribed_plan": "string|null",
  "subscribed_price": "string|null",
  "access_to_prices": "array",
  "is_top_level_domain": "boolean",
  "is_subdomain": "boolean",
  "primary_color": "string|null",
  "banner_position": "string|null",
  "dark_mode": "boolean",
  "overlay_mode": "boolean",
  "enable_brand_icon": "boolean",
  "toggle_position": "string|null",
  "enable_toggle_on_desktop": "boolean",
  "enable_toggle_on_mobile": "boolean",
  "enable_reject_all_button": "boolean",
  "enable_close_icon": "boolean",
  "enable_google_consent_mode": "boolean",
  "enable_uet_consent_mode": "boolean",
  "enable_implicit_consent": "boolean",
  "highlight_accept_all_button": "boolean",
  "hide_inactive_categories": "boolean",
  "has_http_consent_cookies_enabled": "boolean",
  "has_http_consent_cookies_enabled_via_dns_record": "boolean",
  "has_http_consent_cookies_enabled_via_worker": "boolean",
  "enable_http_cookies_via_worker": "boolean",
  "enable_http_cookies_via_cname": "boolean",
  "has_functional_cookies": "boolean",
  "has_analytics_cookies": "boolean",
  "has_marketing_cookies": "boolean",
  "enable_analytics_reprompting": "boolean",
  "enable_marketing_reprompting": "boolean",
  "meta": {
    "usage": {
      "consent_actions": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "languages": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "aliases": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "integrations": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      }
    },
    "billing_period": {
      "start": "string",
      "end": "string"
    }
  }
}

Endpoint: View A Site

Get detailed information about a specific site using its UUID or domain.

Endpoint

GET /api/v1/reseller/sites/{uuid_or_domain}

Response (200 OK)

{
  "uuid": "string",
  "domain": "string",
  "parent_site": "string|null",
  "aliases": "array",
  "languages": "array",
  "last_health_check_at": "string|null",
  "is_active": "boolean",
  "is_trialing": "boolean",
  "is_subscribed": "boolean",
  "subscribed_plan": "string|null",
  "subscribed_price": "string|null",
  "access_to_prices": "array",
  "is_top_level_domain": "boolean",
  "is_subdomain": "boolean",
  "primary_color": "string|null",
  "banner_position": "string|null",
  "dark_mode": "boolean",
  "overlay_mode": "boolean",
  "enable_brand_icon": "boolean",
  "toggle_position": "string|null",
  "enable_toggle_on_desktop": "boolean",
  "enable_toggle_on_mobile": "boolean",
  "enable_reject_all_button": "boolean",
  "enable_close_icon": "boolean",
  "enable_google_consent_mode": "boolean",
  "enable_uet_consent_mode": "boolean",
  "enable_implicit_consent": "boolean",
  "highlight_accept_all_button": "boolean",
  "hide_inactive_categories": "boolean",
  "has_http_consent_cookies_enabled": "boolean",
  "has_http_consent_cookies_enabled_via_dns_record": "boolean",
  "has_http_consent_cookies_enabled_via_worker": "boolean",
  "enable_http_cookies_via_worker": "boolean",
  "enable_http_cookies_via_cname": "boolean",
  "has_functional_cookies": "boolean",
  "has_analytics_cookies": "boolean",
  "has_marketing_cookies": "boolean",
  "enable_analytics_reprompting": "boolean",
  "enable_marketing_reprompting": "boolean",
  "meta": {
    "usage": {
      "consent_actions": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "languages": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "aliases": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "integrations": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      }
    },
    "billing_period": {
      "start": "string",
      "end": "string"
    }
  }
}

Endpoint: Update A Site

Update settings for a site, including language options, cookie settings, or linking it to a parent site by UUID or domain.

Endpoint

PATCH /api/v1/reseller/sites/{uuid_or_domain}

Request

{
  "languages": "array",
  "aliases": "array",
  "link_to_domain": "string|null",
  "link_to_uuid": "string|null",
  "primary_color": "string|null",
  "banner_position": "string|null",
  "dark_mode": "boolean|null",
  "overlay_mode": "boolean|null",
  "enable_brand_icon": "boolean|null",
  "toggle_position": "string|null",
  "enable_toggle_on_desktop": "boolean|null",
  "enable_toggle_on_mobile": "boolean|null",
  "enable_reject_all_button": "boolean|null",
  "enable_close_icon": "boolean|null",
  "enable_google_consent_mode": "boolean|null",
  "enable_uet_consent_mode": "boolean|null",
  "enable_implicit_consent": "boolean|null",
  "highlight_accept_all_button": "boolean|null",
  "hide_inactive_categories": "boolean|null",
  "enable_analytics_reprompting": "boolean|null",
  "enable_marketing_reprompting": "boolean|null",
  "enable_http_cookies_via_worker": "boolean|null",
  "enable_http_cookies_via_cname": "boolean|null"
}

Remarks

  • link_to_domain and link_to_uuid are used to link this site to another domain for simplified/combined invoicing.

  • link_to_domain and link_to_uuid cannot both be present at the same time.

  • primary_color must be a color hex when present.

Response (200 OK)

{
  "uuid": "string",
  "domain": "string",
  "parent_site": "string|null",
  "aliases": "array",
  "languages": "array",
  "last_health_check_at": "string|null",
  "is_active": "boolean",
  "is_trialing": "boolean",
  "is_subscribed": "boolean",
  "subscribed_plan": "string|null",
  "subscribed_price": "string|null",
  "access_to_prices": "array",
  "is_top_level_domain": "boolean",
  "is_subdomain": "boolean",
  "primary_color": "string|null",
  "banner_position": "string|null",
  "dark_mode": "boolean",
  "overlay_mode": "boolean",
  "enable_brand_icon": "boolean",
  "toggle_position": "string|null",
  "enable_toggle_on_desktop": "boolean",
  "enable_toggle_on_mobile": "boolean",
  "enable_reject_all_button": "boolean",
  "enable_close_icon": "boolean",
  "enable_google_consent_mode": "boolean",
  "enable_uet_consent_mode": "boolean",
  "enable_implicit_consent": "boolean",
  "highlight_accept_all_button": "boolean",
  "hide_inactive_categories": "boolean",
  "has_http_consent_cookies_enabled": "boolean",
  "has_http_consent_cookies_enabled_via_dns_record": "boolean",
  "has_http_consent_cookies_enabled_via_worker": "boolean",
  "enable_http_cookies_via_worker": "boolean",
  "enable_http_cookies_via_cname": "boolean",
  "has_functional_cookies": "boolean",
  "has_analytics_cookies": "boolean",
  "has_marketing_cookies": "boolean",
  "enable_analytics_reprompting": "boolean",
  "enable_marketing_reprompting": "boolean",
  "meta": {
    "usage": {
      "consent_actions": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "languages": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "aliases": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      },
      "integrations": {
        "current": "integer",
        "limit": "integer",
        "is_unlimited": "boolean",
        "is_over_limit": "boolean",
        "overage": "integer"
      }
    },
    "billing_period": {
      "start": "string",
      "end": "string"
    }
  }
}

Endpoint: Delete A Site

Permanently deletes a site from our systems and your reseller account.

When deleting a site/domain, all its information and consent action records will be deleted instantly. This action is irreversible.

Endpoint

DELETE /api/v1/reseller/sites/{uuid_or_domain}

Response (200 OK)

{
  "message": "string"
}

Endpoint: Link a Site to a Subscribed Site

Link a site to a subscribed parent site, allowing the child site to share the parent’s plan. This updates the site’s subscription state and the quantity of on the parent's subscription plan.

PATCH /api/v1/reseller/sites/{uuid_or_domain}/link

Request

{
  "target": "string (required)"
}

Remarks

  • target can both be an UUID or a domain name.

  • A top level site cannot become a child site of another child site.

  • Upon connecting new child sites to a top level site, the top level site's subscription quantities will be updated shortly.


Endpoint: Unlink A Site From Its Parent

Unlink a site from its parent site. This removes it from the parent site’s subscription and starts a new trial.

Endpoint

PATCH /api/v1/reseller/sites/{uuid_or_domain}/unlink

Response (200 OK)

{
  "message": "string"
}

Remarks

  • Upon disconnecting a child site from a top level site, it will be considered a top level site again. However, it will not be subscribed anymore and a new trial will start. Please refer to our product website to see the standard length of any new trial.


Endpoint: Invite Users To Manage A Site

Endpoint

POST /api/v1/reseller/users/invite/{uuid_or_domain}

Request

{
  "invite": "string|array (required)"
}

Remarks

  • invite will hold the e-mail addresses of the users that are to be invited. You are responsible yourself for retrieving consent for sharing personal identifiable information.

Response (200 OK)

{
  "message": "string",
  "successful": "array",
  "failed": "array"
}

Endpoint: Detect Site Appearance

Triggers AI-powered color palette detection for a site. The AI analyzes your website and suggests colors for the consent banner based on your site's branding.

Endpoint: POST /api/v1/reseller/sites/{siteUuidOrDomain}/detect-appearance

Rate Limit: 1 request per 60 minutes per domain

Response (202 Accepted):

{
  "message": "Appearance detection initiated",
  "status": "pending"
}

Response (429 Too Many Requests):

{
  "error": "Too many requests",
  "message": "Appearance detection can only be triggered once per hour per site",
  "retry_after_seconds": 1847
}

Endpoint: List Prices

Returns all plan prices your reseller account has access to. Use this to discover plan_uuid / price_uuid values for creating sites or granting site-level price access.

Endpoint

GET /api/v1/reseller/prices

Request

{
  "page": int,
  "per_page": null|int
}

Response (200 OK)

{
  "items": [
    {
      "uuid": "string",
      "plan": "string",
      "description": "string",
      "variant": "string",
      "cycle": "string",
      "price_in_cents": "integer",
      "reseller_share_in_cents": "integer"
    }
  ],
  "meta": {
    "current_page": "integer",
    "last_page": "integer",
    "per_page": "integer",
    "total": "integer"
  }
}

Endpoint: List Site Pages

Returns all pages currently tracked for the site. Pages are scanned URLs (paths) where tracking technologies are detected during site audits.

Endpoint

GET /api/v1/reseller/sites/{uuid_or_domain}/pages

Response (200 OK)

[  {    "id": "integer",    "path": "string",    "originated_from_sitemap": "boolean"  }]

Endpoint: Add A Page To A Site

Manually adds a page (by its path) to the site so it will be included in the next scan.

Endpoint

POST /api/v1/reseller/sites/{uuid_or_domain}/pages

Request

{
  "path": "string (required)"
}

Response (200 OK)

{
  "id": "integer",
  "path": "string",
  "originated_from_sitemap": "boolean"
}

Remarks

  • path must start with a forward slash (/).

  • path must be unique per site. Duplicate paths return a 422 validation error.

  • path length is capped at 255 characters.


Endpoint: Remove A Page From A Site

Deletes a page from the site. The page will not be rescanned unless it is re-added manually or discovered again through a sitemap.

Endpoint

DELETE /api/v1/reseller/sites/{uuid_or_domain}/pages/{pageId}

Response (200 OK)

{
  "message": "Page removed"
}

Endpoint: List Site Tracking Technologies

Returns all tracking technologies detected on (or manually added to) the site. Supported technology_type values: cookie, localStorage, sessionStorage, indexedDB, cacheStorage, pixel, serviceWorker. Paginated, with filters for category, technology_type, and automatically_added.

Endpoint

GET /api/v1/reseller/sites/{uuid_or_domain}/tracking-technologies

Request

{
  "category": "unclassified|functional|analytics|marketing (optional)",
  "technology_type": "cookie|localStorage|sessionStorage|indexedDB|cacheStorage|pixel|serviceWorker (optional)",
  "automatically_added": "boolean (optional)",
  "page": int,
  "per_page": null|int
}

Response (200 OK)

{
  "items": [
    {
      "id": "integer",
      "identifier": "string",
      "technology_type": "string",
      "category": "string",
      "retention_period": "string|null",
      "automatically_added": "boolean",
      "first_found_at": "ISO 8601 datetime|null"
    }
  ],
  "meta": {
    "current_page": "integer",
    "last_page": "integer",
    "per_page": "integer",
    "total": "integer"
  }
}

Remarks

  • automatically_added is true for entries added by the scanner, false for manually created entries.

  • vendor_name, platform_name, descriptions, and privacy_portal_url are write-only. They can be set via POST/PATCH but are not returned on GET. This prevents our tracking-technology catalog from being scraped through reseller-visible endpoints.


Endpoint: Create A Tracking Technology

Manually adds a tracking technology to the site (for example, one that the scanner cannot detect automatically). Only identifier is required; every other field is optional.

Endpoint

POST /api/v1/reseller/sites/{uuid_or_domain}/tracking-technologies

Request

{
  "identifier": "string (required)",
  "technology_type": "cookie|localStorage|sessionStorage|indexedDB|cacheStorage|pixel|serviceWorker (optional, default: cookie)",
  "category": "unclassified|functional|analytics|marketing (optional, default: unclassified)",
  "vendor_name": "string|null",
  "platform_name": "string|null",
  "descriptions": { "locale_code": "string" },
  "privacy_portal_url": "string|null",
  "retention_period": "string|null"
}

Response (200 OK)

{
  "id": "integer",
  "identifier": "string",
  "technology_type": "string",
  "category": "string",
  "retention_period": "string|null",
  "automatically_added": false,
  "first_found_at": "ISO 8601 datetime"
}

Remarks

  • Entries created via this endpoint always have automatically_added = false.

  • Keys in descriptions must be valid locale codes supported by Consent Studio (e.g. en, nl, de). Unknown locales return a 422 validation error.

  • vendor_name, platform_name, descriptions, and privacy_portal_url are write-only. You can set them via POST/PATCH but they're not returned on GET. This prevents our tracking-technology catalog from being scraped through reseller-visible endpoints.


Endpoint: Update A Tracking Technology

Updates any field on a tracking technology. All fields are optional; omitted fields are left unchanged.

Endpoint

PATCH /api/v1/reseller/sites/{uuid_or_domain}/tracking-technologies/{technologyId}

Request

{
  "identifier": "string",
  "technology_type": "cookie|localStorage|sessionStorage|indexedDB|cacheStorage|pixel|serviceWorker",
  "category": "unclassified|functional|analytics|marketing",
  "vendor_name": "string|null",
  "platform_name": "string|null",
  "descriptions": { "locale_code": "string" },
  "privacy_portal_url": "string|null",
  "retention_period": "string|null"
}

Response (200 OK)

{
  "id": "integer",
  "identifier": "string",
  "technology_type": "string",
  "category": "string",
  "retention_period": "string|null",
  "automatically_added": "boolean",
  "first_found_at": "ISO 8601 datetime|null"
}

Remarks

  • Keys in descriptions must be valid locale codes supported by Consent Studio (e.g. en, nl, de). Unknown locales return a 422 validation error.

  • vendor_name, platform_name, descriptions, and privacy_portal_url are write-only. You can set them via POST/PATCH but they're not returned on GET. This prevents our tracking-technology catalog from being scraped through reseller-visible endpoints.


Endpoint: Delete A Tracking Technology

Removes a tracking technology from the site.

Deleting a tracking technology is not permanent if the scanner still detects it on the site. On the next site scan, the entry will be automatically re-created with automatically_added = true. There is no suppression / ignore-list mechanism.

Endpoint

DELETE /api/v1/reseller/sites/{uuid_or_domain}/tracking-technologies/{technologyId}

Response (200 OK)

{
  "message": "Tracking technology removed"
}

Validation Errors

When a request fails validation, the API responds with HTTP status 422 Unprocessable Entity. The response body shape is:

{
  "message": "string",
  "errors": {
    "field_name": ["string"]
  }
}

Each key under errors is the name of a failing field; its value is an array of human-readable messages.

Note

  • Earlier versions of the Reseller API returned HTTP 400 for validation errors. This has been aligned with HTTP conventions β€” clients that branched on 400 should be updated to branch on 422. The response body format is unchanged.