Skip to main content
This guide walks you through sending a generic AS4 user message using the AS4Sender builder. It assumes you have Java 17 and Maven installed.
1

Add the dependency

Add phase4-lib to your Maven pom.xml:
pom.xml
<dependency>
  <groupId>com.helger.phase4</groupId>
  <artifactId>phase4-lib</artifactId>
  <version>4.4.0</version>
</dependency>
See the Installation guide for Gradle syntax and all available modules.
2

Configure your key store

phase4 uses WS-Security for signing and encrypting messages. You need a key store (.jks or .p12) with your private key.Create an AS4CryptoFactoryInMemoryKeyStore pointing to a loaded KeyStore:
import java.security.KeyStore;
import com.helger.phase4.crypto.AS4CryptoFactoryInMemoryKeyStore;

// Load your key store however suits your application
KeyStore keyStore = KeyStore.getInstance("JKS");
try (InputStream is = new FileInputStream("my-keystore.jks")) {
    keyStore.load(is, "keystorePassword".toCharArray());
}

// Optionally load a trust store; null uses the JRE default CA certs
KeyStore trustStore = null;

AS4CryptoFactoryInMemoryKeyStore cryptoFactory =
    new AS4CryptoFactoryInMemoryKeyStore(
        keyStore,
        "my-key-alias",          // key alias
        "keyPassword".toCharArray(), // key password
        trustStore
    );
If your signing and encryption keys are in separate key stores, use cryptoFactorySign() and cryptoFactoryCrypt() on the builder to supply them independently.
3

Send an AS4 user message

Use AS4Sender.builderUserMessage() to build and send a generic AS4 user message. The builder enforces that the payload is placed as a MIME attachment rather than inline in the SOAP body.
import com.helger.phase4.sender.AS4Sender;
import com.helger.phase4.sender.EAS4UserMessageSendResult;
import com.helger.phase4.attachment.AS4OutgoingAttachment;
import com.helger.mime.CMimeType;

EAS4UserMessageSendResult result = AS4Sender.builderUserMessage()
    // Crypto configuration
    .cryptoFactory(cryptoFactory)
    // Sender identity
    .fromPartyID("sender-party-id")
    .fromRole("http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/initiator")
    // Receiver identity
    .toPartyID("receiver-party-id")
    .toRole("http://docs.oasis-open.org/ebxml-msg/ebms/v3.0/ns/core/200704/responder")
    // Message routing
    .service("urn:example:service")
    .action("urn:example:action")
    // Receiver endpoint
    .endpointURL("https://receiver.example.com/as4")
    // Payload
    .payload(
        AS4OutgoingAttachment.builder()
            .data("<Invoice>...</Invoice>".getBytes(java.nio.charset.StandardCharsets.UTF_8))
            .mimeType(CMimeType.APPLICATION_XML)
            .build()
    )
    // Send and check for a receipt
    .sendMessageAndCheckForReceipt();

if (result.isSuccess()) {
    System.out.println("Message delivered successfully.");
} else {
    System.err.println("Send failed: " + result.getID());
}
sendMessageAndCheckForReceipt() returns EAS4UserMessageSendResult.SUCCESS only when the remote endpoint returns a positive AS4 Receipt signal message.
4

Handle the result

EAS4UserMessageSendResult has several outcome values:
ValueMeaning
SUCCESSReceipt received — delivery confirmed
INVALID_PARAMETERSA required builder field was not set
TRANSPORT_ERRORNetwork or HTTP(S) failure; retry may help
TRANSPORT_ERROR_NO_RETRYNetwork failure where retry is not feasible
NO_SIGNAL_MESSAGE_RECEIVEDResponse was not a valid AS4 Signal Message
AS4_ERROR_MESSAGE_RECEIVEDRemote endpoint returned an AS4 Error Message
INVALID_SIGNAL_MESSAGE_RECEIVEDSignal message had neither a receipt nor errors
Use result.isRetryFeasible() to decide whether to attempt a retry when the built-in HTTP retry mechanism is disabled.

Next steps

Installation

All modules, Maven BOM, and Gradle snippets

Crypto setup

Configure signing and encryption in detail

Sending Peppol messages

High-level Peppol sender with dynamic SMP discovery

Generic AS4 sending

Full reference for all builder options

Build docs developers (and LLMs) love