> ## Documentation Index
> Fetch the complete documentation index at: https://docs.member.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Scaffold Hub From Template

> Create a hub from a hubTemplate in ONE transaction (spec §5, create mode).

Returns 201 with the hub id plus the ordered per-resource summary
(created / skipped / reason), so a caller can tell what actually happened
without diffing the hub. A REPLAY (same Idempotency-Key, same request)
returns 201 with the SAME summary and ``replayed: true``.

Error codes
-----------
405 (bare, ``Allow: GET``)        — ``HUB_SCAFFOLD_ENABLED`` is False; the
                                     route answers exactly like a backend
                                     without this op. Enforced by
                                     ``_FlagGatedAPIRoute`` BEFORE body
                                     parsing, auth and the rate limiter
                                     (module docstring).
400  ``idempotency_key_invalid``  — ``Idempotency-Key`` missing, empty, or
                                     over 255 characters.
409  ``catalog_digest_mismatch``  — the client's catalog digest is stale.
404  ``template_not_found``       — hubTemplateId/pageTemplateId unknown to
                                     the served catalog.
409  ``template_not_scaffoldable``— the hubTemplate's lifecycle is not
                                     scaffold-eligible.
422  ``invalid_scaffold_request`` — a malformed template block (spaces,
                                     onboarding, policies, playlists,
                                     navigation), an unresolved token, an
                                     invalid page tree, a batch-limit or
                                     payload-size breach, or an
                                     unresolvable welcome-post space/author.
409  ``hub_slug_unavailable``     — no unique hub slug could be minted
                                     after ``HubService.create``'s race
                                     retries.
409  ``hub_resource_conflict``    — a child resource (space slug, attribute
                                     definition slug, playlist item) was
                                     claimed concurrently mid-op.
409  ``page_conflict`` /
     ``reserved_page_conflict``   — the page matrix's own conflicts.
409  ``idempotency_fingerprint_mismatch`` — the Idempotency-Key was reused
                                     with a different request, or lost a
                                     concurrent claim race.

EVERY code above is a ``ScaffoldError`` subclass RAISED out of this handler
— never returned inline — and mapped by the centrally-registered
``scaffold_error_handler``, which runs AFTER ``get_db()``'s except-branch
has rolled the whole transaction back. See the module docstring.



## OpenAPI

````yaml /openapi/mio-openapi.json post /api/v1/teams/{team_id}/hubs/from-template
openapi: 3.1.0
info:
  description: >-
    Production API reference for Membership.io. Use the authored guides for
    workflows and the generated endpoint pages for exact parameters and schemas.
  title: Membership.io API
  version: 0.1.0
servers:
  - description: Production
    url: https://api.member.dev
security:
  - bearerAuth: []
