diff --git a/mintlify/openapi.yaml b/mintlify/openapi.yaml
index d13da97fd..25844997c 100644
--- a/mintlify/openapi.yaml
+++ b/mintlify/openapi.yaml
@@ -19954,7 +19954,7 @@ components:
|--------|-------------|
| `CREATED` | Initial lookup has been created |
| `PENDING` | Quote has been created |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `PROCESSING` | Funding has been received and payment initiated |
| `COMPLETED` | Cross border payment has been received, converted and payment has been sent to the offramp network |
| `REJECTED` | Receiving institution or wallet rejected payment, payment has been refunded |
@@ -20377,7 +20377,7 @@ components:
| Status | Description |
|--------|-------------|
| `PENDING` | Quote is pending confirmation |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `EXPIRED` | Quote wasn't executed before expiry window |
| `PROCESSING` | Executing the quote after receiving funds |
| `COMPLETED` | Payout successfully reached the destination |
@@ -23318,6 +23318,7 @@ components:
type: string
enum:
- OUTGOING_PAYMENT.PENDING
+ - OUTGOING_PAYMENT.PENDING_AUTHORIZATION
- OUTGOING_PAYMENT.PROCESSING
- OUTGOING_PAYMENT.COMPLETED
- OUTGOING_PAYMENT.FAILED
diff --git a/mintlify/platform-overview/core-concepts/quote-system.mdx b/mintlify/platform-overview/core-concepts/quote-system.mdx
index 13d7f6657..a85a5ac24 100644
--- a/mintlify/platform-overview/core-concepts/quote-system.mdx
+++ b/mintlify/platform-overview/core-concepts/quote-system.mdx
@@ -228,6 +228,44 @@ curl -X POST https://api.lightspark.com/grid/2025-10-13/quotes/Quote:abc123/exec
}
```
+### Strong Customer Authentication (EU Customers)
+
+For customers in regions where Strong Customer Authentication (SCA) is required (e.g., EU), quotes may enter a `PENDING_AUTHORIZATION` status with an `scaChallenge` object. The transfer is not released until the customer authorizes it.
+
+Where the challenge appears depends on how the quote is funded:
+
+- **Prefunded** — `POST /quotes/{quoteId}/execute` returns `PENDING_AUTHORIZATION` with the challenge instead of initiating the transfer. The challenge does not exist until `execute` is called, so the proof always goes on the follow-up authorize; re-calling `execute` returns `409`.
+- **Realtime (JIT) funded** — the challenge arrives earlier and `paymentInstructions` are withheld until it is satisfied.
+
+**Quote response with SCA challenge:**
+
+```json
+{
+ "id": "Quote:019542f5-b3e7-1d02-0000-000000000050",
+ "status": "PENDING_AUTHORIZATION",
+ "scaChallenge": {
+ "id": "ScaChallenge:...",
+ "expiresAt": "2025-10-03T12:05:00Z",
+ "factor": "SMS_OTP",
+ "availableFactors": ["SMS_OTP", "PASSKEY"],
+ "purpose": "PAYOUT"
+ }
+}
+```
+
+To authorize the quote, call `POST /quotes/{quoteId}/authorize` with the appropriate proof:
+
+```bash
+curl -X POST https://api.lightspark.com/grid/2025-10-13/quotes/Quote:abc123/authorize \
+ -u "$GRID_CLIENT_ID:$GRID_CLIENT_SECRET" \
+ -H "Content-Type: application/json" \
+ -d '{"code": "123456"}'
+```
+
+
+ Multiple authorizations may be required in sequence (e.g., currency conversion + payout). After each authorization, check the quote status — if still `PENDING_AUTHORIZATION`, authorize the next challenge.
+
+
### Execution Timing
diff --git a/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx b/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx
index 37197e1ae..34421eedb 100644
--- a/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx
+++ b/mintlify/platform-overview/core-concepts/transaction-lifecycle.mdx
@@ -121,6 +121,7 @@ A single `status` field represents whether the transaction reached its destinati
| Status | Description |
|--------|-------------|
| **PENDING** | Quote is pending confirmation |
+| **PENDING_AUTHORIZATION** | Awaiting Strong Customer Authentication. Only occurs for customers in regions where SCA is required (e.g., EU). The challenge lives on the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` with `POST /quotes/{quoteId}/authorize`. |
| **EXPIRED** | Quote wasn't executed before the expiry window |
| **PROCESSING** | Executing the quote after receiving funds (checking internal balances, or push/pull to/from external account) |
| **COMPLETED** | Payout successfully reached the destination account |
@@ -135,6 +136,9 @@ A single `status` field represents whether the transaction reached its destinati
```mermaid
stateDiagram-v2
[*] --> PENDING : Quote created
+ PENDING --> PENDING_AUTHORIZATION : SCA required (EU)
+ PENDING_AUTHORIZATION --> PROCESSING : Authorized
+ PENDING_AUTHORIZATION --> FAILED : Challenge expired unsatisfied
PENDING --> PROCESSING : Quote confirmed, funds received
PENDING --> EXPIRED : Quote expired before execution
PROCESSING --> COMPLETED : Payout reached destination
@@ -202,6 +206,7 @@ Outgoing payment webhooks use the format `OUTGOING_PAYMENT.`. The webhoo
| Event | Description |
|-------|-------------|
| `OUTGOING_PAYMENT.PENDING` | Transaction created, quote pending confirmation |
+| `OUTGOING_PAYMENT.PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication (EU customers only) |
| `OUTGOING_PAYMENT.PROCESSING` | Quote confirmed, payout in progress |
| `OUTGOING_PAYMENT.COMPLETED` | Payout reached destination |
| `OUTGOING_PAYMENT.FAILED` | Payout failed |
@@ -229,6 +234,26 @@ Outgoing payment webhooks use the format `OUTGOING_PAYMENT.`. The webhoo
```
+
+```json
+{
+ "type": "OUTGOING_PAYMENT.PENDING_AUTHORIZATION",
+ "data": {
+ "id": "Transaction:...",
+ "status": "PENDING_AUTHORIZATION",
+ "type": "OUTGOING",
+ "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
+ "quoteId": "Quote:019542f5-b3e7-1d02-0000-000000000006",
+ "sentAmount": {"amount": 100000, "currency": {"code": "USD"}},
+ "receivedAmount": {"amount": 92000, "currency": {"code": "EUR"}},
+ "createdAt": "2025-10-03T15:00:00Z"
+ }
+}
+```
+
+The payload carries no `scaChallenge` — that field lives on the quote. Use `quoteId` to fetch `GET /quotes/{quoteId}`, read its `scaChallenge`, and authorize with `POST /quotes/{quoteId}/authorize`.
+
+
```json
{
@@ -282,6 +307,13 @@ app.post('/webhooks/grid', async (req, res) => {
const { data, type } = req.body;
switch (type) {
+ case 'OUTGOING_PAYMENT.PENDING_AUTHORIZATION': {
+ // EU customers only: the challenge is on the quote, not the transaction
+ const quote = await getQuote(data.quoteId);
+ await promptScaChallenge(data.customerId, data.quoteId, quote.scaChallenge);
+ break;
+ }
+
case 'OUTGOING_PAYMENT.COMPLETED':
await notifyCustomer(data.customerId, 'Payment delivered!');
break;
@@ -315,6 +347,21 @@ The standard successful payment flow:
3. `OUTGOING_PAYMENT.COMPLETED`
+
+The customer must satisfy a Strong Customer Authentication challenge before the payout proceeds:
+
+1. `OUTGOING_PAYMENT.PENDING`
+2. `OUTGOING_PAYMENT.PENDING_AUTHORIZATION`
+3. `OUTGOING_PAYMENT.PROCESSING`
+4. `OUTGOING_PAYMENT.COMPLETED`
+
+
+A single payment can require more than one authorization in sequence, so `OUTGOING_PAYMENT.PENDING_AUTHORIZATION` may arrive several times before `PROCESSING`. Loop on the quote's status rather than assuming one authorization releases the payment.
+
+
+If the challenge expires before the customer satisfies it, the transaction lands on `OUTGOING_PAYMENT.FAILED` with `failureReason: SCA_NOT_COMPLETED` and no funds move. Create a new quote to try again.
+
+
Payment fails and the refund succeeds:
@@ -455,6 +502,8 @@ When a transaction fails, a refund is initiated automatically. Track the refund
switch (webhookType) {
case 'OUTGOING_PAYMENT.PENDING':
return 'Payment processing...';
+ case 'OUTGOING_PAYMENT.PENDING_AUTHORIZATION':
+ return 'Authorization required. Complete the security challenge to continue.';
case 'OUTGOING_PAYMENT.PROCESSING':
return 'Payment in progress...';
case 'OUTGOING_PAYMENT.COMPLETED':
diff --git a/openapi.yaml b/openapi.yaml
index d13da97fd..25844997c 100644
--- a/openapi.yaml
+++ b/openapi.yaml
@@ -19954,7 +19954,7 @@ components:
|--------|-------------|
| `CREATED` | Initial lookup has been created |
| `PENDING` | Quote has been created |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `PROCESSING` | Funding has been received and payment initiated |
| `COMPLETED` | Cross border payment has been received, converted and payment has been sent to the offramp network |
| `REJECTED` | Receiving institution or wallet rejected payment, payment has been refunded |
@@ -20377,7 +20377,7 @@ components:
| Status | Description |
|--------|-------------|
| `PENDING` | Quote is pending confirmation |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `EXPIRED` | Quote wasn't executed before expiry window |
| `PROCESSING` | Executing the quote after receiving funds |
| `COMPLETED` | Payout successfully reached the destination |
@@ -23318,6 +23318,7 @@ components:
type: string
enum:
- OUTGOING_PAYMENT.PENDING
+ - OUTGOING_PAYMENT.PENDING_AUTHORIZATION
- OUTGOING_PAYMENT.PROCESSING
- OUTGOING_PAYMENT.COMPLETED
- OUTGOING_PAYMENT.FAILED
diff --git a/openapi/components/schemas/transactions/OutgoingTransactionStatus.yaml b/openapi/components/schemas/transactions/OutgoingTransactionStatus.yaml
index d49ffd374..e23f5e263 100644
--- a/openapi/components/schemas/transactions/OutgoingTransactionStatus.yaml
+++ b/openapi/components/schemas/transactions/OutgoingTransactionStatus.yaml
@@ -12,7 +12,7 @@ description: |
| Status | Description |
|--------|-------------|
| `PENDING` | Quote is pending confirmation |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `EXPIRED` | Quote wasn't executed before expiry window |
| `PROCESSING` | Executing the quote after receiving funds |
| `COMPLETED` | Payout successfully reached the destination |
diff --git a/openapi/components/schemas/transactions/TransactionStatus.yaml b/openapi/components/schemas/transactions/TransactionStatus.yaml
index dc5524c0f..767c3176f 100644
--- a/openapi/components/schemas/transactions/TransactionStatus.yaml
+++ b/openapi/components/schemas/transactions/TransactionStatus.yaml
@@ -16,7 +16,7 @@ description: |
|--------|-------------|
| `CREATED` | Initial lookup has been created |
| `PENDING` | Quote has been created |
- | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU); authorize the transaction's `scaChallenge` to proceed. |
+ | `PENDING_AUTHORIZATION` | Awaiting Strong Customer Authentication. Only occurs for customers in a region where SCA is required (e.g. EU). The challenge is carried by the quote, not the transaction — fetch `GET /quotes/{quoteId}` using the transaction's `quoteId`, then authorize its `scaChallenge` via `POST /quotes/{quoteId}/authorize`. |
| `PROCESSING` | Funding has been received and payment initiated |
| `COMPLETED` | Cross border payment has been received, converted and payment has been sent to the offramp network |
| `REJECTED` | Receiving institution or wallet rejected payment, payment has been refunded |
diff --git a/openapi/components/schemas/webhooks/WebhookType.yaml b/openapi/components/schemas/webhooks/WebhookType.yaml
index fab72c524..da61ac7f7 100644
--- a/openapi/components/schemas/webhooks/WebhookType.yaml
+++ b/openapi/components/schemas/webhooks/WebhookType.yaml
@@ -1,6 +1,7 @@
type: string
enum:
- OUTGOING_PAYMENT.PENDING
+ - OUTGOING_PAYMENT.PENDING_AUTHORIZATION
- OUTGOING_PAYMENT.PROCESSING
- OUTGOING_PAYMENT.COMPLETED
- OUTGOING_PAYMENT.FAILED