Profound Documents API

The Documents API from Profound — 3 operation(s) for documents.

Operations 6

GET /v1/documents List documents #
POST /v1/documents Create a document #
GET /v1/documents/{document_id} Read a document #
PATCH /v1/documents/{document_id} Rename or reshare a document #
DELETE /v1/documents/{document_id} Delete a document #
POST /v1/documents/{document_id}/content Replace a document's content #

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/profound-documents-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 email required.

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

OpenAPI Specification

profound-documents-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: External Documents API
  version: 6551bd49db665ffb7f80780b3e150b8e8b780cc3
servers:
- url: https://api.tryprofound.com
  description: Production Server
tags:
- name: Documents
paths:
  /v1/documents:
    get:
      tags:
      - Documents
      summary: List documents
      description: 'List documents visible to your organization, newest-modified-first.


        Documents are ordered by last-modified time, most recent first, with no other

        sort option. This is a walk over a live, mutable collection: a document created

        or modified while you are paging can shift which page it lands on, so a single

        walk may show it to you twice or, rarely, skip it.


        This response never includes a total count. Upstream counts totals before

        applying your organization''s access filter, so a total, or treating a short

        page as the last one, would misreport what you can actually see. Keep

        following `pagination.next_cursor` until it comes back null — that, and not

        a short or even an empty page, is the end of the walk. A page whose rows the

        access filter removed entirely is empty while later pages still hold

        documents, so the last page of a walk may legitimately be an empty one.'
      operationId: list_documents_v1_documents_get
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      parameters:
      - name: organization_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the organization whose documents to list. Required. The caller must be a member of this organization.
          title: Organization Id
        description: ID of the organization whose documents to list. Required. The caller must be a member of this organization.
      - name: q
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: Filter to documents whose name contains this text, case-insensitively. Matches only the document's name, never its content — a query that finds nothing does not mean the topic is unwritten, only that no title mentions it. Blank or omitted returns every document. Ignored when sent alongside `next_cursor`, which carries the filter the walk started with. Matching is name-only as of this release; broader matching may follow if upstream changes how it indexes the name column.
          title: Q
        description: Filter to documents whose name contains this text, case-insensitively. Matches only the document's name, never its content — a query that finds nothing does not mean the topic is unwritten, only that no title mentions it. Blank or omitted returns every document. Ignored when sent alongside `next_cursor`, which carries the filter the walk started with. Matching is name-only as of this release; broader matching may follow if upstream changes how it indexes the name column.
      - name: sort
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          description: 'Documents are always ordered newest-modified-first (`updated_at DESC`, then `created_at DESC`, then `id DESC`); there is no parameter that changes this. `recency` is the only accepted value, and passing it is a no-op that names the guarantee rather than altering it — any other value is rejected outright rather than silently ignored. Ordering is never re-applied to a returned page either: that would only be consistent within the page, not across a paginated walk.'
          title: Sort
        description: 'Documents are always ordered newest-modified-first (`updated_at DESC`, then `created_at DESC`, then `id DESC`); there is no parameter that changes this. `recency` is the only accepted value, and passing it is a no-op that names the guarantee rather than altering it — any other value is rejected outright rather than silently ignored. Ordering is never re-applied to a returned page either: that would only be consistent within the page, not across a paginated walk.'
      - name: limit
        in: query
        required: false
        schema:
          type: integer
          maximum: 50
          exclusiveMinimum: 0
          default: 20
          title: Limit
      - name: next_cursor
        in: query
        required: false
        schema:
          anyOf:
          - type: string
          - type: 'null'
          title: Next Cursor
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListDocumentsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    post:
      tags:
      - Documents
      summary: Create a document
      description: 'Create a Profound document with markdown content.


        `organization_id` is required and you must be a member of it. You choose the

        document''s `id`, and creation is idempotent on it: repeating the request returns

        the existing document rather than creating a second one.


        New documents are visible only to their creator; share them from the Profound app,

        or open one with the `url` in the response.


        A `201` response does not confirm that a new document was created: it is also

        returned when `id` already existed, in which case the existing document comes

        back unchanged. Upstream gives no signal to tell the two apart, so this endpoint

        does not claim to either — it is safe to retry with the same `id` either way.'
      operationId: create_document_v1_documents_post
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateDocumentRequest'
              description: The document to create.
      responses:
        '201':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateDocumentResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/documents/{document_id}:
    get:
      tags:
      - Documents
      summary: Read a document
      description: 'Read a document: its metadata, its default tab''s body, its other tabs, its comments, and its version hash.


        You can read any document you have access to in the Profound app, including ones

        created there rather than through this API.


        By default this is a preview: the body is truncated to save your context, and the

        version hash is withheld so a preview alone can never be used to replace a document

        blindly. Pass `preview=false` when you intend to write.'
      operationId: read_document_v1_documents__document_id__get
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      parameters:
      - name: document_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the document.
          title: Document Id
        description: ID of the document.
      - name: organization_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the organization that owns the document. Required — Profound API keys are user-scoped, so the owning organization must be named explicitly. The caller must be a member of this organization.
          title: Organization Id
        description: ID of the organization that owns the document. Required — Profound API keys are user-scoped, so the owning organization must be named explicitly. The caller must be a member of this organization.
      - name: include_tabs
        in: query
        required: false
        schema:
          type: boolean
          description: Include the document's other tabs. On by default — a tab body is part of the document, not an aside. Off, `additional_tabs` is omitted from the response rather than returned as an empty list.
          default: true
          title: Include Tabs
        description: Include the document's other tabs. On by default — a tab body is part of the document, not an aside. Off, `additional_tabs` is omitted from the response rather than returned as an empty list.
      - name: include_comments
        in: query
        required: false
        schema:
          type: boolean
          description: Include the document's review comments, each mapped to `{content, context}`. On by default — a comment is part of the document's review state, not an aside. Turn it off to skip the comment-thread walk upstream; off, `comments` is omitted from the response rather than returned as an empty list.
          default: true
          title: Include Comments
        description: Include the document's review comments, each mapped to `{content, context}`. On by default — a comment is part of the document's review state, not an aside. Turn it off to skip the comment-thread walk upstream; off, `comments` is omitted from the response rather than returned as an empty list.
      - name: preview
        in: query
        required: false
        schema:
          type: boolean
          description: 'Bound every body in the response — `content_markdown` and each tab''s — and set `content_truncated` if any was cut. On by default. Upstream has no partial-read of its own — every read is a full round trip through the collaborative editor — so this saves your context, not upstream cost. A preview read also omits `version_hash`, on purpose: a hash returned next to a body you have not fully seen invites replacing content you never read. Pass `preview=false` before you intend to write, to get the whole body, `content_truncated: false`, and the hash.'
          default: true
          title: Preview
        description: 'Bound every body in the response — `content_markdown` and each tab''s — and set `content_truncated` if any was cut. On by default. Upstream has no partial-read of its own — every read is a full round trip through the collaborative editor — so this saves your context, not upstream cost. A preview read also omits `version_hash`, on purpose: a hash returned next to a body you have not fully seen invites replacing content you never read. Pass `preview=false` before you intend to write, to get the whole body, `content_truncated: false`, and the hash.'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReadDocumentResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    patch:
      tags:
      - Documents
      summary: Rename or reshare a document
      description: 'Rename a document, change who can see it, or both in one call.


        Renaming sets a permanent lock on the title, and changing visibility can silently

        change who has access — see the `name` and `visibility` field descriptions for what

        each one does before you use it.


        Renaming needs edit access; changing visibility is creator-only, and upstream

        enforces it. You can act on a document this API created, or one you created

        yourself in the Profound app — not one merely shared with you.'
      operationId: patch_document_v1_documents__document_id__patch
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      parameters:
      - name: document_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the document.
          title: Document Id
        description: ID of the document.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateDocumentRequest'
              description: The fields to change.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Document'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
    delete:
      tags:
      - Documents
      summary: Delete a document
      description: 'Delete a document created through this integration.


        Only documents created through this integration can be deleted here. A document

        created in the Profound app can never be deleted through this route, even by the

        person who owns it — creation provenance is stamped once, at creation, and is never

        backfilled onto documents made another way.


        The delete is soft: the row is marked deleted at the storage layer rather than

        destroyed. There is no restore through this API, or any other — treat a delete as

        final even though the data itself is not gone.


        A 404 means the document is not visible to you at all. It covers three cases the

        response does not distinguish, on purpose: the document never existed, it was

        already deleted by an earlier call to this same route, or it exists but your

        credential resolves no role on it. Deleting the same document twice returns 404 on

        the second call, not a second 204.


        A 403 means the opposite: the document is visible to you but not deletable here,

        and the message says which rule refused — it was not created through this

        integration, or you are not its creator. Deleting is creator-only, so edit access

        is not enough to remove a document out from under its owner.'
      operationId: delete_document_v1_documents__document_id__delete
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      parameters:
      - name: document_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the document.
          title: Document Id
        description: ID of the document.
      - name: organization_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the organization that owns the document. You must be a member of it.
          title: Organization Id
        description: ID of the organization that owns the document. You must be a member of it.
      responses:
        '204':
          description: Successful Response
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
  /v1/documents/{document_id}/content:
    post:
      tags:
      - Documents
      summary: Replace a document's content
      description: "Overwrite a document's entire body with new markdown, replacing what it held before.\n\nThis is a whole-body replace, not a patch: send the complete new text every time. An\nempty `content_markdown` is valid and clears the document.\n\nTwo destructive side effects apply on every call, regardless of what you send:\n\n- The document collapses to its default tab. Every non-default tab is deleted, and\n  the comments map is cleared for **all** tabs, including the default one — a\n  document with a live comment thread on any tab loses it.\n- `skip_title_sync` defaults to `false`, matching the Profound app: the title follows\n  the new content's first heading, so a replace silently renames the document unless\n  the heading matches the current title or `skip_title_sync` is set.\n\nThere is no compare-and-swap: this call does not accept a precondition, and nothing\nstops two concurrent replaces from silently overwriting each other last-writer-wins.\nUpstream's own `version_hash` documentation says as much — the token is \"still a\nchange detector rather than a precondition: a caller must not treat a matching token\nas licence to overwrite blindly, because it names the room at a moment cortex\nobserved and not the moment its own write lands.\" Sending a `working_version_hash`\n(or any spelling of it) is rejected with a `400` naming this rather than accepted\nand silently discarded, which is what happens on the upstream route this wraps.\n\nYou can replace a document this API created, or one you created yourself directly —\nnot merely one shared with you."
      operationId: replace_document_content_v1_documents__document_id__content_post
      security:
      - APIKeyHeader: []
      - BearerAuth: []
      parameters:
      - name: document_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
          description: ID of the document.
          title: Document Id
        description: ID of the document.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReplaceDocumentContentRequest'
              description: The content to write.
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReplaceDocumentContentResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
components:
  schemas:
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    UpdateDocumentRequest:
      properties:
        organization_id:
          type: string
          format: uuid
          title: Organization Id
          description: ID of the organization that owns the document. Required — Profound API keys are user-scoped, so the owning organization must be named explicitly. The caller must be a member of this organization.
        name:
          anyOf:
          - type: string
            minLength: 1
          - type: 'null'
          title: Name
          description: 'New title for the document. Renaming sets a permanent lock: once a document is renamed through this route, its title stops following the first heading of its content, for the rest of the document''s life, and no route can undo the lock. Omit to leave the title as it is.'
        visibility:
          anyOf:
          - type: string
            enum:
            - invited_only
            - organization
          - type: 'null'
          title: Visibility
          description: 'New sharing scope: `invited_only` for only the people invited to the document, or `organization` for everyone in the owning organization. Only the document''s creator can change this; omit to leave sharing as it is. Three things worth knowing before you set it: `organization` visibility grants view only — there is no value here that grants the organization edit access. Setting `invited_only` removes the organization''s access entirely. And re-asserting `organization` on a document whose organization grant is already `edit` silently downgrades the whole organization to view — upstream replays the access sync whenever this field is sent, and that sync always upserts view, even when the value you sent matches the one already stored.'
      additionalProperties: false
      type: object
      required:
      - organization_id
      title: UpdateDocumentRequest
      description: Request body for renaming or resharing a document.
    ReadDocumentResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: The document's ID.
        name:
          type: string
          title: Name
          description: The document's title.
        url:
          type: string
          title: Url
          description: Link to open the document in the Profound app.
        visibility:
          type: string
          enum:
          - invited_only
          - organization
          title: Visibility
          description: General access scope. New documents are `invited_only`.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When the document was created.
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When the document was last modified. Seeding the initial content counts, so a freshly created document is normally modified a moment after it was created.
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
          description: ID of the document's owner.
        owner_email:
          anyOf:
          - type: string
          - type: 'null'
          title: Owner Email
          description: Email of the document's owner. `null` when the owning profile has been deleted or could not be resolved.
        author_type:
          type: string
          enum:
          - user
          - agent
          title: Author Type
          description: Whether the document's owner is a person (`user`) or an agent (`agent`).
        app_delegate:
          anyOf:
          - type: string
          - type: 'null'
          title: App Delegate
          description: Which integration created the document, derived server-side from the credential that authenticated the write. `null` for documents created outside any integration. An open-ended value, not a fixed set — known values today include `external-api` and `context-manager`, and more are added as new integrations ship.
        category_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Category Name
          description: Name of the brand category set on the document, if any. Paired with `company_name`; writable only on create.
        company_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Company Name
          description: Name of the brand/company set on the document, if any. Paired with `category_name`; writable only on create.
        content_markdown:
          type: string
          title: Content Markdown
          description: The default tab's body as markdown. Empty string for a document with no content — never absent, so you can read it without a presence check.
        additional_tabs:
          anyOf:
          - items:
              $ref: '#/components/schemas/AdditionalTab'
            type: array
          - type: 'null'
          title: Additional Tabs
          description: 'Every tab beyond the default one, in document order, each as `{title, content_markdown}`. Upstream allows up to twenty. Omitted from the response entirely when `include_tabs=false`; an empty list is a real answer meaning this document has no other tabs, and the two are never confused. Tabs are readable through this API but not writable: create cannot make one, and replacing this document''s content does not preserve them.'
        comments:
          anyOf:
          - items:
              $ref: '#/components/schemas/Comment'
            type: array
          - type: 'null'
          title: Comments
          description: Review comments left on the document, each mapped to `{content, context}` — the comment's text and, if any, the text it was left on. Omitted from the response entirely when `include_comments=false`; an empty list is a real answer meaning this document has no comments. Mapped from upstream's own open, unvalidated shape — commenter identity, reply threads and resolution state are dropped, never relayed. A comment whose shape this mapping cannot read is dropped from the list rather than failing the read, so this list can be shorter than the document's real thread count.
        version_hash:
          anyOf:
          - type: string
          - type: 'null'
          title: Version Hash
          description: 'Opaque token that changes whenever the document''s content changes, sampled before this body was read — so it names this body or an older state, never a newer one. `null` when the collaboration service could not be asked for it; the read itself still succeeded, only the token is missing. Bare hex, up to 128 characters, with no fixed prefix — treat it as opaque and do not parse it. It detects change; it is not a precondition, and a matching token is not licence to overwrite blindly. Omitted entirely — not `null` — on a `preview=true` read: a hash next to a body you have not fully seen invites replacing content you never read. Ask for `preview=false` before you intend to write.'
        content_truncated:
          type: boolean
          title: Content Truncated
          description: Whether any body in this response was cut short — `content_markdown` or any tab's. `true` only on a `preview=true` read where one of them exceeded the preview length; a short document, or a `preview=false` read, always gets `false` and every body whole. It does not say which one was cut. Preview truncation saves your context, not upstream cost — the full round trip through the collaborative editor happens either way.
          default: false
      type: object
      required:
      - id
      - name
      - url
      - visibility
      - created_at
      - updated_at
      - owner_user_id
      - owner_email
      - author_type
      - app_delegate
      - category_name
      - company_name
      - content_markdown
      title: ReadDocumentResponse
      description: 'A document''s metadata, its default tab''s body, its other tabs, its comments, and the

        change-detection token for it.'
    CreateDocumentRequest:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: 'ID for the new document, chosen by you. Creation is idempotent on this ID: repeating a request with the same ID returns the existing document instead of creating a second one, so a retry after a network error is safe.'
        organization_id:
          type: string
          format: uuid
          title: Organization Id
          description: ID of the organization that will own the document. Required — Profound API keys are user-scoped, so the owning organization must be chosen explicitly. The caller must be a member of this organization.
        name:
          type: string
          minLength: 1
          title: Name
          description: Title for the document. Must be non-empty.
        content_markdown:
          type: string
          minLength: 1
          title: Content Markdown
          description: Initial document body as markdown. Must be non-empty. Rendered into the collaborative editor, so the result is real editable content, not a stored blob.
      additionalProperties: false
      type: object
      required:
      - id
      - organization_id
      - name
      - content_markdown
      title: CreateDocumentRequest
      description: Request body for creating a document with markdown content.
    ListDocumentsResponse:
      properties:
        data:
          items:
            $ref: '#/components/schemas/Document'
          type: array
          title: Data
          description: Documents on this page.
        pagination:
          $ref: '#/components/schemas/CursorPagination'
          description: Pagination state for fetching the next page.
      additionalProperties: false
      type: object
      required:
      - data
      - pagination
      title: ListDocumentsResponse
      description: A page of documents.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
            - type: string
            - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
      - loc
      - msg
      - type
      title: ValidationError
    CreateDocumentResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: The document's ID.
        name:
          type: string
          title: Name
          description: The document's title.
        url:
          type: string
          title: Url
          description: Link to open the document in the Profound app.
        visibility:
          type: string
          enum:
          - invited_only
          - organization
          title: Visibility
          description: General access scope. New documents are `invited_only`.
        created_at:
          type: string
          format: date-time
          title: Created At
          description: When the document was created.
        updated_at:
          type: string
          format: date-time
          title: Updated At
          description: When the document was last modified. Seeding the initial content counts, so a freshly created document is normally modified a moment after it was created.
        owner_user_id:
          type: string
          format: uuid
          title: Owner User Id
          description: ID of the document's owner.
        owner_email:
          anyOf:
          - type: string
          - type: 'null'
          title: Owner Email
          description: Email of the document's owner. `null` when the owning profile has been deleted or could not be resolved.
        author_type:
          type: string
          enum:
          - user
          - agent
          title: Author Type
          description: Whether the document's owner is a person (`user`) or an agent (`agent`).
        app_delegate:
          anyOf:
          - type: string
          - type: 'null'
          title: App Delegate
          description: Which integration created the document, derived server-side from the credential that authenticated the write. `null` for documents created outside any integration. An open-ended value, not a fixed set — known values today include `external-api` and `context-manager`, and more are added as new integrations ship.
        category_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Category Name
          description: Name of the brand category set on the document, if any. Paired with `company_name`; writable only on create.
        company_name:
          anyOf:
          - type: string
          - type: 'null'
          title: Company Name
          description: Name of the brand/company set on the document, if any. Paired with `category_name`; writable only on create.
        version_hash:
          anyOf:
          - type: string
          - type: 'null'
          title: Version Hash
          description: Opaque token that changes whenever the document's content changes. `null` when this call found an existing document with the same id (idempotent create) rather than creating one, or when the token could not be minted. Bare hex, up to 128 characters, with no fixed prefix — treat it as opaque and do not parse it. It detects change; it is not a precondition, and a matching token is not licence to overwrite blindly.
      type: object
      required:
      - id
      - name
      - url
      - visibility
      - created_at
      - updated_at
      - owner_user_id
      - owner_email
      - author_type
      - app_delegate
      - category_name
      - company_name
      - version_hash
      title: CreateDocumentResponse
      description: The document that was created, plus the change-detection token minted for this write.
    ReplaceDocumentContentResponse:
      properties:
        id:
          type: string
          format: uuid
          title: Id
          description: The docum

# --- truncated at 32 KB (42 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/profound/refs/heads/main/openapi/profound-documents-api-openapi.yml