@cfxlabsinc/b2b-services
    Preparing search index...
    Index
    userId: string

    The RouteFusion UserAccount id this client acts as, decoded from the org JWT's id claim. Sent as user_id on entity mutations.

    • Registers a payout destination against a RouteFusion business entity and returns its id — the beneficiary_id every createTransfer names, and the value CFX stores as routeFusionBeneficiaryId on the payment instrument.

      One call serves US wire, US ACH and SWIFT: RouteFusion's bank-identifier arguments are polymorphic scalars, so the rails differ only in which of account_number / routing_code / swift_bic are populated. There is no per-rail split to mirror Victor's createUsWireCounterparty / createAchCounterparty.

      user_id is the org JWT's own account, so RouteFusion attributes the beneficiary to the identity CFX acts as — matching the entity mutations.

      Parameters

      Returns Promise<string>

    • Pulls funds from a registered incoming-transfer account. Moves no money on its own — two-phase, like the payout, and committed by finalizeIncomingTransfer.

      This is the ONLY RouteFusion pull path that is safe to retry, and the id it returns is why. createDirectDebitTransfer takes only (direct_debit_account_id, entity_id, amount), is single-phase, and returns a DirectDebitTransfer carrying no field to match on — so a retry after a request that already succeeded re-debits the customer with nothing to detect it by. This one is two-phase, which makes it a ticket, and the id is its handle.

      A caller MUST record this id before finalizing, and consult it with getIncomingTransfer on every attempt. That ordering is the guard: money cannot leave the customer's bank without the id being stored first, so a retry always finds the ticket it already minted rather than opening a second debit. executeRouteFusionPayout in @cfxlabsinc/withdrawal-services is the worked example on the payout side.

      reference is a reconciliation label. Do not build a lookup on it — see getIncomingTransfer.

      Parameters

      • args: {
            amount: string;
            incomingTransferAccountId: string;
            purposeOfPayment?: string;
            reference: string;
            remittanceInfo?: string;
            reverseWire?: boolean;
        }

      Returns Promise<string>

    • Creates an outbound payout. Moves no money on its own — RouteFusion's payout is two-phase and the transfer stays unfinalized until finalizeTransfer commits it.

      There is no idempotency key on this mutation, and none is needed: the id this returns IS the handle. A caller that records it before finalizing can read the ticket back with getTransfer and re-accept it; a caller that does not record it will mint a second ticket on every retry. reference is a label for reconciliation, not a lookup key — RouteFusion offers no way to query by it.

      walletId is the pool debited — for CFX that is the wallet on the source ledger account's RouteFusion virtual account, which IS the pool (RF has no separate FBO account the way Victor does).

      Parameters

      • args: {
            beneficiaryId: string;
            entityId: string;
            paymentMethod: RouteFusionPaymentMethod;
            purposeOfPayment: string;
            reference: string;
            sourceAmount: string;
            sourceCurrency?: string;
            walletId: string;
            wire?: boolean;
        }

      Returns Promise<string>

    • Registers a webhook subscription so RouteFusion pushes events for the given resource category to url. Returns the subscription id.

      headerKey/headerValue set a static header RouteFusion sends on every webhook (e.g. a shared secret). Optional.

      Parameters

      • args: {
            headerKey?: string;
            headerValue?: string;
            subscriptionType:
                | "transfer"
                | "wallet"
                | "incoming_transfer"
                | "entity"
                | "beneficiary"
                | "rfi";
            url: string;
        }

      Returns Promise<string>

    • RouteFusion's onboarding requirements are parameterized by country, entity type, and business type — NOT a fixed set (the documented [proof_of_registration, proof_of_ownership, bank_statement] trio is only the US example response). Returns the OR-of-AND document sets: satisfy every document in ANY ONE inner array to meet KYB requirements. Document types the response returns that this client doesn't recognize are dropped (defensive — an ill-formed set could never be satisfied anyway).

      Parameters

      Returns Promise<
          (
              | "proof_of_registration"
              | "proof_of_ownership"
              | "bank_statement"
              | "proof_of_address"
              | "passport"
              | "front_drivers_license"
              | "back_drivers_license"
              | "front_national_state_id"
              | "back_national_state_id"
          )[][],
      >

    • Commits a created transfer. This is the call that actually moves money.

      Safe to repeat for a transfer already finalized — RouteFusion returns the same id — which is what lets the withdrawal activity recover from a crash between create and finalize.

      Parameters

      • args: { transferId: string }

      Returns Promise<string>

    • Reads a beneficiary's lifecycle state and the rails RouteFusion says it can serve.

      Returns null for an unknown id rather than throwing — unlike getWallet. The asymmetry is deliberate: a missing wallet under a VA we believe is ACTIVE is a state disagreement on the money path, while a missing beneficiary is the ordinary answer for an instrument that was never registered, which every caller here has to handle anyway.

      Parameters

      • args: { beneficiaryId: string }

      Returns Promise<RouteFusionBeneficiary | null>

    • Reads one pull by id, or null if RouteFusion does not know it.

      THE canonical single-pull read, and the pull's whole idempotency guard — the mirror of getTransfer. A retry consults the id it recorded before finalizing: finish the ticket if it is still open, report it if the debit already went through.

      It replaces an incomingTransfers(search_terms: reference) lookup, which was the construction that turned out to be inert on the payout side — search_terms there matches a transfer's own id rather than its reference, so that guard never fired once. This endpoint has NOT been probed, and the swap does not depend on one: addressing a ticket by the id that minted it is exact where a fuzzy scan is not, and it reaches an unfinalized ticket, which a listing does not.

      The stakes are the mirror of the payout's. There, a missed guard pays a beneficiary twice; here it debits the customer's own bank twice, and the money has to be given back.

      Parameters

      • args: { incomingTransferId: string }

      Returns Promise<RouteFusionIncomingTransfer | null>

    • Organization-wide incoming transfers (credits), with the pagination envelope retained — the sync needs items_total to compute its page list up front, the way metcap's sync does. page is 0-indexed here; RouteFusion's PaginationInput is 1-indexed, hence the +1.

      No startDate/endDate: FilterInput — CONFIRMED AGAINST LIVE INTROSPECTION AND A LIVE QUERY PROBE — is { key, values, value }, where key addresses a literal DB column and values does exact/IN-list matching, not a range (see INCOMING_TRANSFERS_PAGE_QUERY). RouteFusion has no range/comparison operator on this endpoint at all, so a date window here is a client-side concern: a caller that needs one must filter transaction_date itself after fetching a page.

      Parameters

      • args: { page: number; pageSize: number }

      Returns Promise<RouteFusionIncomingTransferPage>

    • Reads one transfer by id, or null if RouteFusion does not know it.

      THE canonical single-transfer read, and the only one that reaches a minted but unaccepted ticket: the transfers listing carries transactions, so an open ticket is absent from it under every value of includeNotFinalized, and transfers(search_terms:) matches a transfer's own id rather than its reference (both probed against the sandbox on 2026-09-01). RouteFusion publishes no by-reference query at all.

      That makes the id the whole idempotency story. Both callers turn on it: the webhook consumer re-reads here because the event body's state may be stale, and executeRouteFusionPayout re-reads the ticket it recorded before finalizing, so a retry re-accepts that one instead of minting a second.

      Parameters

      • args: { transferId: string }

      Returns Promise<RouteFusionTransfer | null>

    • Organization-wide outbound transfers, from_date onward. page is 0-indexed for parity with VictorTransactionClient.getTransactions; the offset is derived, so callers never compute it.

      endDate is accepted for interface parity with VictorTransactionClient.getTransactions, but is NOT sent to RouteFusion: ListFilter — CONFIRMED AGAINST LIVE INTROSPECTION — has no upper-bound date field (only from_date; see TRANSFERS_QUERY). There is no server-side way to close the window, so a caller that needs one must stop consuming pages once created_date passes endDate.

      Parameters

      • args: { endDate: string; page: number; pageSize: number; startDate: string }

      Returns Promise<RouteFusionTransfer[]>

    • Reads a wallet's lifecycle state and balances — the two things a payout gate needs, in one round trip. Used by the withdrawal quote path; see lookupRouteFusionRoutingPredicates in @cfxlabsinc/withdrawal-services.

      THROWS when RouteFusion returns no wallet for the id. A wallet missing on an id we hold against a VA we believe is ACTIVE is a state disagreement, not an "unknown balance": returning null would let a caller treat the pool as merely unmeasured and pass the route through, so it fails loudly and retryably instead.

      Parameters

      • args: { walletId: string }

      Returns Promise<RouteFusionWallet>

    • Per-representative document requirements (docs.routefusion.com/reference/representative-required-fields) — same OR-of-AND documents shape as entityRequiredFields, but keyed only by the representative's country + program (no entity/business type). NOTE: for this query the document's type field is a purpose category ("identity_verification") shared across many documents, not the file_enum — the actual RouteFusionFileEnum value lives in enum (e.g. "passport", "front_drivers_license"), so this narrows on doc.enum.

      Returns Promise<
          (
              | "proof_of_registration"
              | "proof_of_ownership"
              | "bank_statement"
              | "proof_of_address"
              | "passport"
              | "front_drivers_license"
              | "back_drivers_license"
              | "front_national_state_id"
              | "back_national_state_id"
          )[][],
      >

    • Applies a PARTIAL update to an existing beneficiary.

      Only the keys the caller supplied are sent. That is load-bearing, not a micro-optimization: RouteFusion reads a present-but-null argument as "blank this field", so serializing every absent key would wipe live KYC data on a beneficiary whose bank name was all the caller meant to change. Same trap toRepresentativeVariables guards on the representative mutations.

      currency and bank_country are not updatable — RF's mutation does not accept them, so BusinessBeneficiaryUpdateInput omits them and rebanking means creating a new beneficiary.

      Parameters

      Returns Promise<boolean>

    • Push CFX-side edits to a representative RouteFusion already holds.

      createRepresentative is the only place CFX ever sends a person's details and it runs exactly once per person (stamped by related_person.data.routeFusionRepresentativeId), so without this an operator who supplies a missing tax number or postal code after onboarding has started sees it land in CFX and never reach RouteFusion — and finalizeEntity keeps refusing the submission for the very field they just filled in. The entity has the same shape and the same fix (updateBusinessEntity via syncPinnedEntity).

      A true partial update: send only what the caller wants written.

      Returns RouteFusion's bare Boolean. There is no accompanying message — a rejection RouteFusion can articulate comes back as a GraphQL error (so it THROWS, carrying the reason), and false is the residual "refused, no reason given" case. A caller that needs to explain a false has nothing beyond the fact of it.

      Parameters

      Returns Promise<boolean>

    • Attaches a document to an entity or a representative via RouteFusion's GraphQL multipart singleUpload mutation (Apollo Upload!, header apollo-require-preflight: true) — NOT the JSON transport graphql uses, since the file body can't be JSON-encoded. entity_id / representative_id and file_enum are inlined into the query string (RF's file_enum is an unquoted GraphQL enum literal, and its id argument is a custom scalar that takes a string literal, so neither rides as a typed $variable the way $file does). Both are therefore validated before interpolation — file_enum against the known enum, the id against a strict id charset — so a crafted value can never break out of the query. Exactly one of entityId/representativeId is required.

      Parameters

      • args: {
            bytes: Uint8Array;
            contentType?: string;
            entityId?: string;
            fileEnum:
                | "proof_of_registration"
                | "proof_of_ownership"
                | "bank_statement"
                | "proof_of_address"
                | "passport"
                | "front_drivers_license"
                | "back_drivers_license"
                | "front_national_state_id"
                | "back_national_state_id";
            filename: string;
            representativeId?: string;
        }

      Returns Promise<void>