Self-hosted & ConnectorsMapping Packs

Mapping Packs

Adopt a newer Standards Release on a self-hosted install without a new image: load a signed mapping pack, reload it without a restart, and confirm which pack is serving.

What a mapping pack is

Mapping between MT and MX is driven by data tables, versioned per SWIFT Standards Release (SR, the annual update to message definitions). A mapping pack carries the table changes for a release that is newer than any release built into your image, as signed data. It lets an air-gapped install adopt that release without upgrading the binary.

A pack can only add a release. It never changes the releases your image already ships, never adds a conversion pair or format, never touches amount or currency fields and never contains code: each rule selects a named, built-in transform. Requests that do not ask for the pack's release produce byte-identical output with or without the pack loaded.

Packs are issued by 403 Finance and signed with the same key that signs your licence. Your release image carries the matching public key, so it accepts only packs from 403 Finance; you cannot sign or edit a pack yourself.

The mappingpack/v1 format

Before signing, a pack is a JSON document. You receive it already signed (a compact token, usually named *.pack.jws), but this is what it contains:

{
  "schema": "mappingpack/v1",
  "version": "2027.1",
  "sr": "SR2027",
  "description": "Optional, at most 512 characters",
  "documents": [
    {
      "schema": "override/v1",
      "pair": { "from": "mt103", "to": "pacs.008" },
      "rules": [
        { "path": ":20:", "action": "transform", "transform": "truncate", "params": { "max": 16 } }
      ]
    }
  ]
}
FieldRules
schemaAlways mappingpack/v1
version1 to 64 characters from A-Z a-z 0-9 . _ -. Reported by /v1/ready
srSRyyyy, strictly newer than every release built into the image
descriptionOptional, at most 512 characters
documents1 to 256 override/v1 documents, with the same rule grammar and guardrails as tenant mapping overrides. A document's own sr, if set, must equal the pack's

At most 10,000 rules and 4 MiB in total. Any violation rejects the whole pack; nothing is partially applied.

For each conversion leg a pack patches, the new release starts as a copy of the newest earlier release's table with the pack's rules applied. Pairs the pack does not touch fall back to the newest earlier release at the pack's SR, the same rule built-in releases follow. Rules the pack applies show up as OVERRIDE_APPLIED or OVERRIDE_SUPPRESSED warnings whose detail names the pack version.

Load a pack

Set TRANSMUTE_MAPPING_PACK to the path of the signed file. The API verifies the signature and every guardrail at startup and refuses to start if the file is unsigned, signed by another key, altered or invalid. The log line mapping pack loaded records the pack version, SR and document and rule counts.

Docker Compose:

services:
  api:
    environment:
      TRANSMUTE_MAPPING_PACK: /etc/transmute/sr2027.pack.jws
    volumes:
      - /opt/transmute/sr2027.pack.jws:/etc/transmute/sr2027.pack.jws:ro

Reload without a restart

Replace the file, then send the API process SIGHUP:

docker compose kill -s HUP api
# or, on a host install:
kill -HUP <api-pid>

The new pack is verified exactly like a startup load. If it passes, the log shows mapping pack reloaded. If it fails, the log shows mapping pack reload refused; keeping the current tables and the pack already in service keeps serving. Requests already in flight always finish on the tables they started with. A SIGHUP with TRANSMUTE_MAPPING_PACK unset is logged and ignored.

Helm

Put the signed file in a ConfigMap (a signed pack is not a secret) and name it in the values:

kubectl -n transmute create configmap transmute-pack --from-file=pack.jws=./sr2027.pack.jws
mappingPack:
  configMap: transmute-pack
  key: pack.jws        # default

The chart mounts the file under /etc/transmute/mappingpack/ and sets TRANSMUTE_MAPPING_PACK. The image has no shell to send a signal from, so to roll a new pack in Kubernetes, update the ConfigMap and restart the Deployment:

kubectl -n transmute create configmap transmute-pack --from-file=pack.jws=./sr2027-2.pack.jws \
  --dry-run=client -o yaml | kubectl apply -f -
kubectl -n transmute rollout restart deployment/<api-deployment>

Check what is serving

GET /v1/ready reports the loaded pack:

curl -s http://localhost:8080/v1/ready
{
  "status": "ready",
  "mappingPack": { "version": "2027.1", "sr": "SR2027", "loadedAt": "2027-03-01T09:00:00Z" }
}

GET /v1/formats lists the pack's release in srVersions alongside the built-in ones. Request it per call with the srVersion option:

curl -sS -X POST "http://localhost:8080/v1/convert?from=mt103&to=pacs.008&srVersion=SR2027" \
  -H "Authorization: Bearer $TRANSMUTE_KEY" \
  -H "Content-Type: text/plain" \
  --data-binary @payment.mt103

Scope limits

The pack's release is available on POST /v1/convert, /v1/normalize and /v1/validate of the API process that loaded it. Batch jobs (POST /v1/convert/batch) and the file-drop connector keep the built-in releases, because the standalone worker and the connector do not load packs. Every replica loads its own copy: give all replicas the same file.