Security

This page describes the flow for utilizing the EBT security features using client certificates, transaction tokens and journey locks.

Issue X.509 client certificate

Operation: POST /v2/auth/device-client-certificates

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token from login

Body

Empty request body. The backend generates the key pair and certificate internally.

Request example

{}

Responses

200 OK (DeviceClientCertificateResponse)

Field Structure St Rep Comments

certificateDer

String (byte, base64)

M

1

X.509 client certificate, DER, base64

Example:

{
  "certificateDer": "MIIDXTCCAkWgAwIBAgIJAK..."
}

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Certificate generation failed",
  "errorCode": "required_info_not_provided",
  "errors": [
    "Certificate generation failed"
  ]
}

401 UNAUTHORIZED (ErrorResponse)

{
  "status": "401 UNAUTHORIZED",
  "statusCode": 401,
  "message": "Invalid or expired access token",
  "errorCode": "unauthorized_token",
  "errors": [
    "Invalid or expired access token"
  ]
}

Get BLE transaction token (unique device id and device nonce)

Operation POST /v2/ebt-authorizations

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token

Body (EbtAuthorizationRequest)

Field Structure St Rep Comments

uniqueDeviceId

String

M

1

EBT device id

nonce

String

M

1

Nonce read from the tag over BLE

L.3 Request example

{
  "uniqueDeviceId": "ebt_unique_01HZ...",
  "nonce": "nonce_from_tag_hex_or_b64"
}

Responses

200 OK (EbtAuthorizationResponse)

Field Structure St Rep Comments

transactionToken

String

M

1

Short-lived token for BLE write/clear

Example:

{
  "transactionToken": "txn_01JABC...signed"
}

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Invalid nonce",
  "errorCode": "required_info_not_provided",
  "errors": [
    "Invalid nonce"
  ]
}

403 FORBIDDEN (ErrorResponse)

{
  "status": "403 FORBIDDEN",
  "statusCode": 403,
  "message": "Authorization denied for this device",
  "errorCode": "error_missing_permission",
  "errors": [
    "Authorization denied for this device"
  ]
}

Attach baggage to device - create journey lock

Attach baggage to a device, creating the journey lock.

Operation : POST /v2/device-attachments

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token

Body (DeviceAttachmentRequest)

Field Structure St Rep Comments

device

DeviceModel

M

1

Device identity and metadata

baggageId

Integer (int32), minimum 1

M

1

Baggage record to attach

DeviceModel — at least one of uniqueID, mac, or guid should be provided.

Field Structure St Rep Comments

uniqueID

String

O

0..1

Unique device id

mac

String

O

0..1

MAC address

guid

String

O

0..1

GUID

ccid

String

O

0..1

CCID

tagName

String

O

0..1

Display name

phoneMac

String

O

0..1

Phone MAC

bagIDModel

String

O

0..1

Hardware model

batteryPercentage

Integer (int32)

O

0..1

Battery %

firmwareVersion

String

O

0..1

Firmware

serialNumber

String

O

0..1

Serial

Request example

{
  "device": {
    "ccid": "8991101200003204512",
    "guid": "550e8400-e29b-41d4-a716-446655440000",
    "mac": "AA:BB:CC:DD:EE:FF",
    "uniqueID": "ebt_unique_01HZ...",
    "tagName": "BagID #1",
    "phoneMac": "11:22:33:44:55:66",
    "bagIDModel": "BAGID-V2",
    "batteryPercentage": 87,
    "firmwareVersion": "1.2.3",
    "serialNumber": "SN-EBT-000123"
  },
  "baggageId": 5001
}

Responses

204 No Content

Attached successfully. No response body.

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Invalid attachment request",
  "errorCode": "device_journey_lock_active",
  "errors": [
    "Invalid attachment request"
  ]
}

Get EBT lock status for unique device id

Operation POST /v2/ebt-lookups

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token

Body (EbtLockLookupRequest)

