Skip to content
5 changes: 5 additions & 0 deletions .redocly.lint-ignore.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@ openapi.yaml:
- '#/paths/~1quotes/post/requestBody/content/application~1json/schema'
no-ambiguous-paths:
- '#/paths/~1customers~1external-accounts~1{externalAccountId}'
# threeDSecurePassword: "threeDSecure" is the industry-standard casing for
# 3DS and matches the EU provider's wire field; the camelCase checker
# rejects the consecutive-capital hump. Deliberate exception.
field-names-camelCase:
- '#/components/schemas/CardCreateRequest/properties/threeDSecurePassword'
11 changes: 11 additions & 0 deletions .spectral.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,14 @@ rules:
function: pattern
functionOptions:
match: "^(\\/([a-z0-9]+(-[a-z0-9]+)*|\\{[a-zA-Z0-9]+\\}))+$"

# Per-pointer exceptions (mirror .redocly.lint-ignore.yaml - both linters run
# the same conventions, and spectral has no ignore-file mechanism).
overrides:
# threeDSecurePassword: "threeDSecure" is the industry-standard casing for
# 3DS and matches the EU provider's wire field; the camelCase checker
# rejects the consecutive-capital hump. Deliberate exception.
- files:
- "**/openapi.yaml#/components/schemas/CardCreateRequest/properties/threeDSecurePassword"
rules:
field-names-camelCase: off
73 changes: 70 additions & 3 deletions mintlify/openapi.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

15 changes: 6 additions & 9 deletions mintlify/snippets/cards/implementation-overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,8 @@ cards. Cards do not require new webhook endpoints or new API
credentials — they reuse what's already configured for the rest of
Grid. You'll only need to:

- Subscribe to the new card-specific webhook types (`CARD.STATE_CHANGE`
and `CARD.FUNDING_SOURCE_CHANGE`). Card-transaction lifecycle events
ride on the generic transaction webhook stream that already covers
outgoing-payment activity.
- Subscribe to the new card-specific webhook types (`CARD.STATE_CHANGE`,
`CARD.FUNDING_SOURCE_CHANGE`, and the `CARD_TRANSACTION.*` family).
- Confirm with your Lightspark contact that cards are enabled for your
platform — issuance requires an issuer-side onboarding.

Expand Down Expand Up @@ -88,11 +86,10 @@ When you're ready to go live:

- Complete card-issuer onboarding through your Lightspark contact.
- Confirm webhook security, monitoring, and alerting cover the
`CARD.*` event types plus card-destination transactions on the
generic transaction webhook stream.
- Build the `EXCEPTION` dashboard view from card-destination
transaction webhooks (filter by `status: "EXCEPTION"`) and wire it
into on-call alerting.
`CARD.*` and `CARD_TRANSACTION.*` event types.
- Build the `EXCEPTION` dashboard view from
`CARD_TRANSACTION.EXCEPTION` webhooks and wire it into on-call
alerting.

