Skip to main content
A tender (gara d’appalto) is the master configuration entity that defines which delivery drivers serve which geographic areas and at what costs. Before pn-paper-channel can route paper notifications, at least one tender must be active.

Lifecycle states

Every tender moves through these states:
DRAFT → ACTIVE → EXPIRED
  • DRAFT — The tender has been created and can be edited. Delivery drivers and costs can be added.
  • ACTIVE — The tender is in use. The service uses its delivery drivers and cost tables to route and price notifications.
  • EXPIRED — The tender’s endDate has passed or another tender was activated in its place.
Activating a new tender replaces the currently active one. Make sure the new tender is fully configured with drivers and costs before activating it.

Creating a tender

Use the POST /paper-channel-bo/v1/tender endpoint. You need the tender-write permission.
curl -X POST https://<host>/paper-channel-bo/v1/tender \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-api-key>" \
  -d '{
    "name": "Gara 2025-Q1",
    "startDate": "2025-01-01",
    "endDate": "2025-03-31"
  }'
The code field is optional. If omitted, the server generates one. Response schema (TenderCreateResponseDTO):
{
  "tender": {
    "code": "TENDER-001",
    "name": "Gara 2025-Q1",
    "startDate": "2025-01-01",
    "endDate": "2025-03-31",
    "status": "DRAFT"
  }
}
Record the code value — you need it for all subsequent operations on this tender.

Adding delivery drivers

Use POST /paper-channel-bo/v1/delivery-driver/{tenderCode} to associate a delivery driver with the tender. You need the tender-write permission.
curl -X POST https://<host>/paper-channel-bo/v1/delivery-driver/TENDER-001 \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-api-key>" \
  -d '{
    "taxId": "12345678901",
    "businessName": "Recapitisti S.p.A.",
    "fiscalCode": "12345678901",
    "pec": "[email protected]",
    "phoneNumber": "+390612345678",
    "registeredOffice": "Via Roma 1, 00100 Roma",
    "fsu": false
  }'
Set "fsu": true if this driver is the Fornitore Servizio Universale (FSU) for the tender. To retrieve all drivers for a tender:
curl -X GET "https://<host>/paper-channel-bo/v1/deliveries-drivers/TENDER-001?page=0&size=20" \
  -H "x-api-key: <your-api-key>"
To retrieve only the FSU:
curl -X GET https://<host>/paper-channel-bo/v1/deliveries-drivers/TENDER-001/fsu \
  -H "x-api-key: <your-api-key>"

Adding costs

Use POST /paper-channel-bo/v1/{tenderCode}/delivery-driver/{deliveryDriverId}/cost to add a cost entry for a driver. You need the tender-write permission. Each cost entry covers one product type and a set of geographic keys (CAP codes or international zones). Prices are given in euro for different weight ranges (grams).
curl -X POST \
  https://<host>/paper-channel-bo/v1/TENDER-001/delivery-driver/<deliveryDriverId>/cost \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-api-key>" \
  -d '{
    "productType": "AR",
    "cap": ["00100", "00118"],
    "price": 1.20,
    "price50": 1.30,
    "price100": 1.50,
    "price250": 1.80,
    "price350": 2.00,
    "price1000": 2.50,
    "price2000": 3.00,
    "priceAdditional": 0.10
  }'
For international deliveries, use "zone" instead of "cap":
curl -X POST \
  https://<host>/paper-channel-bo/v1/TENDER-001/delivery-driver/<deliveryDriverId>/cost \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-api-key>" \
  -d '{
    "productType": "RS",
    "zone": "ZONE_1",
    "price": 2.50,
    "priceAdditional": 0.25
  }'
To view all costs for a driver in a tender:
curl -X GET \
  "https://<host>/paper-channel-bo/v1/TENDER-001/delivery-driver/<deliveryDriverId>/get-cost?page=0&size=50" \
  -H "x-api-key: <your-api-key>"

Activating a tender

Once the tender is fully configured, activate it with PUT /paper-channel-bo/v1/tender/{tenderCode}. You need the tender-write permission.
curl -X PUT https://<host>/paper-channel-bo/v1/tender/TENDER-001 \
  -H "Content-Type: application/json" \
  -H "x-api-key: <your-api-key>" \
  -d '"ACTIVE"'
The request body is a Status enum value: "ACTIVE", "DRAFT", or "EXPIRED".
Activating a tender while another one is already active will replace the active tender. Verify that all drivers and costs are correct before sending this request.

Downloading tender data

The GET /paper-channel-bo/v1/delivery-tender/file-download endpoint returns a presigned download URL or the file content for the tender data export. You need the tender-read permission.
curl -X GET \
  "https://<host>/paper-channel-bo/v1/delivery-tender/file-download?tenderCode=TENDER-001&uuid=<file-uuid>" \
  -H "x-api-key: <your-api-key>"
The response is an InfoDownloadDTO with fields:
FieldTypeDescription
uuidstringFile identifier
statusUPLOADING | UPLOADEDUpload status
databyte (base64)File content when status is UPLOADED
retryAfterintegerMilliseconds to wait before polling again when status is UPLOADING

Using the tenderAPILambda for read operations

For read-only access to tender data outside the Back-Office API, invoke the pn-paper-channel-tenderAPILambda directly. The Lambda reads from DynamoDB and supports five operations.
The Lambda function name follows the pattern {ProjectName}-paper-channel-TenderAPI (e.g., pn-paper-channel-TenderAPI in production).

List tenders

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{
    "operation": "GET_TENDERS",
    "page": 0,
    "size": 20,
    "from": "2025-01-01T00:00:00.000Z",
    "to": "2025-12-31T23:59:59.999Z"
  }' \
  response.json
Omit from and to to return all tenders. The active boolean field in each result indicates whether the tender is currently active.

Get the active tender

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{"operation": "GET_TENDER_ACTIVE"}' \
  response.json
Returns 404 if no tender is currently active.

Get costs for a tender

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{
    "operation": "GET_COSTS",
    "tenderId": "<tenderId>",
    "product": "AR",
    "lot": "LOT-1",
    "zone": "ZONE_1",
    "deliveryDriverId": "<driverId>"
  }' \
  response.json
All filter fields (product, lot, zone, deliveryDriverId) are optional.

Get a specific cost by geokey

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{
    "operation": "GET_COST",
    "tenderId": "<tenderId>",
    "product": "AR",
    "geokey": "00100"
  }' \
  response.json

List geokey versions

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{
    "operation": "GET_GEOKEY",
    "tenderId": "<tenderId>",
    "product": "AR",
    "geokey": "00100"
  }' \
  response.json

List all delivery drivers

aws lambda invoke \
  --function-name pn-paper-channel-tenderAPILambda \
  --payload '{"operation": "GET_DELIVERY_DRIVERS"}' \
  response.json

Deleting tenders and drivers

You can delete a tender that is still in DRAFT state:
curl -X DELETE https://<host>/paper-channel-bo/v1/tender/TENDER-001 \
  -H "x-api-key: <your-api-key>"
To remove a delivery driver from a tender:
curl -X DELETE \
  https://<host>/paper-channel-bo/v1/TENDER-001/delivery-driver/<deliveryDriverId> \
  -H "x-api-key: <your-api-key>"
To remove a specific cost entry:
curl -X DELETE \
  https://<host>/paper-channel-bo/v1/TENDER-001/delivery-driver/<deliveryDriverId>/cost/<uuid> \
  -H "x-api-key: <your-api-key>"
All write endpoints require the tender-write API permission. All read endpoints require tender-read.

Build docs developers (and LLMs) love