openapi: 3.2.0 info: title: CI HUB Access SDK Auth API version: v1 summary: 'Embed CI HUB asset connectivity into a partner platform: exchange a partner-signed JWT for a CI HUB session, connect an end user to a DAM provider, then browse, search and read assets from that DAM over one uniform contract.' description: 'The CI HUB Access SDK API is the HTTP surface a partner platform calls to reach any DAM, MAM, PIM, cloud-storage or work-management system CI HUB connects to, without integrating each one separately. Authentication is a token exchange: the partner backend signs an RS256 JWT for the user and exchanges it at `POST /auth/exchangeToken` for a CI HUB access token (1 hour) and refresh token (30 days). The end user then connects a DAM provider through `POST /auth/login`, which returns a redirect URI plus a `state` the partner polls at `GET /auth/login`. From that point every content call carries two tokens: the CI HUB access token in `Authorization` and the DAM connection token in `provider-authorization`. Content is read-only in this release: folder browse, keyword search, similarity search by reference image, asset detail and asset version history. Every failure returns one error envelope whose `error.source` separates CI HUB platform faults (`cihub`) from DAM provider faults (`integration`). The API is served under the `/api/v1` prefix and is not versioned beyond it; additive changes ship in place, breaking changes are announced on the changelog before they ship.' termsOfService: https://ci-hub.com/legal/terms contact: name: CI HUB GmbH url: https://developer.ci-hub.com/access servers: - url: https://live.ci-hub.com/api/v1 description: Production - url: https://stage.ci-hub.com/api/v1 description: Staging / integration environment used throughout the published examples security: - cihubAccessToken: [] tags: - name: Auth paths: /auth/exchangeToken: post: operationId: exchangeToken summary: Exchange token description: 'Exchanges a partner-signed JWT for CI HUB access and refresh tokens. Required as the first call of every Access SDK session. ## Partner JWT Send the partner-signed JWT as `Authorization: Bearer `. ### Header | Field | Required | Value | |---|---|---| | `alg` | yes | `RS256` | | `kid` | yes | Must match a key published in the partner JWKS | | `typ` | optional | `JWT` | `HS256` is not accepted. ### Payload | Claim | Type | Required | Notes | |---|---|---|---| | `iss` | string | yes | Partner issuer URL. Must match the registered value exactly, including trailing slash. | | `aud` | string | yes | Registered audience. Default `https://api.ci-hub.com`. | | `sub` | string | yes | Stable identifier for the user in the partner system. | | `iat` | number | yes | Unix seconds. Tolerance: up to 30 seconds in the future. The token is rejected once it is older than `maxTokenAge` (now minus `iat`). | | `exp` | number | yes | Unix seconds. Must be in the future. | | `email` | string | yes (in JWT or body) | Used for just-in-time (JIT) user resolution: CI HUB finds the matching user or creates one on first exchange. Must parse as an email. JWT value takes precedence over body. | | `given_name` | string | optional | First name. Falls back to splitting `name`. | | `family_name` | string | optional | Last name. Falls back to splitting `name`. | | `name` | string | optional | Display name. Used when `given_name` and `family_name` are absent. | The token must be no older than `maxTokenAge` seconds (default 3600), measured from `iat` to the current time. Sign a fresh JWT for each exchange. Stale tokens are rejected with `cihub-sdk-token-invalid`. Send `Content-Type: application/json` so the JSON body parser picks up the request. Only an `application/json` body is parsed for the `email` field; other content types leave it unread. Name fields are not read from the body. They come from the partner JWT claims (`given_name`, `family_name`, `name`).' requestBody: description: 'Optional. Used only as a fallback for partners that cannot include the `email` claim in the partner JWT. If the JWT contains `email`, the body value is ignored. The request must include `email` somewhere (JWT or body). If your JWT already carries `email`, send `{}`.' content: application/json: schema: type: object properties: email: type: string description: Fallback email for JIT user resolution when the JWT has no `email` claim. format: email examples: - jane@customer.example.com responses: '200': description: '@description Token exchange successful.' content: application/json: schema: type: object properties: access_token: type: string description: 'CI HUB access token. Sent on subsequent calls as `Authorization: Bearer `. Valid for 1 hour.' examples: - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... refresh_token: type: string description: CI HUB refresh token. 30-day lifetime. Used to mint new access tokens. examples: - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... expires_in: type: number description: Access token lifetime in seconds. Always 3600. examples: - 3600 token_type: type: string const: Bearer description: Always `Bearer`. required: - access_token - refresh_token - expires_in - token_type '400': description: '`cihub-sdk-email-missing`: no `email` claim and no body fallback, or the value fails format validation.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': description: '| Code | When | |---|---| | `cihub-sdk-token-missing` | No `Authorization` header. | | `cihub-sdk-token-invalid` | Malformed JWT, wrong algorithm, missing required field, signature failed, `iat` more than 30s in the future, token older than `maxTokenAge` (now minus `iat`). | | `cihub-sdk-token-expired` | JWT past `exp`. | `cihub-sdk-token-invalid` is rarely also returned when CI HUB fails to persist the user during the exchange (transient backend fault). If a known-good JWT suddenly fails, retry once before treating the token as the problem.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '402': description: '`cihub-sdk-no-subscription`: the partner company has no active SDK subscription. Contact CI HUB before retrying.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: '| Code | When | |---|---| | `cihub-sdk-partner-unknown` | `iss` claim not registered as an SDK partner. | | `cihub-sdk-audience-invalid` | `aud` claim does not match the registered audience. |' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': description: '`cihub-rate-limited`: the partner exceeded its exchange rate limit. Standard `RateLimit-*` headers describe the window; back off and retry after it resets.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] tags: - Auth /auth/checkToken: get: operationId: checkTokenSdk summary: Check token description: 'Verifies that a CI HUB access token is still valid and returns the user profile envelope the partner platform needs to display in its UI. Typical use: confirm an active session before rendering a CI HUB-backed view, or revalidate after a long idle period. `licenseState`, `licenseExpires`, and `isTrialLicense` describe the SDK subscription, not the DAM provider. They are informational; the SDK subscription itself is re-checked on every call. A 401 here is the cue to start a new exchange. A 402 means the subscription state changed: contact CI HUB before retrying.' responses: '200': description: '@description Token is valid.' content: application/json: schema: type: object properties: adapter: type: string description: Always "CI HUB". examples: - CI HUB source: type: string description: CI HUB host that served the response. examples: - api.ci-hub.com user: type: string description: Display name composed from the user record. examples: - Jane Doe account: type: string description: Email address tied to the user record. examples: - jane@customer.example.com licenseState: type: string description: Always "Subscription" for SDK partners. examples: - Subscription licenseExpires: type: number description: 'Unix milliseconds. End of the active SDK subscription''s last day in UTC. Perpetual subscriptions emit a far-future sentinel; treat any value greater than `Date.now()` as valid.' examples: - 1798761599999 isTrialLicense: type: boolean description: Always false for SDK partners. examples: - false userHash: type: string description: Stable, opaque per-user identifier suitable for partner-side analytics. examples: - a1b2c3d4e5f6g7h8i9j0k1l2 '401': description: '| Code | When | |---|---| | `cihub-access-token-missing` | No `Authorization` header. | | `cihub-access-token-invalid` | Token signature failed, token expired, or the user record was removed. |' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '402': description: '@description `cihub-sdk-no-subscription`: the partner''s SDK subscription is no longer active.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: '`cihub-sdk-partner-unknown`: the partner registration was removed since the access token was issued.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': description: '@description `cihub-internal-error`: the subscription re-check failed transiently. Safe to retry.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] tags: - Auth /auth/refreshToken: get: operationId: refreshTokenSdk summary: Refresh token description: 'Renews a session. This is a shared endpoint: the token in `provider-authorization` decides which session is renewed. ## CI HUB session Send the CI HUB refresh token returned at exchange in `provider-authorization` to mint a new access token and a new refresh token. `Authorization` carries the current access token, which may already be expired (only its signature is checked here). The refresh token''s `sub` must match the access token''s `sub`; cross-user refresh attempts are rejected. The new access token is valid for 1 hour, the new refresh token for 30 days. Replace both cached tokens with the values returned here. The previous access token is superseded and should be discarded by the client, but stays valid until its `exp`; the previous refresh token remains valid until its 30-day clock runs out, so a slow client switch-over is safe. Refresh proactively a few minutes before `expires_in`, or reactively after receiving `cihub-access-token-invalid` from any endpoint. Once a refresh token expires the partner must perform a new exchange. ## DAM connection Send the DAM `refresh_token` from the login poll in `provider-authorization` to renew a DAM connection token. The token also identifies the provider. Some providers only return a new `access_token`; in that case keep the prior `refresh_token` and reuse it on the next refresh. A provider with no refresh path returns 404: run a fresh DAM login. Handle every provider the same way: try to refresh, and fall back to a fresh login if the refresh fails. The CI HUB SDK subscription is re-checked on every refresh; partners whose subscription lapsed receive 402 here and must contact CI HUB before continuing.' responses: '200': description: '@description Token refreshed successfully.' content: application/json: schema: type: object properties: access_token: type: string description: New access token (CI HUB session) or new DAM connection token, matching the refreshed session. examples: - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... refresh_token: type: string description: New refresh token. Some DAM providers omit it; keep and reuse the prior refresh token then. examples: - eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... expires_in: type: number description: Access token lifetime in seconds. Omitted when the DAM provider does not supply a token lifetime. examples: - 3600 token_type: type: string description: Token type for the Authorization header. examples: - Bearer required: - access_token - token_type '401': description: '| Code | When | |---|---| | `cihub-access-token-missing` | No `Authorization` header. | | `cihub-access-token-invalid` | Access token signature failed or was malformed. An expired access token is accepted here; only signature and format are checked. | | `cihub-refresh-token-invalid` | The `provider-authorization` token is not a refresh token (for example an access token sent in its place), or its `sub` does not match the access token''s `sub`. | A `cihub-refresh-token-invalid`, and any failure once the 30-day refresh window has lapsed, is the cue to start a new exchange.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '402': description: '@description `cihub-sdk-no-subscription`: the partner''s SDK subscription is no longer active.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '403': description: '| Code | When | |---|---| | `provider-access-token-missing` | No `provider-authorization` header. | | `provider-access-token-invalid` | Refresh token signature failed, was malformed, or has expired. | | `cihub-sdk-partner-unknown` | The partner registration was removed since the tokens were issued. |' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '404': description: 'The DAM provider has no refresh path. No structured `error` envelope. Run a fresh DAM login.' '503': description: '@description `cihub-internal-error`: the subscription re-check failed transiently. Safe to retry.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] damToken: [] tags: - Auth /auth/logout: get: operationId: logoutSdk summary: Logout description: 'Signals the end of a partner-side session. For Access SDK partners this endpoint is advisory: CI HUB does not maintain server-side session state for SDK tokens, so logout returns 200 without revoking the refresh token. The partner platform is responsible for discarding the cached access and refresh tokens locally. CI HUB does not currently maintain a refresh-token blocklist for Access SDK partners. A refresh token remains valid until its 30-day clock runs out, even after a logout call. Partners that need stronger revocation guarantees should: - Drop both the access token and the refresh token from local storage on logout. - Not persist refresh tokens beyond the active session. - Detect compromise on the partner side and avoid reusing a leaked refresh token. Server-side revocation is in progress.' responses: '200': description: '@description Logout acknowledged. The response body is the literal string `OK`.' '401': description: '| Code | When | |---|---| | `cihub-access-token-missing` | No `Authorization` header. | | `cihub-access-token-invalid` | Access token signature failed or was malformed. | A 401 here is harmless from a logout perspective: the token was not valid to begin with. The partner should still discard local copies.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] tags: - Auth /auth/providers: get: operationId: getProvidersSdk summary: Get providers description: 'Returns the list of DAM providers available to the authenticated CI HUB user. The partner platform uses the result to render a connection picker and to pass each provider''s `id` on subsequent login and content calls. This endpoint is intentionally lenient on authentication so the partner platform can render its connection picker before any DAM session exists. A missing or invalid `Authorization` header returns 200 with a single-entry list containing only the CI HUB platform connection. When the list contains only `cihub`, refresh the access token or start a new exchange. The provider list is stable for the lifetime of one access token. Cache it for that long and refetch after a new exchange.' responses: '200': description: '@description List of available providers' content: application/json: schema: type: array items: type: object properties: id: type: string description: '@description Provider identifier' name: type: string description: '@description Provider display name' version: type: string description: '@description Provider version' logo: type: object properties: data: type: string description: Base64 encoded image data examples: - data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... width: type: number description: Logo width in pixels examples: - 249 height: type: number description: Logo height in pixels examples: - 77 backgroundColor: type: string description: Background color in hex format examples: - '#FFFFFF' description: '@description Provider logo with metadata.' glyph: type: object properties: data: type: string description: Base64 encoded image data examples: - data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA... width: type: number description: Glyph width in pixels examples: - 249 height: type: number description: Glyph height in pixels examples: - 77 backgroundColor: type: string description: Background color in hex format examples: - '#FFFFFF' description: '@description Provider glyph/icon with metadata' capabilities: $ref: '#/components/schemas/ProviderCapabilities' loginUrl: type: string description: '@description Login URL for this provider. POST it with `?polling=true` to run the JSON polling login flow.' isDefault: type: boolean description: '@description Whether this is a default provider' isOptional: type: boolean description: '@description Whether this is an optional provider' isLicensed: type: boolean description: '@description Whether the provider requires a paid tier. This does not indicate whether the current end user holds that license.' isUnsupported: type: boolean description: Present with value `true` only when the provider is wired but no longer maintained. Absent otherwise; `false` is never sent. examples: - true unsupportedAdapterTitle: type: string description: Title to display when the provider is unsupported. May be absent even when `isUnsupported` is `true`; null-guard before reading. examples: - Ask your DAM Vendor unsupportedAdapterDescription: type: string description: Description to display when the provider is unsupported. May be absent even when `isUnsupported` is `true`; null-guard before reading. examples: - This Solution is not supported today, please ask the DAM Vendor for a status. isDisabledForHost: type: boolean description: '@description Whether this provider is disabled for the current host.' '500': description: '@description Transient backend failure. Safe to retry.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] tags: - Auth /auth/login: get: operationId: damLoginPoll summary: DAM login (poll) description: 'Returns the current state of a login started by initiate. The `state` value is the credential for this call, so no `Authorization` header is needed. Poll on an interval until the response carries tokens or an error. The returned `access_token` is the DAM connection token and is separate from the CI HUB access token in your `Authorization` header. Content calls carry both: the CI HUB token in `Authorization` and this token in `provider-authorization`. A successful poll consumes the `state`. A `state` lives for 5 minutes from initiate; once it expires (or after a successful poll), further polls take the failure path. Cap your loop at the 5-minute horizon and fall back to a fresh login on failure. The poll always answers 200 with a JSON body. An unknown, expired, or consumed `state`, and a login the end user failed or canceled at the DAM, all return a body carrying an `error` property instead of tokens. Treat any body with `error` as final and start a new DAM login.' parameters: - name: state in: query required: true description: '@description The `state` returned by initiate. Identifies and authorizes the call.' schema: type: string - name: polling in: query required: true description: '@description Send `true` on every initiate and poll call; it selects the JSON response shape.' schema: type: boolean const: true responses: '200': description: 'While the state is alive and the user has not finished signing in, the poll returns an empty object. Once the login completes, it returns the tokens. A dead `state` (unknown, expired, consumed, or failed login) returns an `error` property.' content: application/json: schema: anyOf: - type: object - type: object properties: access_token: type: string description: '@description DAM connection token. Send it as the `provider-authorization` header on content calls.' refresh_token: type: string description: '@description DAM refresh token. Use it to renew the connection.' userHash: type: string description: '@description Stable, opaque per-user identifier for the connected DAM account. Optional for partners to use.' required: - access_token - refresh_token - type: object properties: error: type: string description: Plain-text failure marker. examples: - Not found required: - error security: - cihubAccessToken: [] tags: - Auth post: operationId: damLoginInitiate summary: DAM login (initiate) description: 'Starts a login for the provider named in the `provider` query parameter (an `id` from the providers listing). DAM login is a two-call flow: the partner platform starts a login for a chosen provider, opens the returned URL in the end user''s browser, then polls until the end user finishes signing in at the DAM. Open `redirect_uri` for the end user (popup or full-page redirect). Keep `state` for polling. Failures past the token check (an unknown provider, a provider the user is not licensed for, or a rejected sign-in) have not moved to the error envelope yet. They currently redirect the browser to a CI HUB URL carrying an `error` query parameter with a plain-text message. Treat a redirect or non-JSON response from initiate as a failure and read the `error` value. ## Provider parameters Several providers are multi-tenant, so CI HUB asks the end user which instance of the DAM to sign in to on a page of its own before the provider''s login. A partner platform that already knows the instance sends it as `serverUrl` on the initiate call, and that page drops out of the flow. `bynder`, `dash`, `fotoware`, `frontify`, `picturepark`, and `purered` read it. It is optional. Omit it and the end user answers the prompt as before. A value the provider rejects also falls back to the prompt, so a stale instance URL degrades instead of failing the login.' parameters: - name: provider in: query required: true description: '@description Provider identifier from the providers listing.' schema: type: string - name: polling in: query required: true description: '@description Send `true` on every initiate and poll call; it selects the JSON response shape.' schema: type: boolean const: true - name: serverUrl in: query description: 'Provider parameter. The DAM instance the end user signs in to, as a full origin. Read by `bynder`, `dash`, `fotoware`, `frontify`, `picturepark`, and `purered`.' schema: type: string responses: '200': description: '@description Login initiated.' content: application/json: schema: type: object properties: redirect_uri: type: string description: One-time URL to open in the end user's browser so they can authenticate at the DAM. examples: - https://provider.example.com/oauth/authorize?...&state=Pf3a9c... state: type: string description: Opaque token that identifies this login. Pass it to the poll call. examples: - Pf3a9c... required: - redirect_uri - state '302': description: 'Legacy failure path: an unknown provider, a provider the user is not licensed for, and other failures past the token check redirect to a CI HUB URL with an `error` query parameter instead of answering JSON. Disable redirect-following, read the `error` value from the `Location` header, and treat it as final.' '401': description: '| Code | When | |---|---| | `cihub-access-token-missing` | No `Authorization` header. | | `cihub-access-token-invalid` | Token signature failed, token expired, or the user record was removed. |' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' security: - cihubAccessToken: [] tags: - Auth components: schemas: StructuredError: type: object properties: code: type: string description: 'Machine-readable error code. Format: `{source}-{error-type}` in kebab-case. Clients can switch on this field to handle specific error types.' examples: - integration-forbidden - integration-auth-failed - cihub-access-token-invalid - cihub-license-required - cihub-unknown-error source: type: string enum: - cihub - integration description: 'Where the error originated. `integration` means the DAM/provider caused the problem. `cihub` means the CI-HUB platform itself caused the problem.' status: type: number description: HTTP status code mirrored in the response body for convenience. examples: - 400 - 401 - 403 - 404 - 409 - 501 message: type: string description: Human-readable error message safe to display to end users. examples: - Access denied by the integration - Authentication token has expired details: anyOf: - type: string - type: object description: 'Raw error detail from the provider or additional context. Optional. Can be a simple string or a structured object with machine-readable context. For integration errors this is typically the original DAM error forwarded as-is.' provider: type: string description: 'Name of the integration/provider. Only present when `source` is `integration`. Injected automatically by the server from the authenticated session.' examples: - bynder - dropbox - sharepoint required: - code - source - status - message description: 'Structured error object that provides machine-readable error classification. Declared directly by migrated routes and adapters that use the error builder pattern, and synthesized at the response layer for legacy string/Error failures (best-effort `code`/`source` from the HTTP status and authenticated provider). The `source` field distinguishes CI-HUB platform errors from integration/provider errors, allowing clients to programmatically route errors to the correct team.' ProviderCapabilities: type: object properties: category: type: string description: '@description The category of the provider (e.g., DAM, PIM, Cloud Filehosting)' assetUploadLimitInMB: type: number description: '@description Maximum file size in MB for assets to be uploaded.' directAccessHelper: type: string description: '@description A JavaScript function invoked to return an object with helper functions for uploading/updating files directly to the provider without calling our api first.' assetHashAlgorithm: type: string enum: - Md5 - Sha1 - Sha256 - Sha256Split4MB - Sha256First16MB - Sha512 - FileAttributes - Crc32 description: Name of the supported hashing algorithm for file contents. assetSearch: type: object properties: help: type: object additionalProperties: type: string description: A text describing the search syntax in multiple languages, keyed by language code. examples: - en: Enter a search term and matching files will be displayed. Click on the i icon for help with advanced search options. de: Geben Sie einen Suchbegriff ein und dazu passende Dateien werden angezeigt. Für Hilfe zu erweiterten Suchoptionen auf das i Symbol klicken. supportsParentId: type: boolean description: '@description If true, enables "searchInActiveFolder" for this provider.' alwaysSearchInFolder: type: boolean description: '@description If true, forces the search operation to be scoped in the current folder. This builds upon supportsParentId which should be set to true.' similarSearch: type: boolean description: '@description If true, enables similarity search for this integration.' externalUrl: type: string description: '@description A URL leading to an external website with further instructions on the search syntax.' autoSearchQuery: type: string description: '@description If set, triggers auto search with the specified query when the user navigates to the search view.' canParallelSearch: type: boolean description: If set to false, assets will be searched sequentially instead of in parallel. default: true supportsParallelRelink: type: boolean description: '@description If true, allows multiple concurrent relink operations to happen.' parallelRelinkMax: type: number description: '@description Maximum number of parallel relinking operations allowed for this integration.' searchByHash: type: string description: '@description If set, the user can search assets via hash. The value of this property should be the applied hash algorithm.' required: - canParallelSearch description: type: object additionalProperties: type: string description: The provider's description text in multiple languages, keyed by language code. examples: - en: MediaGraph is a multi-user DAM system that offers permission-controlled access to many media types. de: MediaGraph ist ein Multi-User-DAM-System, das einen berechtigungsgesteuerten Zugriff auf viele Medientypen bietet. directAssetUpload: type: boolean description: If true, the client attempts to upload assets directly to the provider using the uploadUrl of the target folder(the uploadUrl of the target folder is a legacy field though and not send anymore) and directAccessHelper if provided in the capabilities. deprecated: true uploadWithRelinkOptionEnabled: type: boolean description: '@description If true, the "with relink" option will be available for the upload of a placed local file via the link panel. This automatically links the asset to the file in the DAM after the upload.' requestHeaders: type: object additionalProperties: type: string description: Additional headers to be added to every request the client makes to this provider directly. When directly uploading or downloading assets/thumbnails for example. examples: - X-Custom-Header: Custom Value assetComment: type: boolean description: '@description Describes whether the provider supports additional comments on assets. If true, a text field for the comment is presented to the user, and the entered comment is passed to createAsset().' disableDuplicateCheck: type: boolean description: 'If true, it is possible to upload assets even if assets with the same file name already exist in the target folder.' restrictSameNameUpdatesOnly: type: boolean description: 'If true, the update of an asset is only possible if the selected file used to update the existing asset and the existing asset have the exact same filenames.' tasking: type: boolean description: 'Set to true if this integration supports tasking. Expects the integration to implement searchTasks(), getTask(), getTaskAssets(), addTaskComment(), and updateCustomTaskState().' maxMultipleAssetVersions: type: number description: '@description Determines how many assets can be batched in the POST /assets/assetversions endpoint for the provider.' inddAssetUploadAsPackage: type: boolean description: 'Enables a special feature in the Aprimo integration. It allows uploading an InDesign project as an InDesign package. This ZIP contains the INDD-file and all the assets linked to it. Note: This is only used in the Aprimo adapter.' alwaysRefreshFolders: type: boolean description: '@description If true, ignores cached data and refreshes when navigating through folders.' supportsLocalContentView: type: boolean description: '@description If true, the provider supports the local content view. Only used in the siteFusion adapter.' supportsBrandHub: type: boolean description: '@description If true, the provider supports the brand hub.' description: '@description The capabilities of the provider.' ErrorEnvelope: type: object properties: message: type: string const: Error description: Always "Error". For the human-readable message use `error.message` instead. details: type: string description: Request context and error summary. examples: - 'POST /api/v1/auth/exchangeToken failed: SDK authentication token is invalid' errorCode: type: string description: Legacy mirror of `error.code`. New clients should switch on `error.code`. examples: - cihub-sdk-token-invalid error: $ref: '#/components/schemas/StructuredError' required: - message - error description: 'Standard error envelope returned by migrated routes. The `error` object carries the machine-readable classification. `message`, `details`, and `errorCode` are legacy mirrors kept for backward compatibility; new clients should read `error` only.' securitySchemes: cihubAccessToken: type: http scheme: bearer bearerFormat: JWT description: 'CI HUB access token returned by `POST /auth/exchangeToken`, sent as `Authorization: Bearer `. HS256, 1 hour lifetime. Required on every call after the exchange. On `POST /auth/exchangeToken` itself this header instead carries the partner-signed RS256 JWT.' damToken: type: apiKey in: header name: provider-authorization description: 'DAM connection token obtained from the provider login flow, sent as `provider-authorization: Bearer `. Required on calls that reach a specific DAM (folder browse, search, asset detail, versions, download, thumbnail). On `GET /auth/refreshToken` this header carries the CI HUB refresh token instead.' externalDocs: description: CI HUB Access SDK reference url: https://developer.ci-hub.com/access x-provenance: method: derived derived_by: API Evangelist enrichment pipeline derived_on: '2026-08-12' statement: 'CI HUB does not serve its OpenAPI document at a public URL. It does publish the document''s complete machine-readable projection: `@ci-hub/access-sdk` ships `dist/index.d.ts`, generated by `openapi-typescript` from the same OpenAPI specification that renders developer.ci-hub.com/access (''All request and response types are generated from the same OpenAPI specification that produces this reference''). This document is that projection walked back into OpenAPI 3.1. It is a derivation of a first-party artifact, not an authored specification.' sources: - what: paths, operationIds, summaries, descriptions, parameters, request bodies, responses, components.schemas / responses / parameters / requestBodies from: npm @ci-hub/access-sdk@0.2.0 -> package/dist/index.d.ts (openapi-typescript emission, Apache-2.0) url: https://registry.npmjs.org/@ci-hub/access-sdk/-/access-sdk-0.2.0.tgz method: derived - what: info.title, info.description, info.termsOfService, externalDocs, servers[] from: CI HUB Access SDK documentation (openapi-typescript does not emit info/servers) url: https://developer.ci-hub.com/access/llms-full.txt method: searched - what: components.securitySchemes and the security requirements applied per operation from: 'the documented two-token pattern (Authorization: Bearer plus provider-authorization: Bearer ); openapi-typescript does not emit securitySchemes, so this restores information the projection drops rather than adding a new claim' url: https://developer.ci-hub.com/access/authentication method: searched not_derived: - operation tags (the projection carries none; grouping is recorded in overlays/ci-hub-access-overlay.yaml instead of being written into this document) - in-spec examples beyond the @example values openapi-typescript preserved verification: - url: https://live.ci-hub.com/api/v1/auth/providers http_status: 200 note: GET /auth/providers answers anonymously and returns the live provider catalogue, confirming the derived path and method. - url: https://live.ci-hub.com/api/v1/system/providerInfo http_status: 401 note: 'returns the derived ErrorEnvelope shape verbatim: {message, details, errorCode, error:{code, source, status, message, details}}.'