Skip to content

Partner API

Everything the Stayblox CLI does goes through this REST API. You can call it directly (from CI, scripts, or your own tooling) with the same token the CLI uses.

Authentication

All endpoints sit under https://api.stayblox.com/api and require a Sanctum bearer token:

Authorization: Bearer <token>
Accept: application/json

stayblox login obtains and stores one; programmatically, POST /auth/login with your email and password returns { token, ... }.

Your user must belong to a verified partner account. If you belong to several, every endpoint accepts an ?account_id=<id> query parameter to pick the acting account; without it, themes are matched across all your partner accounts and pushes act for the account that owns the manifest slug.

Rate limits

EndpointsLimit
/partner/themes*, /partner/teams30 requests/minute
/partner/dev-themes*240 requests/minute (file sync is chatty)

Error envelope

Failed requests return a consistent JSON envelope:

json
{
  "message": "Theme validation failed.",
  "errors":  { "package": ["The package field is required."] },
  "report":  { "passed": false, "errors": [], "warnings": [] }
}
  • message: always present; human-readable summary.
  • errors: only on request-validation failures: field → list of messages.
  • report: only when a theme package was validated: the full validation report. Each entry is { "rule": "graphql.validate", "message": "…", "file": "graphql/unit_types.graphql" }.

Status codes: 401 unauthenticated, 403 not your theme/team or no partner account, 404 unknown resource, 422 validation or state errors (e.g. deleting a released version), 429 throttled.

Themes and versions

GET /partner/themes

Your themes across all your partner accounts:

json
{ "themes": [ { "slug": "breeze", "name": "Breeze", "status": "active", "is_free": true, "price": "0.00", "desktop_preview_url": null, "mobile_preview_url": null } ] }

POST /partner/themes/validate

Multipart body with a package zip (max 20 MB). Dry-run validation: writes nothing, returns the report with HTTP 200 whether it passed or not.

GET /partner/themes/{slug}/versions

All versions, newest first. Each version:

json
{
  "id": 12,
  "version_name": "1.2.0",
  "version_code": 4,
  "status": "rejected",
  "validation_report": { "passed": true, "errors": [], "warnings": [] },
  "review_notes": "Fix the broken checkout flow.",
  "submitted_at": "2026-06-10T12:00:00.000000Z",
  "reviewed_at": "2026-06-11T09:30:00.000000Z",
  "created_at": "2026-06-10T11:58:21.000000Z",
  "graphql_operations": [
    { "name": "UnitListing", "type": "query", "document_id": "3f1c…64 hex chars" }
  ]
}

status is one of draft, pending_review, approved, rejected.

graphql_operations lists every operation this version declared under graphql/*.graphql, with the document_id your storefront JS sends to the headless GraphQL endpoint — see Storefront data (GraphQL).

POST /partner/themes/{slug}/versions

Multipart package zip. Validates, then creates or re-pushes the draft version named by the manifest. Returns 201 with { version, report }; a failing package returns 422 with { message, report } and writes nothing.

GET /partner/themes/{slug}/versions/{id}

A single version with its full stored validation_report and review_notes.

DELETE /partner/themes/{slug}/versions/{id}

Deletes a draft version: its text files and its private-bucket assets. Released (approved/rejected) versions return 422; they are immutable history. Deleting the last version of a never-released theme removes the theme itself. Returns 204.

POST /partner/themes/{slug}/versions/{id}/submit

Moves a draft into the review queue (pending_review). Only drafts can be submitted; anything else returns 422. You'll be notified by email and in your partner dashboard when it's approved or rejected.

Dev themes

GET /partner/teams

The sites owned by your partner accounts, the candidates for stayblox theme dev. Teams are addressed by their slug:

json
{ "teams": [ { "slug": "demo-hotel", "name": "Demo Hotel", "domain": "demo-hotel.example" } ] }

The payload also carries legacy numeric id and account_id fields for older CLIs; new integrations should use slug.

POST /partner/dev-themes

Multipart body: team (the team slug, from GET /partner/teams) + a package zip. A legacy numeric team_id is still accepted for older CLIs. Imports the package as a private dev theme on that site. Re-posting the same manifest slug reuses the same dev theme (stable id, stable preview URL) and replaces its files:

json
{
  "dev_theme": { "id": 2841, "team": "demo-hotel", "name": "Breeze", "theme_slug": "breeze", "version": "1.0.0" },
  "preview_url": "https://demo-hotel.example/_theme-preview/2841/start?expires=…&signature=…",
  "files_synced": 24,
  "changed_at": 1760000000
}

On first create the dev theme's settings and pages are seeded from config/settings_schema.json / config/pages.json, exactly like a catalog install; re-syncs leave them alone so customizer state survives.

201 when created, 200 when reused. The signed preview_url is valid for two hours and only works in your browser session; visitors never see dev themes. While previewing a dev theme, the page polls for changes and reloads itself when a file is synced.

GET /partner/dev-themes/{id}

Current state plus a fresh preview_url and changed_at (the newest updated_at across the theme and its files, as a Unix timestamp).

PUT /partner/dev-themes/{id}/files

Sync a single file:

  • Text file (liquid, css, js, json, svg, html, txt, xml, graphql): JSON body { "name": "views/index.liquid", "content": "…" }.
  • Binary file (images, fonts, video): multipart body with name and file. Send it as POST with a _method=PUT field: PHP only parses multipart bodies on POST requests.

Names are theme-relative paths, using the same text/binary extensions as the CLI's package rules. Anything outside the supported extensions, or containing .., is rejected with 422.

DELETE /partner/dev-themes/{id}/files

JSON body { "name": "views/index.liquid" } removes the file row (text) or the asset object (binary).

Dev themes are temporary

A dev theme untouched for 30 days is deleted automatically. Run stayblox theme dev again and it is recreated from your local directory.

© Stayblox — Developer Platform