Workshops

4 endpointsEnglish only

List the caller's workshops

get/workshopsexperimentalSession required

Returns every workshop the caller is a member of. Each workshop carries its resolved `plan`, its `context` when notes have been saved and, once synthesized, its `contextDerived`.

Responses

  • 200Success
    FieldTypeRequiredConstraintsDescription
    workshopsarray of WorkshopYes--
    Example
    {
      "workshops": [
        {
          "id": "workshop-1",
          "name": "Extremely Awesome Workshop",
          "tagline": "Solid-wood furniture, built to order",
          "logo": "🛠️",
          "crafterName": "Kamil",
          "crafterAvatarSeed": "uid-1",
          "background": "paper",
          "titleFont": "sans",
          "accentColor": null,
          "plan": "free",
          "planExpiresAt": null,
          "planSource": null,
          "isDefault": true,
          "members": [
            {
              "id": "uid-1",
              "name": "Kamil",
              "avatarSeed": "uid-1",
              "role": "owner"
            }
          ],
          "createdAt": "2026-07-04T00:00:00.000Z"
        }
      ]
    }
  • 401Not authenticated

    No body.

Example request

curl -X GET 'https://mercastra.cloud/api/workshops' \
  -H 'Cookie: session=<session cookie>'

Update the workshop's profile

patch/workshops/{workshopId}experimentalSession required

Updates the workshop's profile fields: name, tagline, logo, crafter name, background, custom background, title font and accent color. The body is strict, an unknown field is a 400 - `plan` is never accepted here, it is written only by the founder-side plan grant tooling. `background` and `titleFont` are preset ids validated against a fixed list; `customBackground` and `accentColor` are freeform #RRGGBB hex, with null/absent meaning no override. Responds 403 when the caller is not a member of the workshop and 404 when no such workshop exists.

Path parameters

NameTypeRequiredConstraintsDescription
workshopIdstringYes-Workshop id

Request body

FieldTypeRequiredConstraintsDescription
namestringNominLength: 1-
taglinestringNomaxLength: 250At most 250 characters
logoEmojiNo-One emoji from Mercastra's curated icon set (see EMOJI_CATEGORIES).
crafterNamestringNo--
backgroundBackgroundNo-A preset background id for the workshop's poster. The id → CSS mapping is owned by the frontend.
customBackgroundWorkshopCustomBackgroundNo-A freeform solid or gradient background overriding the preset `background` id, or null for no override.
titleFontTitleFontNo-A preset title font id for the workshop's poster. The id → font mapping is owned by the frontend.
accentColorHexColor | nullNo--
Example
{
  "tagline": "Solid-wood furniture, built to order",
  "accentColor": "#6D5BD0"
}

