# How the card API works

Back to the [README](../README.md).

## Every request

Each card API call (section 4 of the spec) sends the same five HTTP headers
and a JSON body that starts with `msgHdr` and `txnRefNo`:

```bash
curl -X POST http://localhost:4180/naradaapiservices/api/v1/carddetails \
  -H 'apikey: APCHDT' -H 'clientid: SNDBOX' -H 'channeltype: API' \
  -H 'netid: APIUSER' -H 'timestamp: 01234567891212' \
  -H 'content-type: application/json' \
  -d '{
        "msgHdr": {"msgId": "WIZ202302171684895539768",
                   "timestamp": "2023-04-04T04:54:08.956Z",
                   "channelType": "web"},
        "txnRefNo": "DEMO0001",
        "proxyNumber": "000000012845"
      }'
```

`apikey` is different for every endpoint (see the endpoint table in the [README](../README.md), or appendix 7.1
of the spec). The other four headers are the same everywhere.

The simulator handles each call in this order and stops at the first failure
(`YspSimulator.CardApi.run/3`):

1. Check the headers. This includes the `apikey` for this endpoint.
2. Decode the JSON body and check `msgHdr` and `txnRefNo`.
3. Record the `txnRefNo`. Each one can be used once, even if the call fails
   later, so send a new one on every request. The response code sent is
   kept, so 4.20 Status Request can report it.
4. Run the endpoint's own logic, which reads or changes the card store.

Every response has `txnRefNo`, `responseCode` and `responseText`, plus the
endpoint's own fields. `"00"` means success. Any other code is an error from
appendix 7.3, still sent with HTTP 200. On an error the response also echoes
the `proxyNumber` (or `customerId`) that was sent.

Cards live in memory. They are lost when the simulator restarts and reset by
`POST /_sim/reset`. `GET /_sim/requests` shows what was sent and returned.

## Card numbers and statuses

A card has a 12-digit **proxy number** and a 16-digit **card number**. Every
endpoint that takes `proxyNumber` accepts either one, except instant-card
registration in Purchase Card, which needs the proxy number.

Statuses use the codes from appendix 7.2:

```
Purchase Card ──┬─ cardActivationFlag "Y" ──────────────┐
                └─ otherwise → M (issued, inactive)     │
                                   │ Card Activation    ▼
                                   └──────────────────► I (active)
                                                        │  ▲
                                          Block/Unblock │  │ Block/Unblock
                                                 flag L ▼  │ flag UL
                                                        L (locked)

I ── Block/Unblock flag BL / BS / BD ──► HL / HS / HD (lost / stolen / damaged, permanent)

any status ── Account Closure of the last open account ──► C (closed, permanent)
```

A closed card can still be looked up with Get Card Details, but every
endpoint that would change it returns `CRDCLD`.


## Adding an endpoint

Write a handler in `lib/ysp_simulator/handlers/` with
`handle(body) :: {:ok, fields} | {:error, code, echo_fields}`, and add one
route in `router.ex` that calls `CardApi.run(conn, "<apikey>", &handle/1)`.
Steps 1–3 and the response wrapping come for free. Add any new response code
to `YspSimulator.ResponseCodes`. Tests can use the helpers in
`test/support/card_api_helpers.ex`, such as `card_request/4` and
`purchase_card!/1`.
