From 393eca3144edbd8fdad4be867b63c5b2dd9e0d5c Mon Sep 17 00:00:00 2001 From: Kjetil Valle Date: Tue, 22 Sep 2026 12:02:47 +0200 Subject: [PATCH 1/2] Documentation for v17 --- docs/_config.yml | 3 + docs/_v16_x/index.html | 2 +- docs/_v17_x/1_client_config.md | 71 +++++ docs/_v17_x/2_send.md | 467 +++++++++++++++++++++++++++++++++ docs/_v17_x/3_receive.md | 60 +++++ docs/_v17_x/4_archive.md | 240 +++++++++++++++++ docs/_v17_x/5_batch.md | 94 +++++++ docs/_v17_x/index.html | 15 ++ 8 files changed, 951 insertions(+), 1 deletion(-) create mode 100644 docs/_v17_x/1_client_config.md create mode 100644 docs/_v17_x/2_send.md create mode 100644 docs/_v17_x/3_receive.md create mode 100644 docs/_v17_x/4_archive.md create mode 100644 docs/_v17_x/5_batch.md create mode 100644 docs/_v17_x/index.html diff --git a/docs/_config.yml b/docs/_config.yml index 590e168d..43dee6fd 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -34,6 +34,9 @@ collections: v16_x: output: true permalink: /v16.x/ + v17_x: + output: true + permalink: /v17.x/ # list of additional links on the right of the top menu headerLinks: diff --git a/docs/_v16_x/index.html b/docs/_v16_x/index.html index fef277ee..1dcdf55b 100644 --- a/docs/_v16_x/index.html +++ b/docs/_v16_x/index.html @@ -1,7 +1,7 @@ --- identifier: index layout: default -redirect_from: / +redirect_from: --- diff --git a/docs/_v17_x/1_client_config.md b/docs/_v17_x/1_client_config.md new file mode 100644 index 00000000..6b2a1378 --- /dev/null +++ b/docs/_v17_x/1_client_config.md @@ -0,0 +1,71 @@ +--- +title: Instantiate and configure the client +identifier: client_config +layout: default +--- + +### Install + +The client library is available on the [Maven Central Repository](https://central.sonatype.com/artifact/no.digipost/digipost-api-client-java). +Copy the ``-snippet from that website and put it in your pom.xml file. +Make sure to use the latest version available. + +This client requires Java 11 and `jakarta.xml-bind`. + +### Configure for production use + +To instantiate the client instance you need to supply your assigned _broker ID_, which +is set up to be permitted to integrate with the Digipost API. In addition, you must create +a `Signer` instance, e.g. by using a `.p12` file to read the private key to use for signing +the API requests. + +```java +SenderId senderId = SenderId.of(123456); + +Signer signer; +try (InputStream sertifikatInputStream = Files.newInputStream(Paths.get("certificate.p12"))) { + signer = Signer.usingKeyFromPKCS12KeyStore(sertifikatInputStream, "TheSecretPassword"); +} + +DigipostClient client = new DigipostClient( + DigipostClientConfig.newConfiguration().build(), senderId.asBrokerId(), signer); +``` + +This example will configure the client to communicate with the regular Digipost production +environment. + + +### Other environments + +If you have access to other environments, this can be configured using +`DigipostClientConfig`, e.g: + +```java +URI apiUri = URI.create("https://api.test.digipost.no"); +DigipostClientConfig config = DigipostClientConfig.newConfiguration().digipostApiUri(apiUri).build(); +``` + +#### Norsk Helsenett (NHN) + +The Digipost API is accessible from both internet and Norsk Helsenett (NHN). Both entry points use +the same API, the only difference is the base URL. + +```java +URI nhnApiUri = URI.create("https://api.nhn.digipost.no"); +DigipostClientConfig config = DigipostClientConfig.newConfiguration().digipostApiUri(nhnApiUri).build(); +``` + +### Custom HTTP client + +Since version 17, the client uses Apache HttpClient 5 internally. If you need control over the +underlying HTTP client (e.g. connection pooling or proxy settings), you can supply your own +`HttpClientBuilder`: + +```java +HttpClientBuilder clientBuilder = HttpClientFactory.createDefaultBuilder(); + +DigipostClient client = new DigipostClient( + DigipostClientConfig.newConfiguration().build(), senderId.asBrokerId(), signer, clientBuilder); +``` + + diff --git a/docs/_v17_x/2_send.md b/docs/_v17_x/2_send.md new file mode 100644 index 00000000..5b27f3c4 --- /dev/null +++ b/docs/_v17_x/2_send.md @@ -0,0 +1,467 @@ +--- +title: Send messages +identifier: send +layout: default +--- + +The Java client library also contains some +[example code](https://github.com/digipost/digipost-api-client-java/tree/master/src/test/java/no/digipost/api/client/eksempelkode) +which include similar examples. + +## Send a message to a recipient + +To send a message to a recipient in Digipost, you need to choose a way to identify +the recipient, instantiate a primary `Document` and the containing `Message`. Finally +these are given to the client as well as the content of the document as an `InputStream`. +The actual API communication will happen when you invoke the `.send()` method. + +### Send using a personal identification number for the recipient + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +### Other recipient types + +There are other recipient types available to identify recipients of messages. Note that +some recipient types may require special permissions to be set up in order to be used. +E.g. bank account number requires such permissions, and are _not_ enabled by default. + +```java +NameAndAddress nameAndAddress = new NameAndAddress("Ola Nordmann", "Gateveien 1", "Oppgang B", "0001", "Oslo"); +``` + +```java +BankAccountNumber accountNum = new BankAccountNumber("12345123451"); +``` + +### Multiple documents in one message + +A message is required to have at least one document, the _primary_ document. Additional +documents can also be included as _attachments_. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF); + +Document attachment1 = new Document(UUID2, "Attachment1 subject", FileType.PDF); +Document attachment2 = new Document(UUID3, "Attachment2 subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .attachments(attachment1, attachment2) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("main_document_content.pdf"))) + .addContent(attachment1, Files.newInputStream(Paths.get("attachment1_content.pdf"))) + .addContent(attachment2, Files.newInputStream(Paths.get("attachment2_content.pdf"))) + .send(); +``` +## Send invoice + +```java + +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +//Previous versions of the client uses what is called an Invoice Document. With the release of v15 this has been +//removed. Now we use digipost data types instead. +Document invoice = new Document( + UUID1 + , "Invoice subject" + , FileType.PDF + , new Invoice(null, ZonedDateTime.of(2022, 5, 5, 0, 0, 0, 0, ZoneId.of("Europe/Oslo")), new BigDecimal("1.20"), "704279604", "82760100435") +); + +Message message = Message.newMessage("messageId", invoice) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(invoice, Files.newInputStream(Paths.get("invoice.pdf"))) + .send(); + + +``` + +## Send a message with SMS notification + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +// The time the SMS is sent out can be based on time after letter is delivered +// or a specific date. This example specifies that the SMS should be sent out +// one day after the letter i delivered. +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, + new SmsNotification(1), null, + AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + + +## Send letter with fallback to print + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF); + +PrintDetails printDetails = new PrintDetails( + new PrintRecipient("Ola Nordmann", new NorwegianAddress("Prinsensveien 123", "0460", "Oslo")), + new PrintRecipient("Norgesbedriften", new NorwegianAddress("Akers Àle 2", "0400", "Oslo")), + PrintDetails.PrintColors.MONOCHROME, PrintDetails.NondeliverableHandling.RETURN_TO_SENDER); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(new MessageRecipient(pin, printDetails)) + .build(); + +// addContent can also take a third parameter which is the file/ipnput stream that will be used only +// for physical mail. The below example uses the same file/input stream in both channels (digital and physical mail) +MessageDelivery result = client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +## Send letter with html + +If you want to be able to send HTML-documents you first need to contact Digipost to activate +the feature for your broker/sender. Then it is just matter of specifing HTML as the filetype +and serve an html-file as content. +Bevare that there are strict rules to what is allowed. These rules are quite verbose. But +we have open sourced the html validator and santizer software we use to make sure that +html conforms to these rules. Check out [https://github.com/digipost/digipost-html-validator](digipost-html-validator). +If you preencrypt your document, this validation will be performed in the client instead of the +server so that you can be confident that you recipient will be able to open the document. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.HTML); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.html"))) + .send(); +``` + + +## Send letter with higher security level + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +// TWO_FACTOR - require BankID or BuyPass authentication to open letter +// SENSITIVE - Sender information and subject will be hidden until Digipost user +// is logged in at the appropriate authentication level +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, null, null, + AuthenticationLevel.TWO_FACTOR, SensitivityLevel.SENSITIVE); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream("content.pdf"))) + .send(); +``` + +## Send a message with extra computer readable data + +With version 7 of the Digipost API, messages can have extra bits of computer readable information that +allows the creation of a customized, dynamic user experience for messages in Digipost. These extra bits of +information are referred to as instances of "Datatypes". + +All datatypes are sent in the same way. Each document can accommodate one datatype-object. An exhaustive list of +available datatypes and their documentation can be found at +[digipost/digipost-data-types](https://github.com/digipost/digipost-data-types). + +For convenience, all datatypes are available as java-classes in the java client library. + +### Datatype Appointment + +In this example, an appointment-datatype that allows for certain calendar-related functions is added to a +message. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +ZonedDateTime startTime = ZonedDateTime.of(2017, 10, 23, 10, 0, 0, 0, ZoneId.systemDefault()); +AppointmentAddress address = new AppointmentAddress("Storgata 1", "0001", "Oslo"); +Info preparation = new Info("Preparation", "Please do not eat or drink 6 hours prior to examination"); +Info about = new Info("About Oslo X-Ray center", "Oslo X-Ray center is specialized in advanced image diagnostics..."); +List info = Arrays.asList(preparation, about); + +Appointment appointment = new Appointment( + startTime, startTime.plusMinutes(30), "Please arrive 15 minutes early", + "Oslo X-Ray center", address, "Lower back examination", info, Language.EN); + +Document primaryDocument = new Document(messageUUID, "X-Ray appointment", FileType.PDF, appointment); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +### Datatype ExternalLink + +This Datatype enhances a message in Digipost with a button which sends the user to an external site. The button +can optionally have a deadline, a description and a custom text. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +URI externalLinkTarget = URI.create("https://example.org/loan-offer/uniqueCustomerId/"); +ZonedDateTime deadline = ZonedDateTime.of(2018, 10, 23, 10, 0, 0, 0, ZoneId.systemDefault()); + +ExternalLink externalLink = new ExternalLink(externalLinkTarget, deadline, + "Please read the terms, and use the button above to accept them. The offer expires at 23/10-2018 10:00.", + "Accept offer"); + +Document primaryDocument = new Document(messageUUID, "Housing loan application", FileType.PDF, externalLink); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream("terms.pdf"))) + .send(); +``` + +### Datatype ShareDocumentsRequest + +This datatype enables sharing of documents between an organisation and a Digipost end user. The organisation +first sends a message of datatype ShareDocumentsRequest, to which the end user can attach a list of documents. When +new documents are shared, a DocumentEvent is generated. The organisation can retrieve the status of their +ShareDocumentsRequest. If documents are shared and the sharing is not cancelled, the documents can either be downloaded +or viewed on the digipostdata.no domain. Active requests can be cancelled both by the end user and the organisation. + +The `purpose` attribute of the ShareDocumentsRequest should briefly explain why the sender organisation want to gain +access to the relevant documents. This text will be displayed prominently, and should contain the information necessary +for the user to make an informed choice. The primary document should contain a more detailed explanation. + +#### Send ShareDocumentsRequest +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +ShareDocumentsRequest shareDocumentsRequest = new ShareDocumentsRequest( + Duration.ofDays(60).toSeconds(), + "We require to see your six latest pay slips in order to give you a loan." +); + +Document primaryDocument = new Document(messageUUID, "Request to access your latest payslips", FileType.PDF, shareDocumentsRequest); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Path.of("longer-desc-of-sharing-purpose.pdf"))) + .send(); +``` + +#### Discover new shared documents +The sender organisation can discover new shared documents by polling document events regularly. Use the `uuid` attribute +of the DocumentEvent to match with the `messageUUID` of the origin ShareDocumentsRequest: + +```java +List sharedDocumentEvents = digipostClient.getDocumentEvents(brokerId.asSenderId(), ZonedDateTime.now().minus(Duration.ofDays(1)), ZonedDateTime.now(), 0, 100); + .getEvents() + .stream() + .filter(event -> DocumentEventType.SHARE_DOCUMENTS_REQUEST_DOCUMENTS_SHARED.equals(event.getType())) + .toList() +``` + +NB: events are attached to the broker, _not_ each individual sender. + +#### Get state of ShareDocumentsRequest + +```java +ShareDocumentsRequestState sharedDocumentsRequestState = sendClient.getShareDocumentsRequestState(senderId, uuid); +``` + +#### Get documents + +Each `SharedDocument` has attributes describing the document and its origin. If `SharedDocumentOrigin` is of type +`OrganisationOrigin`, the corresponding document was received by the end user through Digipost from the organisation +with the provided organisation number. If the origin is of type `PrivatePersonOrigin`, the document was received either +from another end user or uploaded by the user itself. + +Get a single document as stream: + +```java +SharedDocument doc1 = sharedDocumentsRequestState.getSharedDocuments().get(0); +InputStream inputStream = sendClient.getSharedDocumentContentStream(doc1.getSharedDocumentContentStream()); +``` + +Get link to view a single document on digipostdata.no + +```java +SharedDocumentContent sharedDocumentContent = sendClient.getSharedDocumentContent(doc1.getSharedDocumentContent()); +String uri = sharedDocumentContent.getUri(); +``` + +#### Stop sharing + +```java +client.stopSharing(senderId, sharedDocumentsRequestState.stopSharing()) +``` + + + +## Send message with request for registration + +It is possible to send a message to a person, who does not have a Digipost account, where the message triggers an SMS notification with a request for registration. The SMS notification says that if they register for a Digipost account the document will be delivered digitally. The actual content of the SMS notification is set manually by Digipost. If the user does not register for a Digipost account within the defined deadline, the document will either be delivered as physical mail or not at all. + +The phone number provided SHOULD include the country code (i.e. +47). If the phone number does not start with either `"+"`, `"00"` or `"011"`, we will prepend `"+47"` if and only if the phone number string is 8 characters long. If this is not the case, the request is rejected. + +### Request for registration with physical mail as fallback + +In this case the document will be delivered as physical mail if the recipient has not registered for a Digipost account by the defined deadline. + +```java +UUID documentId = UUID.randomUUID(); +Document document = new Document(documentId, "Hello!", FileType.PDF); + +PrintDetails printDetails = new PrintDetails(RECIPIENT, RETURN_RECIPIENT); + +RequestForRegistration requestForRegistration = new RequestForRegistration( +// Deadline for when the recipent can no longer register a Digipost account + ZonedDateTime.now().plus(6, ChronoUnit.HOURS), +// Phone number that will be used for the SMS notification. Make sure the country code is included, starting with "+". + new PhoneNumber("+4712345678"), + null, + printDetails +); + +UUID messageId = UUID.randomUUID(); +Message message = Message.newMessage(messageId.toString(), document) + .recipient(new PersonalIdentificationNumber("12345678901")) + .senderId(senderId) + .requestForRegistration(requestForRegistration) + .build(); + +MessageDelivery delivery = sendClient.createMessage(message) + .addContent(document, Contents.filFraDisk("gyldig-for-print.pdf")) + .send(); + +System.out.println("status: " + delivery.getStatus()); +System.out.println("channel: " + delivery.getChannel()); + +// If the recipient does not have a Digipost account already, the value of `getChannel()` will be `null`, otherwise `Channel.DIGIPOST`. +``` + +### Request for registration without physical mail as fallback + +If the sender wishes to send the document as physical mail through its own service (if the recipient does not register a Digipost account), print details must not be included. + +```java +UUID documentId = UUID.randomUUID(); +Document document = new Document(documentId, "Hello!", FileType.PDF); + +RequestForRegistration requestForRegistration = new RequestForRegistration( +// Deadline for when the recipent can receive the document digitally right after Digipost account registration. + ZonedDateTime.now().plus(6, ChronoUnit.HOURS), +// Phone number that will be used for the SMS notification + new PhoneNumber("+4712345678"), + null, + null +); + +UUID messageId = UUID.randomUUID(); +Message message = Message.newMessage(messageId.toString(), document) + .recipient(new PersonalIdentificationNumber("12345678901")) + .senderId(senderId) + .requestForRegistration(requestForRegistration) + .build(); + +MessageDelivery delivery = sendClient.createMessage(message) + .addContent(document, Contents.filFraDisk("gyldig-for-print.pdf")) + .send(); +``` +It is up to the sender to then check if the document has been delivered digitaly prior to the defined deadline. After the deadline has passed the document will not be delivered if recipient registers for a Digipost account. The delivery status can be checked with the following: + +```java +// The messageId would be the UUID that was used when the originating message was sent +UUID messageId = UUID.fromString("efe11ce1-dfce-459a-865b-52dc313dbcb9"); +DocumentStatus status = sendClient.getDocumentStatus(senderId, messageId); +System.out.println("Status: " + status.status); +System.out.println("Channel: " + status.channel); +``` +The following statuses are possible: + +* NOT_DELIVERED +* DELIVERED + * When the document is delivered the channel can be either "DIGITAL" or "PRINT" + +## Identify user based on personal identification number + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Identification identification = new Identification(pin); + +IdentificationResult identificationResult = client.identifyRecipient(identification); +``` + + + +## Create Digipost User Accounts + +Create new or activate existing Digipost user account. + +```java +SenderId sender = SenderId.of(123456); +UserInformation user = new UserInformation( + new NationalIdentityNumber("01013300001"), + new PhoneNumber("+4799998888"), + new EmailAddress("user@example.com") +); + +UserAccount userAccount = client.createOrActivateUserAccount(sender, user); + +DigipostAddress digipostAddress = userAccount.getDigipostAddress(); +EncryptionKey encryptionKey = userAccount.getEncryptionKey(); +``` + + +## Get Status of Document + +After you have sent a message, you can get the _status_ of a document with `getDocumentStatus`. +The response includes basic information about the delivery, like the channel the document was delivered to, as well as +delivery times and more. + +```java +DocumentStatus status = client.getDocumentStatus(senderId, documentUuid); + +System.out.println("Status: " + status.status); +System.out.println("Channel: " + status.channel); +``` diff --git a/docs/_v17_x/3_receive.md b/docs/_v17_x/3_receive.md new file mode 100644 index 00000000..71a49b2f --- /dev/null +++ b/docs/_v17_x/3_receive.md @@ -0,0 +1,60 @@ +--- +title: Receive messages +identifier: inbox +layout: default +--- + +The inbox API makes it possible for an organisation to manage messages received in Digipost. + + + +## Get documents in inbox + +The inbox call outputs a list of documents ordered by delivery time. `Offset` is the start index of the list, and `limit` is the max number of documents to be returned. The `offset` and `limit` is therefore not in any way connected to `InboxDocument.id`. + +The values `offset` and `limit` is meant for pagination so that one can fetch 100 and then the next 100. + + +```java +//get first 100 documents +Inbox first100 = client.getInbox(SenderId.of(123456), 0, 100); + +//get next 100 documents +Inbox next100 = client.getInbox(SenderId.of(123456), 100, 100); +``` + +We have now fetched the 200 newest inbox documents. As long as no new documents are received, the two API-calls shown above will always return the same result. If we now receive a new document, this will change. The first 100 will now contain 1 new document and 99 documents we have seen before. This means that as soon as you stumble upon a document you have seen before you can stop processing, given that all the following older ones have been processed. + +## Download document content + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); + +System.out.println("Content type is: " + documentMetadata.getContentType()); +InputStream documentContent = client.getInboxDocumentContent(documentMetadata); +``` + +## Delete document + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); + +client.deleteInboxDocument(documentMetadata); +``` + +## Download attachment content + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); +InboxDocument attachment = documentMetadata.getAttachments().get(0); + +System.out.println("Content type is: " + attachment.getContentType()); +InputStream attachmentContent = client.getInboxDocumentContent(attachment); +``` + diff --git a/docs/_v17_x/4_archive.md b/docs/_v17_x/4_archive.md new file mode 100644 index 00000000..5df831a8 --- /dev/null +++ b/docs/_v17_x/4_archive.md @@ -0,0 +1,240 @@ +--- +title: Archive functionality +identifier: archive +layout: default +--- + +The archive API makes it possible for an organisation to manage documents in archives. These files are kept in separate +archives, and the files belong to the sender organisation. + + +## Archive documents to an archive + +Let's say you want to archive two documents eg. an invoice and an attachment and +you want to have some kind of reference to both documents. You can do that +by describing the two documents with `ArchiveDocument`. Then you need to create an archive +and add the documents to the archive. In the following example we use a default archive. +You then need to send this archive and attach the actual files to the request by linking +the `ArchiveDocument` with a file and send. + +```java +// 1. We describe the documents +final ArchiveDocument invoice = new ArchiveDocument( + UUID.randomUUID() + , "invoice_123123.pdf" + , "pdf" + , "application/pdf" +); +final ArchiveDocument attachment = new ArchiveDocument( + UUID.randomUUID() + , "attachment_123123.pdf" + , "pdf" + , "application/pdf" +); + +// 2. We create an archive and add the documents to it +Archive archive = Archive.defaultArchive() + .documents(invoice, attachment) + .build(); + +// 3. We create a request to archive the files with reference between the ArchiveDocument and the actual file +client.archiveDocuments(archive) + .addFile(invoice, readFileFromDisk("invoice_123123.pdf")) + .addFile(attachment, readFileFromDisk("attachment_123123.pdf")) + .send(); +``` + +## Get a list of archives + +An organisation can have many archives, or just the default unnamed archive. That is up to +your design wishes. To get a list of the archives for a given Sender, you can do this: + +```java +//get a list of the archives +Archives archives = client.getArchives(SenderId.of(123456)); +``` + +The class `Archives` holds a list of `Archive` where you can see the name of the archive. + +## Iterate documents in an archive + +You _can_ get content of an archive with paged requests. Under is an example of how to iterate +an archive. However, it's use is strongly discouraged because it leads to the idea that +an archive can be iterated. We expect an archive to possibly reach many million rows so the iteration +will possibly give huge loads. On the other hand being able to dump all data is a necessary feature of any archive. + +_Please use fetch document by UUID or referenceID instead to create functionality on top of the archive._ +You should on your side know where and how to get a document from an archive. You do this by knowing where +you put a file you want to retrieve. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocuments() + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` +## Archive Document attributes + +You can add optional attributes to documents. An attribute is a key/val string-map that describe documents. You can add +up to 15 attributes pr. archive document. The attribute key and value is case sensitive. + +```java +final ArchiveDocument invoice = new ArchiveDocument( + UUID.randomUUID() + , "invoice_123123.pdf" + , "pdf" + , "application/pdf" +).withAttribute("INR", "123123").withAttribute("custid", "4321"); +``` + +The attributes can be queried, so that you can get an iterable list of documents. + +```java +final Archives archives = digipostClient.getArchives(); +Archive current = archives.getArchives().get(0); + +final List documents = current.getNextDocumentsWithAttributes(Map.of("INR", "123123", "custid", "4321")) + .map(digipostClient::getArchiveDocuments) + .map(Archive::getDocuments).orElse(emptyList()); + +// This prints to total content of the list of documents +System.out.println(documents); +``` + +We recommend that the usage of attributes is made such that the number of results for a query on attributes +is less than 100. If you still want that, it's ok, but you need to iterate the pages to get all the results. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocumentsWithAttributes(Map.of("INR", "123123")) + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` + +You can now also select by date or by attributes by date. Date is when the documents has been stored in Digipost archive. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocumentsWithAttributesByDate(Map.of("INR", "123123"), OffsetDateTime.now().minus(Period.ofDays(4)), OffsetDateTime.now()) + //current = defaultArchive.getNextDocumentsByDate(OffsetDateTime.now().minus(Period.ofDays(4)), OffsetDateTime.now()); + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` + + +## Get documents by referenceID + +You can retrieve a set of documents by a given referenceID. You will then get the documents listed in their respective +archives in return. + +```java +final Archives archives = client.getArchiveDocumentsByReferenceId("REFERENCE_ID"); +``` + +## Get documents by uuid + +You can retrieve a set of documents by the UUID that you give the document when you archive it. In the example above +we use `UUID.randomUUID()` to generate an uuid. You can either store that random uuid in your database for +retrieval later, or you can generate a deterministic uuid based on your conventions for later retrieval. + +You will get in return an instance of `Archive` which contains information on the archive the document is contained in +and the actual document. From this you can fetch the actual document. + +```java +final UUID myConvensionUUID = UUID.fromString("vedlegg:123123:txt"); + +final Archive archiveWithDocument = client.getArchiveDocumentByUuid(myConvensionUUID); +``` + +## Get content of a document as a single-use link + +You can get the actual content of a document after you have retrieved the archive document. Below is an example of how +you can achieve this with a given `ArchiveDocument`. In the resulting `ArchiveDocumentContent`, you will get a url to +the content which expires after 30 seconds. + +```java +// This ArchiveDocument must be retrieved beforehand using one of the methods described above +final ArchiveDocument archiveDocument; + +URI getDocumentContentURI = archiveDocument.getDocumentContent().orElseThrow(); +ArchiveDocumentContent content = client.getArchiveDocumentContent(getDocumentContentURI); +``` + +## Get content of a document as a stream + +In addition to a single-use link, you also have the option to retrieve the content of a document directly as a +byte stream. + +```java +// This ArchiveDocument must be retrieved beforehand using one of the methods described above +final ArchiveDocument archiveDocument; + +URI getDocumentContentStreamURI = archiveDocument.getDocumentContentStream().orElseThrow(); +InputStream content = client.getArchiveDocumentContentStream(getDocumentContentStreamURI); +``` + +## Update document attributes and/or referenceID + +You can add an attribute or change an attribute value, but not delete an attribute. You can however set the value +to empty string. The value of the field for referenceID can be changed as well. + +```java +final UUID myConvensionUUID = UUID.fromString("vedlegg:123123:txt"); + +final Archive archiveWithDocument = client.getArchiveDocumentByUuid(myConvensionUUID); + +archiveDocument.withReferenceId("My final referenceId").withAttribute("Status", "COMPLETED_PROCESS"); + +client.updateArchiveDocument(archiveDocument, archiveDocument.getUpdate()); +``` + +## Using archive as a broker + +It is possible to be a broker for an actual sender. Most of the api described above also support +the use of SenderId to specify who you are archiving for. + +eg.: +```java +client.getArchives(SenderId.of(123456)) +client.getArchiveDocumentsByReferenceId(SenderId.of(123456), "REFERENCE_ID"); +client.getArchiveDocumentByUuid(SenderId.of(123456), myConvensionUUID); + + +Archive archive = Archive.defaultArchive() + .documents(faktura) + .senderId(SenderId.of(123456)) + .build(); +``` diff --git a/docs/_v17_x/5_batch.md b/docs/_v17_x/5_batch.md new file mode 100644 index 00000000..1732ccc4 --- /dev/null +++ b/docs/_v17_x/5_batch.md @@ -0,0 +1,94 @@ +--- +title: Batch functionality +identifier: batch +layout: default +--- + +The batch API makes it possible for an organisation to manage sending of several messages, both to Digipost and Print, in a +batch. The batch will then be delivered all at the same time atomically. If it has not been sendt yet, the batch can +also be cancelled. + +## Start and get information about a batch + +A batch is identified by a UUID specified by you. To create a batch you send a uuid to the Digipost api. In return~~~~ +you get a batch object with a status and som links for complete and cancel. + +```java +// Create an UUID +final UUID batchUUID = UUID.randomUUID(); + +// Create the batch +final Batch batch = client.createBatch(batchUUID); + +// At any time, read information about the batch +final Batch batchInformation = client.getBatchInformation(batchUUID); + +``` + +A batch can have 4 states: +`CREATED`, `NOT_COMMITTED`, `COMMITTED`, `DONE` + +CREATED is an initial state. NOT_COMMITTED is the state given when there has been added messages to the batch. +COMMITTED is a state that can occur if the batch has to be processed asynchronously. DONE means that the batch has +been commited. Digipost messages are delivered at commit time and Print messages will be delivered on first +possible work day after commit time. + + +## Send messages with batch reference. + +You can send both Digipost and Print messages just as you normally would, but to attach them to a batch you add the +batch as a reference on the message. The IMPORTANT part is visible below. Without this, the message will be delivered as +otherwise specified. + +```java +// Create an UUID +UUID batchUUID = UUID.randomUUID(); + +// Create the batch +client.createBatch(batchUUID); + +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .batch(batchUUID) // <- IMPORTANT + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +## Commit a batch + +After you have created a batch and sendt the messages with the batch you need to commit the batch. Without the commit +Digipost will never send the messages and might at a later time delete the incomplete batch and messages +referred to in the batch. + +To complete the batch, simply complete it: + +``` java +// [...] +// get the information and verify that the count of digipost/print messages are as expected +final Batch batchInformation = client.getBatchInformation(batchUUID); + +// complete the batch +final Batch completedBatch = client.completeBatch(batchInformation); +``` + +## Cancel a batch + +You can at any time before completion cancel a batch. Cancelling means that the batch will be removed and cannot +be processed futher. Digipost will immediately delete all documents, messages and other references to the batch. +Any further attempts to fetch information about the batch will throw a 404. + +``` java +// [...] +// get the batch information +final Batch batchInformation = client.getBatchInformation(batchUUID); + +// cancel the batch +client.cancelBatch(batchInformation); +``` diff --git a/docs/_v17_x/index.html b/docs/_v17_x/index.html new file mode 100644 index 00000000..8e0a51d9 --- /dev/null +++ b/docs/_v17_x/index.html @@ -0,0 +1,15 @@ +--- +identifier: index +layout: default +redirect_from: / +--- + + +{% for dok in site.v17_x %} + {% if dok.identifier != 'index' %} +
+

