# Physical Cards (coming soon) Source: https://docs.confidolegal.com/docs/cards/physical-cards This page outlines how `Physical Cards` are requested, shipped, and managed through Confido Legal. ## The Physical Card Object ```graphql theme={"system"} type PhysicalCard { id: string card: Card cardholder: Cardholder createdOn: Date shipment: Shipment status: string } ``` **Cardholder** ```graphql theme={"system"} type Cardholder { firstName: string lastName: string } ``` **Shipment** ```graphql theme={"system"} type Shipment { address: Address method: 'usps' | 'fedex_priority_overnight' | 'fedex_2_day' | 'dhl_worldwide_express' status: 'pending' | 'canceled' | 'submitted' | 'acknowledged' | 'rejected' | 'shipped' | 'returned' tracking?: TrackingUpdate[] } ``` ## Creating a Physical Card The `physicalCardCreate` mutation requests a new physical card. Call it with the Firm API token. ```graphql theme={"system"} mutation PhysicalCardCreate($input: PhysicalCardCreateInput!) { physicalCardCreate(input: $input) { id status } } ``` **Input** * **`cardId`** — the ID of the card to issue as a physical card * **`cardholder`** — the cardholder for the physical card ## Update a Physical Card The `physicalCardUpdate` mutation updates an existing physical card. Call it with the Firm API token. ```graphql theme={"system"} mutation PhysicalCardUpdate($input: PhysicalCardUpdateInput!) { physicalCardUpdate(input: $input) { id status } } ``` **Input** * **`id`** — the ID of the physical card to update * **`status`** — the status of the physical card # Virtual Cards (coming soon) Source: https://docs.confidolegal.com/docs/cards/virtual-cards This page outlines the `Card` object that will be used to issue and manage virtual cards through Confido Legal. ## The Card Object ```graphql theme={"system"} type Card { id: string authorizationControls?: AuthorizationControls bankAccount: BankAccount billingAddress: Address bin: string cardholderName: CardholderName client?: Client createdOn: Date expMonth: string expYear: string lastFour: string matter?: Matter nickname?: string status: string vendor?: Vendor } ``` **AuthorizationControls** ```graphql theme={"system"} type AuthorizationControls { merchantAcceptorIds: AllowBlockList merchantCategoryCode: AllowBlockList merchantCountry: AllowBlockList usage: UsageControls } type AllowBlockList { allowed: [String] blocked: [String] } type UsageControls { category: 'single_use' | 'multi_use' multiUse?: MultiUseControls singleUse?: SingleUseControls } type MultiUseControls { spendingLimits: SpendingLimit[] } type SpendingLimit { interval: 'all_time' | 'per_transaction' | 'per_day' | 'per_week' | 'per_month' merchantCategoryCodes?: [String] settlementAmount: Int } type SingleUseControls { settlementAmount: SingleUseSettlementAmount } type SingleUseSettlementAmount { comparison: 'equals' | 'less_than_or_equals' value: Int } ``` ## Creating a Card The `cardCreate` mutation issues a new virtual card. Call it with the Firm API token. ```graphql theme={"system"} mutation CardCreate($input: CardCreateInput!) { cardCreate(input: $input) { id bin cardholderName createdOn expMonth expYear lastFour nickname status } } ``` **Input** * **`authorizationControls`** — restrictions on where and how the card can be used (nullable) * **`bankAccountId`** — the ID of the bank account the card is funded from * **`billingAddress`** — the billing address associated with the card, defaults to the firm address (nullable) * **`cardholderName`** — the name of the cardholder, defaults to the firm name (nullable) * **`clientId`** — the ID of the client to associate with the card (nullable) * **`matterId`** — the ID of the matter to associate with the card (nullable) * **`nickname`** — an optional nickname for the card (nullable) * **`vendorId`** — the ID of the vendor to associate with the card (nullable) ## Update a Card The `cardUpdate` mutation updates an existing virtual card. Call it with the Firm API token. ```graphql theme={"system"} mutation CardUpdate($input: CardUpdateInput!) { cardUpdate(input: $input) { id bin cardholderName createdOn expMonth expYear lastFour nickname status } } ``` **Input** * **`id`** — the ID of the card to update * **`authorizationControls`** — restrictions on where and how the card can be used (nullable) * **`billingAddress`** — the billing address associated with the card (nullable) * **`clientId`** — the ID of the client to associate with the card (nullable) * **`matterId`** — the ID of the matter to associate with the card (nullable) * **`nickname`** — an optional nickname for the card (nullable) * **`status`** — the status of the card (nullable) * **`vendorId`** — the ID of the vendor to associate with the card (nullable) ## Viewing Card Details Sensitive card details (PAN, CVV, and expiration) are never returned directly from the API. To view a card, mint a short-lived token from your server, then open Confido's hosted card page or embed it in an iframe. Card data is rendered on Confido's hosted page, so your servers stay out of PCI scope for card display. ### High level flow ### 1. Create a token Call `cardDetailsTokenCreate` with the Firm API token and the card ID: ```graphql theme={"system"} mutation CardDetailsTokenCreate($input: CardDetailsTokenCreateInput!) { cardDetailsTokenCreate(input: $input) { token expiresAt } } ``` **Input** * **`cardId`** — the ID of the card to view **Response** * **`token`** — a short-lived token used to access the card details page * **`expiresAt`** — when the token expires (one hour after creation) Keep the Firm API token on your server. Only the returned `token` should be sent to the browser. ### 2. View the card | Environment | Base URL | | ----------- | -------------------------------------- | | Sandbox | `https://pay.sandbox.confidolegal.com` | | Production | `https://pay.confidolegal.com` | **Hosted page** Redirect the user (or open a new tab) to the card details page with the token as a query parameter: ``` https://pay.sandbox.confidolegal.com/card?token=TOKEN ``` **iframe** Embed the card details iframe in your application: ```html theme={"system"} ``` Register your application's parent-page origin as a [trusted domain](/docs/hosted-fields/trusted-domains) when embedding the iframe. Required in sandbox and production. ### Notes * Tokens expire after **one hour**. When a token expires, call `cardDetailsTokenCreate` again and update the page URL or iframe `src`. * Do not cache or log full card details. Treat the token as sensitive while it is valid. * Your application should never collect or store PAN or CVV from the displayed card. # Stored Disbursement Methods Source: https://docs.confidolegal.com/docs/embedded-forms/stored-disbursement-methods A stored disbursement method (SDM) is a saved ACH bank account or debit card that a Firm can use for later disbursements. This guide explains how to collect the payment details with a Confido-hosted iframe, then create the SDM from your server with the Firm API token. The embed supports **manual ACH** (`ACH_DIRECT`) and **push-to-card** (`PUSH_TO_CARD`, debit cards only). If you are integrating as a partner, use a **Firm API token** (`f_…`) for the Firm whose stored disbursement method you are creating. A Partner API token cannot mint an SDM token or create an SDM. You can obtain a Firm API token by: * Saving the `apiToken` returned by `createFirm` * Exchanging a Connect code for a Firm API token Keep the Firm API token on your server. Only the short-lived SDM token from `storedDisbursementMethodTokenCreate` may be sent to the browser. ## Prerequisites * The Firm is `ACTIVE` and disbursements are enabled for that Firm * You have the Firm API token for the Firm on your server * The Firm is configured to allow the disbursement method you intend to collect * Register your application's parent-page origin as a [trusted domain](/docs/hosted-fields/trusted-domains). Required in sandbox and production. In sandbox, `createFirm(input: { mockOnboarding: true })` activates the Firm, enables disbursements, and returns a Firm API token you can use immediately. `mockOnboarding` is available in sandbox only. ## High level flow ## 1. Mint a token Call `storedDisbursementMethodTokenCreate` with the Firm API token: ```graphql theme={"system"} mutation StoredDisbursementMethodTokenCreate { storedDisbursementMethodTokenCreate { token expiresAt } } ``` Send the returned `token` to your frontend. Mint a fresh token when the form opens. SDM tokens expire after **30 minutes**. If staging fails because the token expired, mint another and reload the iframe `src`. ## 2. Embed the form | Environment | Base URL | | ----------- | -------------------------------------- | | Sandbox | `https://pay.sandbox.confidolegal.com` | | Production | `https://pay.confidolegal.com` | | Path | Form | | ----------------- | --------------------- | | `/sdm/embed` | Tabs for card and ACH | | `/sdm/embed/card` | Push-to-card only | | `/sdm/embed/ach` | Manual ACH only | **Query parameters** * **`token`** (required) — value from `storedDisbursementMethodTokenCreate` * **`opts`** (optional) — `encodeURIComponent(JSON.stringify(branding))` where branding is `{ backgroundColor, centerColor, footerText, headerImg, headerName, partnerImg }` (`footerText` / image fields may be `null`) The tabbed embed loads recipient ACH and instant fees from the Firm's billing settings. You do not pass fees in the URL. ```html theme={"system"} ``` A missing or invalid token, or a parent origin that is not a trusted domain, returns HTTP 403 and posts `confido:sdm_load_error`. ## 3. Submit the form from the parent The iframe has no Save button. Listen for its events, enable your application's Save button when the form is valid, and post `confido:sdm_submit` to the payment-page origin when the user clicks Save. Check `event.origin` against the payment-page origin. Post `confido:sdm_submit` **to that origin**, not `*`. ```javascript theme={"system"} const PAY_ORIGIN = 'https://pay.sandbox.confidolegal.com'; // production: https://pay.confidolegal.com const iframe = document.getElementById('sdm-embed'); const save = document.getElementById('save'); let isReady = false; let isValid = false; function _syncSaveButton() { save.disabled = !(isReady && isValid); } window.addEventListener('message', (event) => { if (event.origin !== PAY_ORIGIN) return; const { type } = event.data || {}; if (type === 'confido:sdm_fields_loaded') { isReady = true; _syncSaveButton(); } if (type === 'confido:sdm_height_change') { iframe.style.height = `${Math.max(480, event.data.height)}px`; } if (type === 'confido:sdm_validity_change') { isValid = event.data.isValid; _syncSaveButton(); } if (type === 'confido:sdm_staged') { fetch('/your-backend/sdm/create', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token, // the SDM token, not the Firm API token vendorId, // or clientId — exactly one payeeEmail, nickname, }), }); } if (type === 'confido:sdm_stage_error' || type === 'confido:sdm_load_error') { // Show event.data.message. If the token expired, mint a new one and reload src. } }); save.addEventListener('click', () => { iframe.contentWindow.postMessage({ type: 'confido:sdm_submit' }, PAY_ORIGIN); }); ``` ### Events from the iframe Every message is `{ type, ...payload }`. | `type` | Payload | When | | --------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `confido:sdm_page_ready` | — | Iframe loaded | | `confido:sdm_fields_loaded` | — | Forms are ready | | `confido:sdm_height_change` | `{ height }` | Content height changed (pixels) | | `confido:sdm_validity_change` | `{ isValid, method }` | Enable or disable your Save button. `method` is `ACH_DIRECT` or `PUSH_TO_CARD` | | `confido:sdm_method_change` | `{ method }` | User switched tabs | | `confido:sdm_bin_change` | `{ brand?, cardType? }` | Card BIN lookup result | | `confido:sdm_field_error` | `{ field, message }` | Field-level validation error | | `confido:sdm_field_error_cleared` | `{ field }` | That error cleared | | `confido:sdm_staging` | — | Submit started | | `confido:sdm_staged` | `{ method, maskedDetails }` | Safe to call `storedDisbursementMethodCreate`. `maskedDetails` includes `lastFour` and `method`; card may include `brand` / `cardType`, ACH may include `bankName` | | `confido:sdm_stage_error` | `{ message }` | Staging failed (expired token, validation, etc.) | | `confido:sdm_load_error` | `{ message? }` | Iframe could not load | ### Command into the iframe | `type` | Payload | When | | -------------------- | ------- | ----------------------------- | | `confido:sdm_submit` | — | User clicked your Save button | ## 4. Create the stored disbursement method After receiving `confido:sdm_staged`, send the SDM token and your non-sensitive metadata to your backend. Call `storedDisbursementMethodCreate` there with the Firm API token. ```graphql theme={"system"} mutation StoredDisbursementMethodCreate( $input: StoredDisbursementMethodCreateInput! ) { storedDisbursementMethodCreate(input: $input) { storedDisbursementMethod { id method nickname displayName details { lastFour brand bankName routingNumber accountHolderName } client { id } vendor { id } } } } ``` **Input** * **`token`** (required) — the same SDM token used in the iframe * **`payeeEmail`** (required) — valid email for the payee * **`clientId`** or **`vendorId`** (required) — exactly one * **`nickname`** (optional) The SDM token is scoped to the Firm, and the Firm API token used for create must belong to that same Firm. The token cannot create an SDM by itself. On success the cache entry is deleted. Creating again with the same token fails. A successful create emits [`stored_disbursement_method.created`](/docs/webhooks/webhook-types). ## Using a stored method List methods for a client or vendor with the Firm API token: ```graphql theme={"system"} query StoredDisbursementMethodsList($vendorId: String, $clientId: String) { storedDisbursementMethodsList(vendorId: $vendorId, clientId: $clientId) { total storedDisbursementMethods { id method nickname displayName archived details { lastFour } } } } ``` To send funds to a saved method, create a disbursement as usual, then call `disbursementInitiateTxnToSdm` with `{ disbursementId, sdmId }` using the Firm API token. ## Limits and errors * **Token TTL** is 30 minutes. Remint and reload the iframe if staging reports an expiry. * **Firm must be active.** Token create fails with `This firm is not active.` * **Method must be allowed** on the Firm. Create fails with `{METHOD} is not allowed for this firm`. * **Parent has no Save control inside the iframe.** If you never post `confido:sdm_submit`, details are never staged. # Connect Source: https://docs.confidolegal.com/docs/firm-onboarding/connect Use Connect when your user already has an existing Confido Legal account. For users without a Confido Legal account, use [Sign Up Links](/docs/firm-onboarding/sign-up-links) or [Onboarding.js](/onboarding-js/overview). With Connect, you'll direct users to a unique Connect URL where they will authorize your application. Upon authorization, they will be redirected back to your configured Callback URL with a one-time-use `code` that can be exchanged for a Firm API Token. You'll then store this token in your database to use in subsequent requests to manage the Firm through the API. Let's get started. First we need to configure some settings in the Partner portal. Log in to the portal and go to Settings > Connect. ## Add your logo It's best if this logo is square and around 200x200 pixels. This logo will show up on the Connect authorization screen as well as the Sign Up screen when users are using a Sign Up Link. ## Copy your Connect URL Each Partner has their own unique Connect URL. You will direct your users here to start the Connect session. You can pass an optional `state` search parameter to this URL that will be threaded through the process and returned back to you at your Callback URL. This `state` parameter can be any string. ## Set up a Callback URL The Callback URL is where we will redirect users after they have authorized your application. The GET request will include a couple search parameters. `https://your_app.com/callback?code=connect_code&state=your_state` You can exchange the `code` for a Firm API Token using the `exchangeCodeForFirmApiToken` mutation and your Partner API Token. You can use the `state` param for anything you like. For example, maybe you want to pass through the `userId` of the user who started the connect session. # Firm Status Source: https://docs.confidolegal.com/docs/firm-onboarding/firm-status When a Firm is onboarding, the `firm.status` field will go through the following values. A `firm.updated` [webhook](/docs/webhooks/configure) will be sent out every time the status changes. `CREATED` -> The Firm was created but there haven't been any edits to the application so far. `APP_IN_DRAFT` -> The application for the Firm has been updated and is currently being filled out. `APP_SUBMITTED` -> The application has been submitted and is waiting for the authorized signer to complete the agreement. `APP_IN_REVIEW` -> Agreement has been signed and the application is under review. `ACTIVE` -> The Firm has passed underwriting and is ready to start processing payments. `INACTIVE` -> The Firm is no longer able to process payments. Below is a simple query that gets the status of a Firm. See the [GraphQL Playground](https://api.sandbox.gravity-legal.com/) for the complete list of fields available on the Firm object. ```graphql theme={"system"} query GetFirm { firm { status } } { "headers": { "x-api-key": "firm_api_token" } } ``` When `status` is `ACTIVE` the Firm is ready to process payments. # Overview Source: https://docs.confidolegal.com/docs/firm-onboarding/overview A Firm represents an actual business with an EIN number. For example, say there is a law firm called Nelson & Murdock. They have 4 physical locations in 2 different states. They share one operating account between all locations but have 2 different trust accounts, one in each state they operate. Nelson & Murdock would be represented as a Firm in Confido. Under that Firm would be 3 Bank Accounts, 1 operating, 2 trust. Since the Confido Legal API handles financial transactions, regulations require that a certain amount of due diligence is performed before we allow businesses to use our platform. We call this process Firm Onboarding. During Firm Onboarding, we collect financial information about the business and its owners. This information then goes through underwriting to validate the legitimacy and financial strength of the Firm. Firms fill out the onboarding form through our [onboarding.js](/onboarding-js/overview) form or the Confido Legal UI. Once a Firm has been approved, they can start moving money. ## One Firm, multiple people A **Firm** in Confido is the business entity. That Firm can then have multiple users (**Firm Admin** and **Firm User** roles) with their own logins; additional users are managed inside the Confido Legal app. For integrations: * **[Sign Up Links](/docs/firm-onboarding/sign-up-links)** attach the person who completes the link as an **admin** on the Firm you already created with `createFirm`. * **[Connect](/docs/firm-onboarding/connect)** lets an existing Confido user authorize your app and yields a **Firm API token** you store server-side. You should map **one legal entity in your product** (one “firm” row) to **one Confido Firm**—not one Confido Firm per attorney. Use Confido’s user roles (and your own `firm_staff` model) for staff vs owner; use **one** stored Firm API token per Confido Firm for server-to-server calls. ## Timeline During onboarding, the `firm.status` field will go through the following values. A `firm.updated` [webhook](/docs/webhooks/configure) will be sent each time the `firm.status` changes. `CREATED` -> The Firm was created but there haven't been any edits to the application yet. `APP_IN_DRAFT` -> The application has been updated and is currently being filled out. `APP_SUBMITTED` -> The application has been submitted and is going through our review process. From this stage on, the application is locked and cannot be modified. `APP_IN_REVIEW` -> The application is currently under review. `ACTIVE` -> The Firm has been approved and is ready to start processing payments. `INACTIVE` -> The Firm is no longer set up to process payments. ## Developing in Sandbox In our sandbox environment, the following methods can be used to set up firms depending on whether or not you are testing the onboarding flow. ### Skip onboarding flow If you are utilizing the `createFirm` mutation, the `mockOnboarding` input parameter can be used **in sandbox only** to transition the Firm directly into the `ACTIVE` status with one default operating and one default trust bank account. This is useful when you are developing payment features and don't want to hassle with "onboarding" the Firm. ### Trigger via the Partner Portal Through the Partner Portal, you can update the Firm status via the Firm settings page. Click `Firms` on the navbar and then click on the Firm you would like to edit. ### Trigger via a Firm Admin If you have created a Firm Admin user for the Firm, you can log in as that user and update the status of the Firm through the Application or Settings page. ### Trigger via the GraphQL API If you are looking to step through the statuses via the GraphQL API, we have created a series of `sandboxOnly` functions for the different steps of the onboarding flow. `sandboxOnlyFillOnboardingData` -> Fills the application with mock data, including one operating and one trust bank account. This will not overwrite fields of the application that have already been filled out (which can be useful to create a Firm with more than one trust account). `sandboxOnlySubmitOnboardingData` -> Transitions the Firm to the `APP_SUBMITTED` status. Under the hood, this will first call `sandboxOnlyFillOnboardingData` so this function can be called when the Firm status is either `CREATED` or `APP_IN_DRAFT`. `sandboxOnlySendFirmToReview` -> Transitions the Firm to the `APP_IN_REVIEW` status. Under the hood, this will first call `sandboxOnlySubmitOnboardingData` so this function can be called when the Firm status is `CREATED`, `APP_IN_DRAFT`, or `APP_SUBMITTED`. `sandboxOnlyActivateFirm` -> Transitions the Firm to the `ACTIVE` status. Under the hood, this will first call `sandboxOnlySubmitOnboardingData` so this function can be called when the Firm status is `CREATED`, `APP_IN_DRAFT`, `APP_SUBMITTED`, or `APP_IN_REVIEW`. It will error out if the Firm is already `ACTIVE` or `INACTIVE`. ## Production To onboard firms in production, your team can utilize our [onboarding.js](/onboarding-js/overview) form or have a Firm user log in to the Confido Legal UI to complete the form. ### Timeline When onboarding firms in the production environment, the typical timeline from initial submission of the Firm application to the Firm being able to accept payments is 2-3 business days. Firms without any underwriting issues that sign the required documents quickly can sometimes be onboarded in under 24 hours. # Sign Up Links Source: https://docs.confidolegal.com/docs/firm-onboarding/sign-up-links Use Sign Up Links when your users do not already have an existing Confido Legal account. With Sign Up Links, you will preemptively create a new Firm using the `createFirm` mutation and then create a unique sign up link where you will direct your user. When the user signs up using this link, they will be added as an admin to the Firm that you previously created. For security reasons, Sign Up Links are short-lived, one-time-use links. They are good for 20 minutes and include an `expiresAt` field for your convenience. ## Create a Firm To get started with Sign Up Links, we will first create a Firm. Use the `createFirm` mutation to do this with your Partner API Token. Here is an example. ```graphql theme={"system"} mutation CreateFirm($input: CreateFirmInput!) { createFirm(input: $input) { apiToken signUpLink { link expiresAt } } } { "input": { "name": "My Firm Name", }, "headers": { "x-api-key": "your_partner_token" } } ``` Once the Firm has been created, save the returned Firm API Token in your database. You will use this in all subsequent requests for the Firm. The Firm can be created at any time. For instance, you could create a Firm for each account in your application in one bulk operation. Then later, when the user is ready, generate a Sign Up Link using the `createFirmSignUpLink` mutation. If you know that you are going to immediately direct your user to the Sign Up Link after creating the Firm, then you can save yourself a network request by asking for the `signUpLink` field in your `createFirm` query. ## Navigate to the link Now direct your user to the Sign Up Link URL. There they will sign up for a Confido Legal account and be placed as an admin under the Firm you created. Once signed in, they will be asked to fill out our payments application so we can begin underwriting their account. Next you will want to know when the Firm has been approved to accept payments. Head to the next section for a discussion on monitoring the Firm's status. # Complete the Session Source: https://docs.confidolegal.com/docs/hosted-fields/complete-session Once the user has entered all their payment information, you are ready to submit the fields and complete the session. This is typically done in a button's `onClick` handler or a form's `onSubmit` handler. To submit the sensitive data in the fields to Confido Legal, use the `submitFields()` method. For a more detailed explanation of the `submitFields()` method, see the [Reference Docs](/hosted-fields-js/submit-fields). ```javascript theme={"system"} window.confidoHostedFields.submitFields(async (err) => { if (err) { // There was an error with submitting the field // data. We should pause here, and let the user // fix the issue. return; } // Field data was submitted successfully. // Now we can finish off the payment from // our backend. const otherFormData = gatherOtherFormData(); const result = await fetch('/my-api/payment-session-complete', { method: 'post', body: JSON.stringify({ paymentToken, ...otherFormData, }), }); // The result from your backend console.log(result); }); ``` You are now ready to finish the session from your server. You'll need to set up an API endpoint where you can send the token and any additional non-sensitive data that was collected in the form. ## Payment Session Call the `paymentSessionComplete` mutation from your server when you are using a Payment Session to collect money. This is where you can set the amount to be paid and additional information. ```graphql theme={"system"} mutation PaymentSessionComplete($input: PaymentSessionCompleteInput!) { paymentSessionComplete(input: $input) { status transactions { amountProcessed } } } ``` Example mutation variables: ```typescript theme={"system"} const variables = { input: { amount: 1500, // amount in cents payerEmail, paymentMethod, // sent from the browser, can be found on the Hosted Fields SDK state paymentToken, // the same paymentToken you used to init the fields }, }; ``` ## Save Payment Method Session Call the `completeSavePaymentMethod` mutation from your server when you are saving a payment method for later use. ```graphql theme={"system"} mutation CompleteSavePaymentMethod( $input: CompleteSavePaymentMethodSessionInput! ) { completeSavePaymentMethod(input: $input) { paymentMethod payerName id lastFour status type } } ``` Example variables: ```typescript theme={"system"} const variables = { input: { payerEmail, payerName, payerZip, paymentMethod, // sent from the browser savePaymentMethodToken, // the same token you used to init the fields }, }; ``` Now you can use the `initiateSPMPayment` mutation at any time to collect a payment using this payment method. # Create a Public Token Source: https://docs.confidolegal.com/docs/hosted-fields/create-public-token To get started, you will need to create a public token from your server. You will then pass this token to your frontend to initialize the SDK. ## Payment Sessions Create a Payment Session Token when you want to accept money now. You can pass a `bankAccountId` to this mutation which determines which of the Firm's Bank Accounts the money will be directed to. If you do not pass a `bankAccountId` the Firm's default operating account will be used. ```graphql theme={"system"} mutation PaymentSessionCreate($input: PaymentSessionCreateInput) { paymentSessionCreate(input: $input) { paymentSessionToken } } ``` ## Save Payment Method Session Create a Save Payment Method Session Token when you want to save the payment details now, then use them to make a payment at a later date. You can optionally pass in a `clientId` if you know which Client this Payment Method should be saved under. ```graphql theme={"system"} mutation StartSavePaymentMethodSession( $input: CreateSavePaymentMethodTokenInput ) { createSavePaymentMethodToken(input: $input) { savePaymentMethodToken } } ``` You'll need to add the Firm API Token as the `x-api-key` header for the request. `x-api-key=f_secret_env_******` Return the `paymentToken` to your frontend to initialize the SDK. # Initialize the SDK Source: https://docs.confidolegal.com/docs/hosted-fields/initialize-sdk ## Load the script Include the JavaScript SDK on each page of your site where your payment form exists. It should always be loaded directly with a `script` tag rather than included in a bundle. ```html theme={"system"}