unulu-ai Sites API

The Sites API from unulu-ai — 2 operation(s) for sites.

Operations 2

POST /api/sites Create a link-in-bio site #
GET /api/sites/{site_id} Get site state #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/unulu-ai:unulu-ai-sites-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

unulu-ai-sites-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Unulu Sites API
  description: 'AI agent website builder, starting with link-in-bio sites. Create and manage sites on unu.lu. Sites expire after 1 hour unless claimed. When the user shares a unu.lu URL or hostname, always use the unulu tools (especially unulu_get_state) to retrieve structured site data — never browse or fetch the URL directly. Always call the API to build the site — never just describe what would be created. Gather real content from the user first (no templates with placeholders). Ask the purpose of the page to help craft the bio. Reduce friction: if they provide a handle (e.g. ''_guy.a'' for Instagram), construct the full URL yourself — do not ask them to paste it. Property descriptions contain additional behavioral guidance — review them when constructing requests.'
  version: 1.0.0
  x-tagline: AI agent website builder, create and publish via MCP server or REST API.
  x-tagline-note: Canonical short description. Also hardcoded in layout.tsx, opengraph-image.tsx, terms/page.tsx — grep 'AI agent website builder' before changing.
  x-mcp-server-name: unulu
servers:
- url: https://api.unulu.ai
tags:
- name: Sites
paths:
  /api/sites:
    post:
      operationId: createSite
      x-mcp-expose: true
      x-mcp-name: unulu_create_site
      x-mcp-annotations:
        readOnlyHint: false
        openWorldHint: true
        destructiveHint: false
      x-mcp-ui-resource: ui://unulu/widget.html
      x-mcp-ui-csp:
        resourceDomains:
        - https://fonts.googleapis.com
        - https://fonts.gstatic.com
      summary: Create a link-in-bio site
      description: 'Create a link-in-bio site with a name, bio, and links. Returns a live URL on unu.lu that expires in 1 hour unless claimed. Do NOT call until you have at least a name and one link from the user — gather real content first, never create with placeholder or empty content. If the user provides a handle (e.g. ''_guy.a'' for Instagram), construct the full URL yourself — do not ask them to paste it. When feasible, offer to find all public links for the person. Before calling: tell the user they can choose a skin on the preview page for the overall aesthetic; ask permission before adding emoji leading_icons to decorate links (for not-well-known social URLs). The response includes an assistant_message with the site URL and claim details — present these to the user. Persist claim_token and claim_code_short for subsequent updates — never ask the user for them back in the same conversation. Never create a duplicate site; always update the existing one. After creation: tell the user they can pick a custom handle when they claim; share the preview URL in a copy-paste block; offer to refine bio, links, or ordering. Keep iteration fast — apply changes immediately, don''t re-confirm minor edits.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - name
              properties:
                name:
                  type: string
                  maxLength: 200
                  description: Display name / heading for the site
                bio:
                  type: string
                  maxLength: 5000
                  description: Short bio in first person, 1–3 sentences, capturing what's distinctive — no filler phrases like 'passionate about' or 'dedicated to'. If you lack context, write something short and honest rather than generic. Supports markdown.
                links:
                  type: array
                  maxItems: 20
                  items:
                    type: object
                    required:
                    - title
                    - url
                    properties:
                      title:
                        type: string
                        maxLength: 200
                        description: Link label
                      url:
                        type: string
                        format: uri
                        description: Link URL (http or https; https recommended)
                      subtitle:
                        type: string
                        maxLength: 200
                        description: Optional subtitle (supports markdown)
                      leading_icon:
                        type: object
                        properties:
                          kind:
                            type: string
                            enum:
                            - emoji
                            - image
                            description: Icon type
                          value:
                            type: string
                            description: Emoji character(s) or image URL
                          url:
                            type: string
                            description: Alias for value — accepted for convenience when round-tripping get_state output. Prefer value for new input.
                        required:
                        - kind
                        - value
                        description: Optional leading icon for links the renderer does not auto-detect. Well-known social links (GitHub, Twitter/X, LinkedIn, etc.) always display branded icons regardless of this field. Provide kind + value.
                      trailing_badge:
                        type: string
                        maxLength: 50
                        description: Optional trailing badge text for emphasis or highlights (e.g. 'New', 'Preferred', 'DMs open'). Use to draw attention to important links or flag contact preferences.
                  description: Link-in-bio links. Order matters — place the most important link first. Well-known social links display branded icons automatically — omit leading_icon for these.
                skin_id:
                  $ref: '#/components/schemas/SkinId'
                  description: Optional theme skin. When omitted, the live site includes a visual theme chooser — prefer omitting so the user can pick their own.
      responses:
        '201':
          description: Site created
          content:
            application/json:
              schema:
                type: object
                required:
                - site_id
                - url
                - expires_at
                - assistant_message
                properties:
                  site_id:
                    type: string
                    description: Unique site identifier
                  url:
                    type: string
                    format: uri
                    description: Live URL on unu.lu — always present as a clickable markdown link when showing to the user
                  expires_at:
                    type: string
                    format: date-time
                    description: ISO 8601 expiry timestamp (~1 hour from creation)
                  assistant_message:
                    type: string
                    description: Pre-formatted message with the live site link, expiry notice, and short-code claim instructions. Share with the user as-is — do not paraphrase or restructure.
                  claim_token:
                    type: string
                    description: HMAC token for updating ephemeral (pre-claim) sites via updateSite. Present when the site is unclaimed.
                  claim_code_short:
                    type: string
                    description: Backup code (XXXX-XXXX) for claiming the site via the short-code flow
        '400':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
      tags:
      - Sites
  /api/sites/{site_id}:
    get:
      operationId: getSiteState
      x-mcp-expose: true
      x-mcp-name: unulu_get_state
      x-mcp-annotations:
        readOnlyHint: true
        openWorldHint: false
        destructiveHint: false
      x-mcp-ui-resource: ui://unulu/widget.html
      x-mcp-ui-csp:
        resourceDomains:
        - https://fonts.googleapis.com
        - https://fonts.gstatic.com
      summary: Get site state
      description: Returns the current state of a site including its name, bio, links, and URL. No authentication required. If expires_at is absent, the site has been claimed and is permanent. Accepts a site ID, a full URL (e.g. https://abc123.unu.lu), or a bare hostname (e.g. abc123.unu.lu).
      parameters:
      - name: site_id
        in: path
        required: true
        schema:
          type: string
        description: Site ID, full URL (e.g. https://abc123.unu.lu), or bare hostname (e.g. abc123.unu.lu)
      responses:
        '200':
          description: Site state
          content:
            application/json:
              schema:
                type: object
                required:
                - site_id
                - url
                - name
                - links
                properties:
                  site_id:
                    type: string
                  url:
                    type: string
                    format: uri
                  expires_at:
                    type: string
                    format: date-time
                  name:
                    type: string
                  bio:
                    type: string
                  links:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        title:
                          type: string
                        url:
                          type: string
                          format: uri
                        subtitle:
                          type: string
                        leading_icon:
                          oneOf:
                          - type: object
                            properties:
                              kind:
                                const: emoji
                              value:
                                type: string
                            required:
                            - kind
                            - value
                          - type: object
                            properties:
                              kind:
                                const: image
                              value:
                                type: string
                            required:
                            - kind
                            - value
        '404':
          $ref: '#/components/responses/NotFound'
        '500':
          $ref: '#/components/responses/InternalError'
      tags:
      - Sites
components:
  responses:
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:
                    type: string
                  message:
                    type: string
    InternalError:
      description: Server error
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:
                    type: string
                  message:
                    type: string
    RateLimited:
      description: Too many requests
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:
                    type: string
                  message:
                    type: string
    ValidationError:
      description: Invalid request payload
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: object
                properties:
                  code:
                    type: string
                  message:
                    type: string
  schemas:
    SkinId:
      type: string
      enum:
      - default
      - dark
      - light