Getting Started

Redirects and sitemap

Resolve renamed paths to their new address, and list every live path of the enabled modules for a sitemap.

View as Markdown

These two endpoints help a storefront keep its search ranking when the merchant renames things. They belong to the platform, not to one module: any module that gives content an address contributes to them. Catalog content uses paths of a fixed shape: a product lives at /products/{slug} and a category at /categories/{slug}. Content records (Objects) live at the type's address prefix for the language plus the record slug, for example /services/kitchen-fitting. If your storefront uses different URLs, map these paths onto your own routes.

The catalog contributes sitemap entries for products and categories, and Objects contributes one entry per published record address (see GET /v1/api/sitemap). When the merchant changes a product, category or record slug, Borkol records a permanent redirect from the old path to the new one; for a record this happens only when the type has a non-empty address prefix for that language. Chains collapse: renaming a to b and then b to c leaves both /products/a and /products/b pointing straight at /products/c. A path that becomes live again (a new product takes the old slug) stops redirecting.

Both endpoints take a tenant API key carrying any one of the catalog:read, commerce:read, tenant:read or objects:read scopes, sent as Authorization: Bearer {api_key}. They do not require the catalog module: a store that only uses Objects can call them too. The shared tenant rate limit of 120 requests per minute applies.

GET /v1/api/redirects

Looks up the redirect for one storefront path. Call it when a product, category or record request on your storefront would otherwise answer 404, and send the visitor on with the returned status code.

The lookup strips one trailing slash (/products/old-chair/ matches /products/old-chair; the root path / is left alone) and is case-sensitive. Only exact paths match: query strings are not part of the path.

Query parameters

NameTypeRequiredDescription
pathstringYesThe storefront path to look up, for example /products/old-chair or /services/old-slug. At most 512 characters.
Request
curl "https://api.borkol.com/v1/api/redirects?path=%2Fproducts%2Fold-chair" \
  -H "Authorization: Bearer {api_key}" \
  -H "Accept: application/json"
Request (JS)
const res = await fetch(
  "https://api.borkol.com/v1/api/redirects?" +
    new URLSearchParams({ path: "/products/old-chair" }),
  {
    headers: {
      Authorization: `Bearer ${apiKey}`,
      Accept: "application/json",
    },
  }
);
if (res.status === 404) {
  // No redirect: render your own not-found page.
} else {
  const { data } = await res.json();
  // Redirect the visitor to data.to_path with data.status.
}
Response
{
  "data": {
    "from_path": "/products/old-chair",
    "to_path": "/products/oak-dining-chair",
    "status": 301
  }
}

Response fields

NameTypeRequiredDescription
from_pathstringalwaysThe stored old path (without a trailing slash).
to_pathstringalwaysThe path to send the visitor to. Redirects are recorded whatever the status of the product, category or record, and archiving or unpublishing does not remove one, so to_path itself may be unavailable; check it before redirecting.
statusintegeralwaysHTTP status to redirect with. Currently always 301 (permanent).

Errors

StatusBodyCause
401{"message":"Unauthenticated."}Missing or invalid API key.
403{"message":"Invalid ability provided."}Key carries none of the catalog:read, commerce:read, tenant:read or objects:read scopes.
403{"message":"Tenant suspended.","code":"tenant_suspended"}Tenant account is suspended.
404{"message":"..."}No redirect exists for this path.
422{"message":"...","errors":{"path":["..."]}}path is missing, not a string, or longer than 512 characters.
429{"message":"Too Many Attempts."}Rate limit of 120 requests per minute exceeded.

GET /v1/api/sitemap

Lists every live path of the modules enabled for the store, ready to render as a sitemap.xml. A module that is disabled contributes nothing, so a store without the catalog module gets no product or category entries (the response is then an empty data array, not an error). The catalog module contributes all products with status active and all categories that are active, products first, then categories, each group ordered by slug. The Objects module contributes one entry per publicly visible record, language and address, for object types that have a non-empty address prefix for that language; types without prefixes have no public pages and are left out, and so are drafts and scheduled records. The response is not paginated.

Parameters

None.

Request
curl "https://api.borkol.com/v1/api/sitemap" \
  -H "Authorization: Bearer {api_key}" \
  -H "Accept: application/json"
Response
{
  "data": [
    {
      "type": "product",
      "path": "/products/oak-dining-chair",
      "lastmod": "2026-10-11T09:14:33+00:00"
    },
    {
      "type": "category",
      "path": "/categories/chairs",
      "lastmod": "2026-10-02T15:20:11+00:00"
    },
    {
      "type": "object_record",
      "object_type": "service",
      "locale": "nl",
      "path": "/diensten/keukenmontage",
      "lastmod": "2026-10-09T12:41:07+00:00",
      "alternates": {
        "en": "/services/kitchen-fitting",
        "nl": "/diensten/keukenmontage"
      }
    }
  ]
}

Response fields

Each entry in data:

NameTypeRequiredDescription
typestringalwaysproduct, category or object_record.
pathstringalwaysStorefront path: /products/{slug}, /categories/{slug}, or for a record the type's address prefix for the language plus the record's address, for example /services/kitchen-fitting.
lastmodstring (ISO 8601) or nullalwaysWhen the product, category or record was last updated.
object_typestringobject_record onlyKey of the record's object type.
localestringobject_record onlyThe language of this entry's address.
alternatesobjectobject_record onlyLanguage tag to path, for every enabled language in which the record has a public address (including this entry's own). Use it for hreflang links.

Errors

StatusBodyCause
401{"message":"Unauthenticated."}Missing or invalid API key.
403{"message":"Invalid ability provided."}Key carries none of the catalog:read, commerce:read, tenant:read or objects:read scopes.
403{"message":"Tenant suspended.","code":"tenant_suspended"}Tenant account is suspended.
429{"message":"Too Many Attempts."}Rate limit of 120 requests per minute exceeded.