Skip to content

Call Palisade Operations Directly

Call any Palisade operation directly, using the palisade.api escape hatch.

/**
 * Call any Palisade operation directly — the `palisade.api` escape hatch.
 *
 * The verticals (`client.xrp`/`iou`/`token`/…) cover the operations simpleXRPL
 * models first-class. For everything else Palisade exposes — vaults,
 * counterparties, policies, webhooks, balances — reach for `palisade.api.call`,
 * a **secondary** surface keyed on the operationId. Path params, query, body,
 * and the response are all typed from the generated OpenAPI schema, so the call
 * autocompletes and type-checks without a hand-written method per resource.
 *
 * Auth routing has two layers. Method-based (the default): reads (`GET`) go on
 * the wallet-read credential, mutations on the transactions one. Tag-based
 * (optional): register a credential per Palisade permission scope under
 * `credentials.scoped` and every operation in that scope routes to it — needed
 * because Palisade scopes one permission set per credential, so policy or
 * webhook administration lives on its own credential.
 */
import { PalisadeCustody } from 'simplexrpl'

// The same two-credential Palisade connector used by the vertical examples,
// plus an optional scoped credential for the `Policies` permission set.
const palisade = await PalisadeCustody.create({
  baseUrl: 'https://api.sandbox.palisade.co', // sandbox (TESTNET data)
  credentials: {
    wallets: {
      clientId: process.env.PALISADE_WALLETS_CLIENT_ID ?? '',
      clientSecret: process.env.PALISADE_WALLETS_CLIENT_SECRET ?? '',
    },
    transactions: {
      clientId: process.env.PALISADE_TX_CLIENT_ID ?? '',
      clientSecret: process.env.PALISADE_TX_CLIENT_SECRET ?? '',
    },
    // Tag-based routing: `Policies` operations use this credential regardless of
    // HTTP method. Omit `scoped` entirely to rely on method-based routing.
    scoped: {
      Policies: {
        clientId: process.env.PALISADE_POLICY_CLIENT_ID ?? '',
        clientSecret: process.env.PALISADE_POLICY_CLIENT_SECRET ?? '',
      },
    },
  },
  primary: {
    vaultId: process.env.PALISADE_VAULT_ID ?? '',
    walletId: process.env.PALISADE_WALLET_ID ?? '',
  },
})

// GET with a query param → routed to the wallet-read credential. `wallets` is
// typed as `vaultv2Wallet[] | undefined` straight off the schema.
const listed = await palisade.api.call('VaultService_ListGlobalWallets', {
  query: { pageSize: 50 },
})
console.log('wallets in org:', listed.wallets?.length ?? 0)

// GET with path + query params. Placeholders in `/v2/vaults/{vaultId}/…` are
// filled from `path`; a missing one throws before any request is sent.
const balances = await palisade.api.call('BalanceService_GetWalletBalances', {
  path: {
    vaultId: process.env.PALISADE_VAULT_ID ?? '',
    walletId: process.env.PALISADE_WALLET_ID ?? '',
  },
  query: { currencyCode: 'USD' },
})
console.log('aggregated fiat value:', balances.aggregatedFiatValue)

// POST → routed to the transactions credential. The body is type-checked
// against the operation's request schema (`name` and `details` are required).
const counterparty = await palisade.api.call(
  'CounterpartyService_CreateCounterparty',
  {
    body: {
      name: 'Acme Capital',
      details: { type: 'ORGANIZATION' },
    },
  },
)
console.log('created counterparty:', counterparty)

// A `Policies` operation → routed to the scoped credential registered above
// (not the wallet-read client its GET method would otherwise select).
const limits = await palisade.api.call('PolicyService_ListGlobalWalletLimits')
console.log('global wallet limits:', limits.walletLimits?.length ?? 0)

See Also