<Check>
Contact your Lightspark representative to enable Production card
Expand Down
6 changes: 3 additions & 3 deletions mintlify/snippets/cards/quickstart.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,9 @@ curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:019542f5-b3e7-1d02-0000-00000000
}'
```

A transaction webhook fires with the updated parent: the transaction
moves to `SETTLED`, `pullSummary.count` becomes `2`, and
`settlementSummary.totalAmount` is `1500`.
A `CARD_TRANSACTION.SETTLED` webhook fires with the updated parent:
the transaction moves to `SETTLED`, `pullSummary.count` becomes `2`,
and `settlementSummary.totalAmount` is `1500`.

The webhook payload carries the full parent `CardTransaction` with
child pull, clearing, and refund events rolled up into the
Expand Down
49 changes: 30 additions & 19 deletions mintlify/snippets/cards/reconciliation.mdx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
A card transaction is not a single event it's a parent row plus a
A card transaction is not a single event - it's a parent row plus a
stream of child events from the card network. This page covers the
event model, the status transitions, and how to handle the
`EXCEPTION` path.
Expand All @@ -7,16 +7,16 @@ event model, the status transitions, and how to handle the

For each card authorization, Grid produces:

1. **One parent `CardTransaction`** created at auth time, persists for
1. **One parent `CardTransaction`** - created at auth time, persists for
the life of the transaction.
2. **Pulls** debits against the funding source that fund approved
2. **Pulls** - debits against the funding source that fund approved
auths and any post-hoc settlements.
3. **Clearings** the network's confirmation that funds have moved.
4. **Refunds** merchant-initiated `RETURN` events.
3. **Clearings** - the network's confirmation that funds have moved.
4. **Refunds** - merchant-initiated `RETURN` events.

Children are reconciled against the parent and rolled up into three
aggregates: `pullSummary`, `settlementSummary`, and `refundSummary`.
You don't see per-child rows on the list endpoint they're summarized
You don't see per-child rows on the list endpoint - they're summarized
on the parent.

## Status transitions
Expand All @@ -32,15 +32,26 @@ AUTHORIZED ──► PARTIALLY_SETTLED ──► SETTLED ──► REFUNDED
| Status | Meaning |
|--------|---------|
| `AUTHORIZED` | Auth approved, hold placed, no clearings yet. |
| `DECLINED` | The authorization was declined by the issuer or program. No funds moved; the transaction is terminal. |
| `PARTIALLY_SETTLED` | At least one clearing landed, but more are still expected (split shipments, multi-leg trips). |
| `SETTLED` | All clearings for the auth have posted. The transaction is closed against the funding source. |
| `REFUNDED` | A `RETURN` was received and the net settled amount has been refunded in full or part. |
| `EXCEPTION` | The transaction settled to the network but the corresponding pull from the funding source failed. |

Every transition is delivered via the generic transaction webhook
stream carrying the post-change parent (a follow-up extends the
Transaction model with a card destination type — see
[Webhooks](/cards/platform-tools/webhooks)).
Every state transition is delivered via a `CARD_TRANSACTION.*` webhook
whose type names the new status (`CARD_TRANSACTION.AUTHORIZED`,
`CARD_TRANSACTION.SETTLED`, ...) and carries the post-update parent.
See [Webhooks](/cards/platform-tools/webhooks) for the full payload
shape.

**Refund linkage differs by card program.** US programs link merchant
refunds to the original purchase: the purchase transitions to `REFUNDED`
and its `refundedAmount`/`refundSummary` update. EU programs receive
merchant refunds from the network WITHOUT a purchase reference, so a
refund arrives as a **standalone CREDIT-direction card transaction** (its
own `CARD_TRANSACTION.*` lifecycle) and the original purchase keeps its
final status with `refundedAmount` unset. Reconcile EU refunds by
merchant/amount/time rather than by parent linkage.

## The over-auth path

Expand All @@ -59,13 +70,13 @@ The post-settlement parent carries `authorizedAmount: 1250`,

An exception happens when the card network has already moved funds for
a settlement but Grid can't pull the matching amount from the funding
source typically because the cardholder's balance no longer covers
source - typically because the cardholder's balance no longer covers
the post-hoc difference.

Signal to watch: a transaction webhook with `status: "EXCEPTION"` for
a card-destination transaction. The payload includes the full parent
record, so your dashboard's exception view is driven entirely by
webhook deliveries — there's no list endpoint to poll.
Signal to watch: a `CARD_TRANSACTION.EXCEPTION` webhook. The payload
includes the full parent record, so your dashboard's exception view is
driven entirely by webhook deliveries - there's no list endpoint to
poll.

Exceptions don't roll back automatically. The standard response is to
top up the funding source (or move the customer to a state where their
Expand All @@ -74,10 +85,10 @@ exception to resolution.

## Idempotency on webhooks

Every transaction webhook carries a unique `id`. Track processed
webhook IDs and treat duplicates as no-ops Grid retries failed
deliveries, and your reconciliation should be safe under at-least-once
delivery.
Every `CARD_TRANSACTION.*` webhook carries a unique `id`. Track
processed webhook IDs and treat duplicates as no-ops - Grid retries
failed deliveries, and your reconciliation should be safe under
at-least-once delivery.

See [Webhooks](/cards/platform-tools/webhooks) for signature
verification and the full payload shape.
4 changes: 2 additions & 2 deletions mintlify/snippets/cards/sandbox-testing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ curl -X POST "$GRID_BASE_URL/sandbox/cards/Card:.../simulate/return" \
-d '{ "cardTransactionId": "CardTransaction:...", "amount": 1500 }'
```

At each step you'll see `CARD.STATE_CHANGE` or
`CARD.FUNDING_SOURCE_CHANGE` webhooks plus transaction webhooks for
At each step you'll see `CARD.STATE_CHANGE`,
`CARD.FUNDING_SOURCE_CHANGE`, or `CARD_TRANSACTION.*` webhooks for
the simulated authorization, clearing, and return — wire those into
your local webhook handler to validate end-to-end.
Loading
Loading