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

# Structure

> Beneficial owners are computed from the shareholding chains. Price: 35 credits per legal entity returned; notFound entries are free. Read-only and idempotent: POST is used only because the request carries a body. The HTTP QUERY method is the preferred verb for this operation and will be accepted on the same path once client support is widespread.



## OpenAPI

````yaml api-reference/openapi.standard.json POST /companies/structure
openapi: 3.1.0
info:
  title: Syrto API - standard endpoints
  version: 1.7.0
  description: >-
    Financial, corporate and market data on Italian companies.


    Every call answers `200 { data, meta }`; `meta.usage.quantity` is what the
    call consumed, in

    credits, and `meta.warnings` lists any non-fatal caveats (empty when there
    are none). Every field

    is always present and unknown values are null. Percentages are fractions
    (0.15 = 15%).


    **Authentication.** Every call needs an API key, sent as `Authorization:
    Bearer sk_...` over

    HTTPS - never in a URL. Keys are scoped to your organization: admins create
    and revoke them in the

    Syrto dashboard (https://dashboard.syrto.ai/api-keys). A missing or
    unrecognised key is a 401

    (`missing_api_key`, `invalid_api_key`); a 503 `auth_unavailable` means the
    key could not be

    checked right now, so retry with backoff rather than rotating it.


    **Billing basis.** negativities, rna and structure bill once per legal
    entity: the individual and

    consolidated records of the same company count once. Every other endpoint
    bills per record (or per

    call), so individual and consolidated count separately. A tax id always
    resolves to a single record

    (`statementBasis`, individual by default): a company is billed twice only
    when both of its

    companyIds are passed. A market call is priced per call, whatever the size
    of its set: omitting

    `filters` and `seedId`, or sending `filters: {}`, is the whole of Italy, at
    the same price.

    notFound entries are never billed, and neither is any error.
servers:
  - url: https://api.syrto.ai
security: []
tags:
  - name: Company data
    description: Identity, risk flags, state aid and branches of known companies.
  - name: Governance
    description: Ownership, officers, beneficial owners and group.
  - name: Financials
    description: Statement items, reclassified statements, indices and spider graph.
  - name: Composite
    description: Comparable companies.
  - name: Search
    description: The companies of a filtered set, row by row.
  - name: Market
    description: Aggregates over a filtered set.
  - name: Catalog
    description: Free reference data.
paths:
  /companies/structure:
    post:
      tags:
        - Governance
      summary: Ownership, officers, beneficial owners and group of up to 20 companies.
      description: >-
        Beneficial owners are computed from the shareholding chains. Price: 35
        credits per legal entity returned; notFound entries are free. Read-only
        and idempotent: POST is used only because the request carries a body.
        The HTTP QUERY method is the preferred verb for this operation and will
        be accepted on the same path once client support is widespread.
      operationId: company-structure
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
                    minLength: 1
                    maxLength: 100
                  minItems: 1
                  maxItems: 20
                  description: >-
                    1-20 references, each a companyId (Syrto id of one statement
                    record, starts with `Zm86`) or a tax id (11-digit partita
                    IVA or 16-character codice fiscale). A tax id resolves to
                    the record selected by `statementBasis`. Duplicates are
                    rejected.
                  example:
                    - '02579690039'
                    - '03841740016'
                roleCategories:
                  type: array
                  items:
                    $ref: '#/components/schemas/RoleCategory'
                  minItems: 1
                  maxItems: 9
                  description: Return only officers holding a role in these categories.
                language:
                  type: string
                  enum:
                    - it
                    - en
                  description: >-
                    Language of metric names, labels and descriptions (never of
                    field names or slugs). Omitted: the account's default.
              required:
                - ids
              additionalProperties: false
      responses:
        '200':
          description: >-
            Ownership, officers, beneficial owners and group of up to 20
            companies.
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/CompanyStructureBatch'
                  meta:
                    $ref: '#/components/schemas/ResponseMeta'
                required:
                  - data
                  - meta
        '401':
          description: missing_api_key | invalid_api_key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: credits_exhausted | limit_reached
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: client_not_configured | not_entitled
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: unknown_endpoint | not_found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '413':
          description: payload_too_large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '415':
          description: unsupported_media_type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: invalid_params
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: rate_limited
          headers:
            Retry-After:
              description: >-
                Seconds to wait before retrying. Neither a 429 nor a 504 is
                billed. A 504 whose query had reached the data service leaves it
                running, and its answer is cached, so the same call after this
                delay is usually fast.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: internal_error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: upstream_error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: auth_unavailable | entitlement_unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '504':
          description: upstream_timeout
          headers:
            Retry-After:
              description: >-
                Seconds to wait before retrying. Neither a 429 nor a 504 is
                billed. A 504 whose query had reached the data service leaves it
                running, and its answer is cached, so the same call after this
                delay is usually fast.
              schema:
                type: integer
                minimum: 0
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - bearerAuth: []
components:
  schemas:
    RoleCategory:
      type: string
      enum:
        - GOVERNING_BODIES
        - ADMINISTRATION_AND_EXECUTIVES
        - AUDITING
        - REPRESENTATION_AND_AUTHORITY
        - EXTRAORDINARY_PROCEDURES
        - FUNCTIONAL_ROLES
        - PARTICIPATION_OWNERSHIP
        - CHIEF_EXECUTIVE_OFFICER
        - OTHER
    CompanyStructureBatch:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/CompanyStructure'
          description: Resolved entries, in input order.
        notFound:
          type: array
          items:
            $ref: '#/components/schemas/NotFoundEntry'
      required:
        - items
        - notFound
    ResponseMeta:
      type: object
      properties:
        requestId:
          type: string
        endpoint:
          type: string
        usage:
          $ref: '#/components/schemas/Usage'
        warnings:
          type: array
          items:
            $ref: '#/components/schemas/Warning'
          description: Empty when there are none.
      required:
        - requestId
        - endpoint
        - usage
        - warnings
    Error:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
              enum:
                - missing_api_key
                - invalid_api_key
                - credits_exhausted
                - limit_reached
                - client_not_configured
                - not_entitled
                - unknown_endpoint
                - not_found
                - payload_too_large
                - unsupported_media_type
                - invalid_params
                - rate_limited
                - internal_error
                - upstream_error
                - auth_unavailable
                - entitlement_unavailable
                - upstream_timeout
            message:
              type: string
            requestId:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  path:
                    type: string
                  message:
                    type: string
                required:
                  - path
                  - message
          required:
            - code
            - message
            - requestId
      required:
        - error
    CompanyStructure:
      allOf:
        - $ref: '#/components/schemas/CompanyHeader'
        - type: object
          properties:
            controllingEntityCategory:
              anyOf:
                - $ref: '#/components/schemas/ControllingEntityCategory'
                - type: 'null'
            isForeignOwned:
              type:
                - boolean
                - 'null'
            isQuoted:
              type:
                - boolean
                - 'null'
            officers:
              $ref: '#/components/schemas/OfficerList'
            shareholders:
              $ref: '#/components/schemas/ShareholderList'
            beneficialOwners:
              $ref: '#/components/schemas/BeneficialOwnerList'
            subsidiaries:
              $ref: '#/components/schemas/SubsidiaryList'
            linkedCompanies:
              $ref: '#/components/schemas/LinkedCompanyList'
            companiesWithSharedOfficers:
              $ref: '#/components/schemas/SharedOfficerCompanyList'
          required:
            - controllingEntityCategory
            - isForeignOwned
            - isQuoted
            - officers
            - shareholders
            - beneficialOwners
            - subsidiaries
            - linkedCompanies
            - companiesWithSharedOfficers
      description: >-
        Lists hold up to 100 entries for a single company and 10 in a
        multi-company call; call a holding on its own for more.
    NotFoundEntry:
      type: object
      properties:
        position:
          type: integer
          minimum: 0
          description: Index in the `ids` array.
        input:
          type: string
        reason:
          type: string
          enum:
            - not_found
            - no_filing_for_year
            - invalid_id
      required:
        - position
        - input
        - reason
      description: An id that did not resolve. Never billed.
    Usage:
      type: object
      properties:
        quantity:
          type: number
        unit:
          type: string
      required:
        - quantity
        - unit
    Warning:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
      required:
        - code
        - message
    CompanyHeader:
      type: object
      properties:
        companyId:
          type: string
          description: >-
            Syrto id of this statement record. Individual and consolidated
            differ.
        legalName:
          type:
            - string
            - 'null'
        taxId:
          type:
            - string
            - 'null'
          description: Codice fiscale / partita IVA.
        consolidated:
          type: boolean
          description: Whether these figures are the consolidated (group) statement.
      required:
        - companyId
        - legalName
        - taxId
        - consolidated
    ControllingEntityCategory:
      type: string
      enum:
        - FAMILY
        - FAMILY_OWNED_GROUP
        - FINANCIALLY_OWNED_GROUP
        - INDUSTRIAL_GROUP
        - FINANCIAL
        - OTHER
    OfficerList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
          description: Counts ROLES; a person can hold several.
        peopleTotal:
          type:
            - integer
            - 'null'
          description: Counts distinct people; null when the list is truncated.
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/Officer'
      required:
        - total
        - peopleTotal
        - truncated
        - items
    ShareholderList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/Holder'
      required:
        - total
        - truncated
        - items
    BeneficialOwnerList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/BeneficialOwner'
      required:
        - total
        - truncated
        - items
    SubsidiaryList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/Holder'
      required:
        - total
        - truncated
        - items
    LinkedCompanyList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/StructureEntity'
      required:
        - total
        - truncated
        - items
    SharedOfficerCompanyList:
      type: object
      properties:
        total:
          type:
            - integer
            - 'null'
          description: 'Always null: the registry exposes no count.'
        truncated:
          type: boolean
          description: True when `items` is shorter than `total`.
        items:
          type: array
          items:
            $ref: '#/components/schemas/StructureEntity'
      required:
        - total
        - truncated
        - items
    Officer:
      allOf:
        - $ref: '#/components/schemas/StructureEntity'
        - type: object
          properties:
            roles:
              type: array
              items:
                $ref: '#/components/schemas/OfficerRole'
          required:
            - roles
      description: A person, a company, or an unclassified entity.
    Holder:
      allOf:
        - $ref: '#/components/schemas/StructureEntity'
        - type: object
          properties:
            share:
              type:
                - number
                - 'null'
              description: Ownership share, fraction (0.51).
          required:
            - share
      description: A person, a company, or an unclassified entity.
    BeneficialOwner:
      allOf:
        - $ref: '#/components/schemas/Holder'
        - type: object
          properties:
            ownershipChains:
              type: array
              items:
                type: array
                items:
                  $ref: '#/components/schemas/Holder'
              description: >-
                Control chains from the company to the owner, nearest link
                first.
          required:
            - ownershipChains
      description: A person, a company, or an unclassified entity.
    StructureEntity:
      type: object
      properties:
        entityType:
          type: string
          enum:
            - person
            - company
            - unclassified
        name:
          type:
            - string
            - 'null'
        personId:
          type:
            - string
            - 'null'
          description: Person id (usable in search filters).
        age:
          type:
            - integer
            - 'null'
          description: Age of the person, in years.
        companyId:
          type:
            - string
            - 'null'
        taxId:
          type:
            - string
            - 'null'
      required:
        - entityType
        - name
        - personId
        - age
        - companyId
        - taxId
      description: A person, a company, or an unclassified entity.
    OfficerRole:
      type: object
      properties:
        roleCategory:
          $ref: '#/components/schemas/RoleCategory'
        role:
          type:
            - string
            - 'null'
      required:
        - roleCategory
        - role
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Org-scoped WorkOS API key (sk_...), sent as `Authorization: Bearer
        <key>`. Admins create and revoke keys in the Syrto dashboard:
        https://dashboard.syrto.ai/api-keys

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.