# Card API in general, and 4.1-4.7

Behaviour the specs don't define (simulator choices). Back to the [index](README.md).

Card API:
- Only 14 of the 40 card endpoints are active (the list is in
  `lib/ysp_simulator/active_endpoints.ex`). The other 26 are checked before
  anything else: HTTP 404 with `{"error": "endpoint_not_enabled", "message": ...}`.
  This is not a YSP answer (YSP has no such code), so it can't be mistaken for
  one. The `txnRefNo` is not claimed, headers and body are not checked, and
  nothing is recorded as a card result. The `gate_endpoints` setting turns
  this off (it is off in the test environment). The payment notification and
  merchant routes are never gated.
- Header failures: wrong or missing `apikey` → `INVAPI`; `clientid` not 6
  alphanumeric characters → `NOCLET`; `channeltype` not `API` → `TXNBLK`;
  missing `netId` → `INVUSR`; `timeStamp` not 12–16 digits → `11`.
- Bad JSON, missing `msgHdr` fields or a `txnRefNo` that is missing or longer than 32 characters → `11`.
- A reused `txnRefNo` → `TIDEXT`, including references whose first use failed.
- Errors are returned with HTTP 200 by default. Set `:error_http_status` in
  config to change this.
- Requests are plain JSON. The encrypted payloads the spec mentions aren't supported.

Purchase Card (4.1):
- With a `proxyNumber` the request registers an instant card, which must be
  in `:seed_inventory` and not yet registered; otherwise `NOTINV`. Without one,
  a new card is created. Personalized and virtual cards aren't told apart:
  both get `proxyNumber`, `cardNumber` and `cardExpiry`, like the spec sample.
- New proxy numbers are sequential (one above the highest known). The card
  number is `512345` + the last 10 digits of the proxy. The expiry is the end of
  the month five years out, e.g. `31-MAR-30`.
- Only `customerInfo` (must be an object) and `loadDetails` are checked:
  `billingAmount` must be whole digits (`11` otherwise) and `productCode` must
  be in `:products` (`INPDID` otherwise). Other fields are stored unchecked.
- The new card's balance is `billingAmount`, in the product's currency.
- `cardActivationFlag` `Y` → status `I` (Active); anything else → `M` (Card
  Issued). An inactive card's response includes a random 6-digit
  `activationCode`. The 4.1 response table has no field for it, but 4.5 says
  Purchase Card returns one.
- A `customerId` can hold any number of cards; `CIDEXT` is never returned.

Update Customer Details (4.2):
- Only `mobileNumber`, `emailAddress`, `address` and `mailAddress` are
  stored. The spec says the name can't be updated, so the name fields,
  `dob`, `identificationType` and `futureUse` are accepted and ignored.
- `customerInfo` must be an object with non-blank `mobileNumber` and
  `emailAddress`, and `address` / `mailAddress`, when sent, must be objects;
  `11` otherwise. No other field is checked.
- An address node that is sent replaces the stored one whole; one that isn't
  sent is left as it was.
- `proxyNumber` wins if both it and `customerId` are sent, as in 4.3. The
  spec's table spells it `customerID`; both spellings are accepted. With
  `customerId`, every card of that customer is updated and the response lists
  their proxy numbers comma-separated, plus the `customerId`. Unknown
  `customerId` → `INVCID`; neither sent → `INVCRD`.
- Cards can be updated in any status, including locked and blocked.
- The response uses `proxyNumber`, as in the sample, not `proxyNumer` from the table.

Get Card Details (4.3):
- `proxyNumber` wins if both it and `customerId` are sent. An unknown
  `customerId` → `INVCID`; neither sent → `INVCRD`.
- With `proxyNumber`, the number sent is echoed back. With `customerId`, the
  cards' proxy numbers are returned.
- `expiryDate` uses the sample's format (`31-JUL-29`), not the table's `DDMMYYYY`.
- `maskedCardNumber` and `cvv` are in the sample but not the table; both are
  returned. The cvv is a fixed 3-digit number derived from the card number.
- `mobileNumber` and `emailId` come from the purchase's `customerInfo`
  (`mobileNumber`, `emailAddress`) and are left out when unknown.

Block/Unblock (4.4):
- `BL`/`BS`/`BD` set `HL`/`HS`/`HD` (Hot List Lock/Stolen/Damaged).
- The spec only says the request fails when the card already has the
  requested status. The codes for the other refused moves (`CRDBLP`, `CRDLKD`,
  `NOTACT`) are the closest matches from appendix 7.3.
- An unknown `flag`, or a missing or blank `reason` → `11`.

Card Activation (4.5):
- A missing, `null` or empty `activationCode` activates the card without a
  check, like the spec sample, which sends `null`.
- `customerId`, `customerNumber` and `appCode` are ignored.

Card Replacement (4.6):
- The real system creates the card at end of day. The simulator creates it
  at once and returns its numbers straight away.
- `PP` needs status `HL`, `HS` or `HD`. A locked (`L`) card isn't blocked, so
  it gets `NTBLCD` too. `VP` takes `I` or `M` cards; locked → `CRDLKD`,
  hot-listed → `CRDBLO`. The spec doesn't say what `VP` needs.
- The new card's balance and added accounts are moved from the old card,
  which keeps its status with zero balances. The spec doesn't say whether
  the two cards share an account.
- The new card starts inactive (`M`) with no activation code, so 4.5
  activates it without one. It gets the default ATM PIN for its own card
  number, even if the old card's PIN was changed. Its expiry is five years out, as in Purchase Card.
- `newCardNumber` is masked, as in the sample. `cardAcctNo` and `cvv` are
  optional and left out.
- A replaced card can't be replaced again (`ORDEXT`); replace the new card instead.
- A missing or unknown `type`, or a `deliveryFlag` other than `B` or `C`,
  → `11`. `deliveryFlag` isn't required. `cardDesign` and `customerId` are
  ignored, so `INVPLA` is never returned.
- The sample uses GET. POST is accepted too.

Account Addition (4.7):
- Accounts are per product. Each `details` entry is checked like a Load
  Card request (`11` for bad amounts or `loadCurrency`), plus `productCode`
  must be in `:products` (`INPDID`) and `billingCurrency` must be its currency
  (`INVCCY`).
- A product the card already has, or the same product twice in one request,
  → `ACTEXT`. Two products in the same currency are allowed, so `ACCEXT` is
  never returned.
- The request is all or nothing: if one entry fails, none are added.
- A missing `productInfo.details`, or an empty list, → `11`.
- The response echoes `proxyNumber` as the table says. The sample shows `null`.
