/**
 * @module Transfers
 */

// This file was auto-generated by Fern from our API Definition.

import type { BaseClientOptions, BaseRequestOptions } from "../../../../BaseClient.js";
import { type NormalizedClientOptionsWithAuth, normalizeClientOptionsWithAuth } from "../../../../BaseClient.js";
import { mergeHeaders, mergeOnlyDefinedHeaders } from "../../../../core/headers.js";
import * as core from "../../../../core/index.js";
import * as environments from "../../../../environments.js";
import { handleNonStatusCodeError } from "../../../../errors/handleNonStatusCodeError.js";
import * as errors from "../../../../errors/index.js";
import * as CoinbaseApi from "../../../index.js";

export declare namespace TransfersClient {
    export type Options = BaseClientOptions;

    export interface RequestOptions extends BaseRequestOptions {}
}

/**
 * **Transfers** represent both the request and execution of fund transfers from a source to a target. They provide upfront fee quotes and track the complete lifecycle from initiation through completion, failure, or reversal.
 * ## Fee Quotes
 * Every transfer provides a comprehensive fee quote in the `fees` array. This allows you to show users exactly what they'll pay before any money moves.
 *
 * To review fees before execution:
 * 1. Create a transfer with `execute: false`
 * 2. Review the `fees` array in the response
 * 3. Call `POST /transfers/{transferId}/execute` when ready to proceed
 *
 *
 * For automatic execution without fee review, create a transfer with `execute: true`.
 *
 * **Fee Expiration**: Fee quotes are valid for a limited time (typically 10-15 minutes from creation). The `expiresAt` field shows exactly when the fee quote will expire. If you don't execute before this time, you'll need to create a new transfer to get updated fees.
 * ## Fees
 * Transfer fees vary by source, target, amount and transfer type:
 * * **Bank fees** - Traditional banking fees for depositing funds (e.g., $15.00 wire transfer fee)
 * * **Conversion fees** - Fees for exchanging between different assets
 * * **Network fees** - Onchain transaction costs to complete the transfer (e.g., ETH gas fees)
 *
 * All fees are disclosed upfront in the `fees` array when you create a transfer.
 * ## Transfer Lifecycle
 * When you create a transfer, it will be in one of these statuses that determine what action you need to take:
 * * **`quoted`** - Transfer is ready but requires manual execution via the `/execute` endpoint
 * * **`processing`** - Transfer is being executed (no action needed - poll for completion)
 * * **`completed`** - Transfer completed successfully
 * * **`failed`** - Transfer failed (see `failureReason` for details)
 * ## Execution Control
 * * **`execute: true`**: Transfer will automatically attempt to execute
 * * **`execute: false`**: Transfer will be created in `quoted` status and you must call the `/execute` endpoint. Use this to obtain a fee quote or validate a transfer destination before deciding whether to execute the Transfer.
 * ## Sources and Targets
 * * A **source** can be an Account or a Payment Method
 * * A **target** can be an Account, Payment Method, Onchain Address, or Email Address
 * ## Transfer Execution
 * When a transfer reaches `completed` status, it contains the final execution details that delivered funds to the target and completion timestamps.
 * ## Failure Reasons
 * When a transfer fails, the `failureReason` field provides a human-readable description of what went wrong.
 * Common failure reasons include:
 * * "Insufficient balance to complete this transfer."
 * * "The recipient address is invalid for the selected network."
 * * "The recipient address failed security validation checks."
 * * "Unable to send to this recipient."
 *
 * Failure reason is only present when the transfer's status is `failed`.
 */
export class TransfersClient {
    protected readonly _options: NormalizedClientOptionsWithAuth<TransfersClient.Options>;

    constructor(options: TransfersClient.Options) {
        this._options = normalizeClientOptionsWithAuth(options);
    }

