@cfxlabsinc/b2b-services
    Preparing search index...

    Customer-scoped escrow transfer request operations. A request is a payment ask that precedes an escrow_transfer; this service is customer-scoped CRUD with no on-chain machinery (contrast EscrowTransferService, whose writes run through Temporal/Solana). Reads live on EscrowTransferRequestQueryService.

    Every write filters on customerId so one customer can never mutate another's requests. Per-actor authorization (only the sender may cancel, only the recipient may reject) is the caller's responsibility — the API has no notion of the acting end user.

    Each create and status transition is published as escrow.escrowTransferRequest.statusUpdated; sms-notification-handler texts the counterparty from it.

    Hierarchy (View Summary)

    Index
    db: B2bDatabase
    instance: (...args: []) => EscrowTransferRequestService = ...

    The process default: built from each dependency's own instance().

    • Complete a request with the transfer that paid it: a COMPLETED phone transfer (claimed) or ledger transfer, sent by the holder of the request's recipientPhone, in its token, for at least its amount, to the requester's phone or one of the requester's ledger accounts. Anything else is TRANSFER_DOES_NOT_PAY. SENT is terminal, so a held escrow the sender could still cancel never counts.

      Parameters

      • __namedParameters: { customerId: string; id: string; transferId: string }

      Returns Promise<
          | { ok: true; value: EscrowTransferRequest }
          | {
              error:
                  | EscrowTransferRequestTransitionError
                  | ServiceError<"ESCROW_TRANSFER_ALREADY_LINKED">
                  | ServiceError<"TRANSFER_NOT_FOUND" | "TRANSFER_DOES_NOT_PAY">;
              ok: false;
          },
      >

    • Customer-scoped search. Filter by ids (request external ids) and/or senderId (requests this identity sent) and/or recipientPhone (requests addressed to this phone) and/or statuses. Ordered newest-first. The customer-scope is a hard WHERE so no filter combination can leak rows across tenants.

      Parameters

      • __namedParameters: {
            customerId: string;
            ids?: string[];
            page?: number;
            pageSize?: number;
            recipientPhone?: string;
            senderId?: string;
            statuses?: ("CREATED" | "CANCELLED" | "REJECTED" | "SENT")[];
        }
        • customerId: string
        • Optionalids?: string[]
        • Optionalpage?: number

          Defaults to 1

        • OptionalpageSize?: number

          Defaults to 50

        • OptionalrecipientPhone?: string
        • OptionalsenderId?: string
        • Optionalstatuses?: ("CREATED" | "CANCELLED" | "REJECTED" | "SENT")[]

      Returns Promise<
          {
              ok: true;
              value: { hasNext: boolean; items: EscrowTransferRequest[]; total: number };
          },
      >

    • Move a CREATED request to its terminal status: CANCELLED (the sender withdrew it), REJECTED (the recipient declined it) or SENT (the recipient paid it, linking the fulfilling escrow transfer). Every target is valid from CREATED alone, so a second transition — even a second SENT naming a different escrow transfer — is INVALID_STATUS_TRANSITION rather than a silent re-link. An escrow transfer id already linked to a different request trips the unique constraint and surfaces as ESCROW_TRANSFER_ALREADY_LINKED — only SENT links one, so only its overload carries that error.

      Parameters

      • args: {
            customerId: string;
            data: { status: "CANCELLED" } | { status: "REJECTED" };
            id: string;
        }

      Returns Promise<
          | { ok: true; value: EscrowTransferRequest }
          | { error: EscrowTransferRequestTransitionError; ok: false },
      >

    • Move a CREATED request to its terminal status: CANCELLED (the sender withdrew it), REJECTED (the recipient declined it) or SENT (the recipient paid it, linking the fulfilling escrow transfer). Every target is valid from CREATED alone, so a second transition — even a second SENT naming a different escrow transfer — is INVALID_STATUS_TRANSITION rather than a silent re-link. An escrow transfer id already linked to a different request trips the unique constraint and surfaces as ESCROW_TRANSFER_ALREADY_LINKED — only SENT links one, so only its overload carries that error.

      Parameters

      • args: {
            customerId: string;
            data: { escrowTransferId: string; status: "SENT" };
            id: string;
        }

      Returns Promise<
          | { ok: true; value: EscrowTransferRequest }
          | {
              error:
                  | EscrowTransferRequestTransitionError
                  | ServiceError<"ESCROW_TRANSFER_ALREADY_LINKED">;
              ok: false;
          },
      >