Internal Accounts
Strong Customer Authentication

Authorize a rule-based account's SCA challenge

Changed on

Satisfy the Strong Customer Authentication challenge carried by a RULE_BASED internal account in PENDING status by submitting an ScaAuthorization proof. The challenge authorizes the account's sweep instruction once; later sweeps need no further authorization.

On success the account is returned ACTIVE with its fundingPaymentInstructions, and an INTERNAL_ACCOUNT.STATUS_UPDATED webhook is sent. As with all SCA, check the returned account: if it is still PENDING it carries the next scaChallenge to authorize.

This endpoint is only meaningful for customers in a region where SCA is required (e.g. EU). For other customers, and for accounts with no pending challenge, this returns 409.

In sandbox, the SMS code is always 123456.

post/internal-accounts/{id}/authorize

Request

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

Request body

codestring nullable

The one-time code the customer received by SMS, or read from their authenticator app. In sandbox, the code is always 000000.

passkeyAssertionobject nullable

Opaque WebAuthn assertion produced by the device from the challenge's passkeyAssertionOptions. Required when satisfying a PASSKEY challenge.

originstring nullable

The WebAuthn origin the passkeyAssertion was produced against. Required alongside passkeyAssertion; omit it for the code path. When the challenge lists passkeyAllowedOrigins (enrollment / login challenges), it must be one of those. A per-transaction passkey challenge carries passkeyAssertionOptions but may omit passkeyAllowedOrigins; in that case supply the origin your app invoked the WebAuthn API from, which must match the relying party in passkeyAssertionOptions.

endUserIpAddressstring nullable

The IP address of the end user's device authorizing this operation, forwarded to the SCA provider where it feeds risk assessment and any transaction-risk exemption. Supply the customer's address, not your server's. Optional: the provider records it for money-movement authorizations, and ignores it for beneficiary trust changes.

Example request

{
  "code": "000000",
  "origin": "https://app.example.com",
  "endUserIpAddress": "203.0.113.42"
}

Response

Challenge authorized; the updated account is returned.

idstring required

The ID of the internal account

customerIdstring

The ID of the customer associated with the internal account. If this field is empty, the internal account belongs to the platform.

type'INTERNAL_FIAT' | 'INTERNAL_CRYPTO' | 'EMBEDDED_WALLET' | 'RULE_BASED' | 'BULK_SETTLEMENT' required

Classification of an internal account.

  • INTERNAL_FIAT: A Grid-managed fiat holding account (for example, the USD holding account used as the source for Payouts flows).
  • INTERNAL_CRYPTO: A Grid-managed crypto holding account denominated in a stablecoin such as USDC.
  • EMBEDDED_WALLET: A self-custodial Embedded Wallet provisioned for the customer. Outbound transfers require a session signature produced by the customer's device — see the Embedded Wallets guide.
  • RULE_BASED: An additional account number for an existing account holder, with a routing rule attached, so incoming payments can be attributed to a specific payer and swept automatically. Created with POST /internal-accounts.
  • BULK_SETTLEMENT: An account for receiving bulk payments (for example, a single settlement from a payment processor) that the platform then pays out to its customers. Only a platform can hold one, and funds in it can move only to the platform's customers.
status'PENDING' | 'ACTIVE' | 'CLOSED' | 'FROZEN' | 'FAILED' required

Status of a Grid internal account. The status determines whether the account can send or receive payments.

  • PENDING: The account is under review and is being provisioned. The account cannot send or receive payments until provisioning completes.
  • ACTIVE: The account is ready to send and receive payments.
  • CLOSED: The account cannot send or receive payments. A customer can initiate the closing of an internal account, after which the account transitions to this status.
  • FROZEN: The account cannot send or receive payments. Grid may freeze an account in response to compliance or fraud signals; payments are blocked while the account remains frozen.
  • FAILED: The account could not be provisioned. Grid was unable to create the underlying account, so it cannot send or receive payments and requires remediation.
onBehalfOfCustomerIdstring

The customer whose payments this platform-owned account receives. Only set by regulated financial institutions. Omitted for accounts that name no such customer, which includes every account owned by a customer.

labelstring

The platform-supplied label recorded when the account was created. Null for accounts that carry none.

privateEnabledboolean

Whether wallet privacy is enabled for the Embedded Wallet. Only present for EMBEDDED_WALLET internal accounts.

createdAtstring date-time required

Timestamp when the internal account was created

updatedAtstring date-time required

Timestamp when the internal account was last updated

Example response

{
  "id": "InternalAccount:12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
  "customerId": "Customer:019542f5-b3e7-1d02-0000-000000000001",
  "status": "ACTIVE",
  "balance": {
    "amount": 12550,
    "currency": {
      "code": "USD",
      "name": "United States Dollar",
      "symbol": "$",
      "decimals": 2
    }
  },
  "totalBalance": {
    "amount": 12550,
    "currency": {
      "code": "USD",
      "name": "United States Dollar",
      "symbol": "$",
      "decimals": 2
    }
  },
  "fundingPaymentInstructions": [
    {
      "instructionsNotes": "Please ensure the reference code is included in the payment memo/description field",
      "isPlatformAccount": true,
      "accountOrWalletInfo": {
        "accountType": "USD_ACCOUNT",
        "accountNumber": "1234567890",
        "routingNumber": "021000021",
        "bankName": "Chase Bank",
        "intermediaryBankName": "JPMorgan Chase Bank",
        "intermediaryRoutingNumber": "021000021",
        "fiToFiInformation": "/BNF/Invoice 4471",
        "bankAccountType": "CHECKING"
      }
    }
  ],
  "onBehalfOfCustomerId": "Customer:019542f5-b3e7-1d02-0000-000000000002",
  "label": "invoice-4417",
  "sweepRule": {
    "destination": {
      "accountId": "ExternalAccount:a12dcbd6-dced-4ec4-b756-3c3a9ea3d123",
      "paymentRail": "ACH"
    },
    "minimumAmount": {
      "amount": 12550,
      "currency": {
        "code": "USD",
        "name": "United States Dollar",
        "symbol": "$",
        "decimals": 2
      }
    },
    "maximumAmount": {
      "amount": 12550,
      "currency": {
        "code": "USD",
        "name": "United States Dollar",
        "symbol": "$",
        "decimals": 2
      }
    },
    "description": "Rent sweep",
    "remittanceInformation": "Unit 4B March",
    "platformFeeOverride": {
      "platformFixedFee": {
        "amount": 50,
        "currency": "USD"
      },
      "platformVariableFeeBps": 30
    }
  },
  "scaChallenge": {
    "id": "ScaChallenge:019542f5-b3e7-1d02-0000-000000000007",
    "expiresAt": "2025-10-03T12:05:00Z",
    "availableFactors": [
      "SMS_OTP"
    ],
    "purpose": "PAYOUT",
    "passkeyAllowedOrigins": [
      "https://app.example.com"
    ]
  },
  "strandedBalances": [
    {
      "amount": 12550,
      "currency": {
        "code": "USD",
        "name": "United States Dollar",
        "symbol": "$",
        "decimals": 2
      }
    }
  ],
  "privateEnabled": true,
  "cardCapabilities": {
    "supportsVelocityLimits": true,
    "supportsPanReveal": true,
    "supportsDigitalWalletTokenization": true
  },
  "createdAt": "2025-10-03T12:30:00Z",
  "updatedAt": "2025-10-03T12:30:00Z"
}

Changes