# Girasol B2B API

<https://docs.girasolpayments.com/girasol-b2b-api>

The vendor publishes its Scalar-hosted document at
<https://docs.girasolpayments.com/girasol-b2b-api/openapi.json> (`.yaml` also
works). It is a **Postman collection export**, and generating from it directly
produces unusable types: 49 of the request/response bodies come out as
`Record<string, never>` — a type that permits no properties at all — because
the export declares them as bare `{"type": "object"}` and keeps the real field
contract in an `examples` blob and a markdown table in the operation
`description`. It also fails `rdme openapi validate` outright.

[`enrich.mjs`](enrich.mjs) recovers the contract and repairs the document
before generation. It

1. infers a schema from each operation's request/response `examples`,
   detecting `uuid` / `date-time` / `date` / `email` string formats,
2. overlays the markdown field bullets, which supply each field's description
   and — authoritatively — whether it is required or optional,
3. re-parameterises the 15 paths that hardcode an example id, e.g.
   `/v1/cards/fa2f46d8-1679-48e0-8c96-39b84141403c/freeze` →
   `/v1/cards/{cardId}/freeze`,
4. declares path parameters the export templates but never defines (the three
   3DS webhook operations template a caller-configured receiver URL),
5. repairs four responses that are not valid Response Objects — two where the
   raw payload sits where `content` belongs, two keyed `"undefined"` rather
   than `default`,
6. drops three `requestBody` entries Postman recorded as an empty string on
   operations that take no body (freeze / unfreeze / block),
7. promotes `x-api-key` / `x-secret-key` / `x-company-id` from ordinary
   parameters to `securitySchemes`, and
8. strips the Express/CORS response headers the export captured as noise
   (`X-Powered-By`, `ETag`, `Date`, `Connection`, …).

Both the fetched document and the enriched one are build intermediates and are
**not** committed — only `girasol.d.ts` is, the same as every other vendor
client here. Run the whole pipeline below to regenerate; running
`openapi-typescript` against the vendor URL alone silently undoes all of the
above.

## Update API spec

1. Fetch the vendor document.

```bash
curl -sSL -o packages/clients/src/girasol/openapi.raw.json \
  "https://docs.girasolpayments.com/girasol-b2b-api/openapi.json"
```

1. Enrich it. Expect this summary — if `reqTyped` collapses toward zero the
   vendor changed its export format and `enrich.mjs` needs revisiting.

```bash
bun packages/clients/src/girasol/enrich.mjs \
  packages/clients/src/girasol/openapi.raw.json \
  packages/clients/src/girasol/openapi.json

rm packages/clients/src/girasol/openapi.raw.json
```

```json
{ "ops": 55, "reqTyped": 26, "resTyped": 54, "renamed": 15, "repaired": 4, "declaredParams": 3, "droppedBodies": 3 }
```

1. Validate. The vendor document does not pass this on its own — if it fails
   here after enrichment, `enrich.mjs` has a new defect class to handle.

```bash
bun rdme openapi validate packages/clients/src/girasol/openapi.json
```

1. Generate, then drop the intermediate.

```bash
bun openapi-typescript \
  packages/clients/src/girasol/openapi.json \
  -o packages/clients/src/girasol/girasol.d.ts

rm packages/clients/src/girasol/openapi.json
```

`rg -c 'Record<string, never>' packages/clients/src/girasol/girasol.d.ts` should
report `3` — the trailing `webhooks` / `$defs` / `operations` declarations every
generated file carries, and nothing else.

## Caveats

- **`GirasolClient.ts` consumes these types**, via `openapi-fetch`, the way the
  other vendor clients here are written. It covers 15 of the 55 operations, and
  because it imports `girasol.d.ts`, `nx run clients:typecheck` now exercises
  the generated file — a regeneration that changes a shape the client reads
  fails there rather than silently.
- **Response schemas are inferred from a single captured example**, so a field
  that happened to be absent — or `null` — in that response may be typed too
  narrowly. The prose bullets only ever describe request bodies and path
  parameters, never responses. Four spots where the document is known to be
  wrong are overridden in `GirasolClient.ts`, each with a comment; regeneration
  will not correct them, so re-check them when the vendor updates the spec:

  | Operation                            | Generated                     | Reality                                                        |
  | ------------------------------------ | ----------------------------- | -------------------------------------------------------------- |
  | `GET /v1/accounts/customer-info/{…}` | response body `unknown`       | no example to infer from; `GirasolAccount` is declared by hand |
  | `GET /v1/clearing`                   | `ref_number` required         | omitted on some historical clearing lines                      |
  | `POST /v1/cards/create-card`         | `desingCode` required         | a typo of the optional `designCode`; Girasol accepts neither   |
  | `POST /v1/cards/create-virtual-card` | `expirationMonth/Year` string | callers stringify either way, so the narrowing is harmless     |

- **`servers` were Postman variables** (`http://{{host}}`, plain `http`). The
  enriched document declares them as OpenAPI server variables; the default
  `host` is a placeholder and the real base URL comes from config.