    /**
     * List transfers for your organization. Use this to view and monitor your transfer activity.
     *
     * **Status Filtering**: Filter by specific status to efficiently manage transfers:
     * * `?status=processing` - Monitor active transfers.
     * * `?status=quoted` - Find transfers awaiting execution.
     * * `?status=failed` - Review failed transfers for troubleshooting.
     * * `?status=completed` - Find completed transfers.
     *
     * **Account Filtering**: Filter by account ID to find transfers involving a specific account:
     * * `?accountId=<ID>` - All transfers where the account is either source or target (OR semantics).
     * * `?sourceAccountId=<ID>` - Only transfers where the account is the source (outbound).
     * * `?targetAccountId=<ID>` - Only transfers where the account is the target (inbound).
     * Providing `accountId` together with `sourceAccountId` or `targetAccountId` is a validation error and returns HTTP 400.
     *
     * **Date Range Filtering**: Filter by creation or last-updated time for reconciliation:
     * * `?createdAfter=2026-01-01T00:00:00Z&createdBefore=2026-01-31T23:59:59Z` - Transfers created within a date range.
     * * `?updatedAfter=2026-01-01T00:00:00Z` - Transfers updated since a given time. Useful for incremental sync.
     *
     * **Asset Filtering**: Filter by source or target asset symbol:
     * * `?sourceAsset=usd` - Transfers funded from a USD account.
     * * `?targetAsset=usdc` - Transfers delivering USDC to the target.
     *
     * **Other Filters**:
     * * `?sourceAddress=0x...` - Transfers from a specific on-chain source address.
     * * `?targetAddress=0x...` - Transfers to a specific on-chain destination address.
     * * `?targetEmail=user@example.com` - Transfers to a specific email recipient.
     * * `?transferId=transfer_...` - Look up a single transfer by ID; bypasses pagination.
     *
     * @param {CoinbaseApi.ListTransfersRequest} request
     * @param {TransfersClient.RequestOptions} requestOptions - Request-specific configuration.
     *
     * @throws CoinbaseApi.BadRequestError
     *
     * @example
     * ```ts
     * await client.transfers.listTransfers({
     *     accountId: "account_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *     sourceAccountId: "account_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *     targetAccountId: "account_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *     createdAfter: "2026-01-01T00:00:00Z",
     *     createdBefore: "2026-01-31T23:59:59Z",
     *     updatedAfter: "2026-01-01T00:00:00Z",
     *     updatedBefore: "2026-01-31T23:59:59Z",
     *     sourceAsset: "usd",
     *     targetAsset: "usdc",
     *     sourceAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
     *     targetAddress: "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
     *     targetEmail: "user@example.com",
     *     transferId: "transfer_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *     pageToken: "eyJsYXN0X2lkIjogImFiYzEyMyIsICJ0aW1lc3RhbXAiOiAxNzA3ODIzNzAxfQ=="
     * })
     * ```
     */
    public listTransfers(
        request: CoinbaseApi.ListTransfersRequest = {},
        requestOptions?: TransfersClient.RequestOptions,
    ): core.HttpResponsePromise<CoinbaseApi.ListTransfersResponse> {
        return core.HttpResponsePromise.fromPromise(this.__listTransfers(request, requestOptions));
    }

    private async __listTransfers(
        request: CoinbaseApi.ListTransfersRequest = {},
        requestOptions?: TransfersClient.RequestOptions,
    ): Promise<core.WithRawResponse<CoinbaseApi.ListTransfersResponse>> {
        const _metadata: core.EndpointMetadata = {
            security: [{ apiKeyAuth: [] }],
            method: "GET",
            path: "v2/transfers",
            operationId: "endpoint_transfers.listTransfers",
        };
        const {
            status,
            accountId,
            sourceAccountId,
            targetAccountId,
            createdAfter,
            createdBefore,
            updatedAfter,
            updatedBefore,
            sourceAsset,
            targetAsset,
            sourceAddress,
            targetAddress,
            targetEmail,
            transferId,
            pageSize,
            pageToken,
        } = request;
        const _queryParams: Record<string, unknown> = {
            status: status != null ? status : undefined,
            accountId,
            sourceAccountId,
            targetAccountId,
            createdAfter: createdAfter != null ? createdAfter : undefined,
            createdBefore: createdBefore != null ? createdBefore : undefined,
            updatedAfter: updatedAfter != null ? updatedAfter : undefined,
            updatedBefore: updatedBefore != null ? updatedBefore : undefined,
            sourceAsset,
            targetAsset,
            sourceAddress,
            targetAddress,
            targetEmail,
            transferId,
            pageSize,
            pageToken,
        };
        const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest({
            endpointMetadata: _metadata,
            clientOptions: this._options,
            request: {
                method: "GET",
            },
        });
        const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
            _authRequest.headers,
            this._options?.headers,
            requestOptions?.headers,
        );
        const _response = await core.fetcher({
            url: core.url.join(
                (await core.Supplier.get(this._options.baseUrl)) ??
                    (await core.Supplier.get(this._options.environment)) ??
                    environments.CoinbaseApiEnvironment.Default,
                "v2/transfers",
            ),
            method: "GET",
            headers: _headers,
            queryString: core.url
                .queryBuilder()
                .addMany(_queryParams)
                .mergeAdditional(requestOptions?.queryParams)
                .build(),
            timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
            maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
            abortSignal: requestOptions?.abortSignal,
            endpointMetadata: _metadata,
            fetchFn: this._options?.fetch,
            logging: this._options.logging,
        });
        if (_response.ok) {
            return { data: _response.body as CoinbaseApi.ListTransfersResponse, rawResponse: _response.rawResponse };
        }