paths:
  /api/v1/teams/{team_id}/hubs/from-template:
    post:
      tags:
        - hubs-admin
      summary: Admin Scaffold Hub From Template
      description: >-
        Create a hub from a hubTemplate in ONE transaction (spec §5, create
        mode).


        Returns 201 with the hub id plus the ordered per-resource summary

        (created / skipped / reason), so a caller can tell what actually
        happened

        without diffing the hub. A REPLAY (same Idempotency-Key, same request)

        returns 201 with the SAME summary and ``replayed: true``.


        Error codes

        -----------

        405 (bare, ``Allow: GET``)        — ``HUB_SCAFFOLD_ENABLED`` is False;
        the
                                             route answers exactly like a backend
                                             without this op. Enforced by
                                             ``_FlagGatedAPIRoute`` BEFORE body
                                             parsing, auth and the rate limiter
                                             (module docstring).
        400  ``idempotency_key_invalid``  — ``Idempotency-Key`` missing, empty,
        or
                                             over 255 characters.
        409  ``catalog_digest_mismatch``  — the client's catalog digest is
        stale.

        404  ``template_not_found``       — hubTemplateId/pageTemplateId unknown
        to
                                             the served catalog.
        409  ``template_not_scaffoldable``— the hubTemplate's lifecycle is not
                                             scaffold-eligible.
        422  ``invalid_scaffold_request`` — a malformed template block (spaces,
                                             onboarding, policies, playlists,
                                             navigation), an unresolved token, an
                                             invalid page tree, a batch-limit or
                                             payload-size breach, or an
                                             unresolvable welcome-post space/author.
        409  ``hub_slug_unavailable``     — no unique hub slug could be minted
                                             after ``HubService.create``'s race
                                             retries.
        409  ``hub_resource_conflict``    — a child resource (space slug,
        attribute
                                             definition slug, playlist item) was
                                             claimed concurrently mid-op.
        409  ``page_conflict`` /
             ``reserved_page_conflict``   — the page matrix's own conflicts.
        409  ``idempotency_fingerprint_mismatch`` — the Idempotency-Key was
        reused
                                             with a different request, or lost a
                                             concurrent claim race.

        EVERY code above is a ``ScaffoldError`` subclass RAISED out of this
        handler

        — never returned inline — and mapped by the centrally-registered

        ``scaffold_error_handler``, which runs AFTER ``get_db()``'s
        except-branch

        has rolled the whole transaction back. See the module docstring.
      operationId: hubs_admin.post_hubs_admin_post_teams_by_team_id_hubs_from_template
      parameters:
        - in: path
          name: team_id
          required: true
          schema:
            title: Team Id
            type: string
        - in: header
          name: Idempotency-Key
          required: false
          schema:
            anyOf:
              - type: string
              - type: 'null'
            title: Idempotency-Key
      requestBody:
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/HubScaffoldEnvelope'
        required: true
      responses:
        '201':
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/HubScaffoldResponse'
          description: Successful Response
        '422':
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
          description: Validation Error
      security:
        - HTTPBearer: []
