Skip to main content

Prerequisites

Before you start, make sure you have the following tools installed:
ToolMinimum versionNotes
Java (JDK)17Required by pn-parent 2.1.2-SPRINGBOOT3
Maven3.8+Used for build and code generation
Docker20.10+Required to run LocalStack
AWS CLI2.xUsed to bootstrap LocalStack resources
LocalStack2.xEmulates DynamoDB, SQS, and KMS locally
1

Clone the repository

Clone the repository and enter the project directory:
git clone https://github.com/pagopa/pn-paper-channel.git
cd pn-paper-channel
2

Start LocalStack and obtain the KMS key ARN

Start LocalStack with the services that Paper Channel depends on:
docker run --rm -d \
  --name localstack \
  -p 4566:4566 \
  -e SERVICES=dynamodb,sqs,kms,events \
  localstack/localstack:latest
Create a KMS key for address encryption:
aws --endpoint-url=http://localhost:4566 \
    kms create-key \
    --region eu-south-1 \
    --query 'KeyMetadata.KeyId' \
    --output text
Save the printed ARN — you will need it in the next step. It looks like:
arn:aws:kms:eu-south-1:000000000000:key/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
The README explicitly calls out this step: for local testing with LocalStack you must retrieve the KMS key ARN from the LocalStack logs (or from the create-key output) and set it as aws.kms.keyId in your configuration.
3

Create the required SQS queues and DynamoDB tables

Create the SQS queues that the service listens on:
for QUEUE in \
  pn-paper-channel-internal \
  pn-paper-channel-national-registries \
  pn-paper-channel-external-channel \
  pn-paper-channel-f24 \
  pn-paper-channel-delayer-to-paperchannel \
  pn-paper-channel-to-delivery-push \
  pn-paper-channel-normalize-address \
  pn-paper-channel-to-delayer; do
  aws --endpoint-url=http://localhost:4566 \
      sqs create-queue \
      --queue-name "$QUEUE" \
      --region eu-south-1
done
4

Configure the application

Create a local properties override file at the project root. Replace <KMS_KEY_ARN> with the value from step 2:
# application-local.properties

spring.application.name=PN-PAPER-CHANNEL
pn.env.runtime=DEV

# AWS / LocalStack endpoints
cloud.aws.region.static=eu-south-1
cloud.aws.credentials.access-key=test
cloud.aws.credentials.secret-key=test

aws.kms.keyId=<KMS_KEY_ARN>

# Endpoint overrides — point all AWS clients at LocalStack
cloud.aws.endpoint=http://localhost:4566

# SQS queue names
pn.paper-channel.queue-internal=pn-paper-channel-internal
pn.paper-channel.queue-national-registries=pn-paper-channel-national-registries
pn.paper-channel.queue-external-channel=pn-paper-channel-external-channel
pn.paper-channel.queue-f24=pn-paper-channel-f24
pn.paper-channel.queue-delayer-to-paperchannel=pn-paper-channel-delayer-to-paperchannel
pn.paper-channel.queue-delivery-push=pn-paper-channel-to-delivery-push
pn.paper-channel.queue-normalize-address=pn-paper-channel-normalize-address
pn.paper-channel.queue-paperchannel-to-delayer=pn-paper-channel-to-delayer

# Core operational settings (from application.properties defaults)
pn.paper-channel.refinement-duration=10d
pn.paper-channel.compiuta-giacenza-ar-duration=30d
pn.paper-channel.prepare-two-phases=true
pn.paper-channel.enabledocfilterruleengine=true
pn.paper-channel.cost-rounding-mode=HALF_UP
5

Build and run

Generate OpenAPI stubs and compile the project:
mvn clean package -DskipTests
Run the application with the local profile:
mvn spring-boot:run \
  -Dspring-boot.run.profiles=local \
  -Dspring-boot.run.arguments="--spring.config.additional-location=file:./application-local.properties"
The service starts on port 8080 by default. Verify it is healthy:
curl -s http://localhost:8080/status
You should receive HTTP 200.
6

Send a test prepare request

Submit a paper-delivery prepare request. The requestId path parameter must be between 5 and 100 characters.
curl -s -X POST \
  'http://localhost:8080/paper-channel-private/v1/b2b/paper-deliveries-prepare/test-request-001' \
  -H 'Content-Type: application/json' \
  -d '{
    "requestId": "test-request-001",
    "iun": "TEST-IUN-2026-001",
    "paId": "00000000000",
    "printType": "BN_FRONTE_RETRO",
    "receiverType": "PF",
    "receiverAddress": {
      "address": "Via Roma 1",
      "city": "Roma",
      "pr": "RM",
      "country": "IT",
      "cap": "00100"
    },
    "attachmentUrls": []
  }'
A 204 No Content response means the request was accepted for asynchronous processing. A 200 OK with a PrepareEvent body means the address was confirmed immediately and the cost is available.Poll the prepare result at any time:
curl -s \
  'http://localhost:8080/paper-channel-private/v1/b2b/paper-deliveries-prepare/test-request-001'
Once the prepare request returns a confirmed address and cost, you can progress to the send phase by calling POST /paper-channel-private/v1/b2b/paper-deliveries-send/{requestId} with the same requestId.

Introduction

Learn what Paper Channel does and which services it integrates with.

Architecture

Explore the REST controllers, DynamoDB tables, and queue topology in depth.

Build docs developers (and LLMs) love