Internal Accounts
Strong Customer Authentication

Move a rule-based account's stranded funds

Changed on

Move funds a sweep converted but could not deliver (listed in the account's strandedBalances) to the account holder's own internal account in the same currency.

The transfer is returned as a quote in PENDING_AUTHORIZATION carrying an scaChallenge. Authorize it with POST /quotes/{quoteId}/authorize, as for any other quote. Once it completes, the currency drops out of strandedBalances and an INTERNAL_ACCOUNT.BALANCE_UPDATED webhook is sent.

Stranded funds only arise for customers in a region where SCA is required (the EU). For other accounts, or when nothing is stranded in that currency, this returns 409.

post/internal-accounts/{id}/stranded-funds/transfer

Request

  • Base URL
    https://api.lightspark.com/grid/2025-10-13
  • URL
    https://api.lightspark.com/grid/2025-10-13/internal-accounts/{id}/stranded-funds/transfer
  • Auth
    HTTP basic

Request body

currencystring required

Currency of the stranded balance to move, as listed in the account's strandedBalances. The whole stranded balance in that currency is moved.

scaFactor'SMS_OTP' | 'PASSKEY'

A Strong Customer Authentication factor that can authorize a single transfer. TOTP is not one, because it cannot carry the required dynamic linking.

Example request

{
  "currency": "USDC",
  "scaFactor": "SMS_OTP"
}

Response

The transfer's quote, awaiting authorization.

idstring required

Unique identifier for this quote

status'PENDING' | 'PENDING_AUTHORIZATION' | 'PROCESSING' | 'COMPLETED' | 'FAILED' | 'EXPIRED' required

Current status of the quote. PENDING_AUTHORIZATION occurs only for customers in a region where Strong Customer Authentication is required (e.g. EU): the quote carries an scaChallenge that must be authorized before execution, and for realtime-funding sources paymentInstructions are withheld until it is satisfied.

createdAtstring date-time required

When this quote was created

expiresAtstring date-time required

Absolute UTC timestamp when the rate locked in this quote becomes invalid and the quote can no longer be executed. The window depends on the rail and corridor: instant rails (Lightning, Spark, USDC on Solana/Base/Polygon, RTP, SEPA Instant) typically expire in 1–5 minutes; corridors with longer settlement guarantees may have longer windows. Always rely on this timestamp rather than assuming a fixed window.

totalSendingAmountinteger required

The total amount that will be sent in the smallest unit of the sending currency (eg. cents).

totalReceivingAmountinteger required

The total amount that will be received in the smallest unit of the receiving currency (eg. cents).

exchangeRatenumber required

Number of sending currency units per receiving currency unit. The rate is fee-exclusive: Grid deducts feesIncluded from totalSendingAmount first, then converts the remainder at this rate to reach totalReceivingAmount.

feesIncludedinteger required

The fees associated with the quote in the smallest unit of the sending currency (eg. cents). Note: this value may fluctuate between quotes — some underlying fee components are defined in the receiving currency, so their equivalent in the sending currency moves with the FX rate. The fees shown here are locked only for the lifetime of this quote.

platformFeesIncludedinteger

The portion of feesIncluded collected by the platform (platform-configured transaction fees), in the smallest unit of the sending currency. 0 when the platform has no applicable fee configured. Already included in feesIncluded. May be omitted from payloads produced before platform fees existed.

transactionIdstring required

The ID of the transaction created from this quote.

counterpartyInformationCounterpartyInformation

Additional information about the counterparty, if available and relevant to the transaction and platform.

purposeOfPayment'GIFT' | 'SELF' | 'GOODS_OR_SERVICES' | 'EDUCATION' | 'HEALTH_OR_MEDICAL' | 'REAL_ESTATE_PURCHASE' | 'TAX_PAYMENT' | 'LOAN_PAYMENT' | 'UTILITY_BILL' | 'DONATION' | 'TRAVEL' | 'FAMILY_SUPPORT' | 'SALARY_PAYMENT' | 'EXPORTED_GOODS_PREPAYMENT' | 'EXPORTED_GOODS_POSTPAYMENT' | 'SERVICE_CHARGES' | 'OFFICE_EXPENSES' | 'DELIVERY_FEES' | 'HOTEL_ACCOMMODATION' | 'COMMISSION_ON_GOODS' | 'COMMISSION_ON_SERVICES' | 'ACCOUNTING_SERVICES' | 'EXHIBITION_SERVICES' | 'OTHER'

The purpose of the payment. This may be required when sending to certain geographies (e.g. India).

Some destinations accept only certain purposes. A business payout to China must use one of the purposes listed in Supporting Documents, and each needs its own supporting documents.

documentIdsstring[]

IDs of the supporting documents attached to the payment behind this quote, as passed in documentIds on POST /quotes. Present only when the quote was created with documentIds. Grid returns such a quote only after it has attached every document. Call GET /payment-documents/{paymentDocumentId} for each document's details, such as its documentType and its ATTACHED status.

Example response

{
  "id": "Quote:019542f5-b3e7-1d02-0000-000000000006",
  "status": "PENDING",
  "createdAt": "2025-10-03T12:00:00Z",
  "expiresAt": "2025-10-03T12:05:00Z",
  "source": {
    "sourceType": "ACCOUNT",
    "accountId": "InternalAccount:e85dcbd6-dced-4ec4-b756-3c3a9ea3d965",
    "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001"
  },
  "destination": {
    "destinationType": "ACCOUNT",
    "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
    "paymentRail": "ACH"
  },
  "sendingCurrency": {
    "code": "USD",
    "name": "United States Dollar",
    "symbol": "$",
    "decimals": 2
  },
  "receivingCurrency": {
    "code": "USD",
    "name": "United States Dollar",
    "symbol": "$",
    "decimals": 2
  },
  "totalSendingAmount": 123010,
  "totalReceivingAmount": 1000,
  "feesIncluded": 10,
  "platformFeesIncluded": 5,
  "paymentInstructions": [
    {
      "accountOrWalletInfo": {
        "accountType": "USD_ACCOUNT",
        "paymentRails": [
          "ACH",
          "WIRE"
        ],
        "accountNumber": "1234567890",
        "routingNumber": "021000021",
        "bankName": "Chase Bank",
        "reference": "UMA-Q12345-REF"
      },
      "instructionsNotes": "Include reference UMA-Q12345-REF in memo"
    },
    {
      "accountOrWalletInfo": {
        "accountType": "SPARK_WALLET",
        "assetType": "BTC",
        "address": "spark1pgssyuuuhnrrdjswal5c3s3rafw9w3y5dd4cjy3duxlf7hjzkp0rqx6dj6mrhu",
        "invoice": "lnbc15u1p3xnhl2pp5jptserfk3zk4qy42tlucycrfwxhydvlemu9pqr93tuzlv9cc7g3sdqsvfhkcap3xyhx7un8cqzpgxqzjcsp5f8c52y2stc300gl6s4xswtjpc37hrnnr3c9wvtgjfuvqmpm35evq9qyyssqy4lgd8tj637qcjp05rdpxxykjenthxftej7a2zzmwrmrl70fyj9hvj0rewhzj7jfyuwkwcg9g2jpwtk3wkjtwnkdks84hsnu8xps5vsq4gj5hs"
      }
    }
  ],
  "transactionId": "Transaction:019542f5-b3e7-1d02-0000-000000000005",
  "counterpartyInformation": {
    "FULL_NAME": "John Sender",
    "BIRTH_DATE": "1985-06-15",
    "NATIONALITY": "DE"
  },
  "rateDetails": {
    "counterpartyMultiplier": 1.08,
    "counterpartyFixedFee": 10,
    "gridApiMultiplier": 0.925,
    "gridApiFixedFee": 10,
    "gridApiVariableFeeRate": 0.003,
    "gridApiVariableFeeAmount": 30
  },
  "documentIds": [
    "PaymentDocument:019542f5-b3e7-1d02-0000-000000000001",
    "PaymentDocument:019542f5-b3e7-1d02-0000-000000000002",
    "PaymentDocument:019542f5-b3e7-1d02-0000-000000000003"
  ],
  "scaChallenge": {
    "id": "ScaChallenge:019542f5-b3e7-1d02-0000-000000000007",
    "expiresAt": "2025-10-03T12:05:00Z",
    "availableFactors": [
      "SMS_OTP"
    ],
    "purpose": "PAYOUT",
    "passkeyAllowedOrigins": [
      "https://app.example.com"
    ]
  }
}

Changes