diff --git a/content/app/guides/shared/api/altinn-token.md b/content/app/guides/shared/api/altinn-token.md new file mode 100644 index 00000000000..61e08b9350d --- /dev/null +++ b/content/app/guides/shared/api/altinn-token.md @@ -0,0 +1,39 @@ +--- +headless: true +hidden: true +--- + + +The {0} API is secured using OAuth2 and all requests must include a valid Altinn token either in the Authorization header or +in the _AltinnStudioRuntime_ cookie. + +For clients within the Altinn eco-system representing an external user or organization, +the Altinn token in an incoming request can be forwarded to the {0} API. + +If you are using the API from an external system you will need to generate a maskinporten or id-porten token +and exchange this for an Altinn token before calling the {0} API. + +Below are two guides on how to achieve this. + +{{% expandlarge id="guide-altinn-token-maskinporten" header="Guide on how to generate an Altinn token with Maskinporten" %}} + + +{{% notice info %}} +We are working on providing you with a guide. +{{% /notice %}} + + +{{% /expandlarge %}} + + +{{% expandlarge id="guide-altinn-token-id-porten" header="Guide on how to generate an Altinn token with id-porten" %}} + +{{% notice info %}} +We are working on providing you with a guide. +{{% /notice %}} + +{{% /expandlarge %}} + diff --git a/content/app/guides/shared/api/base-urls.md b/content/app/guides/shared/api/base-urls.md new file mode 100644 index 00000000000..e20e85ac6c6 --- /dev/null +++ b/content/app/guides/shared/api/base-urls.md @@ -0,0 +1,24 @@ +--- +headless: true +hidden: true +--- + +The following base urls correspond to each environment + +- AT (Private Altinn acceptance test environment) + + ```http + https://platform.{environment}.altinn.cloud/{0}/api/v1 + ``` + +- TT02 (Application owner test environment) + + ```http + https://platform.tt02.altinn.cloud/{0}/api/v1 + ``` + +- Production + + ```http + https://platform.altinn.cloud/{0}/api/v1 + ``` diff --git a/content/app/guides/shared/api/maskinporten-scopes.md b/content/app/guides/shared/api/maskinporten-scopes.md new file mode 100644 index 00000000000..7da87629748 --- /dev/null +++ b/content/app/guides/shared/api/maskinporten-scopes.md @@ -0,0 +1,24 @@ +--- +headless: true +hidden: true +--- + +Some endpoints in the API may require additional authorization in the form of a Maskinporten scope. +A scope represents a permission that a consumer has access to. + +You can connect a given set of scopes to the specific Maskinporten integration instance that +provides your API client with Maskinporten tokens upon request. + +{{% expandlarge id="guide-mp-int-api" header="Guide on how to register a new Maskinporten integration through API" %}} + +Please reference [Maskinporten's own documentation](https://docs.digdir.no/docs/Maskinporten/maskinporten_guide_apikonsument) +on registering a new integration through their self service API. + +{{% /expandlarge %}} + + +{{% expandlarge id="guide-mp-int-samarbeid" header="Guide on how to register a new Maskinporten integration in Samarbeidsportalen" %}} + +{{% insert "content/app/guides/shared/maskinporten-integration/maskinporten-integration-samarbeidsportal.md" %}} +{{% /expandlarge %}} + diff --git a/content/app/guides/shared/api/platform-access-token.md b/content/app/guides/shared/api/platform-access-token.md new file mode 100644 index 00000000000..953091aadac --- /dev/null +++ b/content/app/guides/shared/api/platform-access-token.md @@ -0,0 +1,11 @@ +--- +headless: true +hidden: true +--- + +The access to a subset of endpoints in the API is limited to callers within the Altinn eco-system. +These APIs require additional authorization in the form of a +Platform Access Token. + +Please reference developer documentation for the client system on how to generate +the token. diff --git a/content/events/request-maskinporten-scopes.md b/content/app/guides/shared/api/request-maskinporten-scopes.md similarity index 64% rename from content/events/request-maskinporten-scopes.md rename to content/app/guides/shared/api/request-maskinporten-scopes.md index 24556387d65..7de378e76b1 100644 --- a/content/events/request-maskinporten-scopes.md +++ b/content/app/guides/shared/api/request-maskinporten-scopes.md @@ -1,7 +1,12 @@ -The scope __{0}__ is required when {1}. +--- +headless: true +hidden: true +--- -Currently, access to this scope is limited to the development team and beta testers of generic events. -If you fall under one of these two groups and require access, please contact the development team directly. +The scope **{0}** is required when {1}. -We are working on making requests for access to this scopes available to the public. +Currently, access to this scope is limited to the development team and beta testers. +If you fall under one of these two groups and require access, please contact the development team directly. + +We are working on making requests for access to this scopes available to the public. [The progress of this work can be monitored here](https://github.com/Altinn/altinn-events/issues/319). diff --git a/content/events/api/_index.en.md b/content/events/api/_index.en.md index 7597d8bf4a8..6873213e94f 100644 --- a/content/events/api/_index.en.md +++ b/content/events/api/_index.en.md @@ -1,6 +1,6 @@ --- title: Altinn Events API -linktitle: API +linktitle: API description: An overview of the Altinn Events API weight: 10 toc: true @@ -8,60 +8,25 @@ toc: true The Altinn Events API is an HTTP-based RESTful API that provides endpoints and actions for publishing of events and subscribing to events from Altinn 3 Apps and other registered sources. - ## Base URL -- AT (Private Altinn Acceptance Test environment) - - ```http - https://platform.{environment}.altinn.cloud/events/api/v1 - ``` -- TT02 (Application owner test environment) - - ```http - https://platform.tt02.altinn.no/events/api/v1 - ``` -- Production: - - ```http - https://platform.altinn.no/events/api/v1 - ``` - +{{% insert "content/app/guides/shared/api/base-urls.md" "events"%}} ## Authentication & Authorization -### Altinn token -The Events API is secured using OAuth2 and all requests must include a valid Altinn token either in the Authorization header or -in the _AltinnStudioRuntime_ cookie. - -{{% notice info %}} -TODO: write the guides referenced below.Both with our client libraries and in postman maybe? -{{% /notice %}} +### Altinn token -Here is an overview of guides related to the generation of Altinn token for production and test purposes: -- [Guide on how to generate an Altinn token with Maskinporten]() -- [Guide on how to generate an Altinn token with id-porten]() -- [Guide on how to generate an Altinn token with Altinn test tools]() - +{{% insert "content/app/guides/shared/api/altinn-token.md" "Events"%}} ### Maskinporten scopes -{{% notice info %}} -TODO: find docs to link to or create them. -{{% /notice %}} - -Some endpoints in the API require additional authorization in the form of a -Maskinporten scope. [User documentation on setting up a maskinporten integration with a specific scope -is available here](). - +{{% insert "content/app/guides/shared/api/maskinporten-scopes.md" %}} ### Platform Access token -The use of some endpoints in the API is limited to callers within the Altinn eco-system. -These APIs require additional authorization in the form of a -Platform Access Token. Reference developer documentation for the client system on how to generate -the token. +{{% insert "content/app/guides/shared/api/platform-access-token.md" %}} ### Private APIs + The API contains a set of private APIs that are only accessible within the Events-component. These are marked as _Private API_ in the OpenAPI specification and require an access token in the request header. diff --git a/content/events/publish-events/get-started/api-access/_index.en.md b/content/events/publish-events/get-started/api-access/_index.en.md index 60e79e4dcd9..c2d5548418b 100644 --- a/content/events/publish-events/get-started/api-access/_index.en.md +++ b/content/events/publish-events/get-started/api-access/_index.en.md @@ -7,4 +7,4 @@ description: A guide to requesting access to the event producer APIs ## Requesting required Maskinporten scope -{{% insert "content/events/request-maskinporten-scopes.md" "altinn:events.publish" "publishing events to Altinn"%}} +{{% insert "content/app/guides/shared/api/request-maskinporten-scopes.md" "altinn:events.publish" "publishing events to Altinn"%}} diff --git a/content/events/subscribe-to-events/get-started/api-access/_index.en.md b/content/events/subscribe-to-events/get-started/api-access/_index.en.md index 9a5244a4260..700adada9a0 100644 --- a/content/events/subscribe-to-events/get-started/api-access/_index.en.md +++ b/content/events/subscribe-to-events/get-started/api-access/_index.en.md @@ -8,5 +8,5 @@ description: Guide to requesting access to Altinns APIs ## Requesting required Maskinporten scope* \* Scope is only required when subscribing to events published to a non-Altinn App resource. -{{% insert "content/events/request-maskinporten-scopes.md" "altinn:events.subscribe" "subscribing to events"%}} +{{% insert "content/app/guides/shared/api/request-maskinporten-scopes.md" "altinn:events.subscribe" "subscribing to events"%}} diff --git a/content/notifications/_index.en.md b/content/notifications/_index.en.md new file mode 100644 index 00000000000..766652e16ae --- /dev/null +++ b/content/notifications/_index.en.md @@ -0,0 +1,141 @@ +--- +title: Notifications +description: Description of the notifications capabilities in Altinn 3. +toc: true +weight: 20 +aliases: + - /altinn-notifications/ +--- + +{{% notice warning %}} +This section of the documentation is a work in progress. +There are sub sections with missing and/or only partial documentation. +{{% /notice %}} + +## Main benefits + +Reasons to consider using Altinn Notifications for communication with Norwegian citizens or businesses + +1. Contact information in national registries can be retrieved at send time based on + organisation number or person identification number. +2. Altinn roles can be used to identify the correct recipients within an organisation. +3. Notifications can have send conditions related to the state of, or actions performed on, an Altinn App instance +4. A seamless integration for notifications in an Altinn App workflow. + +## Terminology + +- #### Notification order + + A _notification order_ is the request to send one or multiple notifications to one or multiple recipients. + A single order can result in the creation of one or multiple notifications. + + Here is an example of a standard notification order: + + ```json + { + "id": "a56c0933-d609-4b5c-a5da-bccfd407c9b8", + "creator": "ttd", + "sendersReference": "test-2023-1", + "requestedSendTime": "2024-01-02T13:49:31.5591909Z", + "created": "2024-01-02T13:49:31.5799658Z", + "notificationChannel": "Email", + "recipients": [ + { + "emailAddress": "testuser_1@altinn.no" + }, + { + "emailAddress": "testuser_2@altinn.no" + } + ], + "emailTemplate": { + "fromAddress": "noreply@altinn.cloud", + "subject": "A test email from Altinn Notifications", + "body": "A message sent from an application owner through Altinn.", + "contentType": "Html" + }, + "links": { + "self": "https://platform.at22.altinn.cloud/notifications/api/v1/orders/a56c0933-d609-4b5c-a5da-bccfd407c9b8", + "status": "https://platform.at22.altinn.cloud/notifications/api/v1/orders/a56c0933-d609-4b5c-a5da-bccfd407c9b8/status" + } + } + ``` + +- #### Notification + + A _notification_ is the one instance of an email or SMS that is sent to a single recipient. + + Here is an example of a set of notifications related to an order: + + ```json + { + "orderId": "a56c0933-d609-4b5c-a5da-bccfd407c9b8", + "sendersReference": "test-2023-1", + "generated": 2, + "succeeded": 1, + "notifications": [ + { + "id": "a141753c-557f-4bce-95fd-8fc715ca9a40", + "succeeded": true, + "recipient": { + "emailAddress": "testuser_1@altinn.no" + }, + "sendStatus": { + "status": "Succeeded", + "description": "The email has been accepted by the third party email service and will be sent shortly.", + "lastUpdate": "2024-01-02T13:51:12.706808Z" + } + } + { + "id": "a9d159e2-6a89-4440-80da-7f2a99c775f4", + "succeeded": true, + "recipient": { + "emailAddress": "testuser_2@altinn.no" + }, + "sendStatus": { + "status": "Sending", + "description": "The email is being processed and will be attempted sent shortly." , + "lastUpdate": "2024-01-02T13:51:12.706808Z" + } + } + ] + } + ``` + +- #### Notification channel + + A _notification channel_ is the communication pathways through which Altinn enables you to + communicate with your end users. + +## Notification channels + +Currently, we support sending notifications through two channels: + +- email +- sms + +#### Future improvements + +In the future, we plan to extend our notification channel options to provide even more flexibility and convenience. +Our goal is to support a wider range of communication platforms. This expansion will allow both your organisation +and the end users to communicate through the channels that best suit the end users preferences and communication habits. + +Stay tuned for updates as we continue to enhance our notification capabilities to better serve your needs. + +If you have any questions or feedback regarding notification channels, +please don't hesitate to [reach out to us through GitHub](https://github.com/Altinn/altinn-notifications/issues/new?assignees=&labels=kind%2Fquestion%2Cstatus%2Ftriage&projects=&template=question.yml). + +## Who can use Altinn Notifications + +Altinn Notifications allows the following parties to send messages, +provided they have obtained authorization through Maskinporten: + +- Registered service owners +- Altinn Apps +- Internal Altinn services + + +## Guidelines for usage + + +[Please reference our user guide on how and when to use Altinn Notitifcations](send-notifications/get-started/user-guide/) + diff --git a/content/notifications/api/_index.en.md b/content/notifications/api/_index.en.md new file mode 100644 index 00000000000..a3f360cb30e --- /dev/null +++ b/content/notifications/api/_index.en.md @@ -0,0 +1,30 @@ +--- +title: Altinn Notifications API +linktitle: API +description: An overview of the Altinn Notifications API +weight: 10 +toc: true +--- + +The Altinn Notifications API is an HTTP-based RESTful API that provides endpoints and actions for ordering, +managing and reviewing notifications sent through Altinn. + +## Base URL + +{{% insert "content/app/guides/shared/api/base-urls.md" "notifications"%}} + +## Authentication & Authorization + +### Altinn token + +{{% insert "content/app/guides/shared/api/altinn-token.md" "Notifications"%}} + +### Maskinporten scopes + +{{% insert "content/app/guides/shared/api/maskinporten-scopes.md" %}} + + +### Platform Access token + +{{% insert "content/app/guides/shared/api/platform-access-token.md" %}} + diff --git a/content/notifications/api/openAPI/_index.en.md b/content/notifications/api/openAPI/_index.en.md new file mode 100644 index 00000000000..46922323a7f --- /dev/null +++ b/content/notifications/api/openAPI/_index.en.md @@ -0,0 +1,8 @@ +--- +title: OpenAPI (swagger) for Notifications +linktitle: OpenAPI +type: openapi +spec: "/swagger/altinn-notifications-v1.json" +tags: [swagger, openapi] +--- + diff --git a/content/notifications/architecture/_index.en.md b/content/notifications/architecture/_index.en.md new file mode 100644 index 00000000000..ed955141313 --- /dev/null +++ b/content/notifications/architecture/_index.en.md @@ -0,0 +1,47 @@ +--- +title: Application construction components - Altinn Notifications +linktitle: Architecture +tags: [architecture, solution] +weight: 20 +toc: true +description: "The Notifications solution in Altinn is made up of multiple ASP.NET Web API applications +deployed as Docker containers to a Kubernetes cluster." +--- + + +## System architecture illustration +The solution is supported by multiple cron jobs running in the same Kubernetes cluster, a Kafka server and an instance of +[Azure Communication services](https://learn.microsoft.com/en-us/azure/communication-services/overview). + +The following diagram illustrates the overall data flow. + +![Solution diagram](solution.drawio.svg "Solution diagram Altinn Notifications") + + +## Process flow between microservices and Kafka topics + +![Topics](notifications-topic.drawio.svg "Illustration of the data flow including Kafka Topics") + +## System and service dependencies +### Internal + +- **Altinn Authorization**: used to authorize access to endpoints + + +{{% notice info %}} +The number of internal dependencies for Notifications is currenlty quite limited, +but during 2024 we expect the services below to be utilized by Notifications. +- **Altinn Storage**: used to retrieve status for Altinn app instances to evaluate send conditions +- **Altinn Profile**: used to retrieve recipient information +- **Altinn Register**: used to retrieve recipient information +{{% /notice %}} + + +### External +- [**Azure Kubernetes Services**](https://azure.microsoft.com/en-us/products/kubernetes-service): hosts the docker containers for microservices and cron jobs + in a fully managed Kubernetes cluster +- [**Kafka on Confluent cloud**](https://www.confluent.io/): hosts the kafka cluster the microservices consumes and produces messages to. Say something about why we use kafka vs something else. E.g. storage queues +- [**PostgreSQL**](https://www.postgresql.org/): used for storage +- [**Azure ommunication Services**](https://azure.microsoft.com/en-us/products/communication-services): used to send emails +- [**Azure Event Grid**](https://azure.microsoft.com/en-us/products/event-grid): used to subscribe to status updates for sent emails +- [**LINK Mobility**](https://www.linkmobility.com/) used to send sms diff --git a/content/notifications/architecture/email/_index.en.md b/content/notifications/architecture/email/_index.en.md new file mode 100644 index 00000000000..2a2e516d623 --- /dev/null +++ b/content/notifications/architecture/email/_index.en.md @@ -0,0 +1,11 @@ +--- +title: Notifications email +linktitle: Notifications email +tags: [architecture, solution, notifications, email] +weight: 2 +toc: false +--- + +{{% notice info %}} +TODO: Agree on structure for section +{{% /notice %}} diff --git a/content/notifications/architecture/kafka/_index.en.md b/content/notifications/architecture/kafka/_index.en.md new file mode 100644 index 00000000000..7b639e43338 --- /dev/null +++ b/content/notifications/architecture/kafka/_index.en.md @@ -0,0 +1,213 @@ +--- +title: Kafka +linktitle: Kafka +tags: [architecture, solution, kafka] +weight: 40 +toc: true +description: "Kafka is used as a message broker across the components that make up the Notification solution. +We are currently running Apache Kafka on Confluent Cloud through Azure enabling seamless +integration with the rest of our components hosted in Azure." +--- + +## Kafka topic Overview +{{% notice info %}} +TODO: QA devs +{{% /notice %}} + +{{% notice info %}} +Consideration: + +Do we want to express a description of the topic or rather the event trigger for the topic? +I don't think we need both as they tell the same story. +{{% /notice %}} + + +Below is an overview of the Kafka topics used in our system, +along with information about the producers and the content of each topic + + +### Health + +{{% expandsmall id="altinn.notifications.health.check" header="altinn.notifications.health.check" %}} + +__Description:__ A topic dedicated to verifying the connectivity between microservices and the Kafka cluster. + +__Event trigger:__ External party has requested that the health of the microservice is checked. + +__Producer:__ Altinn Notifications, KafkaHealthCheck + +__Content:__ + +- Format: string +- Description: A string not intended to carry any significant data. Default value: _test_. +{{% /expandsmall %}} + + +{{% expandsmall id="altinn.notifications.email.health.check" header="altinn.notifications.email.health.check" %}} + +__Description:__ A topic dedicated to verifying the connectivity between microservices and the Kafka cluster. + +__Event trigger:__ External party has requested that the health of the microservice is checked. + +__Producer:__ Altinn Notifications Email, KafkaHealthCheck + +__Content:__ + +- Format: string +- Description: A string not intended to carry any significant data. Default value: _test_. +{{% /expandsmall %}} + +### Orders + + +{{% expandsmall id="altinn.notifications.orders.pastdue" header="altinn.notifications.orders.pastdue" %}} + +__Description:__ A topic dedicated to orders where the requested send time is about to pass, or has passed. + +__Event trigger:__ Requested send time of orders is about to, or has, passed. + +__Producer:__ Altinn Notifications, OrderProcessingService + +__Content:__ + +- Format: json +- Data structure: [NotificationOrder](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs) +- Description: An order containing notification templates along with complete or partial recipient data. +{{% /expandsmall %}} + + +{{% expandsmall id="altinn.notifications.orders.pastdue.retry" header="altinn.notifications.orders.pastdue.retry" %}} + +__Description:__ A topic dedicated to orders where the requested send time is about to pass,or has passed +and processing has failed at least once. + +__Event trigger:__ Initial processing of the order after passed send time failed due to an unknown or intermittent reason. + +__Producer:__ Altinn Notifications, PastDueOrdersConsumer + +__Content:__ + +- Format: json +- Data structure: [NotificationOrder](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications.Core/Models/Orders/NotificationOrder.cs) +- Description: An order containing notification templates along with complete or partial recipient data. +{{% /expandsmall %}} + +### Emails + + +{{% expandsmall id="altinn.notifications.email.queue" header="altinn.notifications.email.queue" %}} + +__Description:__ A topic dedicated to emails that are completed and ready to be sent to out. + +__Event trigger:__ All required information has been retrieved and populated to the email + +__Producer:__ Altinn Notifications, EmailNotificationService + +__Content:__ + +- Format: json +- Data structure: [Email](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications.Core/Models/Email.cs) +- Description: An email with all required properties present +{{% /expandsmall %}} + + +{{% expandsmall id="altinn.notifications.email.queue.retry" header="altinn.notifications.email.queue.retry" %}} + +__Description:__ A topic dedicated to emails that are completed and ready to be sent to out where at least +one previous attempt of sending the email has failed. + +__Event trigger:__ Initial attempt to send the email has failed due to an unknown or intermittent reason. + +__Producer:__ Altinn Notifications Email, SendEmailQueueConsumer + +__Content:__ + +- Format: json +- Data structure: [Email](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications.Core/Models/Email.cs) +- Description: An email with all required properties present. +{{% /expandsmall %}} + + +{{% expandsmall id="altinn.notifications.email.sending.accepted" header="altinn.notifications.email.sending.accepted" %}} + +__Description:__ A topic dedicated to send operation identifiers for emails that have been accepted by Azure Communication services. + +__Event trigger:__ The system would like an update on the status for an email that was accepted by Azure Communication Services. + +__Producer:__ Altinn Notifications Email, SendingService and StatusService + +__Content:__ + +- Format: json +- Data structure: [SendNotificationOperationIdentifier](https://github.com/Altinn/altinn-notifications-email/blob/main/src/Altinn.Notifications.Email.Core/SendNotificationOperationIdentifier.cs) +- Description: An object grouping notification id, Azure Communication Services operation Id, and the date and time + for the last status check. +{{% /expandsmall %}} + + +{{% expandsmall id="altinn.notifications.email.status.updated" header="altinn.notifications.email.status.updated" %}} + +__Description:__ A topic dedicated to hold updates on the send status of an email notification + +__Event trigger:__ An update on the progress of sending an email notification has been received from Azure Communication Services. + +__Producer:__ Altinn Notifications Email, StatusService + +__Content:__ + +- Format: json +- Data structure: [SendOperationResult](https://github.com/Altinn/altinn-notifications-email/blob/main/src/Altinn.Notifications.Email.Core/Status/SendOperationResult.cs) +- Description: An object containing the [EmailSendResult](https://github.com/Altinn/altinn-notifications-email/blob/main/src/Altinn.Notifications.Email.Core/Status/EmailSendResult.cs) + for a given notification and operation id for the last status check. +{{% /expandsmall %}} + +### Platform services + + +{{% expandsmall id="altinn.platform.service.updated" header="altinn.platform.service.updated" %}} + +__Description:__ A topic dedicated to hold updates on the Altinn platform components + +__Event trigger:__ An change in the state or availability of a platform service has occurred + +__Producer:__ +- Altinn Notifications Email, SendingService + +__Content:__ + +- Format: json +- Data structure: [GenericServiceUpdate](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications.Core\Models/AltinnServiceUpdate/GenericServiceUpdate.cs) +- Description: An object contaning an Altinn service update of a schema specified in the payload. +{{% /expandsmall %}} + +## Cluster configuration +{{% notice info %}} +TODO: QA infra +{{% /notice %}} + +The kafka cluster used by Altinn Notifications, is a cluster shared between multiple Altinn components. +Configuration in relation to roles and topic policies are in place to ensure integrity in the data on topics +owned by the Notifications solution. + + +### Roles + +Three roles are defined and used by entities interacting with Kafka from the solution. + +- **NotificationsConsumer**: can consume from topics following the naming patterns _altinn.notifications.*_ and _altinn.platform.*_ +- **NotificationsProducer** : can write to topics following the naming patterns _altinn.notifications.*_ and _altinn.platform.*_ +- **ClusterAdmin**: can create a new topics following the naming patterns _altinn.notifications.*_ and _altinn.platform.*_ + + +## Topic configuration + +### Partitions +The number of partitions on a topic is set at creation. As our solution has the ability to auto scale, +we have set the number of partitions equal to the maximum number of nodes available in the AKS cluster +running the consumer microservices. This means the maximum numbers of consumers per consumer group will be equal to +the number of nodes in the cluster. + +### Retention +Retention time varies between the environments. +For all AT environments retention time for a message is 7 days. +In YT, TT and production retention time for a message is 365 days. \ No newline at end of file diff --git a/content/notifications/architecture/notifications-topic.drawio.svg b/content/notifications/architecture/notifications-topic.drawio.svg new file mode 100644 index 00000000000..482656a59d4 --- /dev/null +++ b/content/notifications/architecture/notifications-topic.drawio.svg @@ -0,0 +1,998 @@ + + + + + + + + + +
+
+
+ altinn. +
+ notifications. +
+ orders. +
+ pastdue +
+
+
+
+ + altinn.... + +
+
+ + + + + + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + +
+
+
+ + Generation successful? + +
+
+
+
+ + Generation successful? + +
+
+ + + + + + +
+
+
+ Order processing status set to completed +
+
+
+
+ + Order processing sta... + +
+
+ + + + + +
+
+
+ Order processing status: completed +
+
+
+
+ + Order pr... + +
+
+ + + + + + +
+
+
+ + Generate an email + +
+ + notification for each recipient and persist in database + +
+
+
+
+ + Generate an email... + +
+
+ + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ Order processing status set to processing in DB & order published to topic +
+
+
+
+ + Order processing status se... + +
+
+ + + + + + +
+
+
+ altinn. +
+ notifications. +
+ orders. +
+ pastdue. +
+ retry +
+
+
+
+ + altinn.... + +
+
+ + + + + + +
+
+
+ + Generate an email + +
+ + notification for each recipient not yet persisted in database + +
+
+
+
+ + Generate an email... + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + +
+
+
+ + Generation successful? + +
+
+
+
+ + Generation successful? + +
+
+ + + + + + +
+
+
+ Order processing status set to completed +
+
+
+
+ + Order processing sta... + +
+
+ + + + + +
+
+
+ Order processing status: completed +
+
+
+
+ + Order pr... + +
+
+ + + + + +
+
+
+ Order processing status: processing +
+
+
+
+ + Order pr... + +
+
+ + + + +
+
+
+ Altinn.Notifications +
+
+
+
+ + Altinn.Notifications + +
+
+ + + + +
+
+
+ + Altinn.Notifications.Email + +
+
+
+
+ + Altinn.Notifications... + +
+
+ + + + + +
+
+
+
+ + Time triggered service + +
+ + triggers retrieval of past due orders from db + +
+
+
+
+
+
+
+
+
+
+ + Time triggered service... + +
+
+ + + + + + + + + + + + + + + + +
+
+
+ Sending status set to: sending in DB & email published to topic +
+
+
+
+ + Sending status set to: sen... + +
+
+ + + + +
+
+
+ Time triggered service +
+ triggers retrieval of past due emails from db +
+
+
+
+ + Time triggered service... + +
+
+ + + + + + +
+
+
+ altinn. +
+ notification. +
+ email. +
+ queue +
+
+
+
+ + altinn.... + +
+
+ + + + + + +
+
+
+ + Send email through communication services + +
+
+
+
+ + Send email through c... + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ + Operation accepted? + +
+
+
+
+ + Operation accepted? + +
+
+ + + + + + +
+
+
+ + Publish send notification operation identifier to topic + +
+
+
+
+ + Publish send notific... + +
+
+ + + + + + +
+
+
+ altinn. +
+ notification. +
+ email. +
+ sending. +
+ accepted +
+
+
+
+ + altinn.... + +
+
+ + + + + + +
+
+
+ + Get operation update from communication services + +
+
+
+
+ + Get operation update... + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ + Is result still 'Sending'? + +
+
+
+
+ + Is result still 'Sendi... + +
+
+ + + + + + +
+
+
+ altinn. +
+ notification. +
+ email. +
+ status. +
+ updated +
+
+
+
+ + altinn.... + +
+
+ + + + + + +
+
+
+ + Generate send operation result + +
+
+
+
+ + Generate send operat... + +
+
+ + + + + + +
+
+
+ altinn. +
+ notification. +
+ email. +
+ queue.retry +
+
+
+
+ + altinn.... + +
+
+ + + + + +
+
+
+ No further consumer implemented +
+
+
+
+ + No furth... + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ + Last update more than +
+ 8 secs ago? +
+
+
+
+
+
+ + Last update more than... + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + + + +
+
+
+ + An exception is thrown +
+
+
+
+
+
+ + An exception is thrown + +
+
+ + + + + + +
+
+
+ Persist status update to DB +
+
+
+
+ + Persist status updat... + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ + Successfully persisted? + +
+
+
+
+ + Successfully persisted? + +
+
+ + + + + +
+
+
+ No further actions +
+
+
+
+ + No furth... + +
+
+ + + + + +
+
+
+ NO +
+
+
+
+ + NO + +
+
+ + + + + +
+
+
+ YES +
+
+
+
+ + YES + +
+
+ + + + +
+
+
+ + is +
+ RequestFailedException +
+
+
+
+
+
+ + is... + +
+
+
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file diff --git a/content/notifications/architecture/notifications/_index.en.md b/content/notifications/architecture/notifications/_index.en.md new file mode 100644 index 00000000000..1c8411bf198 --- /dev/null +++ b/content/notifications/architecture/notifications/_index.en.md @@ -0,0 +1,133 @@ +--- +title: Notifications +linktitle: Notifications +tags: [architecture, solution, notifications] +weight: 1 +toc: true +--- + +{{% notice info %}} +TODO: Agree on structure for section. + +Could we split it in two children pages: Functional and Non-functional? +{{% /notice %}} + +## API + +### Public API +The following API controllers are defined: +- [EmailNotificationsOrdersController](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Controllers/EmailNotificationOrdersController.cs): + API for placing new email notification order requests +- [EmailNotificationsController](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Controllers/EmailNotificationsController.cs): + API for retrieving email notifications related to a single order +- [OrdersController](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Controllers/OrdersController.cs): + API for retrieving one or more orders with or without processing details and notification summaries + +### Notifications internal API +The API controllers listed below are exclusively for use within the Notification solution: + +- [Trigger controller](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Controllers/TriggerController.cs): Functionality to trigger the start of order and notifications processing flows. + + +## Database +Add an overview of the various tables and a general descriptions. +Diagram that shows relationships e.g. foreign keys. + +![Database](dbmodel.drawio.svg "Notifications Database") + + +## Integrations + +### Kafka Consumers + +### Kafka Producer + + +## Cron jobs + +[Based of the official docker image for curl](https://hub.docker.com/r/curlimages/curl) + +## Dependencies + +### Services +- Kafka +- Azure Database for PostgreSQL +- APIM +- AI (logging) + + +### Altinn components +- Altinn Notifications Email +- Altinn Authorization + + +### Software +Notifications microservice use a range of libraries to support the provided functionality. + +[See full list of dependencies on GitHub](https://github.com/Altinn/altinn-notifications/network/dependencies). + + +## Testing +Quality gates implemented for a project require an 80 % code coverage for the unit and integration tests combined. + +### Unit tests +[The unit test project is available on Github](https://github.com/Altinn/altinn-notifications/tree/main/test/Altinn.Notifications.Tests). + +[xUnit](https://xunit.net/) is the framework used and the [Moq library](https://github.com/moq) supports mocking +parts of the solution. + +### Integration tests +[The integration test project is available on Github](https://github.com/Altinn/altinn-notifications/tree/main/test/Altinn.Notifications.IntegrationTests). + +[xUnit](https://xunit.net/) is the framework used. + +There are two dependencies for the integration tests: +- A Kafka server +- A PostgreSQL database + +A _docker-compose_ script is available to start all Kafka-related dependencies in a Docker containers. + +A PostgreSQL database needs to be installed wherever the tests are running, either in a Docker container or installed +on the machine and exposed on port 5432. (Roles and database must also be in place). +[A bash script has been implemented for easy setup.](https://github.com/Altinn/altinn-notifications/blob/main/dbsetup.sh) + +### Use case tests +Use case tests are run every 15 minutss through GitHub Actions. +The tests themselves are implemented in k6. +The aim of the tests is to run through core functionality of the solution to ensure that it's available to our end users. + +## Hosting + +### Web API +- The microservice runs in a Docker container hosted in AKS (Azure Kubernetes Service), + and it is deployed as a Kubernetes deployment with autoscaling capabilities + +Notifications listen on port 5090. + +See [DockerFile](https://github.com/Altinn/altinn-notifications/blob/main/Dockerfile) for details. + +### Cron jobs +- The cron jobs run in a docker containers hosted in AKS (Azure Kubernetes Service), + and is started on a schedule configured in the helm chart. + There is a policy in place to ensure that there are no concurrent pods of a singular job. + +### Database +{{% notice info %}} +TODO: Any config that would be useful to share from a functional perspective +{{% /notice %}} + +- The PostgreSQL database is hosted by a dedicated Azure Database for PostgreSQL flexible servers service. + +## Build & deploy + +### Web API + - Build and Code analysis are done by an [Github action](https://github.com/Altinn/altinn-notifications/actions) + - Build of the image is done in an [Azure Devops Pipeline](https://dev.azure.com/brreg/altinn-studio/_build?definitionId=383) + - Deploy of the image is enabled with Helm and implemented in an [Azure Devops Release pipeline](https://dev.azure.com/brreg/altinn-studio/_release?_a=releases&view=all&definitionId=49) + +### Cron jobs + - Deploy of the cron jobs is enabled with Helm and implemented in the same pipeline that deploys the web API. + +### Database + - Migration scripts are copied into the Docker image of the web API when this is build + - Execution of the scripts is on startup of the application and enabled by [YUNIQL](https://yuniql.io/) \ No newline at end of file diff --git a/content/notifications/architecture/notifications/dbmodel.drawio.svg b/content/notifications/architecture/notifications/dbmodel.drawio.svg new file mode 100644 index 00000000000..0bfbbd75141 --- /dev/null +++ b/content/notifications/architecture/notifications/dbmodel.drawio.svg @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ 1:1 +
+
+
+
+ + 1:1 + +
+
+ + + + + + + emailtexts + + + + + + + PK + + + + + + _id + + + + + + + FK + + + + + + _orderid + + + + + + + fromaddress + + + + + + + subject + + + + + + + body + + + + + + + contenttype + + + + + + +
+
+
+ 1:* +
+
+
+
+ + 1:* + +
+
+ + + + + + + orders + + + + + + + PK + + + + + + _id + + + + + + + alternateid + + + + + + + creatorname + + + + + + + sendersreference + + + + + + + created + + + + + + + + requestedsendtime + + + + + + + processed + + + + + + + processedstatus + + + + + + + notificationorder + + + + + + + + + emailnotifications + + + + + + + PK + + + + + + _id + + + + + + + FK + + + + + + _orderid + + + + + + + alternateid + + + + + + + recipientid + + + + + + + toaddress + + + + + + + result + + + + + + + resulttime + + + + + + + expirytime + + + + + + + operationid + + + + + + + + + resourcelimitlog + + + + + + + PK + + + + + + id + + + + + + + emaillimittimeout + + +
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file diff --git a/content/notifications/architecture/sms/_index.en.md b/content/notifications/architecture/sms/_index.en.md new file mode 100644 index 00000000000..3536a317d6d --- /dev/null +++ b/content/notifications/architecture/sms/_index.en.md @@ -0,0 +1,12 @@ +--- +title: Notifications sms +linktitle: Notifications sms +tags: [architecture, solution, notifications, sms] +weight: 2 +toc: false +--- + + +{{% notice info %}} +TODO: Agree on structure for section +{{% /notice %}} diff --git a/content/notifications/architecture/solution.drawio.svg b/content/notifications/architecture/solution.drawio.svg new file mode 100644 index 00000000000..942a4180802 --- /dev/null +++ b/content/notifications/architecture/solution.drawio.svg @@ -0,0 +1,342 @@ + + + + + + + +
+
+
+ Notifications DB +
+
+
+
+ + Notifi... + +
+
+ + + + + + +
+
+
+ Cron jobs +
+
+
+
+ + Cron jobs + +
+
+ + + + + + + +
+
+
+ Agency systems +
+
+
+
+ + Agency systems + +
+
+ + + + Altinn Apps + + + + + + + + + + + + + + + + + + +
+
+
+ REST API users +
+
+
+
+ + REST API us... + +
+
+ + + + + Kafka + + + + + + + + + + + +
+
+
+ Places a notification order +
+
+
+
+ + Places a notification order + +
+
+ + + +
+
+
+ + POST /orders/email +
+
+
+
+
+
+ + POST /orders/email + +
+
+ + + + + +
+
+
+ Send email +
+
+
+
+ + Send email + +
+
+ + + + + +
+
+
+ Report status +
+
+
+
+ + Report status + +
+
+ + + + + + + +
+
+
+ Notifications API +
+
+
+
+ + Notifications API + +
+
+ + + + + + + +
+
+
+ Trigger processing +
+ of orders and +
+ notifications +
+
+
+
+ + Trigger processing... + +
+
+ + + + + + +
+
+
+ Notification Email +
+ service +
+
+
+
+ + Notification Email... + +
+
+ + + +
+
+
+ Consumes status updates +
+
+
+
+ + Consumes status updates + +
+
+ + + + + + +
+
+
+ Publishes notifications +
+
+
+
+ + Publishes notifications + +
+
+ + + + + + +
+
+
+ Publishes status updates +
+
+
+
+ + Publishes status updates + +
+
+ + + +
+
+
+ Consumes notifications +
+
+
+
+ + Consumes notifications + +
+
+ + + + + +
+
+
+ Report status +
+
+
+
+ + Report status + +
+
+ +
+ + + + + Text is not SVG - cannot display + + + +
\ No newline at end of file diff --git a/content/notifications/send-notifications/_index.en.md b/content/notifications/send-notifications/_index.en.md new file mode 100644 index 00000000000..277155bef96 --- /dev/null +++ b/content/notifications/send-notifications/_index.en.md @@ -0,0 +1,66 @@ +--- +title: Send notifications +linktitle: Send notifications +description: "Service owners and internal Altinn systems can send notifications to individuals in a personal +capacity or a proffesional capacity thoguh a role they have within an organisation. The contact point for the +recipient does not need to be known, as Altinn has access to a wide range +of registries to retrieve contact information given an organisation number or a national identity number." +tags: [notifications] +weight: 30 +toc: true + +--- + +## Combining notification channels + +{{% notice info %}} +Per November '23 only one communication chanel is supported. +Once multiple channels are provided, it will be possible to comnine notification channels for a single order request. +{{% /notice %}} + +## Registries used for recipient addresses + +When sending a notification through Altinn the sender can provide the contact details (email +or SMS). In addition to this, Altinn uses a set of registries to retrieve the contact details +if noen have been provided by the sender. + +__The common contact register (Kontakt- og reservasjonsregisteret)__ + +Altinn has a local copy of this register which can be used used to retrieve +contact details if the recipient is identified by person number. + +[Read more about the common contact register is available here](https://eid.difi.no/en/privacy-policy/privacy-policy-common-contact-register-krr). + +__The National Registry for Notification Addresses for Businesses (Varslingsadresser for Enheter)__ + +Altinn has a local copy of this register which can be used used to retrieve contact details if the +recipient is identified by organisation number. + +[Read more about the notification addresses to apply in public administration here](https://www.brreg.no/en/other-topics/notification-addresses-to-apply-in-public-administration/?nocache=1704206499405). + + +__Altinn user profile__ + +End users can register their preferred contact details for notifications related to organisations in their +Altinn profile. These contact details can be used when the recipient is identified by organisation number. + + \ No newline at end of file diff --git a/content/notifications/send-notifications/developer-guides/_index.en.md b/content/notifications/send-notifications/developer-guides/_index.en.md new file mode 100644 index 00000000000..e8936fbea0f --- /dev/null +++ b/content/notifications/send-notifications/developer-guides/_index.en.md @@ -0,0 +1,8 @@ +--- +title: Developer guides +linktitle: Developer guides +description: Guides for the most common notification actions +weight: 50 +--- + +{{}} \ No newline at end of file diff --git a/content/notifications/send-notifications/developer-guides/get-email-notifications/_index.en.md b/content/notifications/send-notifications/developer-guides/get-email-notifications/_index.en.md new file mode 100644 index 00000000000..b07e59b1a5a --- /dev/null +++ b/content/notifications/send-notifications/developer-guides/get-email-notifications/_index.en.md @@ -0,0 +1,131 @@ +--- +title: Get email notifications +linktitle: Get email notifications +description: Endpoint for retrieving the send status of all email notifications generated by a notification order. + +weight: 60 +toc: true +--- + +## Endpoint + +GET /order/{id}/notifications/email + +{id} represents the id of the notification order to retrieve notifications for. + +## Authentication + +This API requires authentication and the request must also include one of the following: +- Maskinporten scope __altinn:serviceowner/notifications.create__ (for external system callers) +- Platform Access Token (for Altinn Apps and internal Altinn systems) + +See [Authentication and Authorization](../../../api/#authentication--authorization) for more information. + +## Response + +### Response codes +- 200 OK: The email notifications were successfully retrieved +- 404 Not Found: No order matching the provided id were found + + Refer to problem details in response body for further information. +- 401 Unauthorized: Indicates a missing, invalid or expired authorization header. +- 403 Forbidden: Indicates that required scope or Platform Access Token is missing or invalid. + +### Content-Type +- application/json + +### Response body +The response body is formatted as an +[EmailNotificationSummaryExt](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/EmailNotificationSummaryExt.cs) +and serialized as a JSON string. + + +### Response body properties + +#### orderId +Type: _Guid_ + +The id of the notification order the listed notifications are related to + +#### sendersReference +Type: _string_ + +The senders reference the creator provided upon the creation of the notification order + +#### generated +Type: _int_ + +The total number of email notifications generated so far based on the notification order + +#### succeeded +Type: _int_ + +The number of email notifications that have been sent successfully so far + +#### notifications +Type: _List\<[EmailNotificationWithResult](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/EmailNotificationWithResultExt.cs)\>_ + +A list of the generated notifications with send result. +Each notification will include the following properties: + - id: the id of the notification + - succeeded: a boolean indicating whether the send status is a successful one. + - _recipient_: the contact details of the recipient that the notification is sent to. + - _sendStatus_: the send status of the notification. + +| Status | Description | +|:-----------------------------:|:-----------------:| +| New | The email has been created, but has not been picked up for processing yet. | +| Sending | The email is being processed and will be attempted sent shortly. | +| Succeeded | The email has been accepted by the third party email service and will be sent shortly. | +| Delivered | The email was delivered to the recipient. No errors reported, making it likely it was received by the recipient. | +| Failed | The email was not sent due to an unspecified failure.| +| Failed_RecipientNotIdentified | The email was not sent because the recipient's email address was not found. | +| Failed_InvalidEmailFormat | The email was not sent because the recipient’s email address is in an invalid format. | + +## Examples + +### Request +{{% notice info %}} +In the example we have included place holders for both the Platform Access and Altinn token. + +__You only need one of them__, reference [Authentication](#authentication) for which one applies to your use case. +{{% /notice %}} + + +```bash +curl --location 'https://platform.altinn.no/notifications/api/v1/orders/f1a1cc30-197f-4f34-8304-006ce4945fd1/notifications/email' \ +--header 'Content-Type: application/json' \ +--header 'PlatformAccessToken: [INSERT PLATFORM ACCESS TOKEN]' \ +--header 'Authorization: Bearer [INSERT ALTINN TOKEN]' +``` + +### Response + +#### 200 OK +Response body contains the email notification summary. + +```json +{ + "orderId": "f1a1cc30-197f-4f34-8304-006ce4945fd1", + "sendersReference": "ref-2023-12-01", + "generated": 1, + "succeeded": 0, + "notifications": [ + { + "id": "e0197ec7-3d82-4917-8329-8c9ecc4c569b", + "succeeded": false, + "recipient": { + "emailAddress": "recipient@domain.com" + }, + "sendStatus": { + "status": "New", + "description": "The email has been created, but has not been picked up for processing yet.", + "lastUpdate": "2023-11-14T16:06:02.877361Z" + } + } + ] +} +``` + +#### 404 Not Found +An empty response is returned with the 404 status code. diff --git a/content/notifications/send-notifications/developer-guides/get-notification-order-by-id/_index.en.md b/content/notifications/send-notifications/developer-guides/get-notification-order-by-id/_index.en.md new file mode 100644 index 00000000000..17f6964d84f --- /dev/null +++ b/content/notifications/send-notifications/developer-guides/get-notification-order-by-id/_index.en.md @@ -0,0 +1,135 @@ +--- +title: Get order details +linktitle: Get order details +description: Endpoint for retrieving the details of a notification order including templates and recipients. +weight: 51 +toc: true +--- + +## Endpoint + +GET /order/{id} + +{id} represents the id of the notification order to retrieve details for. + +## Authentication + +This API requires authentication and the request must also include one of the following: +- Maskinporten scope __altinn:serviceowner/notifications.create__ (for external system callers) +- Platform Access Token (for Altinn Apps and internal Altinn systems) + +See [Authentication and Authorization](../../../api/#authentication--authorization) for more information. + +## Response + +### Response codes +- 200 OK: The notification order was successfully retrieved. +- 404 Not Found: No order matching the provided id were found. Refer to problem details in response body for further information. +- 401 Unauthorized: Indicates a missing, invalid or expired authorization header. +- 403 Forbidden: Indicates that required scope or Platform Access Token is missing or invalid. + +### Content-Type +- application/json + +### Response body +The response body is formatted as an +[NotificationOrderExt.cs](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationOrderExt.cs) +and serialized as a JSON string. + +Find a short description of each property below. + +#### id +Type: _Guid_ + +The id of the notification order. + +#### creator +Type: _string_ + +The short name of the creator of the notification order. + +#### sendersReference +Type: _string_ + +The senders reference the creator provided in the notification order request. + +#### requestedSendTime +Type: _DateTime_ + +The date and time for when the notification generated by the order should be sent. + +#### created +Type: _DateTime_ + +The date and time for when the notification order request was registered. + +#### notificationChannel +Type: enum [_NotificationChannel_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationChannelExt.cs) + +The notification channel used for the notifications sent can be _Email_ or _Sms_. + +#### recipients +Type: List<[_RecipientExt_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/RecipientExt.cs)> + +A list of all provided recipients. + +#### emailTemplate +Type: [_EmailTemplateExt_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/EmailTemplateExt.cs) + +All the email template values used to generate notifications. + +#### links +Type: [_OrderResourceLinksExt_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/OrderResourceLinksExt.cs#L11) + +An object containing a set of self links for the notificatin order. + +## Examples + +### Request +{{% notice info %}} +In the example we have included place holders for both the Platform Access and Altinn token. + +__You only need one of them__, reference [Authentication](#authentication) for which one applies to your use case. +{{% /notice %}} + + +```bash +curl --location 'https://platform.altinn.no/notifications/api/v1/orders/f1a1cc30-197f-4f34-8304-006ce4945fd1' \ +--header 'Content-Type: application/json' \ +--header 'PlatformAccessToken: [INSERT PLATFORM ACCESS TOKEN]' \ +--header 'Authorization: Bearer [INSERT ALTINN TOKEN]' +``` + +### Response + +#### 200 OK +Response body contains the notification order with status information. + +```json +{ + "id": "ca964629-fba5-48e6-80b3-d75502c08f5b", + "creator": "ttd", + "sendersReference": "demo-2023-01", + "requestedSendTime": "2023-12-12T14:13:27.8367317Z", + "created": "2023-12-12T14:13:27.8450294Z", + "notificationChannel": "Email", + "recipients": [ + { + "emailAddress": "testuser_1@altinn.no" + } + ], + "emailTemplate": { + "fromAddress": "noreply@altinn.no", + "subject": "A test email from Altinn Notifications", + "body": "A message sent from an application owner through Altinn.", + "contentType": "Plain" + }, + "links": { + "self": "https://platform.altinn.no/notifications/api/v1/orders/ca964629-fba5-48e6-80b3-d75502c08f5b", + "status": "https://platform.altinn.no/notifications/api/v1/orders/ca964629-fba5-48e6-80b3-d75502c08f5b/status" + } +} +``` + +#### 404 Not Found +An empty response is returned with the 404 status code. diff --git a/content/notifications/send-notifications/developer-guides/get-notification-order-status/_index.en.md b/content/notifications/send-notifications/developer-guides/get-notification-order-status/_index.en.md new file mode 100644 index 00000000000..001ee3b4b76 --- /dev/null +++ b/content/notifications/send-notifications/developer-guides/get-notification-order-status/_index.en.md @@ -0,0 +1,146 @@ +--- +title: Get order status +linktitle: Get order status +description: Endpoint for retrieving the processing status of an order and a summary of all generated notifications. +weight: 51 +toc: true +--- + +## Endpoint + +GET /order/{id}/status + +{id} represents the id of the notification order to retrieve status for. + +## Authentication + +This API requires authentication and the request must also include one of the following: +- Maskinporten scope __altinn:serviceowner/notifications.create__ (for external system callers) +- Platform Access Token (for Altinn Apps and internal Altinn systems) + +See [Authentication and Authorization](../../../api/#authentication--authorization) for more information. + +## Response + +### Response codes +- 200 OK: The notification order status was successfully retrieved. +- 404 Not Found: No order matching the provided id were found. Refer to problem details in response body for further information. +- 401 Unauthorized: Indicates a missing, invalid or expired authorization header. +- 403 Forbidden: Indicates that required scope or Platform Access Token is missing or invalid. + +### Content-Type +- application/json + +### Response body +The response body is formatted as an +[NotificationOrderWithStatusExt.cs](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationOrderWithStatusExt.cs) +and serialized as a JSON string. + +Find a short description of each property below. + +#### id +Type: _Guid_ + +The id of the notification order. + +#### sendersReference +Type: _string_ + +The senders reference the creator provided in the notification order request. + +#### requestedSendTime +Type: _DateTime_ + +The date and time for when the notification generated by the order should be sent. + +#### creator +Type: _string_ + + +#### created +Type: _DateTime_ + +The date and time for when the notification order request was registered. + +#### notificationChannel +Type: enum [_NotificationChannel_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationChannelExt.cs) + +The notification channel used for the notifications sent can be _Email_ or _Sms_. + +#### processingStatus +Type: [_StatusExt_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/StatusExt.cs) + +A status object describing the processing status of the notification order containing the properties below. + + - _status_: current processing status + - _description_: an English description of the status and a timestamp + - _lastupdate_: the date and time when the status was last updated + +| Status | Description | +| :--------: | :------------------------------------------------------------------------------: | +| Registered | Order has been registered and is awaiting requested send time before processing. | +| Processing | Order processing is ongoing. Notifications are being generated. | +| Completed | Order processing is completed. All notifications have been generated. | + + +#### notificationStatusSummary +Type: [_NotificationsStatusSummaryExt_](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationsStatusSummaryExt.cs) + +An object containing a [NotificationStatusExt](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/NotificationStatusExt.cs) +object for for each notification channel used. + +The _NotificationStatusExt_ object contains the properties below. + - links: a set of links to access the notifications generated for the given notification channel + - generated: the number of generated notifications + - succeeded: the number of notifications that have been successfully sent + + +## Examples + +### Request +{{% notice info %}} +In the example we have included place holders for both the Platform Access and Altinn token. + +__You only need one of them__, reference [Authentication](#authentication) for which one applies to your use case. +{{% /notice %}} + + +```bash +curl --location 'https://platform.altinn.no/notifications/api/v1/orders/f1a1cc30-197f-4f34-8304-006ce4945fd1/status' \ +--header 'Content-Type: application/json' \ +--header 'PlatformAccessToken: [INSERT PLATFORM ACCESS TOKEN]' \ +--header 'Authorization: Bearer [INSERT ALTINN TOKEN]' +``` + +### Response + +#### 200 OK +Response body contains the notification order with status information. + +```json +{ + "id": "f1a1cc30-197f-4f34-8304-006ce4945fd1", + "sendersReference": "ref-2023-12-01", + "requestedSendTime": "2023-12-12T14:13:27.836731Z", + "creator": "digdir", + "created": "2023-12-12T14:13:27.845029Z", + "notificationChannel": "Email", + "processingStatus": { + "status": "Completed", + "description": "Order processing is completed. All notifications have been generated.", + "lastUpdate": "2023-12-12T14:13:27.845029Z" + }, + "notificationsStatusSummary": { + "email": { + "links": { + "self": "https://platform.at22.altinn.cloud/notifications/api/v1/orders/f1a1cc30-197f-4f34-8304-006ce4945fd1/notifications/email" + }, + "generated": 1, + "succeeded": 0 + } + } +} +``` + +#### 404 Not Found +An empty response is returned with the 404 status code. diff --git a/content/notifications/send-notifications/developer-guides/send-email-notifications/_index.en.md b/content/notifications/send-notifications/developer-guides/send-email-notifications/_index.en.md new file mode 100644 index 00000000000..3e587a8529b --- /dev/null +++ b/content/notifications/send-notifications/developer-guides/send-email-notifications/_index.en.md @@ -0,0 +1,162 @@ +--- +title: Send email notifications +linktitle: Send email notifications +description: Endpoint for sending an email to one or more recipient with known contact details. +weight: 50 +toc: true +--- + +## Endpoint + +POST /orders/email + +## Authentication + +This API requires authentication and the request must also include one of the following: + +- Maskinporten scope __altinn:serviceowner/notifications.create__ (for external system callers) +- Platform Access Token (for Altinn Apps and internal Altinn systems) + +See [Authentication and Authorization](../../../api/#authentication--authorization) for more information. + +## Request + +### Content-type + +application/json + + +### Request body +The request body must contain the order request formatted as an +[EmailNotificationOrderRequestExt](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/EmailNotificationOrderRequestExt.cs) +and serialized as a JSON string. + + +### Required order request properties +#### __body__ + +Type: _string_ + +The body of the email in either plain text or HTML format. + + +#### subject +Type: _string_ + +The subject of the subject of the email. + +#### recipients +Type: _List of [RecipientExt](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/RecipientExt.cs)_ + +A list containing one or more recipient objects, each representing a recipient with an email address. + +### Optional order request properties + +#### contentType +Type: _enum_ _[EmailContentTypeExt](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/EmailContentTypeExt.cs)_ + +Default: _Plain_ + +The content type of the email can be either `Plain` or `Html`. + +#### requestedSendTime +Type: _DateTime_ + +Default: Current time + +The date and time (with time zone specification) when the notification should be sent to recipient. + +#### sendersReference +Type: _string_ + +An internal reference for notification creator to lookup or identify the notification in +the future. Could be a case number or another id. It is recommended, but not required, +that the sender's reference is unique within the organisation's notification orders. + +## Response + +### Response codes +- 202 Accepted: The notification order request was accepted and a notification order has been successfully generated. +- 400 Bad Request: The request was invalid. Refer to problem details in response body for further information. +- 401 Unauthorized: Indicates a missing, invalid or expired authorization header. +- 403 Forbidden: Indicates missing or invalid scope or Platform Access Token. + +### Content-Type +- application/json + +### Response body + +The response body is formatted as an +[OrderIdExt.cs](https://github.com/Altinn/altinn-notifications/blob/main/src/Altinn.Notifications/Models/OrderIdExt.cs) +and serialized as a JSON string. + +Find a short description of each property below. + +#### orderId +Type: _GUID_ + +The generated id for the notification order + +### Response headers + +#### Location +Type: _URL_ + +The self link for the generated notification order + +## Examples + +### Request +{{% notice info %}} +In the example we have included place holders for both the Platform Access and Altinn token. + +__You only need one of them__, reference the [Authentication section](#authentication) for which one applies to your use case. +{{% /notice %}} + + +```bash +curl --location 'https://platform.altinn.no/notifications/api/v1/orders/email' \ +--header 'Content-Type: application/json' \ +--header 'PlatformAccessToken: [INSERT PLATFORM ACCESS TOKEN]' \ +--header 'Authorization: Bearer [INSERT ALTINN TOKEN]' \ +--data-raw '{ + "sendersReference": "ref-2023-12-01", + "subject": "A test email from Altinn Notifications", + "body": "A message to be sent immediately from an org.", + "contentType": "Plain", + "recipients":[{"emailAddress":"testuser@altinn.no"}] +}' +``` + +### Response + +#### 202 Accepted +Response body contains the ID for the cloud event. + +```json +{ + "orderId": "f1a1cc30-197f-4f34-8304-006ce4945fd1" +} +``` + +Response headers contains a self link for retrieving the generated notification order. +```bash +-- header 'Location: https://platform.altinn.no/notifications/api/v1/orders/f1a1cc30-197f-4f34-8304-006ce4945fd1' +``` + +#### 400 Bad Request +Response contains a problem details object with the error message in the detail property. + +```json +{ + "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", + "title": "One or more validation errors occurred.", + "status": 400, + "traceId": "00-9ac2962c93d79629aa5c3744e4259663-344b49720aa49b0a-00", + "errors": { + "Subject": [ + "'Subject' must not be empty." + ] + } +} +``` \ No newline at end of file diff --git a/content/notifications/send-notifications/get-started/_index.en.md b/content/notifications/send-notifications/get-started/_index.en.md new file mode 100644 index 00000000000..e5375d412d8 --- /dev/null +++ b/content/notifications/send-notifications/get-started/_index.en.md @@ -0,0 +1,8 @@ +--- +title: Get started +linktitle: Get started +description: An overview over administrative tasks required before sending notifications through Altinn +weight: 20 +--- + +{{}} diff --git a/content/notifications/send-notifications/get-started/maskinporten-integration/_index.en.md b/content/notifications/send-notifications/get-started/maskinporten-integration/_index.en.md new file mode 100644 index 00000000000..388bb13ca89 --- /dev/null +++ b/content/notifications/send-notifications/get-started/maskinporten-integration/_index.en.md @@ -0,0 +1,42 @@ +--- +title: Makinporten integration +linktitle: Maskinporten integration +weight: 10 +description: "A guide to setting up a maskinporten integration to generate tokens with +the required scope to access to the Notifications API" +--- + +{{% notice info %}} +NOTE: This is only required by external system clients. +Altinn internal systems should include an Altinn Platform Access Tokens to the request header to gain access +to the API. +{{% /notice %}} + +## Required Maskinporten scope + +The scope **altinn:serviceowner/notifications.create** is required for external clients to gain +access to the Notifications API. + +All registered service owners have been delegated this scope by Digdir and should +be able to find it in their list of scopes in Samarbeidsportalen. + +## Setting up the Maskinporten integration + +A maskinporten client also known as a Maskinporten integration can generate tokens with a set of scopes on request. +The token can then be exchanged for an Altinn token and used to gain access to the API. + +Below are guides on how to set up a new Maskinporten integration that generates tokens with the required scope. + + +{{% expandlarge id="guide-mp-int-api" header="Guide on how to register a new Maskinporten integration through API" %}} + +Please reference [Maskinporten's own documentation](https://docs.digdir.no/docs/Maskinporten/maskinporten_guide_apikonsument) +on registering a new integration through their self service API. + +{{% /expandlarge %}} + + +{{% expandlarge id="guide-mp-int-samarbeid" header="Guide on how to register a new Maskinporten integration in Samarbeidsportalen" %}} +{{% insert "content/app/guides/shared/maskinporten-integration/maskinporten-integration-samarbeidsportal.md" %}} +{{% /expandlarge %}} + diff --git a/content/notifications/send-notifications/get-started/user-guide/_index.en.md b/content/notifications/send-notifications/get-started/user-guide/_index.en.md new file mode 100644 index 00000000000..61a6e2d0c85 --- /dev/null +++ b/content/notifications/send-notifications/get-started/user-guide/_index.en.md @@ -0,0 +1,53 @@ +--- +title: User guide +linktitle: User guide +weight: 10 +description: "A user guide for the notification service" +--- + +{{% notice info %}} +We are working on providing you with new and updated guidelines on usage of Altinn Notification. +In the meantime existing guidelines for sending notifications through Altinn 2 also apply to Altinn Notfications. + + +[Please familiarize yourself with existing documentation and guidelines](https://altinn.github.io/docs/utviklingsguider/varsling/) +{{% /notice %}} + + + + + diff --git a/static/swagger/altinn-notifications-v1.json b/static/swagger/altinn-notifications-v1.json new file mode 100644 index 00000000000..8a0cf86b1ba --- /dev/null +++ b/static/swagger/altinn-notifications-v1.json @@ -0,0 +1,612 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Altinn.Notifications", + "version": "1.0" + }, + "paths": { + "/orders/email": { + "post": { + "tags": [ + "EmailNotificationOrders" + ], + "summary": "Add an email notification order.", + "description": "The API will accept the request after som basic validation of the request.\r\nThe system will also attempt to verify that it will be possible to fulfill the order.", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailNotificationOrderRequestExt" + } + } + } + }, + "responses": { + "401": { + "description": "Caller is unauthorized" + }, + "403": { + "description": "Caller is not authorized to access the requested resource" + }, + "202": { + "description": "The notification order was accepted", + "headers": { + "Location": { + "description": "Link to access the newly created notification order.", + "schema": { + "type": "string", + "description": "Link to access the newly created notification order.", + "format": "" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OrderIdExt" + } + } + } + }, + "400": { + "description": "The notification order is invalid", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ValidationProblemDetails" + } + } + } + } + } + } + }, + "/orders/{id}/notifications/email": { + "get": { + "tags": [ + "EmailNotifications" + ], + "summary": "Endpoint for retrieving a summary of all email notifications related to an order", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The order id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "401": { + "description": "Caller is unauthorized" + }, + "403": { + "description": "Caller is not authorized to access the requested resource" + }, + "200": { + "description": "The notification order was accepted", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmailNotificationSummaryExt" + } + } + } + }, + "404": { + "description": "No notification order mathching the id was found" + } + } + } + }, + "/orders/{id}": { + "get": { + "tags": [ + "Orders" + ], + "summary": "Endpoint for retrieving an order by id.", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The order id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "401": { + "description": "Caller is unauthorized" + }, + "403": { + "description": "Caller is not authorized to access the requested resource" + }, + "200": { + "description": "The notification order matching the provided id was retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationOrderExt" + } + } + } + }, + "404": { + "description": "No order with the provided id was found" + } + } + } + }, + "/orders": { + "get": { + "tags": [ + "Orders" + ], + "summary": "Endpoint for retrieving an order by senders reference", + "parameters": [ + { + "name": "sendersReference", + "in": "query", + "description": "The senders reference", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "401": { + "description": "Caller is unauthorized" + }, + "403": { + "description": "Caller is not authorized to access the requested resource" + }, + "200": { + "description": "The list of notification orders matching the provided senders ref was retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationOrderListExt" + } + } + } + } + } + } + }, + "/orders/{id}/status": { + "get": { + "tags": [ + "Orders" + ], + "summary": "Endpoint for retrieving an order with processing and notificatio status by id", + "parameters": [ + { + "name": "id", + "in": "path", + "description": "The order id", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "401": { + "description": "Caller is unauthorized" + }, + "403": { + "description": "Caller is not authorized to access the requested resource" + }, + "200": { + "description": "The notification order matching the provided id was retrieved successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotificationOrderWithStatusExt" + } + } + } + }, + "404": { + "description": "No order with the provided id was found" + } + } + } + } + }, + "components": { + "schemas": { + "EmailContentTypeExt": { + "enum": [ + "Plain", + "Html" + ], + "type": "string", + "description": "Enum describing available content types for an email." + }, + "EmailNotificationOrderRequestExt": { + "type": "object", + "properties": { + "subject": { + "type": "string", + "description": "Gets or sets the subject of the email", + "nullable": true + }, + "body": { + "type": "string", + "description": "Gets or sets the body of the email", + "nullable": true + }, + "contentType": { + "$ref": "#/components/schemas/EmailContentTypeExt" + }, + "requestedSendTime": { + "type": "string", + "description": "Gets or sets the send time of the email. Defaults to UtcNow.", + "format": "date-time" + }, + "sendersReference": { + "type": "string", + "description": "Gets or sets the senders reference on the notification", + "nullable": true + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecipientExt" + }, + "description": "Gets or sets the list of recipients", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class representing an email notiication order request" + }, + "EmailNotificationStatusExt": { + "type": "object", + "properties": { + "links": { + "$ref": "#/components/schemas/NotificationResourceLinksExt" + }, + "generated": { + "type": "integer", + "description": "Gets or sets the number of generated notifications", + "format": "int32" + }, + "succeeded": { + "type": "integer", + "description": "Gets or sets the number of succeeeded notifications", + "format": "int32" + } + }, + "additionalProperties": false, + "description": "A class representing a status overview for email notifications" + }, + "EmailNotificationSummaryExt": { + "type": "object", + "properties": { + "orderId": { + "type": "string", + "description": "The order id", + "format": "uuid" + }, + "sendersReference": { + "type": "string", + "description": "The senders reference", + "nullable": true + }, + "generated": { + "type": "integer", + "description": "The number of generated email notifications", + "format": "int32" + }, + "succeeded": { + "type": "integer", + "description": "The number of email notifications that were sent successfully", + "format": "int32" + }, + "notifications": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailNotificationWithResultExt" + }, + "description": "A list of notifications with send result", + "nullable": true + } + }, + "additionalProperties": false, + "description": "A class representing an email notification summary" + }, + "EmailNotificationWithResultExt": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The notification id", + "format": "uuid" + }, + "succeeded": { + "type": "boolean", + "description": "Boolean indicating if the sending of the notification was successful" + }, + "recipient": { + "$ref": "#/components/schemas/RecipientExt" + }, + "sendStatus": { + "$ref": "#/components/schemas/StatusExt" + } + }, + "additionalProperties": false, + "description": "EmailNotificationWithResultExt class" + }, + "EmailTemplateExt": { + "type": "object", + "properties": { + "fromAddress": { + "type": "string", + "description": "Gets the from adress of emails created by the template", + "nullable": true + }, + "subject": { + "type": "string", + "description": "Gets the subject of emails created by the template", + "nullable": true + }, + "body": { + "type": "string", + "description": "Gets the body of emails created by the template", + "nullable": true + }, + "contentType": { + "$ref": "#/components/schemas/EmailContentTypeExt" + } + }, + "additionalProperties": false, + "description": "Template for an email notification" + }, + "NotificationChannelExt": { + "enum": [ + "Email" + ], + "type": "string", + "description": "Enum describing available notification channels." + }, + "NotificationOrderExt": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true + }, + "creator": { + "type": "string", + "nullable": true + }, + "sendersReference": { + "type": "string", + "nullable": true + }, + "requestedSendTime": { + "type": "string", + "format": "date-time" + }, + "created": { + "type": "string", + "format": "date-time" + }, + "notificationChannel": { + "$ref": "#/components/schemas/NotificationChannelExt" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RecipientExt" + }, + "description": "Gets or sets the list of recipients", + "nullable": true + }, + "emailTemplate": { + "$ref": "#/components/schemas/EmailTemplateExt" + }, + "links": { + "$ref": "#/components/schemas/OrderResourceLinksExt" + } + }, + "additionalProperties": false, + "description": "A class representing a registered notification order." + }, + "NotificationOrderListExt": { + "type": "object", + "properties": { + "count": { + "type": "integer", + "description": "Gets or sets the number of orders in the list", + "format": "int32" + }, + "orders": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NotificationOrderExt" + }, + "description": "Gets or sets the list of notification orders", + "nullable": true + } + }, + "additionalProperties": false, + "description": "A class representing a list of notification order." + }, + "NotificationOrderWithStatusExt": { + "type": "object", + "properties": { + "id": { + "type": "string", + "nullable": true + }, + "sendersReference": { + "type": "string", + "nullable": true + }, + "requestedSendTime": { + "type": "string", + "format": "date-time" + }, + "creator": { + "type": "string", + "nullable": true + }, + "created": { + "type": "string", + "format": "date-time" + }, + "notificationChannel": { + "$ref": "#/components/schemas/NotificationChannelExt" + }, + "processingStatus": { + "$ref": "#/components/schemas/StatusExt" + }, + "notificationsStatusSummary": { + "$ref": "#/components/schemas/NotificationsStatusSummaryExt" + } + }, + "additionalProperties": false, + "description": "A class representing a registered notification order with status information." + }, + "NotificationResourceLinksExt": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "Gets or sets the self link", + "nullable": true + } + }, + "additionalProperties": false, + "description": "A class representing a set of resource links of a notification" + }, + "NotificationsStatusSummaryExt": { + "type": "object", + "properties": { + "email": { + "$ref": "#/components/schemas/EmailNotificationStatusExt" + } + }, + "additionalProperties": false, + "description": "A class representing a summary of status overviews of all notification channels" + }, + "OrderIdExt": { + "type": "object", + "properties": { + "orderId": { + "type": "string", + "description": "The order id", + "format": "uuid" + } + }, + "additionalProperties": false, + "description": "A class representing a container for an order id." + }, + "OrderResourceLinksExt": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "Gets or sets the self link", + "nullable": true + }, + "status": { + "type": "string", + "description": "Gets or sets the status link", + "nullable": true + }, + "notifications": { + "type": "string", + "description": "Gets or sets the notifications link", + "nullable": true + } + }, + "additionalProperties": false, + "description": "A class representing a set of resource links of a notification order." + }, + "RecipientExt": { + "type": "object", + "properties": { + "emailAddress": { + "type": "string", + "description": "Gets or sets the email address of the recipient", + "nullable": true + } + }, + "additionalProperties": false, + "description": "Class representing a notification recipient" + }, + "StatusExt": { + "type": "object", + "properties": { + "status": { + "type": "string", + "description": "Gets or sets the status", + "nullable": true + }, + "description": { + "type": "string", + "description": "Gets or sets the description", + "nullable": true + }, + "lastUpdate": { + "type": "string", + "description": "Gets or sets the date time of when the status was last updated", + "format": "date-time" + } + }, + "additionalProperties": false, + "description": "A class representing a status summary" + }, + "ValidationProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + }, + "errors": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "nullable": true, + "readOnly": true + } + }, + "additionalProperties": { } + } + } + } + } \ No newline at end of file