{{ dok.title }}

+ {{dok.content}} +
+ {% endif%} +{% endfor %} From 6a3dffe22bdf7da96e9259fce95248ba76100709 Mon Sep 17 00:00:00 2001 From: Kjetil Valle Date: Tue, 22 Sep 2026 12:06:30 +0200 Subject: [PATCH 2/2] Documentation for v18 Document SmsNotification better, including new always-send flag. Also fix mistake (days vs hours) in previous versions. --- docs/_config.yml | 7 +- docs/_v10_x/1_send.md | 2 +- docs/_v11_x/2_send.md | 2 +- docs/_v13_x/2_send.md | 2 +- docs/_v15_x/2_send.md | 2 +- docs/_v16_x/2_send.md | 2 +- docs/_v17_x/2_send.md | 2 +- docs/_v17_x/index.html | 2 +- docs/_v18_x/1_client_config.md | 71 +++++ docs/_v18_x/2_send.md | 519 +++++++++++++++++++++++++++++++++ docs/_v18_x/3_receive.md | 64 ++++ docs/_v18_x/4_archive.md | 242 +++++++++++++++ docs/_v18_x/5_batch.md | 94 ++++++ docs/_v18_x/index.html | 15 + docs/_v8_0/1_send.md | 2 +- docs/_v9_0/1_send.md | 2 +- 16 files changed, 1019 insertions(+), 11 deletions(-) create mode 100644 docs/_v18_x/1_client_config.md create mode 100644 docs/_v18_x/2_send.md create mode 100644 docs/_v18_x/3_receive.md create mode 100644 docs/_v18_x/4_archive.md create mode 100644 docs/_v18_x/5_batch.md create mode 100644 docs/_v18_x/index.html diff --git a/docs/_config.yml b/docs/_config.yml index 43dee6fd..22b8f89a 100644 --- a/docs/_config.yml +++ b/docs/_config.yml @@ -8,8 +8,8 @@ licenseUrl: http://www.apache.org/licenses/LICENSE-2.0 baseurl: "/digipost-api-client-java" -currentVersion: "16.x" -versions: ["16.x", "15.x", "13.x", "11.x", "10.x", "9.0", "8.0"] +currentVersion: "18.x" +versions: ["18.x", "17.x", "16.x", "15.x", "13.x", "11.x", "10.x", "9.0", "8.0"] deprecatedVersions: ["8.0", "9.0", "10.x", "11.x", "13.x"] collections: @@ -37,6 +37,9 @@ collections: v17_x: output: true permalink: /v17.x/ + v18_x: + output: true + permalink: /v18.x/ # list of additional links on the right of the top menu headerLinks: diff --git a/docs/_v10_x/1_send.md b/docs/_v10_x/1_send.md index aa5d239f..b0695927 100644 --- a/docs/_v10_x/1_send.md +++ b/docs/_v10_x/1_send.md @@ -114,7 +114,7 @@ client.createMessage(message) ```java PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); -// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one day after the letter i delivered. +// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); Message message = Message.MessageBuilder.newMessage(UUID2, primaryDocument) diff --git a/docs/_v11_x/2_send.md b/docs/_v11_x/2_send.md index 499baaa9..eb074893 100644 --- a/docs/_v11_x/2_send.md +++ b/docs/_v11_x/2_send.md @@ -103,7 +103,7 @@ PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787 // The time the SMS is sent out can be based on time after letter is delivered // or a specific date. This example specifies that the SMS should be sent out -// one day after the letter i delivered. +// one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); diff --git a/docs/_v13_x/2_send.md b/docs/_v13_x/2_send.md index 9b05d27b..7c16dd8b 100644 --- a/docs/_v13_x/2_send.md +++ b/docs/_v13_x/2_send.md @@ -103,7 +103,7 @@ PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787 // The time the SMS is sent out can be based on time after letter is delivered // or a specific date. This example specifies that the SMS should be sent out -// one day after the letter i delivered. +// one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); diff --git a/docs/_v15_x/2_send.md b/docs/_v15_x/2_send.md index 0e4c842a..dbd9a8ec 100644 --- a/docs/_v15_x/2_send.md +++ b/docs/_v15_x/2_send.md @@ -102,7 +102,7 @@ PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787 // The time the SMS is sent out can be based on time after letter is delivered // or a specific date. This example specifies that the SMS should be sent out -// one day after the letter i delivered. +// one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); diff --git a/docs/_v16_x/2_send.md b/docs/_v16_x/2_send.md index 5b27f3c4..052d2693 100644 --- a/docs/_v16_x/2_send.md +++ b/docs/_v16_x/2_send.md @@ -102,7 +102,7 @@ PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787 // The time the SMS is sent out can be based on time after letter is delivered // or a specific date. This example specifies that the SMS should be sent out -// one day after the letter i delivered. +// one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); diff --git a/docs/_v17_x/2_send.md b/docs/_v17_x/2_send.md index 5b27f3c4..052d2693 100644 --- a/docs/_v17_x/2_send.md +++ b/docs/_v17_x/2_send.md @@ -102,7 +102,7 @@ PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787 // The time the SMS is sent out can be based on time after letter is delivered // or a specific date. This example specifies that the SMS should be sent out -// one day after the letter i delivered. +// one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); diff --git a/docs/_v17_x/index.html b/docs/_v17_x/index.html index 8e0a51d9..12ebab23 100644 --- a/docs/_v17_x/index.html +++ b/docs/_v17_x/index.html @@ -1,7 +1,7 @@ --- identifier: index layout: default -redirect_from: / +redirect_from: --- diff --git a/docs/_v18_x/1_client_config.md b/docs/_v18_x/1_client_config.md new file mode 100644 index 00000000..6b2a1378 --- /dev/null +++ b/docs/_v18_x/1_client_config.md @@ -0,0 +1,71 @@ +--- +title: Instantiate and configure the client +identifier: client_config +layout: default +--- + +### Install + +The client library is available on the [Maven Central Repository](https://central.sonatype.com/artifact/no.digipost/digipost-api-client-java). +Copy the ``-snippet from that website and put it in your pom.xml file. +Make sure to use the latest version available. + +This client requires Java 11 and `jakarta.xml-bind`. + +### Configure for production use + +To instantiate the client instance you need to supply your assigned _broker ID_, which +is set up to be permitted to integrate with the Digipost API. In addition, you must create +a `Signer` instance, e.g. by using a `.p12` file to read the private key to use for signing +the API requests. + +```java +SenderId senderId = SenderId.of(123456); + +Signer signer; +try (InputStream sertifikatInputStream = Files.newInputStream(Paths.get("certificate.p12"))) { + signer = Signer.usingKeyFromPKCS12KeyStore(sertifikatInputStream, "TheSecretPassword"); +} + +DigipostClient client = new DigipostClient( + DigipostClientConfig.newConfiguration().build(), senderId.asBrokerId(), signer); +``` + +This example will configure the client to communicate with the regular Digipost production +environment. + + +### Other environments + +If you have access to other environments, this can be configured using +`DigipostClientConfig`, e.g: + +```java +URI apiUri = URI.create("https://api.test.digipost.no"); +DigipostClientConfig config = DigipostClientConfig.newConfiguration().digipostApiUri(apiUri).build(); +``` + +#### Norsk Helsenett (NHN) + +The Digipost API is accessible from both internet and Norsk Helsenett (NHN). Both entry points use +the same API, the only difference is the base URL. + +```java +URI nhnApiUri = URI.create("https://api.nhn.digipost.no"); +DigipostClientConfig config = DigipostClientConfig.newConfiguration().digipostApiUri(nhnApiUri).build(); +``` + +### Custom HTTP client + +Since version 17, the client uses Apache HttpClient 5 internally. If you need control over the +underlying HTTP client (e.g. connection pooling or proxy settings), you can supply your own +`HttpClientBuilder`: + +```java +HttpClientBuilder clientBuilder = HttpClientFactory.createDefaultBuilder(); + +DigipostClient client = new DigipostClient( + DigipostClientConfig.newConfiguration().build(), senderId.asBrokerId(), signer, clientBuilder); +``` + + diff --git a/docs/_v18_x/2_send.md b/docs/_v18_x/2_send.md new file mode 100644 index 00000000..26326800 --- /dev/null +++ b/docs/_v18_x/2_send.md @@ -0,0 +1,519 @@ +--- +title: Send messages +identifier: send +layout: default +--- + +The Java client library also contains some +[example code](https://github.com/digipost/digipost-api-client-java/tree/master/src/test/java/no/digipost/api/client/eksempelkode) +which include similar examples. + +## Send a message to a recipient + +To send a message to a recipient in Digipost, you need to choose a way to identify +the recipient, instantiate a primary `Document` and the containing `Message`. Finally +these are given to the client as well as the content of the document as an `InputStream`. +The actual API communication will happen when you invoke the `.send()` method. + +### Send using a personal identification number for the recipient + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +### Other recipient types + +There are other recipient types available to identify recipients of messages. Note that +some recipient types may require special permissions to be set up in order to be used. +E.g. bank account number requires such permissions, and are _not_ enabled by default. + +```java +NameAndAddress nameAndAddress = new NameAndAddress("Ola Nordmann", "Gateveien 1", "Oppgang B", "0001", "Oslo"); +``` + +```java +BankAccountNumber accountNum = new BankAccountNumber("12345123451"); +``` + +### Multiple documents in one message + +A message is required to have at least one document, the _primary_ document. Additional +documents can also be included as _attachments_. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF); + +Document attachment1 = new Document(UUID2, "Attachment1 subject", FileType.PDF); +Document attachment2 = new Document(UUID3, "Attachment2 subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .attachments(attachment1, attachment2) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("main_document_content.pdf"))) + .addContent(attachment1, Files.newInputStream(Paths.get("attachment1_content.pdf"))) + .addContent(attachment2, Files.newInputStream(Paths.get("attachment2_content.pdf"))) + .send(); +``` +## Send invoice + +```java + +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +//Previous versions of the client uses what is called an Invoice Document. With the release of v15 this has been +//removed. Now we use digipost data types instead. +Document invoice = new Document( + UUID1 + , "Invoice subject" + , FileType.PDF + , new Invoice(null, ZonedDateTime.of(2022, 5, 5, 0, 0, 0, 0, ZoneId.of("Europe/Oslo")), new BigDecimal("1.20"), "704279604", "82760100435") +); + +Message message = Message.newMessage("messageId", invoice) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(invoice, Files.newInputStream(Paths.get("invoice.pdf"))) + .send(); + + +``` + +## Send a message with SMS notification + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +// The time the SMS is sent out can be based on time after letter is delivered +// or a specific date. This example specifies that the SMS should be sent out +// one hour after the letter i delivered. +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, + new SmsNotification(1), null, + AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +Notifications can be scheduled as a number of hours after the letter is delivered, or at specific +points in time: + +```java +ZonedDateTime specificTime = ZonedDateTime.of(2024, 1, 15, 10, 0, 0, 0, ZoneId.of("Europe/Oslo")); + +SmsNotification smsNotification = new SmsNotification(List.of(new ListedTime(specificTime)), List.of(1)); +``` + +The actual time the SMS is sent may be adjusted to fall within the hours we send SMS notifications, +see [Digipost notifications](https://www.digipost.no/en/consumer/help-and-contact/notifications) for details. + +By default, the SMS notification is not sent if the recipient has already read the letter, or if the +recipient has opted to not receive sender-initiated SMS notifications. Setting `alwaysSend` to +`true` overrides both of these. This feature is not enabled by default, and must be activated for the +specific sender by Digipost admin. + +```java +boolean alwaysSend = true; +SmsNotification smsNotification = new SmsNotification(null, List.of(1), alwaysSend); + +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, + smsNotification, null, + AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); +``` + + +## Send letter with fallback to print + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF); + +PrintDetails printDetails = new PrintDetails( + new PrintRecipient("Ola Nordmann", new NorwegianAddress("Prinsensveien 123", "0460", "Oslo")), + new PrintRecipient("Norgesbedriften", new NorwegianAddress("Akers Àle 2", "0400", "Oslo")), + PrintDetails.PrintColors.MONOCHROME, PrintDetails.NondeliverableHandling.RETURN_TO_SENDER); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(new MessageRecipient(pin, printDetails)) + .build(); + +// addContent can also take a third parameter which is the file/ipnput stream that will be used only +// for physical mail. The below example uses the same file/input stream in both channels (digital and physical mail) +MessageDelivery result = client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +## Send letter with html + +If you want to be able to send HTML-documents you first need to contact Digipost to activate +the feature for your broker/sender. Then it is just matter of specifing HTML as the filetype +and serve an html-file as content. +Bevare that there are strict rules to what is allowed. These rules are quite verbose. But +we have open sourced the html validator and santizer software we use to make sure that +html conforms to these rules. Check out [https://github.com/digipost/digipost-html-validator](digipost-html-validator). +If you preencrypt your document, this validation will be performed in the client instead of the +server so that you can be confident that you recipient will be able to open the document. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.HTML); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.html"))) + .send(); +``` + + +## Send letter with higher security level + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +// TWO_FACTOR - require BankID or BuyPass authentication to open letter +// SENSITIVE - Sender information and subject will be hidden until Digipost user +// is logged in at the appropriate authentication level +Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, null, null, + AuthenticationLevel.TWO_FACTOR, SensitivityLevel.SENSITIVE); + +Message message = Message.newMessage(UUID2, primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream("content.pdf"))) + .send(); +``` + +## Send a message with extra computer readable data + +With version 7 of the Digipost API, messages can have extra bits of computer readable information that +allows the creation of a customized, dynamic user experience for messages in Digipost. These extra bits of +information are referred to as instances of "Datatypes". + +All datatypes are sent in the same way. Each document can accommodate one datatype-object. An exhaustive list of +available datatypes and their documentation can be found at +[digipost/digipost-data-types](https://github.com/digipost/digipost-data-types). + +For convenience, all datatypes are available as java-classes in the java client library. + +### Datatype Appointment + +In this example, an appointment-datatype that allows for certain calendar-related functions is added to a +message. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +ZonedDateTime startTime = ZonedDateTime.of(2017, 10, 23, 10, 0, 0, 0, ZoneId.systemDefault()); +AppointmentAddress address = new AppointmentAddress("Storgata 1", "0001", "Oslo"); +Info preparation = new Info("Preparation", "Please do not eat or drink 6 hours prior to examination"); +Info about = new Info("About Oslo X-Ray center", "Oslo X-Ray center is specialized in advanced image diagnostics..."); +List info = Arrays.asList(preparation, about); + +Appointment appointment = new Appointment( + startTime, startTime.plusMinutes(30), "Please arrive 15 minutes early", + "Oslo X-Ray center", address, "Lower back examination", info, Language.EN); + +Document primaryDocument = new Document(messageUUID, "X-Ray appointment", FileType.PDF, appointment); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +### Datatype ExternalLink + +This Datatype enhances a message in Digipost with a button which sends the user to an external site. The button +can optionally have a deadline, a description and a custom text. + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +URI externalLinkTarget = URI.create("https://example.org/loan-offer/uniqueCustomerId/"); +ZonedDateTime deadline = ZonedDateTime.of(2018, 10, 23, 10, 0, 0, 0, ZoneId.systemDefault()); + +ExternalLink externalLink = new ExternalLink(externalLinkTarget, deadline, + "Please read the terms, and use the button above to accept them. The offer expires at 23/10-2018 10:00.", + "Accept offer"); + +Document primaryDocument = new Document(messageUUID, "Housing loan application", FileType.PDF, externalLink); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream("terms.pdf"))) + .send(); +``` + +### Datatype ShareDocumentsRequest + +This datatype enables sharing of documents between an organisation and a Digipost end user. The organisation +first sends a message of datatype ShareDocumentsRequest, to which the end user can attach a list of documents. When +new documents are shared, a DocumentEvent is generated. The organisation can retrieve the status of their +ShareDocumentsRequest. If documents are shared and the sharing is not cancelled, the documents can either be downloaded +or viewed on the digipostdata.no domain. Active requests can be cancelled both by the end user and the organisation. + +The `purpose` attribute of the ShareDocumentsRequest should briefly explain why the sender organisation want to gain +access to the relevant documents. This text will be displayed prominently, and should contain the information necessary +for the user to make an informed choice. The primary document should contain a more detailed explanation. + +#### Send ShareDocumentsRequest +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID messageUUID = UUID.randomUUID(); + +ShareDocumentsRequest shareDocumentsRequest = new ShareDocumentsRequest( + Duration.ofDays(60).toSeconds(), + "We require to see your six latest pay slips in order to give you a loan." +); + +Document primaryDocument = new Document(messageUUID, "Request to access your latest payslips", FileType.PDF, shareDocumentsRequest); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .addContent(primaryDocument, Files.newInputStream(Path.of("longer-desc-of-sharing-purpose.pdf"))) + .send(); +``` + +#### Discover new shared documents +The sender organisation can discover new shared documents by polling document events regularly. Use the `uuid` attribute +of the DocumentEvent to match with the `messageUUID` of the origin ShareDocumentsRequest: + +```java +List sharedDocumentEvents = digipostClient.getDocumentEvents(brokerId.asSenderId(), ZonedDateTime.now().minus(Duration.ofDays(1)), ZonedDateTime.now(), 0, 100); + .getEvents() + .stream() + .filter(event -> DocumentEventType.SHARE_DOCUMENTS_REQUEST_DOCUMENTS_SHARED.equals(event.getType())) + .toList() +``` + +NB: events are attached to the broker, _not_ each individual sender. + +#### Get state of ShareDocumentsRequest + +```java +ShareDocumentsRequestState sharedDocumentsRequestState = sendClient.getShareDocumentsRequestState(senderId, uuid); +``` + +#### Get documents + +Each `SharedDocument` has attributes describing the document and its origin. If `SharedDocumentOrigin` is of type +`OrganisationOrigin`, the corresponding document was received by the end user through Digipost from the organisation +with the provided organisation number. If the origin is of type `PrivatePersonOrigin`, the document was received either +from another end user or uploaded by the user itself. + +Get a single document as stream: + +```java +SharedDocument doc1 = sharedDocumentsRequestState.getSharedDocuments().get(0); +try (InputStream inputStream = sendClient.getSharedDocumentContentStream(doc1.getSharedDocumentContentStream())) { + // use inputStream +} +``` + +Get link to view a single document on digipostdata.no + +```java +SharedDocumentContent sharedDocumentContent = sendClient.getSharedDocumentContent(doc1.getSharedDocumentContent()); +String uri = sharedDocumentContent.getUri(); +``` + +#### Stop sharing + +```java +client.stopSharing(senderId, sharedDocumentsRequestState.stopSharing()) +``` + + + +## Send message with request for registration + +It is possible to send a message to a person, who does not have a Digipost account, where the message triggers an SMS notification with a request for registration. The SMS notification says that if they register for a Digipost account the document will be delivered digitally. The actual content of the SMS notification is set manually by Digipost. If the user does not register for a Digipost account within the defined deadline, the document will either be delivered as physical mail or not at all. + +The phone number provided SHOULD include the country code (i.e. +47). If the phone number does not start with either `"+"`, `"00"` or `"011"`, we will prepend `"+47"` if and only if the phone number string is 8 characters long. If this is not the case, the request is rejected. + +### Request for registration with physical mail as fallback + +In this case the document will be delivered as physical mail if the recipient has not registered for a Digipost account by the defined deadline. + +```java +UUID documentId = UUID.randomUUID(); +Document document = new Document(documentId, "Hello!", FileType.PDF); + +PrintDetails printDetails = new PrintDetails(RECIPIENT, RETURN_RECIPIENT); + +RequestForRegistration requestForRegistration = new RequestForRegistration( +// Deadline for when the recipent can no longer register a Digipost account + ZonedDateTime.now().plus(6, ChronoUnit.HOURS), +// Phone number that will be used for the SMS notification. Make sure the country code is included, starting with "+". + new PhoneNumber("+4712345678"), + null, + printDetails +); + +UUID messageId = UUID.randomUUID(); +Message message = Message.newMessage(messageId.toString(), document) + .recipient(new PersonalIdentificationNumber("12345678901")) + .senderId(senderId) + .requestForRegistration(requestForRegistration) + .build(); + +MessageDelivery delivery = sendClient.createMessage(message) + .addContent(document, Contents.filFraDisk("gyldig-for-print.pdf")) + .send(); + +System.out.println("status: " + delivery.getStatus()); +System.out.println("channel: " + delivery.getChannel()); + +// If the recipient does not have a Digipost account already, the value of `getChannel()` will be `null`, otherwise `Channel.DIGIPOST`. +``` + +### Request for registration without physical mail as fallback + +If the sender wishes to send the document as physical mail through its own service (if the recipient does not register a Digipost account), print details must not be included. + +```java +UUID documentId = UUID.randomUUID(); +Document document = new Document(documentId, "Hello!", FileType.PDF); + +RequestForRegistration requestForRegistration = new RequestForRegistration( +// Deadline for when the recipent can receive the document digitally right after Digipost account registration. + ZonedDateTime.now().plus(6, ChronoUnit.HOURS), +// Phone number that will be used for the SMS notification + new PhoneNumber("+4712345678"), + null, + null +); + +UUID messageId = UUID.randomUUID(); +Message message = Message.newMessage(messageId.toString(), document) + .recipient(new PersonalIdentificationNumber("12345678901")) + .senderId(senderId) + .requestForRegistration(requestForRegistration) + .build(); + +MessageDelivery delivery = sendClient.createMessage(message) + .addContent(document, Contents.filFraDisk("gyldig-for-print.pdf")) + .send(); +``` +It is up to the sender to then check if the document has been delivered digitaly prior to the defined deadline. After the deadline has passed the document will not be delivered if recipient registers for a Digipost account. The delivery status can be checked with the following: + +```java +// The messageId would be the UUID that was used when the originating message was sent +UUID messageId = UUID.fromString("efe11ce1-dfce-459a-865b-52dc313dbcb9"); +DocumentStatus status = sendClient.getDocumentStatus(senderId, messageId); +System.out.println("Status: " + status.status); +System.out.println("Channel: " + status.channel); +``` +The following statuses are possible: + +* NOT_DELIVERED +* DELIVERED + * When the document is delivered the channel can be either "DIGITAL" or "PRINT" + +## Identify user based on personal identification number + +```java +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); + +Identification identification = new Identification(pin); + +IdentificationResult identificationResult = client.identifyRecipient(identification); +``` + + + +## Create Digipost User Accounts + +Create new or activate existing Digipost user account. + +```java +SenderId sender = SenderId.of(123456); +UserInformation user = new UserInformation( + new NationalIdentityNumber("01013300001"), + new PhoneNumber("+4799998888"), + new EmailAddress("user@example.com") +); + +UserAccount userAccount = client.createOrActivateUserAccount(sender, user); + +DigipostAddress digipostAddress = userAccount.getDigipostAddress(); +EncryptionKey encryptionKey = userAccount.getEncryptionKey(); +``` + + +## Get Status of Document + +After you have sent a message, you can get the _status_ of a document with `getDocumentStatus`. +The response includes basic information about the delivery, like the channel the document was delivered to, as well as +delivery times and more. + +```java +DocumentStatus status = client.getDocumentStatus(senderId, documentUuid); + +System.out.println("Status: " + status.status); +System.out.println("Channel: " + status.channel); +``` + + +## Get document events + +In addition to `getDocumentStatus`, you can poll for a broader history of events with `getDocumentEvents`. +This includes events such as `OPENED`, `POSTMARKED`, `PRINT_FAILED`, `SHREDDED` and more - see `DocumentEventType` +for the full list. + +```java +List events = client.getDocumentEvents(senderId, ZonedDateTime.now().minus(Duration.ofDays(1)), ZonedDateTime.now(), 0, 100) + .getEvents(); + +for (DocumentEvent event : events) { + System.out.println(event.getType() + " for document " + event.getUuid() + " at " + event.getCreated()); +} +``` + +`maxResults` is a cap on the response, not a guarantee that all events in the time interval are +returned. If you get back exactly `maxResults` events, there may be more - fetch the same interval +again with `offset` increased by `maxResults`. You have received all events in the interval once a +call returns fewer events than `maxResults`. + +Events are only retained for 30 days, and there is no way to delete an event through the API - store +the polling state (e.g. the last `to` timestamp used) so you can resume from where you left off. diff --git a/docs/_v18_x/3_receive.md b/docs/_v18_x/3_receive.md new file mode 100644 index 00000000..73d07f7b --- /dev/null +++ b/docs/_v18_x/3_receive.md @@ -0,0 +1,64 @@ +--- +title: Receive messages +identifier: inbox +layout: default +--- + +The inbox API makes it possible for an organisation to manage messages received in Digipost. + + + +## Get documents in inbox + +The inbox call outputs a list of documents ordered by delivery time. `Offset` is the start index of the list, and `limit` is the max number of documents to be returned. The `offset` and `limit` is therefore not in any way connected to `InboxDocument.id`. + +The values `offset` and `limit` is meant for pagination so that one can fetch 100 and then the next 100. + + +```java +//get first 100 documents +Inbox first100 = client.getInbox(SenderId.of(123456), 0, 100); + +//get next 100 documents +Inbox next100 = client.getInbox(SenderId.of(123456), 100, 100); +``` + +We have now fetched the 200 newest inbox documents. As long as no new documents are received, the two API-calls shown above will always return the same result. If we now receive a new document, this will change. The first 100 will now contain 1 new document and 99 documents we have seen before. This means that as soon as you stumble upon a document you have seen before you can stop processing, given that all the following older ones have been processed. + +## Download document content + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); + +System.out.println("Content type is: " + documentMetadata.getContentType()); +try (InputStream documentContent = client.getInboxDocumentContent(documentMetadata)) { + // use documentContent +} +``` + +## Delete document + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); + +client.deleteInboxDocument(documentMetadata); +``` + +## Download attachment content + +```java +Inbox inbox = client.getInbox(SenderId.of(123456)); + +InboxDocument documentMetadata = inbox.documents.get(0); +InboxDocument attachment = documentMetadata.getAttachments().get(0); + +System.out.println("Content type is: " + attachment.getContentType()); +try (InputStream attachmentContent = client.getInboxDocumentContent(attachment)) { + // use attachmentContent +} +``` + diff --git a/docs/_v18_x/4_archive.md b/docs/_v18_x/4_archive.md new file mode 100644 index 00000000..e6112ce0 --- /dev/null +++ b/docs/_v18_x/4_archive.md @@ -0,0 +1,242 @@ +--- +title: Archive functionality +identifier: archive +layout: default +--- + +The archive API makes it possible for an organisation to manage documents in archives. These files are kept in separate +archives, and the files belong to the sender organisation. + + +## Archive documents to an archive + +Let's say you want to archive two documents eg. an invoice and an attachment and +you want to have some kind of reference to both documents. You can do that +by describing the two documents with `ArchiveDocument`. Then you need to create an archive +and add the documents to the archive. In the following example we use a default archive. +You then need to send this archive and attach the actual files to the request by linking +the `ArchiveDocument` with a file and send. + +```java +// 1. We describe the documents +final ArchiveDocument invoice = new ArchiveDocument( + UUID.randomUUID() + , "invoice_123123.pdf" + , "pdf" + , "application/pdf" +); +final ArchiveDocument attachment = new ArchiveDocument( + UUID.randomUUID() + , "attachment_123123.pdf" + , "pdf" + , "application/pdf" +); + +// 2. We create an archive and add the documents to it +Archive archive = Archive.defaultArchive() + .documents(invoice, attachment) + .build(); + +// 3. We create a request to archive the files with reference between the ArchiveDocument and the actual file +client.archiveDocuments(archive) + .addFile(invoice, readFileFromDisk("invoice_123123.pdf")) + .addFile(attachment, readFileFromDisk("attachment_123123.pdf")) + .send(); +``` + +## Get a list of archives + +An organisation can have many archives, or just the default unnamed archive. That is up to +your design wishes. To get a list of the archives for a given Sender, you can do this: + +```java +//get a list of the archives +Archives archives = client.getArchives(SenderId.of(123456)); +``` + +The class `Archives` holds a list of `Archive` where you can see the name of the archive. + +## Iterate documents in an archive + +You _can_ get content of an archive with paged requests. Under is an example of how to iterate +an archive. However, it's use is strongly discouraged because it leads to the idea that +an archive can be iterated. We expect an archive to possibly reach many million rows so the iteration +will possibly give huge loads. On the other hand being able to dump all data is a necessary feature of any archive. + +_Please use fetch document by UUID or referenceID instead to create functionality on top of the archive._ +You should on your side know where and how to get a document from an archive. You do this by knowing where +you put a file you want to retrieve. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocuments() + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` +## Archive Document attributes + +You can add optional attributes to documents. An attribute is a key/val string-map that describe documents. You can add +up to 15 attributes pr. archive document. The attribute key and value is case sensitive. + +```java +final ArchiveDocument invoice = new ArchiveDocument( + UUID.randomUUID() + , "invoice_123123.pdf" + , "pdf" + , "application/pdf" +).withAttribute("INR", "123123").withAttribute("custid", "4321"); +``` + +The attributes can be queried, so that you can get an iterable list of documents. + +```java +final Archives archives = digipostClient.getArchives(); +Archive current = archives.getArchives().get(0); + +final List documents = current.getNextDocumentsWithAttributes(Map.of("INR", "123123", "custid", "4321")) + .map(digipostClient::getArchiveDocuments) + .map(Archive::getDocuments).orElse(emptyList()); + +// This prints to total content of the list of documents +System.out.println(documents); +``` + +We recommend that the usage of attributes is made such that the number of results for a query on attributes +is less than 100. If you still want that, it's ok, but you need to iterate the pages to get all the results. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocumentsWithAttributes(Map.of("INR", "123123")) + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` + +You can now also select by date or by attributes by date. Date is when the documents has been stored in Digipost archive. + +```java +final Archives archives = client.getArchives(); + +Archive current = archives.getArchives().get(0); +final List documents = new ArrayList<>(); + +while (current.getNextDocuments().isPresent()) { + current = current.getNextDocumentsWithAttributesByDate(Map.of("INR", "123123"), OffsetDateTime.now().minus(Period.ofDays(4)), OffsetDateTime.now()) + //current = defaultArchive.getNextDocumentsByDate(OffsetDateTime.now().minus(Period.ofDays(4)), OffsetDateTime.now()); + .map(client::getArchiveDocuments) + .orElse(new Archive()); + + documents.addAll(current.getDocuments()); +} + +// This prints to total content of the list of documents +System.out.println(documents); +``` + + +## Get documents by referenceID + +You can retrieve a set of documents by a given referenceID. You will then get the documents listed in their respective +archives in return. + +```java +final Archives archives = client.getArchiveDocumentsByReferenceId("REFERENCE_ID"); +``` + +## Get documents by uuid + +You can retrieve a set of documents by the UUID that you give the document when you archive it. In the example above +we use `UUID.randomUUID()` to generate an uuid. You can either store that random uuid in your database for +retrieval later, or you can generate a deterministic uuid based on your conventions for later retrieval. + +You will get in return an instance of `Archive` which contains information on the archive the document is contained in +and the actual document. From this you can fetch the actual document. + +```java +final UUID myConvensionUUID = UUID.fromString("vedlegg:123123:txt"); + +final Archive archiveWithDocument = client.getArchiveDocumentByUuid(myConvensionUUID); +``` + +## Get content of a document as a single-use link + +You can get the actual content of a document after you have retrieved the archive document. Below is an example of how +you can achieve this with a given `ArchiveDocument`. In the resulting `ArchiveDocumentContent`, you will get a url to +the content which expires after 30 seconds. + +```java +// This ArchiveDocument must be retrieved beforehand using one of the methods described above +final ArchiveDocument archiveDocument; + +URI getDocumentContentURI = archiveDocument.getDocumentContent().orElseThrow(); +ArchiveDocumentContent content = client.getArchiveDocumentContent(getDocumentContentURI); +``` + +## Get content of a document as a stream + +In addition to a single-use link, you also have the option to retrieve the content of a document directly as a +byte stream. + +```java +// This ArchiveDocument must be retrieved beforehand using one of the methods described above +final ArchiveDocument archiveDocument; + +URI getDocumentContentStreamURI = archiveDocument.getDocumentContentStream().orElseThrow(); +try (InputStream content = client.getArchiveDocumentContentStream(getDocumentContentStreamURI)) { + // use content +} +``` + +## Update document attributes and/or referenceID + +You can add an attribute or change an attribute value, but not delete an attribute. You can however set the value +to empty string. The value of the field for referenceID can be changed as well. + +```java +final UUID myConvensionUUID = UUID.fromString("vedlegg:123123:txt"); + +final Archive archiveWithDocument = client.getArchiveDocumentByUuid(myConvensionUUID); + +archiveDocument.withReferenceId("My final referenceId").withAttribute("Status", "COMPLETED_PROCESS"); + +client.updateArchiveDocument(archiveDocument, archiveDocument.getUpdate()); +``` + +## Using archive as a broker + +It is possible to be a broker for an actual sender. Most of the api described above also support +the use of SenderId to specify who you are archiving for. + +eg.: +```java +client.getArchives(SenderId.of(123456)) +client.getArchiveDocumentsByReferenceId(SenderId.of(123456), "REFERENCE_ID"); +client.getArchiveDocumentByUuid(SenderId.of(123456), myConvensionUUID); + + +Archive archive = Archive.defaultArchive() + .documents(faktura) + .senderId(SenderId.of(123456)) + .build(); +``` diff --git a/docs/_v18_x/5_batch.md b/docs/_v18_x/5_batch.md new file mode 100644 index 00000000..1732ccc4 --- /dev/null +++ b/docs/_v18_x/5_batch.md @@ -0,0 +1,94 @@ +--- +title: Batch functionality +identifier: batch +layout: default +--- + +The batch API makes it possible for an organisation to manage sending of several messages, both to Digipost and Print, in a +batch. The batch will then be delivered all at the same time atomically. If it has not been sendt yet, the batch can +also be cancelled. + +## Start and get information about a batch + +A batch is identified by a UUID specified by you. To create a batch you send a uuid to the Digipost api. In return~~~~ +you get a batch object with a status and som links for complete and cancel. + +```java +// Create an UUID +final UUID batchUUID = UUID.randomUUID(); + +// Create the batch +final Batch batch = client.createBatch(batchUUID); + +// At any time, read information about the batch +final Batch batchInformation = client.getBatchInformation(batchUUID); + +``` + +A batch can have 4 states: +`CREATED`, `NOT_COMMITTED`, `COMMITTED`, `DONE` + +CREATED is an initial state. NOT_COMMITTED is the state given when there has been added messages to the batch. +COMMITTED is a state that can occur if the batch has to be processed asynchronously. DONE means that the batch has +been commited. Digipost messages are delivered at commit time and Print messages will be delivered on first +possible work day after commit time. + + +## Send messages with batch reference. + +You can send both Digipost and Print messages just as you normally would, but to attach them to a batch you add the +batch as a reference on the message. The IMPORTANT part is visible below. Without this, the message will be delivered as +otherwise specified. + +```java +// Create an UUID +UUID batchUUID = UUID.randomUUID(); + +// Create the batch +client.createBatch(batchUUID); + +PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); +UUID documentUuid = UUID.randomUUID(); +Document primaryDocument = new Document(documentUuid, "Document subject", FileType.PDF); + +Message message = Message.newMessage("messageId", primaryDocument) + .recipient(pin) + .build(); + +client.createMessage(message) + .batch(batchUUID) // <- IMPORTANT + .addContent(primaryDocument, Files.newInputStream(Paths.get("content.pdf"))) + .send(); +``` + +## Commit a batch + +After you have created a batch and sendt the messages with the batch you need to commit the batch. Without the commit +Digipost will never send the messages and might at a later time delete the incomplete batch and messages +referred to in the batch. + +To complete the batch, simply complete it: + +``` java +// [...] +// get the information and verify that the count of digipost/print messages are as expected +final Batch batchInformation = client.getBatchInformation(batchUUID); + +// complete the batch +final Batch completedBatch = client.completeBatch(batchInformation); +``` + +## Cancel a batch + +You can at any time before completion cancel a batch. Cancelling means that the batch will be removed and cannot +be processed futher. Digipost will immediately delete all documents, messages and other references to the batch. +Any further attempts to fetch information about the batch will throw a 404. + +``` java +// [...] +// get the batch information +final Batch batchInformation = client.getBatchInformation(batchUUID); + +// cancel the batch +client.cancelBatch(batchInformation); +``` diff --git a/docs/_v18_x/index.html b/docs/_v18_x/index.html new file mode 100644 index 00000000..c6d805d8 --- /dev/null +++ b/docs/_v18_x/index.html @@ -0,0 +1,15 @@ +--- +identifier: index +layout: default +redirect_from: / +--- + + +{% for dok in site.v18_x %} + {% if dok.identifier != 'index' %} +
+