Field Structure St Rep Comments

uniqueDeviceId

String

M

1

Selected EBT device id

Request example

{
  "uniqueDeviceId": "ebt_unique_01HZ..."
}

Responses

200 OK (EbtLockLookupResponse)

Field Structure St Rep Comments

locked

Boolean

O

0..1

Whether tag is locked to a journey

sameTravelPlan

Boolean

O

0..1

Same travel plan as current session

requiresCustodyProof

Boolean

O

0..1

Whether PNR/surname proof is required

hints

EbtLockHints

O

0..1

Masked hints for custody proof UI

EbtLockHints (optional fields): maskedRecordLocator, maskedSurname, departureAirport, destinationAirport.

Example:

{
  "locked": true,
  "sameTravelPlan": false,
  "requiresCustodyProof": true,
  "hints": {
    "maskedRecordLocator": "••••23",
    "maskedSurname": "Lo••••••",
    "departureAirport": "OSL",
    "destinationAirport": "ARN"
  }
}

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Missing uniqueDeviceId",
  "errorCode": "required_info_not_provided",
  "errors": [
    "Missing uniqueDeviceId"
  ]
}

Provide custody proof (PNR and surname) and unlock EBT

Operation POST /v2/ebt-custody-proofs

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token

Body (EbtCustodyProofRequest)

Field Structure St Rep Comments

uniqueDeviceId

String

M

1

EBT device id

recordLocator

String

M

1

PNR / record locator

surname

String

M

1

Passenger surname for the locking journey

J.3 Request example

{
  "uniqueDeviceId": "ebt_unique_01HZ...",
  "recordLocator": "ABC123",
  "surname": "Lovelace"
}

Responses

204 No Content

No response body.

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Invalid custody proof",
  "errorCode": "required_info_not_provided",
  "errors": [
    "Invalid custody proof"
  ]
}

403 FORBIDDEN (ErrorResponse)

{
  "status": "403 FORBIDDEN",
  "statusCode": 403,
  "message": "Custody proof rejected",
  "errorCode": "ebt_custody_proof_not_allowed",
  "errors": [
    "Custody proof rejected"
  ]
}

Remove EBT custody lock (only for lock holder)

Authenticated lock holder removes the DeviceTicketLock for the device (same persistence effect as a successful POST /v2/ebt-custody-proofs). Use for flows such as clear EBT at end of journey without submitting PNR and surname. Callers who are not the lock holder receive 403. Does not replace POST /v2/ebt-custody-proofs for non-holders with valid proof.

Operation: POST /v2/ebt-unlocks

Headers

Scheme Structure St Rep Comments

X-Source-App-Key

Header

M

1

Issued client key

bearerAuth

HTTP Bearer (JWT)

M

1

Access token

Body (EbtUnlockRequest)

Field Structure St Rep Comments

uniqueDeviceId

String

M

1

Device identifier (same as POST /v2/ebt-lookups)

Request example

{
  "uniqueDeviceId": "ebt_unique_01HZ..."
}

Responses

204 No Content

Lock removed or already absent (idempotent per server rules). No response body.

400 BAD_REQUEST (ErrorResponse)

{
  "status": "400 BAD_REQUEST",
  "statusCode": 400,
  "message": "Missing uniqueDeviceId",
  "errorCode": "required_info_not_provided",
  "errors": [
    "Missing uniqueDeviceId"
  ]
}

401 UNAUTHORIZED (ErrorResponse)

{
  "status": "401 UNAUTHORIZED",
  "statusCode": 401,
  "message": "Invalid or expired access token",
  "errorCode": "unauthorized_token",
  "errors": [
    "Invalid or expired access token"
  ]
}

403 FORBIDDEN (ErrorResponse)

{
  "status": "403 FORBIDDEN",
  "statusCode": 403,
  "message": "Caller is not the lock holder",
  "errorCode": "error_missing_permission",
  "errors": [
    "Caller is not the lock holder"
  ]
}