# Amex GFSG/CAPN Settlement Submission — Build Status & Gap Analysis

**Source reviewed:** `docs/Clearing-System/Acquirer Submission Guidelines v2.4.pdf`
("Acquirer Submission Guidelines," American Express, Global Financial Submission (GFSG) —
Middle East (excl. KSA) & North Africa, May 2025, Version 2.4, 26 pages, read in full — also
duplicated at `docs/Switch-System/Amex-Acquirer-Submission-Guidelines-v2.4.pdf`, identical file,
confirmed by checksum). This is this repo's only Amex spec.

**Compared against:** this umbrella as of `feature/amex-gfsg-settlement`, principally
`clearing_core` (`ClearingCore.Amex.*`), `settlement_core`
(`SettlementCore.AmexOutboundPresentment`), and the `platform_web` Clearing/Schemes screens —
same real-spec-or-nothing standard as the Mastercard IPM, JCB Interchange, and Visa BASE II
builds.

**No Way4 Amex interface manual exists in this repo** — `PlatformWeb.SchemeLive.CoverageCatalog`'s
`@amex_groups` is grounded in GFSG/CAPN's own record taxonomy (TFH/TAB/TAA/TBT/TFS), the same
method `@visa_groups` uses for the same reason.

---

## 1. The one fact that shapes everything else: Amex is outbound-only

This document describes what an acquirer **submits to** Amex. Nothing in its 26 pages, and
nothing anywhere else in this repo (grepped: zero hits), describes a reciprocal Amex-to-acquirer
clearing file for Mercury to ingest. Every other scheme built in this project (Mastercard IPM,
JCB Interchange, Visa BASE II) is bidirectional — Mercury both decodes a real inbound clearing
file and builds a real outbound one. Amex is not: there is no `Amex.Ingestor`, no
`Amex.FileReader`, and the coverage catalog's Amex "Daily Procedures" group has exactly one item
instead of the two-or-three every other scheme has (an inward + outward pair). This is a
structural fact about the format, not a scope cut made under time pressure — stated once here so
it isn't rediscovered as a suspected gap later.

## 2. Executive summary

| Area | Status |
|---|---|
| GFSG/CAPN record codec (TFH/TAB/TAA-Location-Detail/TBT/TFS) | **Built** — real spec, full field tables |
| TAA EMV (Chip Card) record | **Gap** — real, documented; no ICC data captured anywhere in `core_transactions` to populate it from |
| File writer (batching by currency+Merchant-ID, real TBT/TFS invariants) | **Built** |
| Outbound submitter (local write + `ClearingBatch`) | **Built** — no real Amex transport spec (SFTP details provisioned per-acquirer during certification, not published) |
| `SettlementCore.AmexOutboundPresentment` | **Built**, with two named limitations (§3) |
| Coverage catalog | **Built**, taxonomy-derived, no inbound items (§1) |
| Reports | **Built** — one real report (Submission Volume Summary); no further report menu exists to catalog since there's no Way4 manual naming one |
| Real sample data | **None** — unlike Visa/JCB, this repo has no real Amex sample file; codec tests validate against the spec's own field-position tables directly |

---

## 3. Two real, named limitations in `AmexOutboundPresentment`

1. **No full PAN** — `core_transactions.masked_pan` is the only PAN this app ever stores, same
   limitation as the Visa/JCB/Mastercard outbound builders.
2. **No real card expiry.** The TAB record's Regional Requirements table marks `CARD_EXPIRY_DATE`
   (Field 10) **mandatory** in every transaction record. Grepping the full POS/settlement
   pipeline found expiry captured only as `PosTransaction.encrypted_expiry` — pre-settlement,
   encrypted, never carried into `core_transactions`. `AmexOutboundPresentment` writes the
   placeholder `"0000"` and names this explicitly in its own `summary.warning` — not silently
   faked as a real date. Closing this gap for real would mean either adding a plaintext (or
   decryptable) expiry field to the settlement pipeline, or accepting Amex's own file-rejection
   risk for this field until one exists.

Both limitations mean **a file built here today is not submission-ready**, the same honest
framing every other scheme's outbound builder uses.

## 4. Inferred, not spec-stated, and safe to revisit

- **`RECORD_TYPE` literal values** (`"TFH"`, `"TAB"`, `"TAA"`, `"TBT"`, `"TFS"`) — the document
  names every record by these exact 3-letter acronyms and gives each a 3-byte `RECORD_TYPE`
  field, but never prints a literal example value in the pages read. Using the acronym itself is
  the only reasonable reading.
- **`TBT_AMOUNT_SIGN` code values** — the field is defined, its values are not. This build writes
  `"C"` for a net-debit (net amount owed to merchant) batch and `"D"` for net-credit (net refund),
  a reasonable convention, not a confirmed spec value.
- **`TFS`'s three totals are read as independent unsigned hash sums** (`HASH_TOTAL_DEBIT_AMOUNT`,
  `HASH_TOTAL_CREDIT_AMOUNT`, and `HASH_TOTAL_AMOUNT` as their arithmetic sum), not a signed net
  balance — inferred from the spec's own "hash total" terminology and its bullet-list phrasing,
  not a worked example. `TBT_AMOUNT`/`_SIGN`, by contrast, **is** built as a real net balance,
  because the spec's own words for TBT are "the TBT must balance with its corresponding TABs" —
  a netting concept, a different framing than TFS's.
- **`ADDENDA_TYPE_CODE`** (TAA record, distinguishes Location Detail vs. EMV Chip Card) — written
  as spec-blank; its code values are not given in the pages read.

## 5. Blocked pending material not in this repo

The document itself defers several field **code-value enumerations** — not positions or
lengths, which are fully specified — to the **"official Global Financial Submission Guide"**,
which is not in this repo:

- `FORMAT_CODE`, `MEDIA_CODE`, `SUBMISSION_METHOD` (TAB)
- `EXTENDED_PAYMENT_DATA` (TAB)
- `ELECTRONIC_COMMERCE_INDICATOR` (TAB) — beyond knowing it's mandatory for e-commerce along with
  the Web Order Number field
- The full `MATCHING_KEY_TYPE`/`MATCHING_KEY` semantics (regional requirement marks both "not in
  use, zero-filled" for this region, so this is a real, confirmed non-gap for MENA/excl.-KSA — not
  every deferred field is a live gap)

These fields are written zero/space-filled per their own type rather than guessed. If the full
Global Financial Submission Guide is ever supplied, revisit this list first.

Also out of scope, real and documented but with nothing in `core_transactions` to build from:

- **TAA EMV (Chip Card) record** — a full, real 256-byte packed ICC subfield block (application
  cryptogram, IAD, ATC, TVR, terminal transaction data, etc.) is specified in detail, but Mercury's
  settlement pipeline doesn't capture EMV/ICC data at the transaction level anywhere — same "don't
  build what there's no real data for" reasoning JCB's CP02-12 addenda were deferred for.
- **Payment Facilitator (Aggregator) fields** (`SELLER_ID`, PF-specific `LOCATION_NAME` format) —
  real and documented, but Mercury's own direct-acquiring model doesn't currently model Payment
  Facilitator/sub-merchant relationships the way this section assumes; left blank rather than
  guessed at.
- **Real SFTP transport** — the document states production submission requires SFTP but the
  actual host/credentials are provisioned per-acquirer during Amex certification, not published
  here. `Amex.OutboundSubmitter` writes locally only, same scope Visa's own submitter has.

None of this is guessed at anywhere in this codebase. If any of this material becomes available,
this document is the starting scope for the next phase, not a rediscovery exercise.
