ReviewTycoon API

v1 Public documentation

Introduction

A simple JSON REST API to read your review sites, offers and articles, and to add new offers and articles programmatically. Everything you can do through the API you can also do in the dashboard — it writes the exact same data.

Base URL: https://cms.reviewtycoon.com/api/v1

MethodEndpointDescription
GET/sitesList your review sites
GET/sites/{id}Get one review site
GET/sites/{id}/categoriesList categories on a site
POST/sites/{id}/categoriesAdd a category
GET/categories/{id}Get one category
PATCH/categories/{id}Update a category
DELETE/categories/{id}Delete a category
GET/sites/{id}/offersList offers on a site
POST/sites/{id}/offersAdd an offer
GET/offers/{id}Get one offer
PATCH/offers/{id}Update an offer
DELETE/offers/{id}Delete an offer
GET/sites/{id}/articlesList articles on a site
POST/sites/{id}/articlesAdd an article
GET/articles/{id}Get one article
PATCH/articles/{id}Update an article
DELETE/articles/{id}Delete an article
Get your API key by logging in to the dashboard at cms.reviewtycoon.com → My Profile → API. An administrator of your account can generate one there.

Authentication

Every request must include your API key as a Bearer token in the Authorization header:

Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Alternatively you may send it in an X-Api-Key header. All requests must use HTTPS.

Your key is tied to your account and grants access to only your own review sites, offers and articles. Requests for data that doesn't belong to your account return 404; a missing or wrong key returns 401.

Making requests

curl https://cms.reviewtycoon.com/api/v1/sites \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

Responses & errors

Successful responses wrap the result in a data field (list endpoints add meta):

{
  "data": { ... },
  "meta": { "page": 1, "per_page": 50, "total": 12, "total_pages": 1 }
}

Errors use a consistent shape and the matching HTTP status code:

{
  "error": {
    "code": "validation_error",
    "message": "Validation failed.",
    "details": { "fields": { "name": "This field is required." } }
  }
}
StatuscodeMeaning
400invalid_jsonBody is not valid JSON.
401missing_api_key / invalid_api_keyNo key, or an unknown key.
403account_blockedThe account is blocked.
404site_not_found / offer_not_found / article_not_foundUnknown resource, or not yours.
405method_not_allowedWrong HTTP method for this endpoint.
409duplicate_offer / duplicate_categoryAn offer/category with that name already exists on the site.
409category_not_emptyCategory still has offers/articles — reassign them first (see below).
413payload_too_largeBody exceeds 1 MB.
415unsupported_media_typeBody wasn't sent as application/json.
422validation_errorOne or more fields are invalid (see details.fields).
429rate_limitedToo many requests — slow down.
500internal_errorSomething went wrong on our side.

Rate limiting

Up to 120 requests per minute per account. Every response carries X-RateLimit-Limit and X-RateLimit-Remaining headers; exceeding the limit returns 429 with a retry_after (seconds) in the error details.

Pagination

List endpoints accept ?page= (default 1) and ?per_page= (default 50, max 200). The meta object reports total and total_pages.

Updating

Update a single offer, article or category with PATCH. Updates are partial: send only the fields you want to change — everything else stays as it is. The accepted fields are the same as for the matching POST, plus an optional slug (changing it registers a 301 redirect from the old URL). A successful update returns 200 with the full updated resource.

# set an offer inactive and bump its rating — nothing else changes
curl -X PATCH "https://cms.reviewtycoon.com/api/v1/offers/12345" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "status": "inactive", "rating_editor": 9.2 }'

Deleting

DELETE is available for single offers, articles and categories. Offers and articles are soft-deleted (hidden from your live site and from the API, but recoverable by support if needed). Categories are removed permanently. A successful delete returns 200 with { "data": { "id": …, "deleted": true } }; deleting an unknown/already-deleted resource returns 404.

Review sites

GET /sites

List all your review sites.

curl "https://cms.reviewtycoon.com/api/v1/sites" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

{
  "data": [
    {
      "id": 8,
      "domain": "saastoolsreviews.com",
      "url": "https://www.saastoolsreviews.com",
      "type": "review",
      "is_active": true,
      "dns_active": true,
      "created_at": "2018-10-10T12:54:01+02:00"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 1, "total_pages": 1 }
}

GET /sites/{id}

Fetch a single review site by id.

Categories

Every offer belongs to a category. Use these endpoints to look up the categories on a site (to get a category_id for an offer) or to create a new one. You can also create a category on the fly when adding an offer by passing category (a name) instead of category_id — see Offers.

GET /sites/{id}/categories

List the categories on one of your sites. Supports pagination.

curl "https://cms.reviewtycoon.com/api/v1/sites/8/categories" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

{
  "data": [
    {
      "id": 7,
      "site_id": 8,
      "parent_id": null,
      "name": "SEO Tools",
      "slug": "seo-tools",
      "offer_count": 12,
      "article_count": 3,
      "subcategory_count": 0,
      "public_url": "https://www.saastoolsreviews.com/seo-tools/"
    }
  ],
  "meta": { "page": 1, "per_page": 50, "total": 1, "total_pages": 1 }
}

GET /categories/{id}

Fetch a single category (any of your sites).

POST /sites/{id}/categories

Add a new category to a site. Send a JSON body with these fields:

FieldTypeNotes
namestringRequired. Category name (max 255). Must be unique on the site.
parent_idintParent category on this site (omit for a top-level category).
descriptionstringDescription (HTML allowed).
meta_titlestringSEO title (max 1000).
meta_descriptionstringSEO description.
sort_orderintManual sort position.
curl "https://cms.reviewtycoon.com/api/v1/sites/8/categories" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Web Hosting", "description": "<p>Hosting providers.</p>" }'

# → 201 Created
{ "data": { "id": 42, "site_id": 8, "name": "Web Hosting",
            "slug": "web-hosting", "parent_id": null,
            "public_url": "https://www.saastoolsreviews.com/web-hosting/", ... } }

PATCH /categories/{id}

Update a category (partial). Fields: name, description, meta_title, meta_description, parent_id, sort_order, slug.

curl -X PATCH "https://cms.reviewtycoon.com/api/v1/categories/42" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "name": "Managed Hosting", "sort_order": 3 }'