{{ dok.title }}

+ {{dok.content}} +
+ {% endif%} +{% endfor %} diff --git a/docs/_v8_0/1_send.md b/docs/_v8_0/1_send.md index 85e6f906..53cc60c8 100644 --- a/docs/_v8_0/1_send.md +++ b/docs/_v8_0/1_send.md @@ -95,7 +95,7 @@ client.createMessage(message) ```java PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); -// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one day after the letter i delivered. +// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); Message message = Message.MessageBuilder.newMessage(UUID2, primaryDocument) diff --git a/docs/_v9_0/1_send.md b/docs/_v9_0/1_send.md index ab5d94e4..2c84f9b8 100644 --- a/docs/_v9_0/1_send.md +++ b/docs/_v9_0/1_send.md @@ -95,7 +95,7 @@ client.createMessage(message) ```java PersonalIdentificationNumber pin = new PersonalIdentificationNumber("26079833787"); -// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one day after the letter i delivered. +// The time the SMS is sent out can be based on time after letter is delivered or a specific date. This example specifies that the SMS should be sent out one hour after the letter i delivered. Document primaryDocument = new Document(UUID1, "Document subject", FileType.PDF, null, new SmsNotification(1), null, AuthenticationLevel.PASSWORD, SensitivityLevel.NORMAL); Message message = Message.MessageBuilder.newMessage(UUID2, primaryDocument)