components:
  schemas:
    HubScaffoldEnvelope:
      additionalProperties: false
      properties:
        data:
          $ref: '#/components/schemas/HubScaffoldResource'
      required:
        - data
      title: HubScaffoldEnvelope
      type: object
    HubScaffoldResponse:
      properties:
        data:
          $ref: '#/components/schemas/HubScaffoldResultResource'
      required:
        - data
      title: HubScaffoldResponse
      type: object
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          title: Detail
          type: array
      title: HTTPValidationError
      type: object
    HubScaffoldResource:
      additionalProperties: false
      properties:
        attributes:
          $ref: '#/components/schemas/HubScaffoldAttributes'
        type:
          const: hub_scaffolds
          title: Type
          type: string
      required:
        - type
        - attributes
      title: HubScaffoldResource
      type: object
    HubScaffoldResultResource:
      properties:
        attributes:
          $ref: '#/components/schemas/HubScaffoldResultAttributes'
        id:
          title: Id
          type: string
        type:
          const: hub_scaffolds
          default: hub_scaffolds
          title: Type
          type: string
      required:
        - id
        - attributes
      title: HubScaffoldResultResource
      type: object
    ValidationError:
      properties:
        ctx:
          title: Context
          type: object
        input:
          title: Input
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          title: Location
          type: array
        msg:
          title: Message
          type: string
        type:
          title: Error Type
          type: string
      required:
        - loc
        - msg
        - type
      title: ValidationError
      type: object
    HubScaffoldAttributes:
      additionalProperties: false
      properties:
        catalog_digest:
          maxLength: 128
          title: Catalog Digest
          type: string
        hub_template_id:
          maxLength: 100
          pattern: ^[a-z0-9][a-z0-9-]*$
          title: Hub Template Id
          type: string
        name:
          maxLength: 255
          minLength: 1
          title: Name
          type: string
        overrides:
          $ref: '#/components/schemas/HubScaffoldOverridesPayload'
        slug:
          maxLength: 100
          pattern: ^[a-z0-9-]+$
          title: Slug
          type: string
      required:
        - hub_template_id
        - name
        - slug
        - catalog_digest
      title: HubScaffoldAttributes
      type: object
    HubScaffoldResultAttributes:
      properties:
        created_resource_ids:
          additionalProperties:
            items:
              type: string
            type: array
          title: Created Resource Ids
          type: object
        hub_id:
          title: Hub Id
          type: string
        replayed:
          title: Replayed
          type: boolean
        summary:
          items:
            $ref: '#/components/schemas/HubScaffoldSummaryEntry'
          title: Summary
          type: array
      required:
        - hub_id
        - summary
        - created_resource_ids
        - replayed
      title: HubScaffoldResultAttributes
      type: object
    HubScaffoldOverridesPayload:
      additionalProperties: false
      description: >-
        The operator's presentation overrides — the CLI's flags, as JSON.


        Every field is OPTIONAL and every omitted field means "the template

        decides". ``publish`` is the exception in kind: it is a tri-state on the

        wire (absent / false / true) that collapses to a plain bool in the
        service,

        because absent and false mean the same thing — the hub stays private.

        ``HubScaffoldOverrides.to_fingerprint_payload()`` folds all four keys

        unconditionally, so "omitted" and "sent at its default" produce the SAME

        idempotency fingerprint: a client that starts sending an explicit

        ``publish: false`` mid-retry is making the same request, not a new one.
      properties:
        favicon_url:
          anyOf:
            - maxLength: 2048
              minLength: 1
              type: string
            - type: 'null'
          description: >-
            Absolute URL or relative asset path for the hub favicon. Same
            contract as logo_url: omit or null to defer to the template, "" is a
            caller bug and 422s rather than being silently ignored.
          title: Favicon Url
        logo_url:
          anyOf:
            - maxLength: 2048
              minLength: 1
              type: string
            - type: 'null'
          description: >-
            Absolute URL or relative asset path for the hub logo. Omit the field
            (or send null) to let the template decide. An empty string "" is
            REJECTED rather than treated as clear-the-logo: the service applies
            this override only when it is truthy, so an empty string would do
            nothing while still changing the idempotency fingerprint — the same
            key would then 409 against the omitted form for a request that meant
            the same thing. Clearing branding is the PATCH
            /api/teams/{team_id}/hubs/{id} endpoint's job.
          title: Logo Url
        publish:
          default: false
          title: Publish
          type: boolean
        registration_enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          title: Registration Enabled
      title: HubScaffoldOverridesPayload
      type: object
    HubScaffoldSummaryEntry:
      description: >-
        One row of the per-resource summary (spec §5).


        ``resource`` is the step name, qualified by the template key where a
        step

        is per-item (``space:general``, ``onboarding:company``,
        ``page:homepage``,

        ``policy:terms``, ``playlist:getting-started``, and

        ``document:getting-started:0`` for each ``playlists[].documents[]``
        entry —

        which needs its ORDINAL because two placeholder lessons may share a
        title)

        and bare where it is not (``hub``, ``branding``, ``navigation``,

        ``settings``, ``policy_gate``, ``playlists``, ``publish``,

        ``welcome_post``). ``reason`` is present on skips ONLY — spec §5 asks
        for

        "created / skipped / reason", and a created row has no reason to give.
      properties:
        action:
          enum:
            - created
            - skipped
          title: Action
          type: string
        reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Reason
        resource:
          title: Resource
          type: string
      required:
        - resource
        - action
      title: HubScaffoldSummaryEntry
      type: object
  securitySchemes:
    bearerAuth:
      bearerFormat: JWT or mio_sk API key
      description: >-
        Send platform JWTs, contact JWTs, or team API keys as `Authorization:
        Bearer <token>`.
      scheme: bearer
      type: http
    HTTPBearer:
      scheme: bearer
      type: http

````