Kamai Projects API

Projects group sheets. Every key sees only its own user's projects.

GitHub OpenAPI

Operations 6

GET /v1/projects List your projects #
POST /v1/projects Create a project #
GET /v1/projects/{project_id} Get a project #
PATCH /v1/projects/{project_id} Rename a project or change its description #
DELETE /v1/projects/{project_id} Delete a project #
GET /v1/projects/{project_id}/sheets List a project's sheets in the app's order #

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/kamai-io:kamai-io-projects-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

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

kamai-io-projects-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Kamai Projects API
  description: 'Read construction drawings from your own software. Upload a PDF plan; Kamai reads it and gives you back every room, wall,

    door and window with measurements in metres, every printed word, and every printed table (schedules, legends, revision

    blocks), as JSON. ## Authentication


    Create an API key at Kamai → Settings → API keys and send it on every request:


    ```

    Authorization: Bearer

    ```


    A key acts as the user who created it and sees only that user''s projects. Keep it on your server. A call without a key,

    or with a revoked one, gets `401`. Revoking a key, or a change Kamai makes to its settings, takes effect within 3 minutes. ## Acting for your users


    A partner whose users sign in through it can use any API key to act for those users. The request carries, next to the

    key, `X-Kamai-Partner` (your partner ID, as Kamai gave it to you) and `X-Kamai-Partner-User-Token` (that user''s own token

    from you). Kamai checks the token with you and acts as that user: that user''s projects, that user''s page quota, as if the

    user did it in Kamai. Without the two headers the key acts as its own owner. One header without the other is `400`

    (`partner_id_required`, `partner_user_token_required`). A user who does not exist in Kamai or is disabled gets `403`

    (`act_as_not_allowed`). A key Kamai has tied to one partner always needs both headers and never acts as its owner. What the key may do for a user is set by Kamai on the key:


    | | routes | needs |

    |---|---|---|

    | read | every `GET`, and `POST /v1/blueprints/{blueprint_id}/markups/clip` | the key enabled for partner users |

    | change | create and update projects, upload, update sheets, create and update markups, rename conversations | edit enabled |

    | delete | delete projects, jobs, markups and conversations, cancel jobs | delete enabled, separately from edit |


    A route the key may not use gets `403` (`edit_not_allowed`, `delete_not_allowed`). On every key, not only for partner users, renaming a conversation needs edit enabled and deleting one needs delete enabled; a new key has both off. Replacing a sheet''s features with

    `PUT /v1/blueprints/{blueprint_id}` for a user needs the `revision` you read as `base_revision` (`422`

    `base_revision_required`), and replacing them with none counts as a delete. Conversations work the same way;

    with edit enabled for the key, the assistant may change the user''s drawings and undo that user''s own changes; keys

    without it never write. Uploads count against the user''s own page quota. Kamai keeps the answer of each token check for up to 60 seconds, so a user you disable on your side can still be served

    for that long. ## The usual flow


    1. `POST /v1/blueprints/upload/init` returns a signed URL. 2. `PUT` the PDF to that URL. 3. `POST /v1/blueprints/upload/complete` returns a `job_id`. It starts one job per upload: calling it again with the

    same `file_uuid` returns the same `job_id` (`409` with `Retry-After` while the first call is still running). To send

    another file, start a new upload with `init`. 4. Poll `GET /v1/projects/{project_id}/jobs/{job_id}` every 5–10 s until `status` is final: `SUCCEEDED`, or

    `FAILED` / `CANCELLED` / `ABANDONED`, which end the job; for those, show `error_code` and `error_message`. The PDF check fails a job with `pdf_incomplete` (the file looks cut off or damaged: download or export it again),

    `pdf_filter_unsupported` (Brotli compression, or a PDF that cannot be read) or `pdf_scan_over_budget` (too large or

    complex to check). New `error_code` values can be added over time: treat one you do not know as a failure and show

    its `error_message`. The job record is written when processing starts, not when the upload returns, and when many uploads are queued that

    can take minutes. Until then, a `job_id` you got from an upload answers `404` with `detail` `Job not found`: keep

    polling it. `Project not found` is final. 5. On `SUCCEEDED`, read the sheet with `GET /v1/blueprints/{blueprint_id}`.'
  version: 0.1.0