        if (_response.error.reason === "status-code") {
            switch (_response.error.statusCode) {
                case 400:
                    throw new CoinbaseApi.BadRequestError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                default:
                    throw new errors.CoinbaseApiError({
                        statusCode: _response.error.statusCode,
                        body: _response.error.body,
                        rawResponse: _response.rawResponse,
                    });
            }
        }

        return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v2/transfers");
    }

    /**
     * Create a new transfer to move funds from a source to a target.
     * All transfers first transition to `quoted`. If `execute: false`, the transfer stays quoted until you call `/v2/transfers/{transferId}/execute`.
     * If `execute: true`, quoted status emits momentarily before the transfer moves to `processing`, where execution proceeds. Subscribe to the transfers webhook to  follow progress in real time instead of polling.
     *
     * @param {CoinbaseApi.TransferRequest} request
     * @param {TransfersClient.RequestOptions} requestOptions - Request-specific configuration.
     *
     * @throws CoinbaseApi.BadRequestError
     * @throws CoinbaseApi.ForbiddenError
     * @throws CoinbaseApi.UnprocessableEntityError
     *
     * @example
     * ```ts
     * await client.transfers.createTransfer({
     *     idempotencyKey: "8e03978e-40d5-43e8-bc93-6894a57f9324",
     *     source: {
     *         accountId: "account_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *         asset: "usd"
     *     },
     *     target: {
     *         address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
     *         network: "base",
     *         asset: "usdc"
     *     },
     *     amount: "100.00",
     *     asset: "usd",
     *     validateOnly: false,
     *     execute: false,
     *     metadata: {
     *         "invoiceId": "12345",
     *         "reference": "Payment for invoice #12345"
     *     },
     *     travelRule: {
     *         isSelf: false,
     *         isIntermediary: true,
     *         originator: {
     *             financialInstitution: "PayPal, Inc.",
     *             name: "John Doe",
     *             address: {
     *                 line1: "123 Main St",
     *                 line2: "Unit 201",
     *                 city: "San Francisco",
     *                 state: "California",
     *                 postCode: "94105",
     *                 countryCode: "US"
     *             },
     *             personalId: "123-45-6789",
     *             dateOfBirth: {
     *                 day: "15",
     *                 month: "08",
     *                 year: "1990"
     *             }
     *         },
     *         beneficiary: {
     *             name: "Jane Smith",
     *             address: {
     *                 line1: "456 Oak Ave",
     *                 city: "Paris",
     *                 postCode: "75001",
     *                 countryCode: "FR"
     *             },
     *             walletType: "custodial"
     *         }
     *     }
     * })
     * ```
     */
    public createTransfer(
        request: CoinbaseApi.TransferRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): core.HttpResponsePromise<CoinbaseApi.Transfer> {
        return core.HttpResponsePromise.fromPromise(this.__createTransfer(request, requestOptions));
    }

    private async __createTransfer(
        request: CoinbaseApi.TransferRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): Promise<core.WithRawResponse<CoinbaseApi.Transfer>> {
        const _metadata: core.EndpointMetadata = {
            security: [{ apiKeyAuth: [] }],
            method: "POST",
            path: "v2/transfers",
            operationId: "endpoint_transfers.createTransfer",
            headers: ["X-Idempotency-Key"],
        };
        const { idempotencyKey, ..._body } = request;
        const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest({
            endpointMetadata: _metadata,
            clientOptions: this._options,
            request: {
                method: "POST",
                body: _body,
            },
        });
        const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
            _authRequest.headers,
            this._options?.headers,
            mergeOnlyDefinedHeaders({ "X-Idempotency-Key": idempotencyKey }),
            requestOptions?.headers,
        );
        const _response = await core.fetcher({
            url: core.url.join(
                (await core.Supplier.get(this._options.baseUrl)) ??
                    (await core.Supplier.get(this._options.environment)) ??
                    environments.CoinbaseApiEnvironment.Default,
                "v2/transfers",
            ),
            method: "POST",
            headers: _headers,
            contentType: "application/json",
            queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
            requestType: "json",
            body: _body,
            timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
            maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
            abortSignal: requestOptions?.abortSignal,
            endpointMetadata: _metadata,
            fetchFn: this._options?.fetch,
            logging: this._options.logging,
        });
        if (_response.ok) {
            return { data: _response.body as CoinbaseApi.Transfer, rawResponse: _response.rawResponse };
        }

        if (_response.error.reason === "status-code") {
            switch (_response.error.statusCode) {
                case 400:
                    throw new CoinbaseApi.BadRequestError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 403:
                    throw new CoinbaseApi.ForbiddenError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 422:
                    throw new CoinbaseApi.UnprocessableEntityError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                default:
                    throw new errors.CoinbaseApiError({
                        statusCode: _response.error.statusCode,
                        body: _response.error.body,
                        rawResponse: _response.rawResponse,
                    });
            }
        }

        return handleNonStatusCodeError(_response.error, _response.rawResponse, "POST", "/v2/transfers");
    }

    /**
     * Get a transfer by its ID.
     *
     * @param {CoinbaseApi.GetTransferByIdRequest} request
     * @param {TransfersClient.RequestOptions} requestOptions - Request-specific configuration.
     *
     * @throws CoinbaseApi.NotFoundError
     *
     * @example
     * ```ts
     * await client.transfers.getTransferById({
     *     transferId: "transfer_af2937b0-9846-4fe7-bfe9-ccc22d935114"
     * })
     * ```
     */
    public getTransferById(
        request: CoinbaseApi.GetTransferByIdRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): core.HttpResponsePromise<CoinbaseApi.Transfer> {
        return core.HttpResponsePromise.fromPromise(this.__getTransferById(request, requestOptions));
    }

    private async __getTransferById(
        request: CoinbaseApi.GetTransferByIdRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): Promise<core.WithRawResponse<CoinbaseApi.Transfer>> {
        const _metadata: core.EndpointMetadata = {
            security: [{ apiKeyAuth: [] }],
            method: "GET",
            path: "v2/transfers/{transferId}",
            operationId: "endpoint_transfers.getTransferById",
        };
        const { transferId } = request;
        const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest({
            endpointMetadata: _metadata,
            clientOptions: this._options,
            request: {
                method: "GET",
            },
        });
        const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
            _authRequest.headers,
            this._options?.headers,
            requestOptions?.headers,
        );
        const _response = await core.fetcher({
            url: core.url.join(
                (await core.Supplier.get(this._options.baseUrl)) ??
                    (await core.Supplier.get(this._options.environment)) ??
                    environments.CoinbaseApiEnvironment.Default,
                `v2/transfers/${core.url.encodePathParam(transferId)}`,
            ),
            method: "GET",
            headers: _headers,
            queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
            timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
            maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
            abortSignal: requestOptions?.abortSignal,
            endpointMetadata: _metadata,
            fetchFn: this._options?.fetch,
            logging: this._options.logging,
        });
        if (_response.ok) {
            return { data: _response.body as CoinbaseApi.Transfer, rawResponse: _response.rawResponse };
        }

        if (_response.error.reason === "status-code") {
            switch (_response.error.statusCode) {
                case 404:
                    throw new CoinbaseApi.NotFoundError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                default:
                    throw new errors.CoinbaseApiError({
                        statusCode: _response.error.statusCode,
                        body: _response.error.body,
                        rawResponse: _response.rawResponse,
                    });
            }
        }

        return handleNonStatusCodeError(_response.error, _response.rawResponse, "GET", "/v2/transfers/{transferId}");
    }

    /**
     * Executes a transfer which was created using the Create a transfer endpoint.
     *
     * @param {CoinbaseApi.ExecuteFundTransferRequest} request
     * @param {TransfersClient.RequestOptions} requestOptions - Request-specific configuration.
     *
     * @throws CoinbaseApi.BadRequestError
     * @throws CoinbaseApi.UnauthorizedError
     * @throws CoinbaseApi.ForbiddenError
     * @throws CoinbaseApi.NotFoundError
     * @throws CoinbaseApi.UnprocessableEntityError
     * @throws CoinbaseApi.TooManyRequestsError
     * @throws CoinbaseApi.InternalServerError
     * @throws CoinbaseApi.BadGatewayError
     * @throws CoinbaseApi.ServiceUnavailableError
     *
     * @example
     * ```ts
     * await client.transfers.executeFundTransfer({
     *     idempotencyKey: "8e03978e-40d5-43e8-bc93-6894a57f9324",
     *     transferId: "transfer_af2937b0-9846-4fe7-bfe9-ccc22d935114"
     * })
     * ```
     */
    public executeFundTransfer(
        request: CoinbaseApi.ExecuteFundTransferRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): core.HttpResponsePromise<CoinbaseApi.Transfer> {
        return core.HttpResponsePromise.fromPromise(this.__executeFundTransfer(request, requestOptions));
    }

    private async __executeFundTransfer(
        request: CoinbaseApi.ExecuteFundTransferRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): Promise<core.WithRawResponse<CoinbaseApi.Transfer>> {
        const _metadata: core.EndpointMetadata = {
            security: [{ apiKeyAuth: [] }],
            method: "POST",
            path: "v2/transfers/{transferId}/execute",
            operationId: "endpoint_transfers.executeFundTransfer",
            headers: ["X-Idempotency-Key"],
        };
        const { transferId, idempotencyKey } = request;
        const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest({
            endpointMetadata: _metadata,
            clientOptions: this._options,
            request: {
                method: "POST",
            },
        });
        const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
            _authRequest.headers,
            this._options?.headers,
            mergeOnlyDefinedHeaders({ "X-Idempotency-Key": idempotencyKey }),
            requestOptions?.headers,
        );
        const _response = await core.fetcher({
            url: core.url.join(
                (await core.Supplier.get(this._options.baseUrl)) ??
                    (await core.Supplier.get(this._options.environment)) ??
                    environments.CoinbaseApiEnvironment.Default,
                `v2/transfers/${core.url.encodePathParam(transferId)}/execute`,
            ),
            method: "POST",
            headers: _headers,
            queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
            timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
            maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
            abortSignal: requestOptions?.abortSignal,
            endpointMetadata: _metadata,
            fetchFn: this._options?.fetch,
            logging: this._options.logging,
        });
        if (_response.ok) {
            return { data: _response.body as CoinbaseApi.Transfer, rawResponse: _response.rawResponse };
        }

        if (_response.error.reason === "status-code") {
            switch (_response.error.statusCode) {
                case 400:
                    throw new CoinbaseApi.BadRequestError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 401:
                    throw new CoinbaseApi.UnauthorizedError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 403:
                    throw new CoinbaseApi.ForbiddenError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 404:
                    throw new CoinbaseApi.NotFoundError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 422:
                    throw new CoinbaseApi.UnprocessableEntityError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 429:
                    throw new CoinbaseApi.TooManyRequestsError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 500:
                    throw new CoinbaseApi.InternalServerError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 502:
                    throw new CoinbaseApi.BadGatewayError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 503:
                    throw new CoinbaseApi.ServiceUnavailableError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                default:
                    throw new errors.CoinbaseApiError({
                        statusCode: _response.error.statusCode,
                        body: _response.error.body,
                        rawResponse: _response.rawResponse,
                    });
            }
        }

        return handleNonStatusCodeError(
            _response.error,
            _response.rawResponse,
            "POST",
            "/v2/transfers/{transferId}/execute",
        );
    }

    /**
     * Submit travel rule information for a deposit transfer held pending compliance review.
     *
     * Required fields vary by jurisdiction and may include originator name, address, date of birth, personal ID, and VASP information.
     *
     * If the submitted information satisfies all jurisdictional requirements, `status` will be `completed` and the transfer will proceed. Otherwise, `status` will be `incomplete` and `missingFields` will indicate which fields still need to be provided.
     *
     * @param {CoinbaseApi.DepositTravelRuleRequest} request
     * @param {TransfersClient.RequestOptions} requestOptions - Request-specific configuration.
     *
     * @throws CoinbaseApi.BadRequestError
     * @throws CoinbaseApi.NotFoundError
     * @throws CoinbaseApi.UnprocessableEntityError
     *
     * @example
     * ```ts
     * await client.transfers.submitDepositTravelRule({
     *     idempotencyKey: "8e03978e-40d5-43e8-bc93-6894a57f9324",
     *     transferId: "transfer_af2937b0-9846-4fe7-bfe9-ccc22d935114",
     *     originator: {
     *         name: "John Doe",
     *         address: {
     *             line1: "123 Main St",
     *             city: "San Francisco",
     *             state: "CA",
     *             postCode: "94105",
     *             countryCode: "US"
     *         }
     *     },
     *     beneficiary: {
     *         name: "Jane Smith"
     *     },
     *     isSelf: false
     * })
     * ```
     */
    public submitDepositTravelRule(
        request: CoinbaseApi.DepositTravelRuleRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): core.HttpResponsePromise<CoinbaseApi.DepositTravelRuleResponse> {
        return core.HttpResponsePromise.fromPromise(this.__submitDepositTravelRule(request, requestOptions));
    }

    private async __submitDepositTravelRule(
        request: CoinbaseApi.DepositTravelRuleRequest,
        requestOptions?: TransfersClient.RequestOptions,
    ): Promise<core.WithRawResponse<CoinbaseApi.DepositTravelRuleResponse>> {
        const _metadata: core.EndpointMetadata = {
            security: [{ apiKeyAuth: [] }],
            method: "POST",
            path: "v2/transfers/{transferId}/travel-rule",
            operationId: "endpoint_transfers.submitDepositTravelRule",
            headers: ["X-Idempotency-Key"],
        };
        const { transferId, idempotencyKey, ..._body } = request;
        const _authRequest: core.AuthRequest = await this._options.authProvider.getAuthRequest({
            endpointMetadata: _metadata,
            clientOptions: this._options,
            request: {
                method: "POST",
                body: _body,
            },
        });
        const _headers: core.Fetcher.Args["headers"] = mergeHeaders(
            _authRequest.headers,
            this._options?.headers,
            mergeOnlyDefinedHeaders({ "X-Idempotency-Key": idempotencyKey }),
            requestOptions?.headers,
        );
        const _response = await core.fetcher({
            url: core.url.join(
                (await core.Supplier.get(this._options.baseUrl)) ??
                    (await core.Supplier.get(this._options.environment)) ??
                    environments.CoinbaseApiEnvironment.Default,
                `v2/transfers/${core.url.encodePathParam(transferId)}/travel-rule`,
            ),
            method: "POST",
            headers: _headers,
            contentType: "application/json",
            queryString: core.url.queryBuilder().mergeAdditional(requestOptions?.queryParams).build(),
            requestType: "json",
            body: _body,
            timeoutMs: (requestOptions?.timeoutInSeconds ?? this._options?.timeoutInSeconds ?? 60) * 1000,
            maxRetries: requestOptions?.maxRetries ?? this._options?.maxRetries,
            abortSignal: requestOptions?.abortSignal,
            endpointMetadata: _metadata,
            fetchFn: this._options?.fetch,
            logging: this._options.logging,
        });
        if (_response.ok) {
            return {
                data: _response.body as CoinbaseApi.DepositTravelRuleResponse,
                rawResponse: _response.rawResponse,
            };
        }

        if (_response.error.reason === "status-code") {
            switch (_response.error.statusCode) {
                case 400:
                    throw new CoinbaseApi.BadRequestError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 404:
                    throw new CoinbaseApi.NotFoundError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                case 422:
                    throw new CoinbaseApi.UnprocessableEntityError(
                        _response.error.body as CoinbaseApi.Error_,
                        _response.rawResponse,
                    );
                default:
                    throw new errors.CoinbaseApiError({
                        statusCode: _response.error.statusCode,
                        body: _response.error.body,
                        rawResponse: _response.rawResponse,
                    });
            }
        }

        return handleNonStatusCodeError(
            _response.error,
            _response.rawResponse,
            "POST",
            "/v2/transfers/{transferId}/travel-rule",
        );
    }
}
