Reseller API (v1)

API for resellers to programmatically register sites with us

Last updated 9 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.