Skip to content

Profile

Your public profile is the link-in-bio style page served at /t/<slug>. The API edits a draft, then publishes it. Editing never changes the live page until you call publish.

OperationEndpointScope
Read draft + publish stateGET /api/v1/profileapi:profile:read
Update draft (merge patch)PATCH /api/v1/profileapi:profile:write
Publish draftPOST /api/v1/profile/publishapi:profile:write

Get the draft

GET /api/v1/profile

Response

json
{
  "data": {
    "draft": { "slug": "your-slug", "displayName": "…", "bio": "…", "layoutBlocks": [] },
    "isPublished": true,
    "publishedAt": "2026-06-23T00:00:00.000Z",
    "slug": "your-slug"
  }
}

Update the draft

PATCH /api/v1/profile
Content-Type: application/json

The body is a JSON Merge Patch (RFC 7396):

  • Keys you include are updated; keys you omit are left unchanged.
  • null clears a nullable field (or resets it to its default).
  • layoutBlocks is replaced wholesale when present.

Patchable fields

FieldTypeNotes
slugstringPublic URL segment. 409 if already taken.
displayNamestringUp to 100 chars.
biostringUp to 1000 chars.
themePresetstringA built-in theme name, or custom.
customColorsobject | nullprimaryColor, accentColor, backgroundColor, textColor, surfaceColor, borderColor.
ctaLabel / ctaUrlstring | nullPrimary call-to-action button.
bookingLabelstring | nullBooking button label.
joinRequestEnabledbooleanShow the "request to join" button.
joinRequestDescriptionstring | nullHelper text for join requests.
layoutBlocksarrayOrdered content blocks (see below). Up to 30.
avatarUrl / bannerUrl / pageBackgroundUrlstring | nullImage URLs only — see note.
avatarFocalX / avatarFocalYnumber01.
avatarZoomnumber13.
bannerFocalX / bannerFocalYnumber01.
bannerZoomnumber13.
pageBackgroundFocalX / pageBackgroundFocalYnumber01.
pageBackgroundZoomnumber13.
pageBackgroundOverlayOpacitynumber01.

isPublished and teacher_id are not patchable — publishing is a separate call and the owner is always the key holder.

Images are URL-only

The API does not upload files. Set avatarUrl / bannerUrl / pageBackgroundUrl to an absolute https:// URL you already host. Unsafe URL schemes (javascript:, data:, protocol-relative //…) are rejected.

Layout blocks

layoutBlocks is an array of blocks. Common types:

json
[
  {
    "id": "block-features",
    "type": "features",
    "data": { "items": [
      { "title": "Card title", "body": "Card body", "linkUrl": "https://example.com/page" }
    ] }
  },
  {
    "id": "block-links",
    "type": "links",
    "data": { "items": [
      { "label": "Browse Quizzes", "url": "/quizzes" }
    ] }
  }
]
  • features card linkUrl must be an absolute https:// URL. Internal app paths (e.g. /quizzes) are rejected for feature cards — use a links block for in-app shortcuts (its url accepts relative paths).
  • Up to 24 feature items and 50 link items.

Example

bash
curl -X PATCH https://quizzz.techtranslab.com/api/v1/profile \
  -H "Authorization: Bearer qz_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{"bio":"New bio","ctaLabel":"Start now","ctaUrl":"https://example.com"}'

Response:

json
{ "data": { "draft": { "…": "…" }, "saved": true } }

Publish

POST /api/v1/profile/publish

Publishes the current saved draft to the live /t/<slug> page.

json
{ "data": { "published": true, "slug": "your-slug", "publishedAt": "2026-06-23T00:00:00.000Z" } }
  • 404 — no draft to publish.
  • 409 — slug taken at publish time.
  • 400 — branding payload invalid.
  • 200 with "brandingPartial": true — the profile is live; the branding half failed and is retried automatically.

SEO (page <title> and meta description) is set via the Branding resource, not the profile.

TechTrans Lab