DELETE /categories/{id}

Delete a category. By default only an empty category can be deleted; if it still has offers or articles you get 409 category_not_empty (with offer_count/article_count in the details). Pass the optional query parameter ?move_to_category_id=<id> to move all its offers and articles to another category on the same site first, then delete. Any subcategories become top-level.

# delete an empty category
curl -X DELETE "https://cms.reviewtycoon.com/api/v1/categories/42" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# or move its contents to category 7, then delete
curl -X DELETE "https://cms.reviewtycoon.com/api/v1/categories/42?move_to_category_id=7" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

{ "data": { "id": 42, "deleted": true,
            "moved_to_category_id": 7, "moved_offers": 3, "moved_articles": 1 } }

Offers

GET /sites/{id}/offers

List the offers on one of your sites. Optional filters ?status=active|inactive|all (default all, excludes deleted) and ?category_id=<id> (only offers in that category — an unknown category on this site returns 422). Supports pagination.

curl "https://cms.reviewtycoon.com/api/v1/sites/8/offers?status=active&category_id=42&per_page=25" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

GET /offers/{id}

Fetch a single offer (any of your sites).

POST /sites/{id}/offers

Add a new offer to a site. Send a JSON body with these fields:

Every offer must be in a category. You must provide either category_id (an existing category — look it up via Categories) or category (a name, which is created or reused). Omitting both returns 422 validation_error.
FieldTypeNotes
namestringRequired. Offer name (max 100). Must be unique on the site.
urlstringRequired. Destination / fallback URL (http:// is added if missing).
category_idintRequired (this or category). An existing category on this site.
categorystringRequired (this or category_id). Name of a category to create/reuse (max 255).
descriptionstringDescription (HTML allowed).
statusstringactive (default) or inactive.
labelstringShort label badge (max 100).
pricestringPrice text (max 25).
summarystringShort summary.
meta_titlestringSEO title (max 1000).
meta_descriptionstringSEO description.
h1stringPage heading (defaults to the name).
affiliate_urlstringTracking / affiliate URL (max 255).
affiliate_url_mobilestringMobile tracking URL.
program_idstringAffiliate program id (max 100).
affiliate_network_idintAffiliate network id.
ecpcnumberEstimated eCPC (0–32767).
rating_editornumberEditor rating 0–10 (1 decimal).
is_topboolMark as a top pick.
is_spotlightboolShow in the spotlight.
in_carouselboolShow in the carousel.
is_popularboolMark as popular.
sort_orderintManual sort position.
curl "https://cms.reviewtycoon.com/api/v1/sites/8/offers" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Hosting",
    "url": "https://acme.example/go",
    "category": "Web Hosting",
    "description": "<p>Reliable hosting for small business.</p>",
    "rating_editor": 8.5,
    "is_top": true
  }'

# → 201 Created
{ "data": { "id": 12345, "site_id": 8, "name": "Acme Hosting",
            "slug": "acme-hosting", "status": "active",
            "public_url": "https://www.saastoolsreviews.com/reviews/acme-hosting/", ... } }

PATCH /offers/{id}

Update an offer (partial). Accepts the same fields as POST above (except category — use category_id to move it), plus slug.

curl -X PATCH "https://cms.reviewtycoon.com/api/v1/offers/12345" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "affiliate_url": "https://acme.example/new-tracking", "is_top": true }'

DELETE /offers/{id}

Soft-delete an offer (hidden from your live site; recoverable by support).

curl -X DELETE "https://cms.reviewtycoon.com/api/v1/offers/12345" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

{ "data": { "id": 12345, "deleted": true } }

Articles

GET /sites/{id}/articles

List the articles on one of your sites. Optional filters ?status=published|draft|all (default all) and ?category_id=<id> (only articles in that category — an unknown category on this site returns 422). Supports pagination.

GET /articles/{id}

Fetch a single article (any of your sites).

POST /sites/{id}/articles

Add a new article to a site. Send a JSON body with these fields:

FieldTypeNotes
titlestringRequired. Article title (max 255).
contentstringBody (HTML allowed).
subtitlestringSubtitle.
offer_idintLink the article to one of your offers.
category_idintA category on this site.
author_idintAn author on your account.
statusstringpublished (default) or draft.
published_atstringISO-8601 date/time (defaults to now).
keywordstringFocus keyword (max 250).
meta_titlestringSEO title (max 1000).
meta_descriptionstringSEO description.
h1stringPage heading.
show_tocboolShow a table of contents.
hide_pictureboolHide the featured image.
curl "https://cms.reviewtycoon.com/api/v1/sites/8/articles" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Best hosting of 2026",
    "content": "<p>Our full comparison…</p>",
    "offer_id": 12345,
    "status": "published"
  }'

PATCH /articles/{id}

Update an article (partial). Accepts the same fields as POST above, plus slug. Example: publish a draft.

curl -X PATCH "https://cms.reviewtycoon.com/api/v1/articles/6789" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "status": "published" }'

DELETE /articles/{id}

Soft-delete an article (hidden from your live site; recoverable by support).

curl -X DELETE "https://cms.reviewtycoon.com/api/v1/articles/6789" \
  -H "Authorization: Bearer rt_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

{ "data": { "id": 6789, "deleted": true } }

ReviewTycoon API v1 · Get your API key