diff --git a/code/API_definitions/click-to-dial.yaml b/code/API_definitions/click-to-dial.yaml index 0fca08b..fbfffb9 100644 --- a/code/API_definitions/click-to-dial.yaml +++ b/code/API_definitions/click-to-dial.yaml @@ -36,7 +36,7 @@ info: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html version: wip - x-camara-commonalities: "0.7" + x-camara-commonalities: "0.8.0-rc.2" externalDocs: description: Product documentation at CAMARA @@ -49,6 +49,12 @@ servers: default: http://localhost:9091 description: API root, defined by the service provider, e.g. `api.example.com` or `api.example.com/somepath` +tags: + - name: Calls + description: Operations related to Click to Dial calls + - name: Recording + description: Operations related to Call Recordings + paths: /calls: post: @@ -95,6 +101,8 @@ paths: '{$request.body#/sink}': post: summary: Call status changed event + security: + - notificationsBearerAuth: [] description: | Event notification delivered to the sink URL when the call status changes (CloudEvents structured mode). @@ -110,6 +118,12 @@ paths: responses: '2XX': description: Event successfully received by the sink. + '400': + $ref: '#/components/responses/Generic400' + '401': + $ref: '#/components/responses/Generic401' + '403': + $ref: '#/components/responses/Generic403' /calls/{callId}: get: tags: @@ -222,39 +236,26 @@ paths: components: securitySchemes: openId: - type: openIdConnect - description: This API uses OpenID Connect for authentication and authorization. - openIdConnectUrl: "https://example.com/.well-known/openid-configuration" + $ref: "../common/CAMARA_common.yaml#/components/securitySchemes/openId" notificationsBearerAuth: - type: http - scheme: bearer - bearerFormat: "{$request.body#/sinkCredential.credentialType}" + $ref: "../common/CAMARA_event_common.yaml#/components/securitySchemes/notificationsBearerAuth" headers: x-correlator: - description: Correlation id for the different services - schema: - $ref: '#/components/schemas/XCorrelator' - example: 'b4333c46-49c0-4f62-80d7-f0ef930f1c46' + $ref: "../common/CAMARA_common.yaml#/components/headers/x-correlator" parameters: x-correlator: - name: x-correlator - in: header - description: Correlation ID for the different services - schema: - $ref: '#/components/schemas/XCorrelator' - example: 'b4333c46-49c0-4f62-80d7-f0ef930f1c46' + $ref: "../common/CAMARA_common.yaml#/components/parameters/x-correlator" schemas: XCorrelator: - type: string - pattern: '^[a-zA-Z0-9-_:;./<>{}]{0,256}$' - description: Correlation id for tracking API calls across systems. + $ref: "../common/CAMARA_common.yaml#/components/schemas/XCorrelator" callId: description: Call identification type: string + maxLength: 256 example: 'call_550e8400-e29b-41d4-a716-446655440000' Call: @@ -270,12 +271,7 @@ components: status: $ref: '#/components/schemas/status' createdAt: - type: string - format: date-time - description: > - Time when the call session was created. - It must follow RFC 3339 and must have time zone. - Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ. + $ref: '../common/CAMARA_common.yaml#/components/schemas/DateTime' recordingEnabled: type: boolean description: Whether recording is enabled for this call. @@ -318,6 +314,7 @@ components: recordingEnabled: true Caller: + description: The phone number of the caller. type: object properties: number: @@ -326,6 +323,7 @@ components: - number Callee: + description: The phone number of the callee. type: object properties: number: @@ -334,66 +332,20 @@ components: - number PhoneNumber: - description: Phone number in E.164 format - type: string - pattern: '^\+[1-9]\d{1,14}$' - example: '+12345678' + $ref: "../common/CAMARA_common.yaml#/components/schemas/PhoneNumber" sink: description: The address to which events shall be delivered, using the HTTP protocol. type: string format: uri + maxLength: 2048 example: "https://endpoint.example.com/sink" SinkCredential: - description: A sink credential provides authentication or authorization information necessary to enable delivery of events to a target. - type: object - properties: - credentialType: - description: "The type of the credential. MUST be set to ACCESSTOKEN. Discriminator for credential subtypes." - type: string - enum: - - ACCESSTOKEN - discriminator: - propertyName: credentialType - mapping: - ACCESSTOKEN: "#/components/schemas/AccessTokenCredential" - required: - - credentialType + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/SinkCredential" AccessTokenCredential: - description: An access token credential. - type: object - allOf: - - $ref: "#/components/schemas/SinkCredential" - - type: object - properties: - credentialType: - description: MUST be `ACCESSTOKEN` for this concrete credential schema. - type: string - enum: - - ACCESSTOKEN - example: ACCESSTOKEN - accessToken: - description: REQUIRED. An access token is a previously acquired token granting access to the target resource. - type: string - accessTokenExpiresUtc: - type: string - format: date-time - description: > - REQUIRED. An absolute UTC instant at which the token shall be considered expired. - It must follow RFC 3339 and must have time zone. - Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ. - accessTokenType: - description: REQUIRED. Type of the access token (See [OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-7.1)). - type: string - enum: - - bearer - required: - - credentialType - - accessToken - - accessTokenExpiresUtc - - accessTokenType + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/AccessTokenCredential" RecordingResource: description: Recording file for a Click to Dial call @@ -403,6 +355,8 @@ components: $ref: '#/components/schemas/callId' content: type: string + format: byte + maxLength: 20971520 description: Base64 encoded audio content. contentType: type: string @@ -413,33 +367,32 @@ components: - audio/mpeg - audio/ogg generatedAt: - type: string - format: date-time - description: > - Timestamp when the recording was generated. - It must follow RFC 3339 and must have time zone. - Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ. + $ref: '../common/CAMARA_common.yaml#/components/schemas/DateTime' required: - callId - content - contentType EventCTDStatusChanged: - description: Common attributes of Click to Dial + description: ClickToDial call status changed event allOf: - - $ref: "#/components/schemas/CloudEvent" + - $ref: "../common/CAMARA_event_common.yaml#/components/schemas/CloudEvent" - type: object properties: + type: + type: string + enum: + - "org.camaraproject.click-to-dial.v0.status-changed" data: type: object description: Event details depending on the event type properties: callId: - $ref: '#/components/schemas/callId' + $ref: "#/components/schemas/callId" caller: - $ref: '#/components/schemas/PhoneNumber' + $ref: "#/components/schemas/PhoneNumber" callee: - $ref: '#/components/schemas/PhoneNumber' + $ref: "#/components/schemas/PhoneNumber" status: type: object description: | @@ -447,17 +400,17 @@ components: and `reason` contains an optional disconnection reason when applicable. properties: state: - $ref: '#/components/schemas/status' + $ref: "#/components/schemas/status" reason: - $ref: '#/components/schemas/reason' + $ref: "#/components/schemas/reason" required: - state recordingResult: - $ref: '#/components/schemas/recordingResult' + $ref: "#/components/schemas/recordingResult" callDuration: - $ref: '#/components/schemas/callDuration' + $ref: "#/components/schemas/callDuration" timestamp: - $ref: '#/components/schemas/timestamp' + $ref: "../common/CAMARA_common.yaml#/components/schemas/DateTime" required: - callId - caller @@ -465,6 +418,7 @@ components: - status - timestamp required: + - type - data status: @@ -506,87 +460,15 @@ components: callDuration: description: This field indicates the duration of the calls, in seconds. This field is mandatory when status is 'disconnected'. type: string + maxLength: 256 + pattern: '^[0-9]+$' example: '1600' - timestamp: - description: > - Time stamp, UTC time. - It must follow RFC 3339 and must have time zone. - Recommended format is yyyy-MM-dd'T'HH:mm:ss.SSSZ. - type: string - format: date-time - example: '2017-12-04T18:07:57Z' - ErrorInfo: - description: Common schema for errors - type: object - properties: - status: - type: integer - description: HTTP status code returned along with this error response - code: - type: string - description: Code given to this error - message: - type: string - description: Detailed error description - required: - - status - - code - - message + $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" CloudEvent: - description: | - Event compliant with the CloudEvents specification. - Note: Providers MUST deliver events using CloudEvents structured mode - (HTTP header `Content-Type: application/cloudevents+json`). - type: object - properties: - id: - description: Identifier of this event, unique within the event `source` context. UUID is recommended. - type: string - format: uuid - example: 83a0d986-0866-4f38-b8c0-fc65bfcda452 - source: - description: | - Identifies the context in which an event happened in the Provider implementation. - It SHOULD be an absolute URI identifying the producer (for example the API root or producer instance). - type: string - format: uri-reference - example: https://api.example.com/click-to-dial - type: - description: The type of the event. Use a vendor namespaced event type. - type: string - enum: - - "org.camaraproject.click-to-dial.v0.status-changed" - specversion: - description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) - type: string - enum: - - "1.0" - datacontenttype: - description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' - type: string - enum: - - "application/json" - data: - description: Event notification details payload, which depends on the event type - type: object - time: - description: | - Timestamp of when the occurrence happened. It must follow RFC 3339 - type: string - format: date-time - discriminator: - propertyName: 'type' - mapping: - org.camaraproject.click-to-dial.v0.status-changed: "#/components/schemas/EventCTDStatusChanged" - required: - - id - - source - - specversion - - type - - time + $ref: "../common/CAMARA_event_common.yaml#/components/schemas/CloudEvent" responses: Generic400: @@ -597,7 +479,17 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE examples: GENERIC_400_INVALID_ARGUMENT: description: Invalid Argument. Generic Syntax Exception @@ -620,14 +512,23 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED examples: GENERIC_401_UNAUTHENTICATED: description: Request cannot be authenticated. value: status: 401 code: UNAUTHENTICATED - message: Request not authenticated due to missing, invalid, or expired credentials. + message: Request not authenticated due to missing, invalid, or expired credentials. A new authentication is required. Generic403: description: Forbidden @@ -637,7 +538,17 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - INVALID_TOKEN_CONTEXT examples: GENERIC_403_PERMISSION_DENIED: description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security @@ -650,7 +561,7 @@ components: value: status: 403 code: INVALID_TOKEN_CONTEXT - message: "{{field}} is not consistent with access token." + message: "Request body is not consistent with access token." Generic404: description: Not found @@ -660,7 +571,17 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND examples: GENERIC_404_NOT_FOUND: description: Resource is not found @@ -677,7 +598,24 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - INVALID_PHONE_NUMBER + - SAME_CALLER_CALLEE + - RECORDING_NOT_SUPPORTED + - CALLER_NOT_AVAILABLE + - CALLEE_NOT_AVAILABLE examples: INVALID_PHONE_NUMBER: value: @@ -714,12 +652,21 @@ components: content: application/json: schema: - $ref: "#/components/schemas/ErrorInfo" + allOf: + - $ref: "../common/CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 409 + code: + enum: + - ALREADY_EXISTS examples: - CALL_ALREADY_ACTIVE: + ALREADY_EXISTS: value: status: 409 - code: CALL_ALREADY_ACTIVE + code: ALREADY_EXISTS message: An active call already exists for the given caller and callee. examples: diff --git a/code/common/.sync-manifest.yaml b/code/common/.sync-manifest.yaml new file mode 100644 index 0000000..fbce3ef --- /dev/null +++ b/code/common/.sync-manifest.yaml @@ -0,0 +1,6 @@ +sources: +- repository: Commonalities + release: r4.2 + files: + CAMARA_common.yaml: f5122885eab0d3bc7424cf26e2087d4d02c9b96d + CAMARA_event_common.yaml: 9d74ec530af38045dc3d02772407a1d2d4f2f746 diff --git a/code/common/CAMARA_common.yaml b/code/common/CAMARA_common.yaml new file mode 100644 index 0000000..f512288 --- /dev/null +++ b/code/common/CAMARA_common.yaml @@ -0,0 +1,931 @@ +info: + title: CAMARA common data types + description: | + Common data types for CAMARA APIs. + This file contains Commonalities-owned schemas that are identical across all + CAMARA APIs, including error responses, common parameters, headers, and + reusable data types. + + API repositories place this file in `code/common/` and reference schemas + via `$ref: "../common/CAMARA_common.yaml#/components/schemas/"`. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + x-camara-commonalities: 0.8.0-rc.2 + +components: + securitySchemes: + openId: + type: openIdConnect + openIdConnectUrl: https://example.com/.well-known/openid-configuration + description: OpenID Connect authentication via discovery metadata. + + headers: + x-correlator: + description: Correlation id for the different services + schema: + $ref: "#/components/schemas/XCorrelator" + + x-total-count: + description: Total number of items. Mirrors `pagination.totalCount` in the response body. + required: false + schema: + $ref: "#/components/schemas/TotalCount" + + x-total-pages: + description: Total number of pages. Mirrors `pagination.totalPages` in the response body. + required: false + schema: + $ref: "#/components/schemas/TotalPages" + + link: + description: | + Navigation links for paginated results following + [RFC 8288](https://www.rfc-editor.org/rfc/rfc8288). + Includes only the rels applicable to the current position + (`first`, `prev`, `next`, `last`). All original query parameters + are preserved in Link URLs. + Example: + Link: ; rel="first", + ; rel="prev", + ; rel="next", + ; rel="last" + required: false + schema: + type: string + maxLength: 8192 + + parameters: + x-correlator: + name: x-correlator + in: header + description: Correlation id for the different services + schema: + $ref: "#/components/schemas/XCorrelator" + + page: + name: page + in: query + description: > + Requested page number. Pages are 1-indexed. + Values below 1 are rejected with `400 INVALID_ARGUMENT`. + required: false + schema: + $ref: "#/components/schemas/Page" + + perPage: + name: perPage + in: query + description: > + Number of subscriptions to return per page. + Values outside the allowed range are rejected with `400 INVALID_ARGUMENT`. + required: false + schema: + $ref: "#/components/schemas/PerPage" + + schemas: + XCorrelator: + type: string + description: Correlator string, UUID format recommended but any string matching the pattern can be used + pattern: ^[a-zA-Z0-9-_:;.\/<>{}]{0,256}$ + maxLength: 256 + example: "b4333c46-49c0-4f62-80d7-f0ef930f1c46" + DateTime: + type: string + format: date-time + maxLength: 64 + description: Timestamp. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. + example: "2018-04-05T17:31:00Z" + TimePeriod: + type: object + description: A period of time defined by a start date and an optional end date. If `endDate` is not included, then the period has no ending date. + properties: + startDate: + $ref: "#/components/schemas/DateTime" + endDate: + $ref: "#/components/schemas/DateTime" + required: + - startDate + ErrorInfo: + type: object + description: A structured error response providing details about a failed request, including the HTTP status code, an error code, and a human-readable message + required: + - status + - code + - message + properties: + status: + type: integer + format: int32 + minimum: 100 + maximum: 599 + description: HTTP response status code + code: + type: string + maxLength: 96 + description: A human-readable code to describe the error + message: + type: string + maxLength: 512 + description: A human-readable description of what the event represents + Device: + description: | + End-user equipment able to connect to a mobile network. Examples of devices include smartphones or IoT sensors/actuators. + The developer can choose to provide the below specified device identifiers: + * `ipv4Address` + * `ipv6Address` + * `phoneNumber` + * `networkAccessIdentifier` + NOTE1: the network operator might support only a subset of these options. The API Consumer can provide multiple identifiers to ensure compatibility across different network operators. In this case, the API Provider will use one of the identifiers for the API logic without performing any matching checks among the provided identifiers. + NOTE2: as for this Commonalities release, we are enforcing that the networkAccessIdentifier is only part of the schema for future-proofing, and CAMARA does not currently allow its use. After the CAMARA meta-release work is concluded and the relevant issues are resolved, its use will need to be explicitly documented in the guidelines. + type: object + properties: + phoneNumber: + $ref: "#/components/schemas/PhoneNumber" + networkAccessIdentifier: + $ref: "#/components/schemas/NetworkAccessIdentifier" + ipv4Address: + $ref: "#/components/schemas/DeviceIpv4Address" + ipv6Address: + $ref: "#/components/schemas/DeviceIpv6Address" + minProperties: 1 + + DeviceResponse: + description: | + An identifier for the end-user equipment able to connect to the network that the response refers to. This parameter is only returned when the API consumer includes the `device` parameter in their request (i.e. they are using a two-legged access token), and is relevant when more than one device identifier is specified, as only one of those device identifiers is allowed in the response. + + If the API consumer provides more than one device identifier in their request, and this schema is included in the response definition, the API provider MUST use it to return a single identifier which is the one they are using to fulfil the request, even if the identifiers do not match the same device. API provider does not perform any logic to validate/correlate that the indicated device identifiers match the same device. No error should be returned if the identifiers are otherwise valid to prevent API consumers correlating different identifiers with a given end user. + + allOf: + - $ref: "#/components/schemas/Device" + - maxProperties: 1 + + PhoneNumber: + description: A public identifier addressing a telephone subscription. In mobile networks it corresponds to the MSISDN (Mobile Station International Subscriber Directory Number). In order to be globally unique it has to be formatted in international format, according to E.164 standard, prefixed with '+'. + type: string + pattern: '^\+[1-9][0-9]{4,14}$' + maxLength: 16 + example: "+123456789" + + NetworkAccessIdentifier: + description: A public identifier addressing a subscription in a mobile network. In 3GPP terminology, it corresponds to the GPSI formatted with the External Identifier ({Local Identifier}@{Domain Identifier}). Unlike the telephone number, the network access identifier is not subjected to portability ruling in force, and is individually managed by each operator. + type: string + maxLength: 2048 + example: "123456789@example.com" + + DeviceIpv4Address: + type: object + description: | + The device should be identified by either the public (observed) IP address and port as seen by the application server, or the private (local) and any public (observed) IP addresses in use by the device (this information can be obtained by various means, for example from some DNS servers). + + If the allocated and observed IP addresses are the same (i.e. NAT is not in use) then the same address should be specified for both publicAddress and privateAddress. + + If NAT64 is in use, the device should be identified by its publicAddress and publicPort, or separately by its allocated IPv6 address (field ipv6Address of the Device object) + + In all cases, publicAddress must be specified, along with at least one of either privateAddress or publicPort, dependent upon which is known. In general, mobile devices cannot be identified by their public IPv4 address alone. + properties: + publicAddress: + $ref: "#/components/schemas/SingleIpv4Address" + privateAddress: + $ref: "#/components/schemas/SingleIpv4Address" + publicPort: + $ref: "#/components/schemas/Port" + anyOf: + - required: [publicAddress, privateAddress] + - required: [publicAddress, publicPort] + example: + publicAddress: "84.125.93.10" + publicPort: 59765 + + SingleIpv4Address: + description: A single IPv4 address with no subnet mask + type: string + format: ipv4 + maxLength: 15 + example: "84.125.93.10" + + Port: + description: TCP or UDP port number + type: integer + format: int32 + minimum: 1 + maximum: 65535 + + DeviceIpv6Address: + description: | + The device should be identified by the observed IPv6 address, or by any single IPv6 address from within the subnet allocated to the device (e.g. adding ::0 to the /64 prefix). + type: string + format: ipv6 + maxLength: 45 + example: 2001:db8:85a3:8d3:1319:8a2e:370:7344 + + Area: + description: Base schema for all areas + type: object + properties: + areaType: + $ref: "#/components/schemas/AreaType" + required: + - areaType + discriminator: + propertyName: areaType + mapping: + CIRCLE: "#/components/schemas/Circle" + POLYGON: "#/components/schemas/Polygon" + + AreaType: + type: string + description: | + Type of this area. + CIRCLE - The area is defined as a circle. + POLYGON - The area is defined as a polygon. + enum: + - CIRCLE + - POLYGON + + Circle: + description: Circular area + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - center + - radius + properties: + center: + $ref: "#/components/schemas/Point" + radius: + type: number + description: Distance from the center in meters + minimum: 1 + + Polygon: + description: Polygonal area. The Polygon should be a simple polygon, i.e. should not intersect itself. + allOf: + - $ref: "#/components/schemas/Area" + - type: object + required: + - boundary + properties: + boundary: + $ref: "#/components/schemas/PointList" + + PointList: + description: List of points defining a polygon + type: array + items: + $ref: "#/components/schemas/Point" + minItems: 3 + maxItems: 15 + + Point: + type: object + description: Coordinates (latitude, longitude) defining a location in a map + required: + - latitude + - longitude + properties: + latitude: + $ref: "#/components/schemas/Latitude" + longitude: + $ref: "#/components/schemas/Longitude" + example: + latitude: 50.735851 + longitude: 7.10066 + + Latitude: + description: Latitude component of a location + type: number + format: double + minimum: -90 + maximum: 90 + + Longitude: + description: Longitude component of location + type: number + format: double + minimum: -180 + maximum: 180 + + # ───────────────────────────────────────────────────────────────────────── + # Pagination + # ───────────────────────────────────────────────────────────────────────── + + Pagination: + description: Pagination details helping to navigate through paged results efficiently. + type: object + properties: + page: + $ref: "#/components/schemas/Page" + perPage: + $ref: "#/components/schemas/PerPage" + totalCount: + $ref: "#/components/schemas/TotalCount" + totalPages: + $ref: "#/components/schemas/TotalPages" + + Page: + type: integer + format: int32 + minimum: 1 + maximum: 2147483647 + default: 1 + description: Current page number (1-indexed). + example: 1 + PerPage: + type: integer + format: int32 + minimum: 1 + maximum: 100 + default: 20 + description: Number of items per page. + example: 20 + TotalCount: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Total number of items matching the query, after filters applied. MAY be omitted where a full count query is prohibitively expensive. + example: 87 + TotalPages: + type: integer + format: int32 + minimum: 0 + maximum: 2147483647 + description: Total number of pages. Equals ceil(totalCount / perPage). MAY be omitted where totalCount is omitted. + example: 5 + responses: + ####################################################### + ####################################################### + # ERROR RESPONSE SCHEMA TEMPLATE + # - Objective: Make normative error `status` and `code` values + # - Schema Template rationale: + # - The `allOf` in content.application/json.schema allows a combination of both the generic ErrorInfo schema and the specific schema for this error response, + # which validates that `status` and `code` have only the specified values. + # This `allOf` is used without discriminator because it does not imply any hierarchy between the models, just 2 schemas that must be independently validated. + ####################################################### + # ErrorResponseSchema: + # ... + # content: + # application/json: + # schema: + # allOf: + # - $ref: '#/components/schemas/ErrorInfo' + # - type: object + # properties: + # status: + # enum: + # - + # code: + # enum: + # - + # - + # examples: + # ExampleKey1: + # value: + # status: + # code: + # message: + # ExampleKey2: + # value: + # status: + # code: + # message: + ####################################################### + ####################################################### + Generic400: + description: Bad Request + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + # - "{{SPECIFIC_CODE}}" - API-specific codes added if needed + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + # GENERIC_400_{{SPECIFIC_CODE}}: + # description: Specific Syntax Exception regarding a field that is relevant in the context of the API + # value: + # status: 400 + # code: "{{SPECIFIC_CODE}}" + # message: Message for specific code + Generic401: + description: Unauthorized + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 401 + code: + enum: + - UNAUTHENTICATED + examples: + GENERIC_401_UNAUTHENTICATED: + description: Request cannot be authenticated and a new authentication is required + value: + status: 401 + code: UNAUTHENTICATED + message: Request not authenticated due to missing, invalid, or expired credentials. A new authentication is required. + Generic403: + description: Forbidden + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - INVALID_TOKEN_CONTEXT + # - "{{SPECIFIC_CODE}}" - API-specific codes added if needed + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + GENERIC_403_INVALID_TOKEN_CONTEXT: + description: Reflect some inconsistency between information in some field of the API and the related OAuth2 Token + value: + status: 403 + code: INVALID_TOKEN_CONTEXT + # message: "{{field}} is not consistent with access token." + message: "Request body is not consistent with access token." + # GENERIC_403_{{SPECIFIC_CODE}}: + # description: Indicate a Business Logic condition that forbids a process not attached to a specific field in the context of the API + # value: + # status: 403 + # code: "{{SPECIFIC_CODE}}" + # message: Message for specific code + Generic404: + description: Not found + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 404 + code: + enum: + - NOT_FOUND + - IDENTIFIER_NOT_FOUND + # - "{{SPECIFIC_CODE}}" - API-specific codes added if needed + examples: + GENERIC_404_NOT_FOUND: + description: Resource is not found + value: + status: 404 + code: NOT_FOUND + message: The specified resource is not found. + GENERIC_404_IDENTIFIER_NOT_FOUND: + description: Some identifier cannot be matched to a device + value: + status: 404 + code: IDENTIFIER_NOT_FOUND + message: Device identifier not found. + # GENERIC_404_{{SPECIFIC_CODE}}: + # description: Specific situation to highlight the resource/concept not found + # value: + # status: 404 + # code: "{{SPECIFIC_CODE}}" + # message: Message for specific code + Generic405: + description: Method Not Allowed + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 405 + code: + enum: + - METHOD_NOT_ALLOWED + examples: + GENERIC_405_METHOD_NOT_ALLOWED: + description: Invalid HTTP verb used with a given endpoint + value: + status: 405 + code: METHOD_NOT_ALLOWED + message: The requested method is not allowed/supported on the target resource. + Generic406: + description: Not Acceptable + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 406 + code: + enum: + - NOT_ACCEPTABLE + examples: + GENERIC_406_NOT_ACCEPTABLE: + description: API Server does not accept the media type (`Accept-*` header) indicated by API client + value: + status: 406 + code: NOT_ACCEPTABLE + message: The server cannot produce a response matching the content requested by the client through `Accept-*` headers. + Generic409: + description: Conflict + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 409 + code: + enum: + - ABORTED + - ALREADY_EXISTS + - CONFLICT + - INCOMPATIBLE_STATE + # - "{{SPECIFIC_CODE}}" - API-specific codes added if needed + examples: + GENERIC_409_ABORTED: + description: The resource is undergoing modification by another process + value: + status: 409 + code: ABORTED + message: Resource is being modified by another operation. Please wait, and retry if appropriate. + GENERIC_409_ALREADY_EXISTS: + description: Trying to create an existing resource + value: + status: 409 + code: ALREADY_EXISTS + message: The resource that a client tried to create already exists. + GENERIC_409_CONFLICT: + ################################### + # This Error Code is DEPRECATED + ################################### + description: Duplication of an existing resource + value: + status: 409 + code: CONFLICT + message: A specified resource duplicate entry found. + GENERIC_409_INCOMPATIBLE_STATE: + description: | + The status of the referenced resource is not compatible. + value: + status: 409 + code: INCOMPATIBLE_STATE + message: Resource must be in AVAILABLE state to extend. Current state is UNAVAILABLE. + # GENERIC_409_{{SPECIFIC_CODE}}: + # description: Specific conflict situation that is relevant in the context of the API + # value: + # status: 409 + # code: "{{SPECIFIC_CODE}}" + # message: Message for specific code + Generic410: + description: Gone + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 410 + code: + enum: + - GONE + examples: + GENERIC_410_GONE: + description: Use in notifications flow to allow API Consumer to indicate that its callback is no longer available + value: + status: 410 + code: GONE + message: Access to the target resource is no longer available. + Generic412: + description: Failed precondition + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 412 + code: + enum: + - FAILED_PRECONDITION + examples: + GENERIC_412_FAILED_PRECONDITION: + description: Indication by the API Server that the request cannot be processed in current system state + value: + status: 412 + code: FAILED_PRECONDITION + message: Request cannot be executed in the current system state. + Generic415: + description: Unsupported Media Type + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 415 + code: + enum: + - UNSUPPORTED_MEDIA_TYPE + examples: + GENERIC_415_UNSUPPORTED_MEDIA_TYPE: + description: Payload format of the request is in an unsupported format by the Server. Should not happen + value: + status: 415 + code: UNSUPPORTED_MEDIA_TYPE + message: The server refuses to accept the request because the payload format is in an unsupported format. + Generic422: + description: Unprocessable Content + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + # - "{{SPECIFIC_CODE}}" - API-specific codes added if needed + examples: + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + # GENERIC_422_{{SPECIFIC_CODE}}: + # description: Any semantic condition associated to business logic, specifically related to a field or data structure + # value: + # status: 422 + # code: "{{SPECIFIC_CODE}}" + # message: Message for specific code + Generic429: + description: Too Many Requests + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 429 + code: + enum: + - QUOTA_EXCEEDED + - TOO_MANY_REQUESTS + examples: + GENERIC_429_QUOTA_EXCEEDED: + description: Request is rejected due to exceeding a business quota limit + value: + status: 429 + code: QUOTA_EXCEEDED + message: Out of resource quota. + GENERIC_429_TOO_MANY_REQUESTS: + description: Access to the API has been temporarily blocked due to rate or spike arrest limits being reached + value: + status: 429 + code: TOO_MANY_REQUESTS + message: Rate limit reached. + Generic500: + description: Internal Server Error + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 500 + code: + enum: + - INTERNAL + examples: + GENERIC_500_INTERNAL: + description: Problem in Server side. Regular Server Exception + value: + status: 500 + code: INTERNAL + message: Unknown server error. Typically a server bug. + Generic501: + description: Not Implemented + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 501 + code: + enum: + - NOT_IMPLEMENTED + examples: + GENERIC_501_NOT_IMPLEMENTED: + description: Service not implemented. The use of this code should be avoided as far as possible to get the objective to reach aligned implementations + value: + status: 501 + code: NOT_IMPLEMENTED + message: This functionality is not implemented yet. + Generic502: + description: Bad Gateway + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 502 + code: + enum: + - BAD_GATEWAY + examples: + GENERIC_502_BAD_GATEWAY: + description: Internal routing problem in the Server side that blocks to manage the service properly + value: + status: 502 + code: BAD_GATEWAY + message: An upstream internal service cannot be reached. + Generic503: + description: Service Unavailable + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 503 + code: + enum: + - UNAVAILABLE + examples: + GENERIC_503_UNAVAILABLE: + description: Service is not available. Temporary situation usually related to maintenance process in the server side + value: + status: 503 + code: UNAVAILABLE + message: Service Unavailable. + Generic504: + description: Gateway Timeout + headers: + x-correlator: + $ref: "#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 504 + code: + enum: + - TIMEOUT + examples: + GENERIC_504_TIMEOUT: + description: API Server Timeout + value: + status: 504 + code: TIMEOUT + message: Request timeout exceeded. diff --git a/code/common/CAMARA_event_common.yaml b/code/common/CAMARA_event_common.yaml new file mode 100644 index 0000000..9d74ec5 --- /dev/null +++ b/code/common/CAMARA_event_common.yaml @@ -0,0 +1,627 @@ +info: + title: CAMARA common event and subscription data types + description: | + Common data types for CAMARA event notification and subscription management. + This file contains Commonalities-owned schemas that are identical across all + CAMARA APIs supporting event notifications and/or explicit subscriptions. + + API repositories place this file in `code/common/` alongside `CAMARA_common.yaml` + and reference schemas via `$ref: "../common/CAMARA_event_common.yaml#/components/schemas/"`. + license: + name: Apache 2.0 + url: https://www.apache.org/licenses/LICENSE-2.0.html + version: wip + x-camara-commonalities: 0.8.0-rc.2 + +components: + securitySchemes: + notificationsBearerAuth: + type: http + scheme: bearer + bearerFormat: "{$request.body#/sinkCredential.credentialType}" + description: | + Bearer token for notification delivery. Token format is determined + by `sinkCredential.credentialType` in the subscription request. + + schemas: + + # ───────────────────────────────────────────────────────────────────────── + # Section 1: CloudEvents 1.0 envelope + # + # Pure CloudEvents 1.0 specification envelope. Knows nothing about CAMARA + # event types, data payloads, or discriminator mappings. Any CAMARA API + # that needs to send a notification starts here. + # ───────────────────────────────────────────────────────────────────────── + + CloudEvent: + type: object + description: | + CloudEvents 1.0 specification envelope. + This schema is the stable base for all CAMARA event notifications. + It imposes no constraints on `type` values or `data` structure — + those concerns belong to the API-specific and lifecycle group schemas. + required: + - id + - source + - specversion + - type + - time + properties: + id: + type: string + maxLength: 256 + description: Identifier of this event, unique within the source context. + source: + $ref: "#/components/schemas/Source" + type: + type: string + maxLength: 512 + description: | + Identifies the event type. CAMARA APIs use reverse-DNS notation: + `org.camaraproject...` + The api-name segment makes each type globally unique across API groups. + specversion: + type: string + description: Version of the specification to which this event conforms (must be 1.0 if it conforms to cloudevents 1.0.2 version) + enum: + - "1.0" + datacontenttype: + type: string + description: 'media-type that describes the event payload encoding, must be "application/json" for CAMARA APIs' + enum: + - application/json + data: + type: object + description: Event details payload. Structure is defined by each concrete event schema. + time: + $ref: "CAMARA_common.yaml#/components/schemas/DateTime" + + Source: + type: string + format: uri-reference + minLength: 1 + maxLength: 2048 + description: | + Identifies the context in which an event happened - be a non-empty `URI-reference` like: + - URI with a DNS authority: + * https://github.com/cloudevents + * mailto:cncf-wg-serverless@lists.cncf.io + - Universally-unique URN with a UUID: + * urn:uuid:6e8bc430-9c3a-11d9-9669-0800200c9a66 + - Application-specific identifier: + * /cloudevents/spec/pull/123 + * 1-555-123-4567 + example: "https://notificationSendServer12.example.com" + + # ───────────────────────────────────────────────────────────────────────── + # Section 2: Subscription management + # + # Configuration and identification schemas used by the subscription + # management endpoints. These are Commonalities-owned and identical + # across all CAMARA APIs that support explicit subscriptions. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionId: + type: string + maxLength: 256 + description: The unique identifier of the subscription in the scope of the subscription manager. When this information is contained within an event notification, it SHALL be referred to as `subscriptionId` as per the Commonalities Event Notification Model. + example: qs15-h556-rt89-1298 + + Config: + description: | + Implementation-specific configuration parameters needed by the subscription manager for acquiring events. + In CAMARA we have predefined attributes like `subscriptionExpireTime`, `subscriptionMaxEvents`, `initialEvent` + Specific event type attributes must be defined in `subscriptionDetail`. + Note: if a request is performed for several event types, all subscribed events will use same `config` parameters. + type: object + required: + - subscriptionDetail + properties: + subscriptionDetail: + $ref: "#/components/schemas/CreateSubscriptionDetail" + subscriptionExpireTime: + type: string + format: date-time + maxLength: 64 + example: 2023-01-17T13:18:23.682Z + description: The subscription expiration time (in date-time format) requested by the API consumer. It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. Up to API project decision to keep it. + subscriptionMaxEvents: + type: integer + format: int32 + description: Identifies the maximum number of event reports to be generated (>=1) requested by the API consumer - Once this number is reached, the subscription ends. Up to API project decision to keep it. + minimum: 1 + maximum: 1000000 + example: 5 + initialEvent: + type: boolean + description: | + Set to `true` by API consumer if consumer wants to get an event as soon as the subscription is created and current situation reflects event request. + Example: Consumer request Roaming event. If consumer sets initialEvent to true and device is in roaming situation, an event is triggered + Up to API project decision to keep it. + + CreateSubscriptionDetail: + description: The detail of the requested event subscription. + type: object + + # ───────────────────────────────────────────────────────────────────────── + # Section 3: Protocol support + # + # Protocol selection and protocol-specific delivery settings. + # These are Commonalities-owned and identical across all CAMARA APIs. + # ───────────────────────────────────────────────────────────────────────── + + Protocol: + type: string + enum: + - HTTP + # Future protocol support (not yet used in CAMARA): + # - MQTT3 + # - MQTT5 + # - AMQP + # - NATS + # - KAFKA + description: Identifier of a delivery protocol. Only HTTP is allowed for now + example: "HTTP" + + HTTPSettings: + type: object + description: HTTP protocol settings for event delivery. + properties: + headers: + type: object + description: |- + A set of key/value pairs that is copied into the HTTP request as custom headers. + + NOTE: Use/Applicability of this concept has not been discussed in Commonalities. When required by an API project as an option to meet a UC/Requirement, please generate an issue for Commonalities discussion about it. + additionalProperties: + type: string + maxLength: 512 + method: + type: string + description: The HTTP method to use for sending the message. + enum: + - POST + + # Future protocol support (not yet used in CAMARA): + # MQTTSettings: + # type: object + # properties: + # topicName: + # type: string + # maxLength: 256 + # description: MQTT topic name + # qos: + # type: integer + # format: int32 + # minimum: 0 + # maximum: 2 + # description: Quality of Service level (0, 1, or 2) + # retain: + # type: boolean + # expiry: + # type: integer + # format: int32 + # minimum: 0 + # maximum: 2147483647 + # description: Message expiry interval in seconds + # userProperties: + # type: object + # required: + # - topicName + + # AMQPSettings: + # type: object + # properties: + # address: + # type: string + # maxLength: 512 + # linkName: + # type: string + # maxLength: 256 + # senderSettlementMode: + # type: string + # enum: ["settled", "unsettled"] + # linkProperties: + # type: object + # additionalProperties: + # type: string + # maxLength: 1024 + + # ApacheKafkaSettings: + # type: object + # properties: + # topicName: + # type: string + # maxLength: 249 + # partitionKeyExtractor: + # type: string + # maxLength: 512 + # clientId: + # type: string + # maxLength: 256 + # ackMode: + # type: integer + # format: int32 + # minimum: 0 + # maximum: 2 + # description: Acknowledgment mode (0=no ack, 1=leader ack, 2=all replicas ack) + # required: + # - topicName + + # NATSSettings: + # type: object + # properties: + # subject: + # type: string + # maxLength: 256 + # description: NATS subject + # required: + # - subject + + # ───────────────────────────────────────────────────────────────────────── + # Section 4: Sink credentials + # + # Authentication and authorization information for event delivery. + # These are Commonalities-owned and identical across all CAMARA APIs. + # ───────────────────────────────────────────────────────────────────────── + + SinkCredential: + description: A sink credential provides authentication or authorization information necessary to enable delivery of events to a target. + type: object + properties: + credentialType: + type: string + enum: + # - PLAIN # not used in CAMARA + - ACCESSTOKEN + - PRIVATE_KEY_JWT + description: | + The type of the credential - MUST be set to ACCESSTOKEN or PRIVATE_KEY_JWT for now + discriminator: + propertyName: credentialType + mapping: + # PLAIN: "#/components/schemas/PlainCredential" # not used in CAMARA + ACCESSTOKEN: "#/components/schemas/AccessTokenCredential" + PRIVATE_KEY_JWT: "#/components/schemas/PrivateKeyJWTCredential" + required: + - credentialType + + # PlainCredential: # not used in CAMARA + # type: object + # description: A plain credential as a combination of an identifier and a secret. + # allOf: + # - $ref: "#/components/schemas/SinkCredential" + # - type: object + # required: + # - identifier + # - secret + # properties: + # identifier: + # description: The identifier might be an account or username. + # type: string + # maxLength: 256 + # secret: + # description: The secret might be a password or passphrase. + # type: string + # maxLength: 512 + + AccessTokenCredential: + type: object + description: An access token credential. This type of credential is meant to be used by API Consumers that have limited capabilities to handle authorization requests. + allOf: + - $ref: "#/components/schemas/SinkCredential" + - type: object + properties: + accessToken: + description: REQUIRED. An access token is a token granting access to the target resource. + type: string + maxLength: 4096 + accessTokenExpiresUtc: + type: string + format: date-time + maxLength: 64 + description: | + REQUIRED. An absolute (UTC) timestamp at which the token shall be considered expired. + In the case of an ACCESS_TOKEN_EXPIRED termination reason, implementation should notify the client before the expiration date. + If the access token is a JWT and registered "exp" (Expiration Time) claim is present, the two expiry times should match. + It must follow [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339#section-5.6) and must have time zone. + example: "2023-07-03T12:27:08.312Z" + accessTokenType: + description: REQUIRED. Type of the access token (See [OAuth 2.0](https://tools.ietf.org/html/rfc6749#section-7.1)). + type: string + enum: + - bearer + required: + - accessToken + - accessTokenExpiresUtc + - accessTokenType + + PrivateKeyJWTCredential: + type: object + description: Use PRIVATE_KEY_JWT to get an access token. The authorization server information needed for this type of sink credential (token endpoint, client ID, JWKS URL) is shared upfront between the client and the CAMARA entity. This type of credential is to be used by clients that have an authorization server. + allOf: + - $ref: "#/components/schemas/SinkCredential" + + # ───────────────────────────────────────────────────────────────────────── + # Section 5: Subscription lifecycle data + # + # Data payload schemas for subscription lifecycle events. These define the + # `data` content of subscription-started, subscription-updated, and + # subscription-ended events. The lifecycle event wrappers (which contain + # api-name placeholders in their event type strings) stay in API templates. + # ───────────────────────────────────────────────────────────────────────── + + SubscriptionStarted: + description: Event detail structure for subscription started event + type: object + required: + - initiationReason + - subscriptionId + properties: + initiationReason: + $ref: "#/components/schemas/InitiationReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + initiationDescription: + type: string + maxLength: 512 + description: Description of subscription initiation + + InitiationReason: + type: string + description: | + - SUBSCRIPTION_CREATED - Subscription created by API Server + enum: + - SUBSCRIPTION_CREATED + + SubscriptionUpdated: + description: Event detail structure for subscription updated event + type: object + required: + - updateReason + - subscriptionId + properties: + updateReason: + $ref: "#/components/schemas/UpdateReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + updateDescription: + type: string + maxLength: 512 + description: Description of subscription update + + UpdateReason: + type: string + description: | + - SUBSCRIPTION_ACTIVE - API server transitioned subscription status to `ACTIVE` + - SUBSCRIPTION_INACTIVE - API server transitioned subscription status to `INACTIVE` + enum: + - SUBSCRIPTION_ACTIVE + - SUBSCRIPTION_INACTIVE + + SubscriptionEnded: + description: Event detail structure for subscription ended event + type: object + required: + - terminationReason + - subscriptionId + properties: + terminationReason: + $ref: "#/components/schemas/TerminationReason" + subscriptionId: + $ref: "#/components/schemas/SubscriptionId" + terminationDescription: + type: string + maxLength: 512 + description: Description of subscription termination + + TerminationReason: + type: string + description: | + - NETWORK_TERMINATED - API server stopped sending notification + - SUBSCRIPTION_EXPIRED - Subscription expire time (optionally set by the requester) has been reached + - MAX_EVENTS_REACHED - Maximum number of events (optionally set by the requester) has been reached + - ACCESS_TOKEN_EXPIRED - Access Token sinkCredential (optionally set by the requester with credential type `ACCESSTOKEN`) expiration time has been reached + - SUBSCRIPTION_DELETED - Subscription was deleted by the requester + enum: + - MAX_EVENTS_REACHED + - NETWORK_TERMINATED + - SUBSCRIPTION_EXPIRED + - ACCESS_TOKEN_EXPIRED + - SUBSCRIPTION_DELETED + + # ───────────────────────────────────────────────────────────────────────── + # Subscription-specific error responses + # + # These extend generic CAMARA error codes with subscription-specific codes. + # Commonalities-owned and identical across all APIs using explicit subscriptions. + # ───────────────────────────────────────────────────────────────────────── + + responses: + CreateSubscriptionBadRequest400: + description: Problem with the client request + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + - OUT_OF_RANGE + - INVALID_PROTOCOL + - INVALID_CREDENTIAL + - INVALID_TOKEN + - INVALID_SINK + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_OUT_OF_RANGE: + description: Out of Range. Specific Syntax Exception used when a given field has a pre-defined range or a invalid filter criteria combination is requested + value: + status: 400 + code: OUT_OF_RANGE + message: Client specified an invalid range. + GENERIC_400_INVALID_PROTOCOL: + description: Invalid protocol for events subscription management + value: + status: 400 + code: INVALID_PROTOCOL + message: Only HTTP is supported + GENERIC_400_INVALID_CREDENTIAL: + description: Invalid sink credential type + value: + status: 400 + code: INVALID_CREDENTIAL + message: Only Access token or Private key JWT are supported + GENERIC_400_INVALID_SINK: + description: Invalid sink value + value: + status: 400 + code: INVALID_SINK + message: sink not valid for the specified protocol + + SubscriptionIdRequired400: + description: Problem with the client request + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 400 + code: + enum: + - INVALID_ARGUMENT + examples: + GENERIC_400_INVALID_ARGUMENT: + description: Invalid Argument. Generic Syntax Exception + value: + status: 400 + code: INVALID_ARGUMENT + message: Client specified an invalid argument, request body or query param. + GENERIC_400_SUBSCRIPTION_ID_REQUIRED: + description: subscription id is required + value: + status: 400 + code: INVALID_ARGUMENT + message: "Expected property is missing: subscriptionId" + + SubscriptionPermissionDenied403: + description: Client does not have sufficient permission + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 403 + code: + enum: + - PERMISSION_DENIED + - SUBSCRIPTION_MISMATCH + examples: + GENERIC_403_PERMISSION_DENIED: + description: Permission denied. OAuth2 token access does not have the required scope or when the user fails operational security + value: + status: 403 + code: PERMISSION_DENIED + message: Client does not have sufficient permissions to perform this action. + GENERIC_403_SUBSCRIPTION_MISMATCH: + description: Inconsistent access token for requested subscription + value: + status: 403 + code: "SUBSCRIPTION_MISMATCH" + message: "Inconsistent access token for requested events subscription" + + CreateSubscriptionUnprocessableEntity422: + description: Unprocessable Entity + headers: + x-correlator: + $ref: "CAMARA_common.yaml#/components/headers/x-correlator" + content: + application/json: + schema: + allOf: + - $ref: "CAMARA_common.yaml#/components/schemas/ErrorInfo" + - type: object + properties: + status: + enum: + - 422 + code: + enum: + - SERVICE_NOT_APPLICABLE + - MISSING_IDENTIFIER + - UNSUPPORTED_IDENTIFIER + - UNNECESSARY_IDENTIFIER + - MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED + - MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED + - PRIVATE_KEY_JWT_NOT_CONFIGURED + examples: + GENERIC_422_SERVICE_NOT_APPLICABLE: + description: Service not applicable for the provided identifier + value: + status: 422 + code: SERVICE_NOT_APPLICABLE + message: The service is not available for the provided identifier. + GENERIC_422_MISSING_IDENTIFIER: + description: An identifier is not included in the request and the device or phone number identification cannot be derived from the 3-legged access token + value: + status: 422 + code: MISSING_IDENTIFIER + message: The device cannot be identified. + GENERIC_422_UNSUPPORTED_IDENTIFIER: + description: None of the provided identifiers is supported by the implementation + value: + status: 422 + code: UNSUPPORTED_IDENTIFIER + message: The identifier provided is not supported. + GENERIC_422_UNNECESSARY_IDENTIFIER: + description: An explicit identifier is provided when a device or phone number has already been identified from the access token + value: + status: 422 + code: UNNECESSARY_IDENTIFIER + message: The device is already identified by the access token. + GENERIC_422_MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED: + description: Multi event types subscription is not supported + value: + status: 422 + code: MULTIEVENT_SUBSCRIPTION_NOT_SUPPORTED + message: Multi event types subscription not managed + GENERIC_422_MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED: + description: Combination of multiple event types is temporarily not supported + value: + status: 422 + code: MULTIEVENT_COMBINATION_TEMPORARILY_NOT_SUPPORTED + message: The requested combination of event types is temporarily not supported. + GENERIC_422_PRIVATE_KEY_JWT_NOT_CONFIGURED: + description: Private key JWT sink credential type is used but no configuration was pre-shared + value: + status: 422 + code: PRIVATE_KEY_JWT_NOT_CONFIGURED + message: No JWK Set configured for PRIVATE_KEY_JWT authentication.