openapi: 3.1.0 info: title: Acquia Content API version: "1.1" description: > The stable JSON:API surface shared by every Source CMS site, plus the OAuth 2.0 authentication endpoints that issue the tokens it accepts. Base URL, endpoint shapes, headers, query parameters, and error codes are identical on every site; a site's live per-bundle endpoint list is generated on the site itself at `API > OpenAPI documentation`. Values were verified against a live site. Captured request and response shapes for each endpoint are in the [Content API reference](/source-cms/reference/content-api/); the grant types, scopes, and token lifetimes are in the [authentication reference](/source-cms/reference/authentication/). servers: - url: "{siteUrl}" description: > Your site's base URL, the canonical ACQUIA_SITE_URL environment variable, with no trailing slash. Source CMS serves JSON:API under /api; headless Cloud Platform sites serve it under /jsonapi. variables: siteUrl: default: https://your-site.example.com description: The ACQUIA_SITE_URL environment variable (no trailing slash). tags: - name: Authentication description: OAuth 2.0 token and authorization endpoints. - name: Content description: JSON:API resource endpoints for reading and writing entries. paths: /oauth/token: post: tags: [Authentication] operationId: issueToken summary: Issue an access token description: > Issues access tokens for all three grant types. The request body is form-encoded. `client_credentials` is server-to-server; `authorization_code` exchanges a code from `GET /oauth/authorize`; `refresh_token` exchanges a refresh token. Only `authorization_code` and `refresh_token` return a `refresh_token`; `client_credentials` never does. requestBody: required: true content: application/x-www-form-urlencoded: schema: type: object required: [grant_type, client_id, client_secret] properties: grant_type: type: string enum: [client_credentials, authorization_code, refresh_token] client_id: type: string description: The API client's ID (ACQUIA_CLIENT_ID). client_secret: type: string description: The API client's secret (ACQUIA_CLIENT_SECRET). scope: type: string description: > Space-separated subset of the client's selected scopes. Omit to receive every selected scope. client_credentials and authorization_code only. code: type: string description: The authorization code from the redirect (authorization_code grant only). redirect_uri: type: string description: The same redirect URI used at /oauth/authorize (authorization_code grant only). refresh_token: type: string description: The refresh token to exchange (refresh_token grant only). examples: clientCredentials: summary: client_credentials value: grant_type: client_credentials client_id: "$ACQUIA_CLIENT_ID" client_secret: "$ACQUIA_CLIENT_SECRET" responses: "200": description: A newly issued access token. content: application/json: schema: $ref: "#/components/schemas/TokenResponse" example: token_type: Bearer expires_in: 300 access_token: eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1Ni "400": description: > Invalid request, most commonly `invalid_scope` when the `scope` parameter names a scope that does not exist or is not selected on the client. content: application/json: schema: $ref: "#/components/schemas/OAuthError" example: error: invalid_scope error_description: The requested scope is invalid, unknown, or malformed hint: "Check the `content:read` scope" "401": description: "Client authentication failed (`invalid_client`): the client ID or secret is wrong." content: application/json: schema: $ref: "#/components/schemas/OAuthError" example: error: invalid_client error_description: Client authentication failed /oauth/authorize: get: tags: [Authentication] operationId: authorize summary: Start the authorization_code grant description: > Redirects the user to log in and grant permissions, then redirects back to `redirect_uri` with a temporary authorization code to exchange at `POST /oauth/token`. Used only by the authorization_code grant. parameters: - name: response_type in: query required: true schema: { type: string, enum: [code] } description: The literal value `code`. - name: client_id in: query required: true schema: { type: string } description: The API client's ID. - name: redirect_uri in: query required: true schema: { type: string } description: Must match one of the client's configured Redirect URIs. - name: scope in: query required: false schema: { type: string } description: Space-separated subset of the client's selected scopes. responses: "302": description: Redirect to `redirect_uri` carrying the temporary authorization code. /api: get: tags: [Content] operationId: apiRoot summary: List available resource endpoints description: > Returns the index of resource endpoints available on the site, keyed by resource type (for example `node--article`). No version segment appears in the path; every response reports `jsonapi.version` `1.1`. security: - bearerAuth: [] responses: "200": description: The API root document. content: application/vnd.api+json: schema: { type: object } "401": $ref: "#/components/responses/Unauthorized" /api/{entityType}/{bundle}: parameters: - $ref: "#/components/parameters/entityType" - $ref: "#/components/parameters/bundle" get: tags: [Content] operationId: listEntries summary: List entries of a bundle description: > A collection of entries of one bundle, for example `/api/node/article`. `data` is an array. `meta.count` is the collection total including entries the request cannot see, so `data` can be shorter than `meta.count`, or empty; check `meta.omitted` and follow `links.next`. security: - bearerAuth: [] - {} parameters: - $ref: "#/components/parameters/filter" - $ref: "#/components/parameters/fields" - $ref: "#/components/parameters/include" - $ref: "#/components/parameters/page" - $ref: "#/components/parameters/sort" responses: "200": description: A JSON:API collection document. content: application/vnd.api+json: schema: $ref: "#/components/schemas/CollectionDocument" "401": $ref: "#/components/responses/Unauthorized" post: tags: [Content] operationId: createEntry summary: Create an entry description: > Requires the site's allowed-operations setting (`API > JSON:API`) set to "Read and write" and a token whose client has the `content:administer` scope. security: - bearerAuth: [] requestBody: required: true content: application/vnd.api+json: schema: $ref: "#/components/schemas/EntityDocument" responses: "201": description: The created entry. content: application/vnd.api+json: schema: $ref: "#/components/schemas/EntityDocument" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/{entityType}/{bundle}/{uuid}: parameters: - $ref: "#/components/parameters/entityType" - $ref: "#/components/parameters/bundle" - $ref: "#/components/parameters/uuid" get: tags: [Content] operationId: getEntry summary: Get one entry description: One entry addressed by its UUID (the `id` in every response). `data` is a single object. security: - bearerAuth: [] - {} parameters: - $ref: "#/components/parameters/fields" - $ref: "#/components/parameters/include" responses: "200": description: A JSON:API entity document. content: application/vnd.api+json: schema: $ref: "#/components/schemas/EntityDocument" "401": $ref: "#/components/responses/Unauthorized" patch: tags: [Content] operationId: updateEntry summary: Update an entry description: Requires writes enabled and the `content:administer` scope (same as POST). security: - bearerAuth: [] requestBody: required: true content: application/vnd.api+json: schema: $ref: "#/components/schemas/EntityDocument" responses: "200": description: The updated entry. content: application/vnd.api+json: schema: $ref: "#/components/schemas/EntityDocument" "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" delete: tags: [Content] operationId: deleteEntry summary: Delete an entry description: Requires writes enabled and the `content:administer` scope (same as POST). security: - bearerAuth: [] responses: "204": description: The entry was deleted. "401": $ref: "#/components/responses/Unauthorized" "403": $ref: "#/components/responses/Forbidden" /api/{entityType}/{bundle}/{uuid}/{field}: parameters: - $ref: "#/components/parameters/entityType" - $ref: "#/components/parameters/bundle" - $ref: "#/components/parameters/uuid" - name: field in: path required: true schema: { type: string } description: A relationship field machine name. get: tags: [Content] operationId: getRelated summary: Get related entries description: The referenced entries themselves, with full attributes, that a relationship field points at. security: - bearerAuth: [] - {} responses: "200": description: A JSON:API document of the related entries. content: application/vnd.api+json: schema: { type: object } "401": $ref: "#/components/responses/Unauthorized" /api/{entityType}/{bundle}/{uuid}/relationships/{field}: parameters: - $ref: "#/components/parameters/entityType" - $ref: "#/components/parameters/bundle" - $ref: "#/components/parameters/uuid" - name: field in: path required: true schema: { type: string } description: A relationship field machine name. get: tags: [Content] operationId: getRelationship summary: Get a relationship's linkage description: The linkage only (type + id identifiers, no attributes). Use it to read or rewrite what an entry points at without fetching the targets. security: - bearerAuth: [] - {} responses: "200": description: A JSON:API relationship document. content: application/vnd.api+json: schema: { type: object } "401": $ref: "#/components/responses/Unauthorized" components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: JWT description: > `Authorization: Bearer ` with one space after Bearer. Tokens come from POST /oauth/token. Not required for published-content GETs when the site's `Public access` (`API > JSON:API`) is Yes. oauth2: type: oauth2 flows: clientCredentials: tokenUrl: https://your-site.example.com/oauth/token scopes: "content:administer": Create, update, and delete entries over JSON:API. authorizationCode: authorizationUrl: https://your-site.example.com/oauth/authorize tokenUrl: https://your-site.example.com/oauth/token scopes: "content:administer": Create, update, and delete entries over JSON:API. parameters: entityType: name: entityType in: path required: true schema: { type: string, example: node } description: An entity type machine name (for example `node`, `media`, `taxonomy_term`). bundle: name: bundle in: path required: true schema: { type: string, example: article } description: A bundle machine name (for example `article`). The [content model reference](/source-cms/reference/content-model/#entity-types-and-bundles) maps each entity type to its bundle term and endpoint pattern. uuid: name: uuid in: path required: true schema: { type: string, format: uuid } description: The entry's UUID, the `id` member of every response. filter: name: filter in: query required: false style: deepObject explode: true schema: { type: object } description: > Match entries by field value. Short form `filter[field]=value` (equality) or canonical form with `[condition][path]`, `[condition][operator]`, `[condition][value]`. Operators: =, <>, >, >=, <, <=, STARTS_WITH, CONTAINS, ENDS_WITH, IN, NOT IN, BETWEEN, NOT BETWEEN, IS NULL, IS NOT NULL. Date fields compare as UNIX timestamps. Field paths use machine names. Every operator is shown with a worked example in the [query parameter reference](/source-cms/reference/query-parameters/#operators). fields: name: fields in: query required: false style: deepObject explode: true schema: { type: object } description: "Sparse fieldsets: `fields[node--article]=title,created` limits returned fields per type." include: name: include in: query required: false schema: { type: string } description: "Comma-separated relationship paths to embed in `included`, for example `image,tags`." page: name: page in: query required: false style: deepObject explode: true schema: { type: object } description: "Pagination: `page[limit]` and `page[offset]`." sort: name: sort in: query required: false schema: { type: string } description: "Comma-separated field machine names; prefix with `-` for descending, for example `-created`." responses: Unauthorized: description: > Missing, malformed, or expired token. Access tokens live 300 seconds. The diagnostic is in the `WWW-Authenticate` response header; the body may be HTML, not JSON. content: application/vnd.api+json: schema: $ref: "#/components/schemas/ErrorDocument" Forbidden: description: > The token is valid but lacks the required scope (for example writing without `content:administer`). The JSON:API error `detail` names the missing permission. content: application/vnd.api+json: schema: $ref: "#/components/schemas/ErrorDocument" example: errors: - status: "403" detail: "The 'administer nodes' permission is required." schemas: TokenResponse: type: object required: [token_type, expires_in, access_token] properties: token_type: { type: string, const: Bearer } expires_in: { type: integer, description: Access token lifetime in seconds (300). } access_token: { type: string } refresh_token: type: string description: Returned by authorization_code and refresh_token grants only; never by client_credentials. OAuthError: type: object properties: error: { type: string } error_description: { type: string } hint: { type: string } ResourceObject: type: object properties: type: { type: string, example: node--article } id: { type: string, format: uuid } attributes: { type: object } relationships: { type: object } CollectionDocument: type: object properties: jsonapi: type: object properties: version: { type: string, const: "1.1" } data: type: array items: $ref: "#/components/schemas/ResourceObject" meta: type: object properties: count: { type: integer } links: { type: object } included: type: array items: $ref: "#/components/schemas/ResourceObject" EntityDocument: type: object properties: jsonapi: type: object properties: version: { type: string, const: "1.1" } data: $ref: "#/components/schemas/ResourceObject" links: { type: object } included: type: array items: $ref: "#/components/schemas/ResourceObject" ErrorDocument: type: object properties: errors: type: array items: type: object properties: status: { type: string } title: { type: string } detail: { type: string }