tags:
- name: Projects
  description: Projects group sheets. Every key sees only its own user's projects.
paths:
  /v1/projects:
    get:
      tags:
      - Projects
      summary: List your projects
      description: All projects of the API key's user. `last_modified` is in milliseconds since the Unix epoch (UTC).
      operationId: list_projects_v1_projects_get
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectListResponse'
              examples:
                real:
                  summary: Two of the user's projects
                  description: Real response shape from a Kamai test account, 2026-10-13. Names, text and ids are illustrative; numbers and structure are as returned. Trimmed to 2 projects.
                  value:
                    projects:
                    - id: aaaa00000002
                      name: Ben Yehuda 7 — offices
                      description: ''
                      last_modified: 1791457324000
                    - id: aaaa00000001
                      name: Herzl 12 — renovation
                      description: Apartment, 3 rooms
                      last_modified: 1791204314000
                    message: Projects fetched successfully
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - HTTPBearer: []
    post:
      tags:
      - Projects
      summary: Create a project
      description: Create an empty project. Pass its `id` as `project_id` when you upload a sheet into it.
      operationId: create_project_v1_projects_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProjectCreateRequest'
            examples:
              real:
                summary: Name and description
                value:
                  name: Rothschild 45 — tender
                  description: Residential, 6 floors
        required: true
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectCreateResponse'
              examples:
                real:
                  summary: Created
                  description: Real response shape from a Kamai test account, 2026-10-13. Ids are illustrative.
                  value:
                    project:
                      id: aaaa00000003
                      name: Rothschild 45 — tender
                      description: Residential, 6 floors
                      last_modified: 1791894411000
                    message: Project created successfully
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
      - HTTPBearer: []
  /v1/projects/{project_id}:
    get:
      tags:
      - Projects
      summary: Get a project
      description: 'One project with its upload jobs, keyed by job id.


        409 `project_unreadable` (with a `request_id`) when the project''s stored record cannot be read; contact support.'
      operationId: get_project_v1_projects__project_id__get
      security:
      - HTTPBearer: []
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          type: string
          title: Project Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectDetailResponse'
              examples:
                real:
                  summary: A project with one sheet
                  description: 'Real response shape from a Kamai test account, 2026-10-13. Names, text and ids are illustrative; numbers and structure are as returned. Trimmed: 1 of 8 sheet records.'
                  value:
                    project:
                      id: aaaa00000001
                      name: Herzl 12 — renovation
                      description: Apartment, 3 rooms
                      last_modified: 1791204314000
                      jobs: {}
                      blueprint_records:
                        bbbbbbbb-0000-4000-8000-000000000001:
                          id: bbbbbbbb-0000-4000-8000-000000000001
                          name: A-101 Ground floor
                          description: '[A-101] GROUND FLOOR PLAN'
                          created: '2026-03-01T12:18:55.800347Z'
                          updated: '2026-10-10T18:47:27.386246Z'
                          ready:
                            pdf_file: true
                            main_tile: true
                            all_tiles: true
                            preview_image: true
                            vector_image: true
                            geojson: true
                            regions: true
                            ocr_text: true
                            ml_metadata: true
                            ocr_connected: false
                            autoclassify_polygons: false
                    message: Project fetched successfully
        '409':
          description: The project's stored record cannot be read (it does not match the project schema). Nothing was changed; contact support with the request id.
          content:
            application/json:
              examples:
                unreadable:
                  summary: A project whose stored record cannot be read
                  description: Response shape; ids are illustrative.
                  value:
                    detail:
                      error: project_unreadable
                      message: This project's stored record cannot be read. Contact support with this request id.
                      request_id: cccccccc-0000-4000-8000-000000000001
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    patch:
      tags:
      - Projects
      summary: Rename a project or change its description
      description: 'Rename a project, change its description, or set how door handing is shown in it

        (`handing_convention`). Send at least one of them; `handing_convention: null` clears the setting.


        409 `project_unreadable` (with a `request_id`) when the project''s stored record cannot be read; contact support.'
      operationId: update_project_v1_projects__project_id__patch
      security:
      - HTTPBearer: []
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          type: string
          title: Project Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ProjectUpdateRequest'
            examples:
              real:
                summary: Rename
                value:
                  name: Rothschild 45 — tender (rev B)
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectUpdateResponse'
              examples:
                real:
                  summary: Renamed
                  description: Real response shape from a Kamai test account, 2026-10-13. Ids are illustrative.
                  value:
                    project:
                      id: aaaa00000003
                      name: Rothschild 45 — tender (rev B)
                      description: Residential, 6 floors
                      last_modified: 1791894411000
                    message: Project updated successfully
        '409':
          description: The project's stored record cannot be read (it does not match the project schema). Nothing was changed; contact support with the request id.
          content:
            application/json:
              examples:
                unreadable:
                  summary: A project whose stored record cannot be read
                  description: Response shape; ids are illustrative.
                  value:
                    detail:
                      error: project_unreadable
                      message: This project's stored record cannot be read. Contact support with this request id.
                      request_id: cccccccc-0000-4000-8000-000000000001
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - Projects
      summary: Delete a project
      description: 'Delete the project and what is in it: its sheets, jobs and integration links. There is no undo through the API.'
      operationId: delete_project_v1_projects__project_id__delete
      security:
      - HTTPBearer: []
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          type: string
          title: Project Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectDeleteResponse'
              examples:
                real:
                  summary: Deleted
                  description: Real response shape from a Kamai test account, 2026-10-13. Ids are illustrative.
                  value:
                    project_id: aaaa00000003
                    message: Project deleted successfully
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/projects/{project_id}/sheets:
    get:
      tags:
      - Projects
      summary: List a project's sheets in the app's order
      description: 'Every sheet of the project, in the order and with the names the Kamai app shows, so

        an integration can show a sheet list that matches the app and let a user pick a sheet.


        The order is the natural order of the sheet names (A-2 before A-10), the same for every

        user, computed on each call: it can change when an upload finishes or a sheet is

        renamed, so keep each sheet''s `blueprint_id` rather than its place. `label` is the name

        to show; `display_name`, `sheet_number` and `title` give its parts. Uploads still

        processing are not listed until their sheet exists.


        403 when the project belongs to another account; 404 when no project has this id.'
      operationId: list_sheets_v1_projects__project_id__sheets_get
      security:
      - HTTPBearer: []
      parameters:
      - name: project_id
        in: path
        required: true
        schema:
          type: string
          title: Project Id
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProjectSheetsResponse'
              example:
                project_id: aaaa00000005
                sheets:
                - blueprint_id: bbbbbbbb-0000-5000-8000-000000000006
                  label: A-101 FLOOR PLAN
                  display_name: A-101 FLOOR PLAN
                  sheet_number: A-101
                  title: FLOOR PLAN
                - blueprint_id: bbbbbbbb-0000-5000-8000-000000000007
                  label: A-201 ELEVATIONS
                  display_name: A-201 ELEVATIONS
                  sheet_number: A-201
                  title: ELEVATIONS
        '403':
          description: The project belongs to another account.
        '404':
          description: No project has this id.
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    SheetPublic:
      properties:
        blueprint_id:
          type: string
          title: Blueprint Id
          description: 'The sheet''s id. Refer to a sheet by it: the list order can change when an upload finishes or a sheet is renamed.'
        label:
          type: string
          title: Label
          description: 'What the Kamai app calls this sheet. Usually equal to display_name; a sheet named only by a meaningless file name reads ''Sheet N · <file name>'', and two sheets that would read the same each get a hint: ''(p. 3)'' is the page of the upload file, ''(#4)'' the place in this list.'
        display_name:
          type: string
          title: Display Name
          description: The user's own name if they renamed the sheet, else its title block ('A-101 FLOOR PLAN'), else its file name.
        sheet_number:
          anyOf:
          - type: string
          - type: 'null'
          title: Sheet Number
          description: The sheet number from the title block, e.g. A-101. Not unique and not an address.
        title:
          anyOf:
          - type: string
          - type: 'null'
          title: Title
          description: The sheet title from the title block.
      type: object
      required:
      - blueprint_id
      - label
      - display_name
      title: SheetPublic
    ProjectCreateRequest:
      properties:
        name:
          type: string
          maxLength: 256
          minLength: 1
          title: Name
        description:
          type: string
          maxLength: 2048
          title: Description
          default: ''
      type: object
      required:
      - name
      title: ProjectCreateRequest
    BlueprintReadyRecord:
      properties:
        pdf_file:
          type: boolean
          title: Pdf File
          default: false
        main_tile:
          type: boolean
          title: Main Tile
          default: false
        all_tiles:
          type: boolean
          title: All Tiles
          default: false
        preview_image:
          type: boolean
          title: Preview Image
          default: false
        vector_image:
          type: boolean
          title: Vector Image
          default: false
        geojson:
          type: boolean
          title: Geojson
          default: false
        regions:
          type: boolean
          title: Regions
          default: false
        ocr_text:
          anyOf:
          - type: boolean
          - type: 'null'
          title: Ocr Text
        ml_metadata:
          type: boolean
          title: Ml Metadata
          default: false
        ocr_connected:
          type: boolean
          title: Ocr Connected
          default: false
        autoclassify_polygons:
          type: boolean
          title: Autoclassify Polygons
          default: false
      type: object
      title: BlueprintReadyRecord
    ProjectUpdateResponse:
      properties:
        project:
          $ref: '#/components/schemas/ProjectPublic'
        message:
          type: string
          title: Message
          default: Project updated successfully
      type: object
      required:
      - project
      title: ProjectUpdateResponse
    ProjectSheetsResponse:
      properties:
        project_id:
          type: string
          title: Project Id
          description: The project.
        sheets:
          items:
            $ref: '#/components/schemas/SheetPublic'
          type: array
          title: Sheets
          description: 'Every sheet of the project in the app''s order: the natural order of the names, the same for every user. Uploads still processing are not listed.'
      type: object
      required:
      - project_id
      title: ProjectSheetsResponse
    ProjectDetailResponse:
      properties:
        project:
          $ref: '#/components/schemas/ProjectDetailPublic'
        message:
          type: string
          title: Message
          default: Project fetched successfully
      type: object
      required:
      - project
      title: ProjectDetailResponse
    ProjectListResponse:
      properties:
        projects:
          items:
            $ref: '#/components/schemas/ProjectPublic'
          type: array
          title: Projects
        message:
          type: string
          title: Message
          default: Projects fetched successfully
      type: object
      required:
      - projects
      title: ProjectListResponse
    ProjectDeleteResponse:
      properties:
        project_id:
          type: string
          title: Project Id
        message:
          type: string
          title: Message
          default: Project deleted successfully
      type: object
      required:
      - project_id
      title: ProjectDeleteResponse
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ProjectCreateResponse:
      properties:
        project:
          $ref: '#/components/schemas/ProjectPublic'
        message:
          type: string
          title: Message
          default: Project created successfully
      type: object
      required:
      - project
      title: ProjectCreateResponse
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    ProjectDetailPublic:
      properties:
        id:
          type: string
          title: Id
        name:
          type: string
          title: Name
        description:
          type: string
          title: Description
        last_modified:
          anyOf:
          - type: integer
          - type: 'null'
          title: Last Modified
          description: Last modified timestamp in milliseconds
        handing_convention:
          anyOf:
          - type: string
            enum:
            - us
            - din
          - type: 'null'
          title: Handing Convention
          description: 'How door handing is shown in this project: ''us'' (LH / RH, seen from the side the door swings away from) or ''din'' (DIN 107: DIN links / DIN rechts, seen from the side it opens towards). `null` = not set: German readers see DIN 107, everyone else ''us''. Display only: every door still carries both `handing` and `handing_din`.'
        jobs:
          additionalProperties:
            $ref: '#/components/schemas/JobPublic'
          type: object
          title: Jobs
        blueprint_records:
          additionalProperties:
            $ref: '#/components/schemas/BlueprintRecordPublic'
          type: object
          title: Blueprint Records
      type: object
      required:
      - id
      - name
      - description
      title: ProjectDetailPublic
    ProjectUpdateRequest:
      properties:
        name:
          anyOf:
          - type: string
            maxLength: 256
            minLength: 1
          - type: 'null'
          title: Name
        description:
          anyOf:
          - type: string
            maxLength: 2048
          - type: 'null'
          title: Description
        handing_convention:
          anyOf:
          - type: string
            enum:
            - us
            - din
          - type: 'null'
          title: Handing Convention
          description: 'How door handing is shown in this project: ''us'' (LH / RH, seen from the side the door swings away from) or ''din'' (DIN 107: DIN links / DIN rechts, seen from the side it opens towards). `null` = not set: German readers see DIN 107, everyone else ''us''. Display only: every door still carries both `handing` and `handing_din`. Send `null` to clear it.'
      type: object
      title: ProjectUpdateRequest
    JobPublic:
      properties:
        id:
          type: string
          title: Id
        status:
          type: string
          title: Status
        state:
          anyOf:
          - type: string
          - type: 'null'
          title: State
        blueprint_id:
          type: string
          title: Blueprint Id
        filename:
          type: string
          title: Filename
        progress:
          type: integer
          title: Progress
          default: 0
        error_code:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Code
        error_message:
          anyOf:
          - type: string
          - type: 'null'
          title: Error Message
        page_index:
          anyOf:
          - type: integer
          - type: 'null'
          title: Page Index
          description: The page of the uploaded file this job reads, 0-based. `null` until the page is cut from the upload.
        auto_rotation:
          anyOf:
          - type: integer
          - type: 'null'
          title: Auto Rotation
          description: Degrees clockwise (0, 90, 180, 270) Kamai turned this page at upload to bring it upright; 0 = left as the PDF had it. `null` until the page is cut, or when the check did not run. The sheet carries the same value (`auto_rotation` on GET /v1/blueprints/{id}).
      type: object
      required:
      - id
      - status
      - blueprint_id
      - filename
      title: JobPublic
    ProjectPublic:
      properties:
        id:
          type: string
          title: Id
        name:
          type: string
          title: Name
        description:
          type: string
          title: Description
        last_modified:
          anyOf:
          - type: integer
          - type: 'null'
          title: Last Modified
          description: Last modified timestamp in milliseconds
        handing_convention:
          anyOf:
          - type: string
            enum:
            - us
            - din
          - type: 'null'
          title: Handing Convention
          description: 'How door handing is shown in this project: ''us'' (LH / RH, seen from the side the door swings away from) or ''din'' (DIN 107: DIN links / DIN rechts, seen from the side it opens towards). `null` = not set: German readers see DIN 107, everyone else ''us''. Display only: every door still carries both `handing` and `handing_din`.'
      type: object
      required:
      - id
      - name
      - description
      title: ProjectPublic
    BlueprintRecordPublic:
      properties:
        id:
          type: string
          title: Id
        name:
          type: string
          title: Name
        description:
          anyOf:
          - type: string
          - type: 'null'
          title: Description
        created:
          type: string
          format: date-time
          title: Created
        updated:
          type: string
          format: date-time
          title: Updated
        ready:
          $ref: '#/components/schemas/BlueprintReadyRecord'
          default:
            pdf_file: false
            main_tile: false
            all_tiles: false
            preview_image: false
            vector_image: false
            geojson: false
            regions: false
            ml_metadata: false
            ocr_connected: false
            autoclassify_polygons: false
      type: object
      required:
      - id
      - name
      - created
      - updated
      title: BlueprintRecordPublic
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer