Skip to main content

Reports — share and embed

Branded reports — the merchant-facing feature is documented in Branded reports — can be shared three ways once generated:

  1. As a public URL (token-gated, no auth, anyone with the link).
  2. As a dashboard URL (auth-gated, only your tenant).
  3. Embedded as an iframe in your own site (using either of the above).

This page documents the endpoints and the iframe contract. For creating reports programmatically, see the dashboard API (POST /api/v1/dashboard/org/reports) — but in practice reports are created in the dashboard UI and shared via the endpoints below.


Endpoint summary

MethodPathAuthPurpose
POST/api/v1/dashboard/org/reports/:id/shareJWT (owner / admin)Mint or rotate a share token.
DELETE/api/v1/dashboard/org/reports/:id/shareJWT (owner / admin)Revoke the share token.
GET/api/v1/dashboard/org/reports/:idJWTRead report metadata (no HTML).
GET/api/v1/dashboard/org/reports/:id/htmlJWTRead the rendered HTML for in-dashboard preview.
GET/api/v1/public/reports/:shareTokennoneRead the rendered HTML by share token.

Production base URL: https://api.clione.ai.


1. Mint a share URL

POST /api/v1/dashboard/org/reports/:id/share
Authorization: Bearer <JWT>
Content-Type: application/json

{ "expiresInDays": 30 }

Body:

FieldTypeNotes
expiresInDaysnumber or nullDays until the token stops working. null or omitted = no expiry.

Response:

{
"id": "rep_...",
"shareToken": "9f2c...64hex...",
"expiresAt": "2026-07-05T00:00:00.000Z"
}

Token shape: 32 bytes of random hex (256 bits of entropy). Treat as a bearer secret.

The token is unique-indexed in the DB. Re-calling this endpoint rotates the token — the old one stops working immediately, even if it hadn't expired yet.

Revoke

DELETE /api/v1/dashboard/org/reports/:id/share
Authorization: Bearer <JWT>

Response: 204 No Content. Sets shareToken=null and expiresAt=null. The previous URL hits 404 from that moment on.


2. Build the public URL

Default domain:

https://app.clione.ai/r/<shareToken>

The dashboard /r/:token route is a thin wrapper that iframes https://api.clione.ai/api/v1/public/reports/:shareToken. You can link to either:

  • https://app.clione.ai/r/<token> — what end-users see, includes app chrome.
  • https://api.clione.ai/api/v1/public/reports/<token> — raw HTML, what you embed.

Custom domain (Pro and Agency)

If the tenant has a verified custom domain (reports.acme.com), shared URLs use it instead:

https://reports.acme.com/r/<shareToken>

Setup is documented in Branded reports — Custom domain. The custom domain is a CNAME to custom-reports.clione.ai and is verified by the dashboard against both CNAME and resolving IP (CNAME-flattening tolerant).


3. Public fetch endpoint

GET /api/v1/public/reports/:shareToken

No auth. The token validates the request.

Responses

CodeWhen
200 OKToken valid and not expired. Body is the full rendered HTML.
404 Not FoundToken unknown, revoked, or past expiresAt. We return 404 (not 410) intentionally — we don't leak whether a token ever existed.
500Server error.

Response headers

Content-Type: text/html; charset=utf-8
Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline' https://fonts.googleapis.com; font-src 'self' https://fonts.gstatic.com data:; img-src 'self' https: data:; script-src 'none'; frame-ancestors 'self' https://app.clione.ai https://*.vercel.app http://localhost:5173
Cross-Origin-Resource-Policy: cross-origin
Cross-Origin-Embedder-Policy: unsafe-none
Referrer-Policy: no-referrer
Cache-Control: private, max-age=300

Notes on the CSP:

  • script-src 'none' — the rendered HTML never executes JS. You can safely iframe it anywhere.
  • style-src 'unsafe-inline' is required because the renderer embeds all CSS inline.
  • frame-ancestors allows the Clione dashboard, Vercel preview deployments, and localhost. To embed in your own site, you'll need to use the dashboard-rendered URL (which has the same body but no frame-ancestors restriction relative to your domain) or contact us to add your domain to the allowlist.

Cache: 5 minutes private. Token rotation invalidates immediately on the server side, so a fresh fetch after revoke always hits 404.


4. Auth-gated fetch (dashboard preview)

GET /api/v1/dashboard/org/reports/:id/html
Authorization: Bearer <JWT>

Same body as the public endpoint, same headers, but scoped to the requester's tenant. Superadmins also see cross-tenant reports (those with tenantId=null created via /admin/reports/from-scans).

Use this when you want to preview inside a tenant-scoped tool and don't want to mint a public token.


5. Iframe embed pattern

Reports are designed to be iframed. The CSP allows it for app.clione.ai out of the box.

<iframe
src="https://app.clione.ai/r/9f2c...64hex..."
title="Q2 SEO performance — Acme"
style="width:100%; height:100vh; border:0;"
loading="lazy"
referrerpolicy="no-referrer"
></iframe>

For a custom-domain embed:

<iframe
src="https://reports.acme.com/r/9f2c...64hex..."
...
></iframe>

If you need to embed in a domain that's not on the frame-ancestors list, two options:

  • Recommended — request your domain be added. Email admin@takefortytwo.com with the hostname.
  • Workaround — proxy the report HTML through your backend and re-serve it from your own origin with your own CSP.

Security model

  • Tokens are 256 bits of entropy from a CSPRNG. Brute force is not practical.
  • Tokens are not scoped to a viewer identity — anyone with the URL can view.
  • Token rotation is the only revocation primitive (set shareToken=null or call POST /share to mint a new one).
  • Tokens with a past expiresAt return 404 on lookup — the row is not deleted.
  • HTML is sanitized at render time — there are no script tags in the output regardless of the source data.
  • The endpoint sets Referrer-Policy: no-referrer so the viewing browser does not leak the token to outbound links inside the report.