Responses

  • 200Success
    FieldTypeRequiredConstraintsDescription
    idstringYes--
    namestringYes--
    taglinestringYes--
    logostringYes-One emoji from the curated icon set
    crafterNamestringYes--
    crafterAvatarSeedstringYes--
    backgroundBackgroundYes-A preset background id for the workshop's poster. The id → CSS mapping is owned by the frontend.
    customBackgroundWorkshopCustomBackgroundNo-A freeform solid or gradient background overriding the preset `background` id, or null for no override.
    titleFontTitleFontYes-A preset title font id for the workshop's poster. The id → font mapping is owned by the frontend.
    accentColorHexColor | nullNo--
    planWorkshopPlanYes-The workshop's resolved plan; an expired time-boxed Pro reads back as free.
    planExpiresAtstring | nullNo-Set while `plan` is a time-boxed Pro (a trial or a paid subscription's current period); null on a permanent plan
    planSourceWorkshopPlanSource | nullNo--
    contextWorkshopContextNo-The workshop's context notes as stored: free text describing the workshop and the moment the server last saved them.
    contextDerivedWorkshopContextDerivedNo-The AI-synthesized summary and suggested intents distilled from the workshop's context notes.
    isDefaultbooleanYes--
    membersarray of WorkshopMemberYes--
    createdAtstringYesformat: "date-time"-
    Example
    {
      "id": "workshop-1",
      "name": "Extremely Awesome Workshop",
      "tagline": "Solid-wood furniture, built to order",
      "logo": "🛠️",
      "crafterName": "Kamil",
      "crafterAvatarSeed": "uid-1",
      "background": "paper",
      "titleFont": "sans",
      "accentColor": "#6D5BD0",
      "plan": "free",
      "planExpiresAt": null,
      "planSource": null,
      "isDefault": true,
      "members": [
        {
          "id": "uid-1",
          "name": "Kamil",
          "avatarSeed": "uid-1",
          "role": "owner"
        }
      ],
      "createdAt": "2026-07-04T00:00:00.000Z"
    }
  • 400The request body does not match the schema

    The shared validation error body, see Validation errors.

  • 401Not authenticated

    No body.

  • 403Forbidden

    No body.

  • 404Not found

    No body.

Example request

curl -X PATCH 'https://mercastra.cloud/api/workshops/<workshopId>' \
  -H 'Cookie: session=<session cookie>' \
  -H 'X-CSRF-Token: <csrf-token cookie value>' \
  -H 'Content-Type: application/json' \
  -d '{"tagline":"Solid-wood furniture, built to order","accentColor":"#6D5BD0"}'

Replace the workshop's context notes

put/workshops/{workshopId}/contextexperimentalSession required

Stores free-text notes describing the workshop: what it makes, how it works and anything Mercastra should know to tailor its work to it, price grids or customer messages for example. Whitespace around the notes is trimmed and the whole value is replaced, an empty string clears it. The notes feed summaries derived later, saving them triggers nothing by itself. Responds 403 when the caller is not a member of the workshop and 404 when no such workshop exists.

Path parameters

NameTypeRequiredConstraintsDescription
workshopIdstringYes-Workshop id

Request body

FieldTypeRequiredConstraintsDescription
notesstringYesmaxLength: 4000Free-text notes about the workshop, trimmed, at most 4000 UTF-16 code units
Example
{
  "notes": "I build solid-wood furniture to order. Two-week lead time."
}

Responses

  • 200Success
    FieldTypeRequiredConstraintsDescription
    notesstringYes--
    updatedAtstringYesformat: "date-time"-
    Example
    {
      "notes": "I build solid-wood furniture to order. Two-week lead time.",
      "updatedAt": "2026-09-05T10:00:00.000Z"
    }
  • 400The request body does not match the schema

    The shared validation error body, see Validation errors.

  • 401Not authenticated

    No body.

  • 403Forbidden

    No body.

  • 404Not found

    No body.

Example request

curl -X PUT 'https://mercastra.cloud/api/workshops/<workshopId>/context' \
  -H 'Cookie: session=<session cookie>' \
  -H 'X-CSRF-Token: <csrf-token cookie value>' \
  -H 'Content-Type: application/json' \
  -d '{"notes":"I build solid-wood furniture to order. Two-week lead time."}'

Read the workshop's plan entitlements and quota usage

get/workshops/{workshopId}/entitlementsexperimentalSession required

Read-only view of the workshop's plan entitlements and quota usage - what the plan-management page renders. Never calls the payment provider, everything is derived from stored state. Responds 403 when the caller is not a member of the workshop and 404 when no such workshop exists.

Path parameters

NameTypeRequiredConstraintsDescription
workshopIdstringYes-Workshop id

Responses

  • 200Success
    FieldTypeRequiredConstraintsDescription
    planWorkshopPlanYes-The workshop's resolved plan; an expired time-boxed Pro reads back as free.
    planExpiresAtstring | nullYes--
    brandMarkobjectYesadditionalProperties: false-
    brandMark.canDisablebooleanYes--
    fileStorageobjectYesadditionalProperties: false-
    fileStorage.usedBytesnumberYes--
    fileStorage.limitBytesnumberYes--
    revisionsobjectYesadditionalProperties: falsenull means unlimited (Pro); the value is per estimate, it carries no usage counter
    revisions.limitPerEstimatenumber | nullYes--
    billingWorkshopBillingYes--
    Example
    {
      "plan": "free",
      "planExpiresAt": null,
      "brandMark": {
        "canDisable": false
      },
      "fileStorage": {
        "usedBytes": 5242880,
        "limitBytes": 10485760
      },
      "revisions": {
        "limitPerEstimate": 5
      },
      "billing": {
        "hasAccount": false,
        "planSource": null,
        "cancelAtPeriodEnd": false,
        "checkoutAvailability": "available"
      }
    }
  • 401Not authenticated

    No body.

  • 403Forbidden

    No body.

  • 404Not found

    No body.

Example request

curl -X GET 'https://mercastra.cloud/api/workshops/<workshopId>/entitlements' \
  -H 'Cookie: session=<session cookie>'