# JustiFi > JustiFi is payments infrastructure for software platforms. A platform onboards its merchants as sub accounts, accepts card, ACH, Apple Pay, Google Pay, buy now pay later and in-person terminal payments for them through the JustiFi REST API or embeddable web components, and manages refunds, disputes, payouts and platform fees. Key facts for working with the API: - Base URL: `https://api.justifi.ai/v1`. Requests and responses are JSON, and amounts are integers in cents. - Authenticate with OAuth2 client credentials: `POST https://api.justifi.ai/oauth/token` with `client_id` and `client_secret` returns an `access_token`, valid for 24 hours, sent as `Authorization: Bearer `. - Test and live accounts have separate API keys. Requests made with test keys never move real money. - A platform acts for one of its merchants by sending that merchant's account id in the `Sub-Account` header. - Send an `Idempotency-Key` header (any unique string up to 100 characters, such as a UUID) on payment requests so retries cannot charge twice. - List endpoints use cursor pagination: `limit` (1 to 100, default 25), `after_cursor` and `before_cursor`, with a `page_info` object in every list response. - Raw card and bank details should not reach your servers. Collect them with the tokenize payment method web component and pass the resulting payment method token to Create Payment. - Web components (`@justifi/webcomponents`) run in the browser and authenticate with a web component token, created server-side via `POST /v1/web_component_tokens`, scoped to specific resources and valid for 60 minutes. Never send client secrets to a browser. --- # Getting Started with JustiFi Source: https://docs.justifi.tech/gettingStarted Welcome to JustiFi, where we empower software companies to transform into trailblazing Fintech leaders. Our suite of Fintech products is designed to seamlessly integrate financial technology into your offerings and open new horizons in the fintech world. ## Overview JustiFi provides a complete payment infrastructure solution that enables platforms to: - Onboard and underwrite merchants (sub accounts) - Process merchants' payments through multiple channels - Manage merchant payouts and platform earnings - Provide comprehensive reporting and analytics ### 1. Merchant Onboarding The onboarding process collects necessary business information for underwriting - **Business Creation**: Store merchant details via the Business API - **Sub-Account**: Automatically created upon successful form submission and needed for payment processing - **Underwriting**: JustiFi reviews and approves merchants (1-2 business days) - **Status Monitoring**: Subscribe to `sub_account.updated` webhooks Collect your merchants' business information via the following options: - **Hosted Onboarding**: Include a JustiFi-hosted form via iframe (is automatically kept up to date) - [see details](https://docs.justifi.tech/api-spec#tag/Hosted-Onboarding) - **Payment Provisioning Web Component**: Embed a pre-designed form on your platform (requires regular version updates) - [see details](https://docs.justifi.tech/api-spec#tag/Onboarding-via-Component) ### 2. Payment Processing JustiFi offers flexible E-commerce and card present payment solutions. #### E-commerce Options - **Hosted Checkout**: Minimal integration, JustiFi-hosted checkout form - [see details](https://docs.justifi.tech/checkouts/hosted-checkout) - **Unified Checkout Web Component**: Embedded pre-designed checkout form - [see details](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) - **Modular Checkout Web Component**: Fully customizable checkout flow - [see details](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) The following add ons are available in each of these E-commerce solutions: - **Apple Pay**: Adds Apple Pay to the checkout form - [see details](https://docs.justifi.tech/payments/applePay) - **Google Pay**: Adds Google Pay to the checkout form - [see details](https://docs.justifi.tech/payments/googlePay) - **Bank Account Verification via Plaid**: Allows customers to link their bank account for payment - [see details](https://docs.justifi.tech/paymentMethods/bankAccountVerification) - **Buy Now Pay Later via Sezzle** - **Insurance**: Add insurance to the checkout flow #### Additional Payment Features - **Card Present Solution**: Terminal integration via Verifone partnership - [see details](https://docs.justifi.tech/category/terminals) - **Payment Method Tokenization**: Collect payment methods for later and recurring charges - [see details](https://docs.justifi.tech/api-spec#tag/Tokenize-via-Component) ### Currency & Regional Processing JustiFi supports payment processing in USD and CAD. Each platform and its sub-accounts are scoped to a single currency. - **Currency Scoping**: Sub-accounts are configured for one currency type (e.g., `usd` or `cad`). A sub-account that processes USD cannot process CAD, and vice versa. - **Canada (CAD) Processing**: To process payments in Canadian dollars, you must have a separate Canada platform provisioned by JustiFi. CAD processing differs from USD in fee handling, payout timing, and supported payment methods. See the [Canadian Payments guide](https://docs.justifi.tech/payments/canadianPayments) for details. - **Payouts**: USD payouts follow standard daily payout schedules. CAD payouts follow a different schedule. > **Info** > > If your business operates in both the US and Canada, you will need separate platform accounts and sub-accounts for each currency. Your USD platform and its sub-accounts handle USD processing, and your CAD platform and its sub-accounts handle CAD processing. ### 3. Reporting & Analytics Access comprehensive reporting on all transaction for your platform as well as merchant specific data. #### Platform Level Reporting - **API Access**: Payments, Payouts, Proceeds, and Reporting APIs - **JustiFi Dashboard**: Visual reporting interface at [app.justifi.ai](https://app.justifi.ai/) #### Merchant Specific Reporting - **Filtered API Access**: APIs offer merchant-specific data via sub-account filtering - **Embedded Web Components**: Provide insights to your merchants on your platform via PaymentsList, PaymentDetails, PayoutsList, PayoutDetails, etc. ## Important Identifiers Keep track of these key identifiers throughout your integration: | Identifier | Purpose | Example | | ------------------- | ------------------------------- | --------------- | | API Key | Environment-specific API access | `test_abc123` | | Access Token | API request authorization | `Bearer eyJ...` | | Web Component Token | Embed component authorization | `wct_123456` | | Business ID | Unique business identifier | `biz_a1b2c3d4` | | Sub-Account ID | Payment processing identifier | `acc_x1y2z3w4` | ## Testing Your Integration JustiFi provides a comprehensive sandbox environment. It can be accessed via API and on the JustiFi dashboard via Test Mode - Utilize the developer dashboard ([https://app.justifi.ai/](https://app.justifi.ai) -> Developers) - Use test API keys for all development - Full API response simulation For detailed testing scenarios, visit ## Security Best Practices 1. **Never expose API keys in client-side code** 2. **Always use HTTPS for API communications** 3. **Implement webhook signature validation** [see details](https://docs.justifi.tech/api-spec#tag/Webhook-Delivery) 4. **Store sensitive data securely** 5. **Use web component tokens with appropriate expiration times** [see details](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens) ## Resources - **API Reference**: - **Web Component Documentation**: - **Developer Dashboard**: [https://app.justifi.ai/](https://app.justifi.ai) -> Developers - **Status Page**: ## Support and Feedback Need additional help or want to share suggestions or comments? Our dedicated support team is here to assist you. Contact us at or visit our [Support Center](https://docs.justifi.tech/contact). Embark on your journey with JustiFi and unlock the potential of fintech in your software solutions. We're excited to see what you'll build! --- # JustiFi’s Fintech Infrastructure Source: https://docs.justifi.tech/infrastructure/overview Learn what sets JustiFi apart from the competition ## Introduction JustiFi goes beyond being a mere Payments Gateway; we are your accelerator towards becoming a leading Fintech innovator. Our ecosystem is not just rich in partnerships and product variety, but also in specialized solutions, all accessible through a single, streamlined API set. Understanding the key terms and relationships within JustiFi's Fintech Infrastructure is essential for leveraging its full potential. This section is dedicated to familiarizing you with these critical concepts, ensuring a solid foundation for your Fintech journey. ## Our Fintech Products - **Payments:** Seamless transaction handling. - **Insurance:** Innovative features. - **Lending:** Details and benefits. - **Issuing:** Customized financial solutions. ![Definition of Fintech Products](https://docs.justifi.tech/assets/images/definition-fintech-products-new-b19d1ed9379f3a6fdace2c8ca32b28e9.png) JustiFi’s embedded fintech infrastructure empowers platform companies to easily integrate fintech products like payments and insurance faster than ever before. # Seamless Integration and Flexibility - Easy integration into existing systems. - Adaptability for various business needs. ## Success Stories - Real-world examples of diverse fintech product deployment. ![Crossbar Case Study](https://docs.justifi.tech/assets/images/success-stories-new-b721cda73c52faf6683568df86fb70d6.png) ## Unparalleled Support and Scalability - Ongoing support and expertise. - Scalable solutions for growing businesses. Cutting edge technology is critical, but without expert support, achieving transformative fintech results is nearly impossible. As part of our platform, we provide you with a fintech team, called Engage, to consult on go-to-market product strategy, feature utilization, forecasting, fundraising, and everything in between. ![High-level engage diagram](https://docs.justifi.tech/assets/images/engage-new-7c7fbf229d7b74ff641002acacaa88e4.png) ## Conclusion - JustiFi: Your partner in pioneering diverse fintech solutions. --- # Architectural Diagram Source: https://docs.justifi.tech/infrastructure/architectureDiagram ## JustiFi's Infrastructure ![High-level infrastructure diagram](https://docs.justifi.tech/assets/images/infrastructure-diagram-new-4863353016c6abdba34f8bde1a625bec.png) ## Superior Design Our design philosophy centers on simplicity and power. The single API gateway serves as the conduit for all interactions, ensuring that you don't have to juggle multiple integration points. This unified approach not only simplifies development but also significantly reduces the time-to-market for your Fintech products. ## Orchestration Layer: The Heart of Integration The Orchestration Layer is the heart of our infrastructure. It intelligently manages the flow between our entities and the suite of services like Payment, Insurance, and Lending. This layer abstracts the complexity of multi-service coordination, providing you with a cohesive and holistic view of all financial activities. # Key Advantages: - **Simplified Integration:** One API to connect you to abroad spectrum of Fintech services. - **Holistic View:** Seamless orchestration for a comprehensive understanding of financial operations. - **Scalable Architecture:** Designed to grow with your business, handling increased volume and complexity with ease. - **Reduced Complexity:** Our layer does the heavy lifting, so you can focus on building and scaling your products. With JustiFi, you're not just adopting a service; you're integrating a solution that evolves with the landscape of Fintech innovation. Our infrastructure is designed for those who envision a future where Fintech is not just a part of their business—it is their business. --- # The Strategic Advantage of Entities in JustiFi's Fintech Ecosystem Source: https://docs.justifi.tech/infrastructure/entities JustiFi is revolutionizing Fintech infrastructure by introducing a sophisticated entity framework. This innovative approach unites Businesses and Identities, creating a versatile and cohesive ecosystem that is more than the sum of its parts. ## Identities: A New Paradigm In the JustiFi ecosystem, an "Identity" extends beyond traditional customer boundaries, offering a rich, multidimensional portrait of an individual's financial life: - **Beyond Transactions:** An Identity represents an individual's entire financial existence—encompassing their roles as a business owner, investor, borrower, and more. - **Personalized Financial Narrative:** By consolidating an individual’s various financial personas under a single Identity, JustiFi delivers personalized financial experiences and precise service delivery. ![Definition of Identity](https://docs.justifi.tech/assets/images/definition-identity-new-d5ae7703d1136c41b0567fb16902a6c6.png) ## Businesses: The Multifaceted Financial Entity The concept of a "Business" within JustiFi is expansive, reflecting the dynamic nature of modern financial ecosystems: - **Multiple Roles, One Entity:** A Business may interact with your platform as a direct customer, a vendor, or as part of a larger supply chain, showcasing JustiFi's adaptive platform in action. - **Comprehensive Business Profiles:** Linking Businesses to Identities provides a granular view of their financial behaviors, offering insights into operations, risk assessment, and relationship management. - **Fintech Synergies:** Understanding the multifaceted aspects of Businesses enables JustiFi to facilitate targeted Fintech offerings, enhancing trust and driving revenue growth through strategic engagement. ![Definition of Business](https://docs.justifi.tech/assets/images/definition-business-new-1dd465410ea1324055a3b4b4368dc16a.png) ## A Future-Proof Infrastructure Adopting "Entities" as a central concept provides tangible, strategic advantages: - **Scalable Architecture:** Designed to accommodate growth, JustiFi’s infrastructure scales effortlessly, supporting a seamless expansion of services and market reach. - **Seamless Product Integration:** The orchestration between Entities paves the way for a smooth rollout of innovative Fintech products, ensuring that partners can adapt to market demands with agility. - **Data-Driven Insights:** A holistic view of Entities empowers partners with the data needed to make informed decisions, customize services, and offer timely, relevant Fintech solutions. - **Regulatory Alignment:** JustiFi's entity-centric approach streamlines compliance, simplifying the intricacies of regulatory adherence across financial operations. - **Accelerated Market Entry:** By unifying various financial operations under a coherent framework, JustiFi significantly shortens the development cycle, enabling quicker launches and adaptability. JustiFi's commitment to a sophisticated entity-based architecture not only enhances current operational efficiency but also ensures readiness for the future of Fintech, keeping our partners ahead of the curve. --- # Web Development Strategy at JustiFi Source: https://docs.justifi.tech/infrastructure/webComponents ## The JustiFi Way: Web Components By integrating Web Components into our workflow, we at JustiFi are setting a standard for modern, efficient, and scalable web development. They align perfectly with our goal to deliver **white-labeled, versatile, high-performance Fintech solutions.** With these components, we're not just building for today; we're gearing up for the future of web development, ready to adapt, grow, and lead in the Fintech industry. ![Definition of Web Components](https://docs.justifi.tech/assets/images/definition-web-components-new-dc462439b5974eb3b709146825e534ab.png) ## The Power of Web Components At JustiFi, we're excited about Web Components and how they're transforming web development. These aren't just new tools; they're a new way of thinking about building and deploying web applications. Web Components allow us to create custom, reusable HTML tags that work across any framework. This means we can develop more efficiently, reduce redundancy, and ensure a consistent experience across various platforms. *As a matter-of-fact, all of JustiFi's dashboards are built using the same Web Components that we open-source and share with you!* **Explore JustiFi's Web Component Library using our [Storybook](https://docs.justifi.tech/web-components/introduction)** ## Benefits of Web Components Over Framework-Specific Libraries Why opt for Web Components instead of sticking with traditional libraries? It's all about flexibility and future-proofing. Web Components are framework-agnostic, meaning they play nicely with whatever web technology you're using. This universality is a big plus in our rapidly evolving tech landscape. It makes our products more adaptable and saves time otherwise spent on compatibility issues. Moreover, these components make our code cleaner and more maintainable. They encourage a modular approach, where each piece of your application is a building block that can be reused and repurposed as needed. This not only speeds up the development process but also enhances the overall performance of our applications. Lighter and faster is the way to go in today's web world. #### Learn how to use JusitFi's Web Components using popular frameworks: - [Native HTML](https://docs.justifi.tech/web-components/introduction#usage) - [Angular](https://docs.justifi.tech/web-components/frameworks/angular) - [React](https://docs.justifi.tech/web-components/frameworks/react) - [Vue3](https://docs.justifi.tech/web-components/frameworks/vue) ## Ease of Implementation Across Multiple Frameworks One of the most compelling aspects of Web Components is their ease of implementation across various web frameworks. Whether you're working with React, Angular, Vue, or any other framework, integrating Web Components is straightforward. This cross-framework compatibility is a significant advantage, eliminating the need to rewrite or adapt components for different frameworks. It streamlines the development process, allowing us to focus on innovation rather than worrying about framework-specific limitations. ## Styling and Customization: The Creative Advantage One of the coolest things about Web Components is how they handle styling. Thanks to Shadow DOM, styles in a Web Component are scoped to the component itself. This means no more unexpected style clashes or overrides — a big relief for developers and designers alike. It ensures that our components look consistent, no matter where they are used. But there's more. Web Components come with the ability to expose CSS variables, making them incredibly flexible for styling. This is great for keeping branding consistent and allows for a lot of creative freedom in design. We can tailor the look and feel of components to fit any environment, making our products not just functionally robust but also visually appealing. **Learn how to style JustiFi's Web Components using [CSS Parts](https://docs.justifi.tech/web-components/introduction#styling).** --- # Web Component Token Examples Source: https://docs.justifi.tech/infrastructure/webComponentTokens ## Overview of Web Component tokens Due to the inherent risk of front end authorization, we have a fine-grained access token pattern for our web components. The following table describes which roles can be used to render a web component. We assume you have an authorize admin API key to complete the example API calls, and use that key to generate the Web Component Token. ### Roles need for each component | Component | Pre-Requisite | Role | | ------------------- | -------------------- | ----------------------------------------------------------- | | BusinessDetails | Existing Business Id | read:business:`business_id` or write:business:`business_id` | | BusinessForm | Existing Business Id | write:business:`business_id` | | BusinessFormStepped | Existing Business Id | write:business:`business_id` | | GrossPaymentChart | Existing Sub Account | read:account:`account_id` or write:account:`id` | | PaymentDetails | Existing Sub Account | read:account:`account_id` or write:account:`id` | | PaymentList | Existing Sub Account | read:account:`account_id` or write:account:`id` | | PayoutDetails | Existing Sub Account | read:account:`account_id` or write:account:`id` | | PayoutList | Existing Sub Account | read:account:`account_id` or write:account:`id` | | Checkout | Checkout created | write:checkout:`checkout_id` | | CardForm | Existing Sub Account | write:tokenize:`account_id` | | BankAccountForm | Existing Sub Account | write:tokenize:`account_id` | ## General Usage The pattern for using a web component starts in a backend request. Your backend should have a client token generated. Then, you need to find or create the resource the component needs to function, for example create a business before rendering the BusinessForm component. Next, you generate a web component token, which is good for 60 minutes, using the id(s) of the resources you will render. You then use this as the auth-token attribute to render the component in your front end. ### Here is an example of retrieving a payment and rendering the payment details. The following steps show how to get the latest payment, generate a web component token, and render the PaymentDetails web component (copy and paste each block of code in a terminal to test using your credentials): > We use [curl](https://curl.se/) to make the API calls in the terminal, and [jq](https://stedolan.github.io/jq/) to parse the json response. You can install using [homebrew](https://brew.sh/) on a mac or [chocolatey](https://chocolatey.org/) on windows. 1. Generate Access Token [API](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken) ```bash ACCESS_TOKEN_RESPONSE=$(curl -sS --request POST \ --url https://api.justifi.ai/oauth/token \ --header 'Content-Type: application/json' \ --data '{ "client_id":"test_abc1234", "client_secret":"test_xyz9876" }' ) ``` 2. Get the access\_token and print to the console ```bash ACCESS_TOKEN=$(echo $ACCESS_TOKEN_RESPONSE | jq -r '.access_token') echo "Access Token: ${ACCESS_TOKEN}" ``` 3. List Payments [API](https://docs.justifi.tech/api-spec#tag/Payments/operation/ListPayments) using the access\_token generated above and a test account: ```bash ACCOUNT_ID="acc_abc1234" PAYMENT_LIST=$(curl -sS --request GET \ --url https://api.justifi.ai/v1/payments \ --header 'Authorization: Bearer '${ACCESS_TOKEN}'' \ --header 'Sub-Account: '${ACCOUNT_ID}'' ) ``` 4. Get the first payment\_id from payment list (= latest payment) and print to the console ```bash PAYMENT_ID=$(echo ${PAYMENT_LIST} | jq -r '.data[0].id') echo "Payment ID: ${PAYMENT_ID}" ``` 5. Generate Web Component Token [API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens) (*note: replace acc\_abc1234 with the account id from step 3*) ```bash WC_TOKEN_RESPONSE=$(curl -sS --request POST \ --url https://api.justifi.ai/v1/web_component_tokens \ --header 'Authorization: Bearer '${ACCESS_TOKEN}'' \ --header 'Content-Type: application/json' \ --data '{ "resources": [ "read:account:acc_abc1234" ] }' ) ``` 6. Get the web*component\_token and print to the console (\_note: this token is good for 60 minutes*) ```bash WEB_COMPONENT_TOKEN=$(echo $WC_TOKEN_RESPONSE | jq -r '.access_token') echo "Web Component Token: ${WEB_COMPONENT_TOKEN}" ``` #### Front end code: payment\_details.html *note: replace WEB\_COMPONENT\_TOKEN and PAYMENT\_ID with the values from the terminal script above* ```html justifi-payment-details ``` Open the file in your browser OR run a local web server (you may use any web server) *note: if you have python3 installed, you can run the following command on the folder the html file was created to start a local web server.* ```bash # example using Python python3 -m http.server ``` Open the file OR go to , you should see the [payment details web component](https://docs.justifi.tech/web-components/merchant-tools/payout-details): ![PaymentDetails](https://docs.justifi.tech/assets/images/wc_payment_details-e5c2cbcd52e0ff61f18cd5695fcc25a5.png) #### Front end code: payment\_list.html *note: replace WEB\_COMPONENT\_TOKEN and ACCOUNT\_ID with the values from the terminal script above* ```html justifi-payments-list ``` Open the file or go to , you should see the [payment list web component](https://docs.justifi.tech/web-components/merchant-tools/payments-list): ![PaymentList](https://docs.justifi.tech/assets/images/wc_payment_list-ff3feea99be65a60b0fbb4a910a5e0b8.png) ### Create a business and render the Payment Provisioning component The following steps shows how to create a business entity, generate a web component token, and render the [PaymentProvisioning web component](https://docs.justifi.tech/web-components/entities/payment-provisioning): 1. Generate Access Token [API](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken) ```bash ACCESS_TOKEN_RESPONSE=$(curl -sS --request POST \ --url https://api.justifi.ai/oauth/token \ --header 'Content-Type: application/json' \ --data '{ "client_id":"test_abc1234", "client_secret":"test_xyz9876" }' ) ``` 2. Get the access\_token from the response and print to the console ```bash ACCESS_TOKEN=$(echo $ACCESS_TOKEN_RESPONSE | jq -r '.access_token') echo "Access Token: ${ACCESS_TOKEN}" ``` 3. Create a business entity [API](https://docs.justifi.tech/api-spec#tag/Business/operation/CreateBusiness) using the access\_token generated above: ```bash BUSINESS_RESPONSE=$(curl -sS --request POST \ --url https://api.justifi.ai/v1/entities/business \ --header 'Authorization: Bearer '${ACCESS_TOKEN}'' \ --header 'Content-Type: application/json' \ --data '{ "legal_name": "USS Enterprise" }' ) ``` 4. Get the business\_id from the resopnse and print to the console ```bash BUSINESS_ID=$(echo ${BUSINESS_RESPONSE} | jq -r '.id') echo "Business ID: ${BUSINESS_ID}" ``` 5. Generate Web Component Token [API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens) (*note: replace biz\_abc1234 with the business id from step 4 above*) ```bash WC_TOKEN_RESPONSE=$(curl -sS --request POST \ --url https://api.justifi.ai/v1/web_component_tokens \ --header 'Authorization: Bearer '${ACCESS_TOKEN}'' \ --header 'Content-Type: application/json' \ --data '{ "resources": [ "write:business:biz_abc1234" ] }' ) ``` 6. Get the web\_component\_token from the response and print to the console ```bash WEB_COMPONENT_TOKEN=$(echo $WC_TOKEN_RESPONSE | jq -r '.access_token') echo "Web Component Token: ${WEB_COMPONENT_TOKEN}" ``` #### Front end code: payment\_provisioning.html *note: replace WEB\_COMPONENT\_TOKEN and BUSINESS\_ID with the values from the terminal script above* ```html justifi-payment-details ``` Open the file or go to , you should see the payment\_provisioning form used for Onboarding: ![PaymentProvisioning](https://docs.justifi.tech/assets/images/wc_business_form_stepped-46ac54a9748466675885a00fc5644557.png) ## Example Web Component implementations ### Payment/Payout Components To use our payment and payout components, you must grant a web component token for the sub account for which you'd like to show the payments or payouts. - Choose the sub account id (acc\_abc1234) - With business OR sub account id, generate WC session read:account:`id` - Render component ### Business Onboarding - Create a business via create business API - Create Web Compontent Token for Business write:business:`id` - (optional) confirm WC token on Customer Admin Dashboard - Render the Payment Provisioning Component with the WC Token (note good 60 minutes) #### (optional) Activate business for payments - Accept terms of service via [Terms and Conditions API](https://docs.justifi.tech/api-spec#tag/Terms-and-Conditions/operation/TermsAndConditions) - Upload onboarding documents via [Documents API](https://docs.justifi.tech/api-spec#tag/Document/operation/CreateDocument) - Add a payout bank account for the business via [Bank Accounts API](https://docs.justifi.tech/api-spec#tag/Bank-Account/operation/CreateBankAccount) - Provision Payments product via [Provisioning API](https://docs.justifi.tech/api-spec#tag/Provisioning/operation/ProductProvisioning) ### View Business Details Management - With Business ID, generate WC session read:business:`id` - Render Component ## Future documentation We will document our checkout components and the card, bank account and payment forms here as they become available. --- # JustiFi API Overview Source: https://docs.justifi.tech/apiFundamentals Harness the power of JustiFi's RESTful API to seamlessly integrate Fintech solutions into your applications. Our API is designed for ease of use, scalability, and secure, efficient interactions. ## RESTful API Design JustiFi's API adheres to RESTful principles, offering a predictable and intuitive interface for developers. This design approach ensures standardized communication using familiar HTTP methods and status codes, facilitating a smooth integration process. ## Core Features - **Standardized Communication:** Utilize standard HTTP methods for clear, efficient interactions. - **Scalability:** Robustly built to handle increasing volumes of requests as your business grows. - **Security:** Strong authentication protocols and encryption safeguard your data and transactions. ## Explore Our API Guides Dive deeper into each aspect of our API with these detailed guides: These guides provide comprehensive insights and practical examples to optimize your use of the JustiFi API. Leverage the JustiFi API to innovate and elevate your Fintech offerings, and experience a world of possibilities at your fingertips. --- # Authentication While Using JustiFi's API Source: https://docs.justifi.tech/apiFundamentals/authentication Secure and efficient access to JustiFi's API is paramount. We use OAuth2 authentication, a standard protocol for authorization, and secure your API requests with Bearer tokens for robust protection. [API Specification](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken) ## OAuth2 and Bearer Token Authentication OAuth2 provides a secure and standardized way to authorize API requests. When you access JustiFi's API, your request must include a Bearer token, which is a unique token obtained after a successful OAuth2 authentication process. This token ensures that your interactions with our API are secure and authenticated. ## Obtaining Your API Key To start using our API, you'll need an API Key, which you can obtain from our customer dashboard. This key is essential for the OAuth2 authentication process. ### Steps to Get Your API Key: 1. **Access the Customer Dashboard:** Log in to your JustiFi [account](https://app.justifi.ai). 2. **Navigate to the Developer Section:** Find the API section where you can manage your keys. 3. **Continue to the API Keys Section:** Follow the steps to generate a new API key. > **Tip** > > ## Don't Have an Account? > > If you're new to JustiFi and don't have an account yet, getting started is easy: > > 1. **Contact Us:** [Reach out to our team](https://docs.justifi.tech/contact) to set up an account. > 2. **Account Setup:** Our team will guide you through the account setup process and help you get your API Key. ## Create Your Bearer Token Once you have your API Key, you'll use it to obtain a Bearer token. Here's an example to generate an Authentication Token. You can replace the `client_id` and `client_secret` to use your own. **Be sure to use TEST keys!** --- # Understanding Idempotency in JustiFi API Source: https://docs.justifi.tech/apiFundamentals/idempotency Idempotency is a fundamental concept in API design, especially when dealing with critical operations like financial transactions. At JustiFi, we ensure the reliability and consistency of transactions through idempotent requests. ## What is Idempotency? Idempotency in API terms means that making multiple identical requests results in the same outcome as making a single request. This is particularly important for financial transactions, where the risk of duplicate processing needs to be eliminated. ## Implementing Idempotency with JustiFi's APIs To achieve idempotency, JustiFi leverages the `Idempotency-Key` header in our payment APIs. ### The Idempotency-Key Header > **Warning** > > Failing to provide an `Idempotency-Key` will exclude your requests from the protections described. - **Optional Usage:** Each request may include an `Idempotency-Key` header. - **Preventing Duplicates:** If a second request with the same idempotent key is processed concurrently, it will return a 409 error, preventing double processing. - **Error Handling:** - **Network Timeouts and 5XX Errors:** Retry these requests with the exact same parameters and idempotency key. - **2XX Responses:** Indicate successful processing. Repeating an identical request with the same key will return the original response. - **4XX Errors (Except 409):** Do not retry these requests as they indicate client-side errors. ### Choosing an Idempotency-Key - **String Identifier:** You can use any string up to 100 characters long as your `Idempotency-Key`. We recommend using a UUID for uniqueness, but any distinctive string (100 character max) that identifies the transaction will work. ### Idempotency Key Constraints - **Uniqueness Per Transaction:** The key should be unique to each transaction. Using the same key with different parameters will result in an error. - **Single Transaction Use:** The key is intended to safeguard a single transaction. Altering the request parameters makes it a distinct request, requiring a new idempotency key. - **Character Limit:** If the length of the key exceeds 100 characters a 422 error `Validation failed: Idempotency key is too long (maximum is 100 characters)` is returned. ## Best Practices - **Generate Unique Keys:** Ensure each key is unique to prevent unintended conflicts. - **Consistent Parameters:** Use the same parameters when retrying requests to maintain idempotency. - **Error Code Awareness:** Understand the error codes to determine when it's appropriate to retry a request. By adhering to these guidelines and effectively utilizing the `Idempotency-Key` header, you can ensure that your transactions via JustiFi's API are processed reliably and consistently, without the risk of duplication. --- # Pagination in JustiFi API Source: https://docs.justifi.tech/apiFundamentals/pagination Effective management of large datasets is crucial in API interactions. JustiFi's API employs cursor-based pagination, ensuring efficient and scalable data retrieval for bulk fetches. ## Cursor-Based Pagination Explained Cursor-based pagination involves navigating through data using cursor pointers (`before_cursor` and `after_cursor`), making it ideal for handling extensive datasets. Each response in our API includes a `page_info` object, crucial for understanding your position in the data set and managing the flow of information. ### Using the Page Info Object: - **Navigation Fields:** The `page_info` object contains `has_next` and `has_previous` fields to indicate more available items. - **Cursor Values:** `start_cursor` and `end_cursor` are included for precise data retrieval. ## API Request Parameters When fetching data, these parameters are key: - **`limit`:** Controls the number of resources retrieved per request. It can range from 1 to 100, with a default value of 25. - **`after_cursor`:** Fetches the next page of data. - **`before_cursor`:** Retrieves the previous page of data. ### Standard Response Structure All responses follow a consistent structure: - **`id`:** The ID of the object returned, null for array responses. - **`type`:** Indicates the type of object returned, typically an "array" for bulk fetches. - **`data`:** Contains the requested resource(s) or an empty array if no resources are available. - **`page_info`:** Provides pagination details, including cursor positions. ##### Example Paginated Request ```sh curl -X GET https://api.justifi.ai/v1/payments?limit=25&after_cursor=token-from-page-info \ -H 'Authorization: Bearer [access_token]' \ -H 'Accept: application/json' ``` ##### Example Paginated Response ```sh { "id": null, "type": "array", "data":[ { "id":"py_438xBom2Drh55kE1WfyGLg", "amount": 1000, ... additional response attributes based on resource schema } ], "page_info": { "has_previous": false, "has_next": true, "start_cursor": "WyIyMDIyLTAxLTExIDE1OjI3OjM2LjAyNzc3MDAwMCIsImNhNjQwMTk1LTEzYzMtNGJlZi1hZWQyLTU3ZjA1MzhjNjNiYSJd", "end_cursor": "WyIyMDIyLTAxLTExIDEyOjU5OjQwLjAwNTkxODAwMCIsImQ0Njg5MGE2LTJhZDItNGZjNy1iNzdkLWFiNmE3MDJhNTg3YSJd" } } ``` ## Best Practices for Pagination - **Determine Optimal Page Size:** Balance performance and usability by setting an appropriate `limit`. - **Consistent Cursor Usage:** Utilize `before_cursor` and `after_cursor` effectively for predictable navigation. - **Understand Response Structure:** Familiarize yourself with the standard response envelope for efficient data handling. By leveraging JustiFi's pagination system, you can efficiently navigate through large datasets, ensuring your application remains responsive and data retrieval remains manageable. --- # Entities: The Core of JustiFi Platform Source: https://docs.justifi.tech/entities/overview ## Overview At the heart of JustiFi’s platform lie Entities, a foundational concept designed to encapsulate the diverse aspects of your business operations and customer interactions. Entities are not just for tracking payments; they are instrumental in knitting together JustiFi’s suite of products to offer a holistic view of each entity within your platform. ## Unifying Business Operations and Insights Entities serve as a comprehensive data model that represents both Businesses and Identities (individuals or customers) on your platform. By centralizing data ranging from transaction histories to product usage, Entities enable a deep understanding of how each entity interacts with your platform and their profitability. ### Key Benefits - **Holistic View:** Gain a 360-degree perspective of each entity, encompassing financial transactions, product interactions, and more. - **Enhanced Profitability:** Utilize insights derived from entity data to identify and capitalize on profitability drivers within your platform. - **Customized Offerings:** Leverage historical data and engagement patterns to tailor product offerings, including pre-approvals for lending or insurance products. ## Driving Revenue and Gross Margin Growth Entities are pivotal in transforming JustiFi from a mere payment processor to a growth engine for your platform. By intelligently analyzing entity data, JustiFi enables the creation of targeted, value-added services that drive revenue and elevate gross margins. ### Real-World Application: Enhancing Customer Value Imagine a SaaS platform for small businesses that utilizes JustiFi. By analyzing data from the Entities model, the platform can: 1. **Identify Top Customers:** Understand which businesses generate the most revenue and why. 2. **Cross-Sell Effectively:** Use past product usage to offer relevant financial products, such as short-term loans for inventory purchases or insurance for asset protection. 3. **Automate Pre-Approvals:** Implement data-driven criteria to offer pre-approvals for financial products, reducing friction and enhancing customer engagement. ## Implementing Entities in Your Platform - **Integration:** Seamlessly integrate Entities into your platform with JustiFi’s APIs, enriching your data ecosystem. - **Customization:** Tailor the Entities model to capture and utilize data points critical to your operational and strategic goals. - **Scalability:** Leverage JustiFi’s scalable infrastructure to grow with your platform, accommodating an expanding volume of entities and transactions. ## Conclusion Entities are the cornerstone of the JustiFi platform, enabling businesses to not only process payments efficiently but also to unlock deeper insights and drive profitability. By embracing this comprehensive approach, platforms can significantly enhance their gross margin and foster unprecedented growth. --- # Businesses Source: https://docs.justifi.tech/entities/businesses ## Overview Explore how JustiFi's concept of Businesses within Entities allows for detailed management and growth of business customers on your platform. This section will cover how to utilize Businesses to streamline operations, enhance customer relationships, and drive revenue. ## Key Features and Benefits - **Data Management:** Centralize business information, including banking details, contact information, and transaction history. - **Customization:** Tailor data fields to fit the specific needs of your industry or operational requirements. - **Integration:** Seamlessly connect with other JustiFi components for a cohesive financial management experience. ## Real-World Application: General Contractor Management Platform ### Scenario A general contractor construction management platform uses JustiFi to manage a diverse portfolio of business clients, handling sub-contractor payments, vendor payments and providing unique financial insights. ### Implementation Steps 1. **Onboarding General Contractors:** Collect and store essential business details using JustiFi's Business Entities and provision payment processing and sales of additional fintech products during the customer signup process. 2. **Onboard Vendors and Suppliers:** Leveage Business Entities to securely store vendor and supplier information that can be reused throughout your platform, simplifying the experience for General Contractors. 3. **Onboard Sub-Contractors:** Create Business Entities for Sub-Contractors utilized by your customers creating a simple workflow your Sub-Contractors to make future payments and store additional doccumentation related to the sub-contractor. 4. **Utilize Identities for Home Owners:** Securely store homewoner information and payment methods to make it simple for your customers to get paid. ### Benefits 1. **Secure Payment Method Storage:** Linking Entities and payment methods minimizes risk and simplifies General Contractor's workflows to pay Vendors and Sub-Contractors. 2. **Understand Platform Customer's Finacial Value:** Business Entities centralize all fintech products utilized by General Contractors, Vendors, Suppliers, and Sub-Contractors. You can easily understand the revenue each of your customers add to your platform. 3. **Targeted Marketing Towards Vendors, Suppliers and Sub-Contractors:** By creating Entities for each business, you are able to leverage your unique insights on outstanding invoices or deliverables to present present relevent offers. For example, when a vendor sends a General Contractor an invoice for a large delivery of concrete, both the Vendor and General Contractor likely have a need for a line of credit to meet cash flow demands. 4. **Targeted Marketing Towards General Contractors:** Leverage the Business or Identity Entities to create timely revenue generating offers. Some examples: liability insurance, fleet insurance, equipment lending, line of credit, and many more. ## Best Practices - **Data Security:** Ensure sensitive business information is handled according to industry standards. - **User Experience:** Design a streamlined onboarding process for businesses using JustiFi's flexible data models. - **Compliance:** Stay informed about regulatory requirements affecting business data management and financial transactions. --- # Identites Source: https://docs.justifi.tech/entities/identities ## Overview Dive into the Identities aspect of JustiFi's Entities, focusing on managing individual user data to personalize services, enhance security, and optimize user experience. This section will illustrate how Identities can be leveraged to support your platform's diverse needs. ## Key Features and Benefits - **Unified Profiles:** Create and manage detailed profiles for each user, consolidating financial and personal information. - **Authentication and Security:** Leverage JustiFi's built-in security measures for identity verification and fraud prevention. - **Customization and Flexibility:** Adapt the identity management system to support the unique needs of different SaaS verticals. ## Real-World Application: Real Estate Management Platform ### Scenario A real estate management platform leverages JustiFi to streamline rent payments, security deposits, and maintenance fee transactions for tenants and property owners. ### Implementation Steps 1. **Property Management Company:** Utilize JustiFi's Business Entities to onboard your platform's customer and provision the payment processing account and sales of insurance products. 2. **Property Owners:** Utilize JustiFi's Business and Identity Entities to create property owners linked to Propery Management Companies. 3. **Tenants:** Utilize JustiFi's Identity Entities to collect and safely store all tenant demographics. Attach tenant's payment accounts and payment methods for seamless payment processing. ### Benefits 1. **Secure Payment Method Storage:** Linking Entities and payment methods minimizes risk involved with processing recurring rent payments. 2. **Understand Platform Customer's Finacial Value:** Business Entities centralize all fintech products utilized by Property Management Company. You can easily understand the revenue each of your customers add to your platform. 3. **Targeted Marketing Towards Tenants:** By creating and Identity for each tenant you are able to leverage unique information to create timely and highly profitable offers for your customer. Example offers include renter's insurance, banking promotions, car insurance, and more. 4. **Targeted Marketing Towards Property Owners:** Leverage the Business or Identiy Entities to create timely revenue generating offers. Some examples: home owners insurance, rent payment insurance, line of credit, liability insurance. ## Best Practices - **Privacy Protection:** Implement robust measures to protect the personal information of users in line with data protection regulations using Identities. - **Seamless Integration:** Ensure the identity management system works harmoniously with other platform components for a cohesive user experience. - **Scalability:** Design the system with scalability in mind to accommodate growing numbers of users without compromising performance. --- # Checkouts: Unified Fintech Checkout™ Source: https://docs.justifi.tech/checkouts/overview ## Overview The JustiFi Unified Fintech Checkout (UFC) is a streamlined API solution designed to integrate embedded payments, insurance, and BNPL (Buy Now, Pay Later) options within a single checkout. This API minimizes deployment time and maximizes revenue opportunities for platforms, enabling companies to implement fintech solutions within a single development sprint. JustiFi’s solution includes white-label web component for seamless integration, supported by tailored activation services for UI/UX, technical setup, and go-to-market strategies. [vimeo Video Player](https://player.vimeo.com/video/944938875?color\&autopause=0\&loop=0\&muted=0\&title=1\&portrait=1\&byline=1#t=) ## Checkout abstraction The checkout API provides access to multiple products and features from the JustiFi platform using a single API. By orchestrating multiple backend resources, it enables seamless payment collection, integration with terminal readers, BNPL transactions, insurance quote processing, and more in a unified flow. ### Key Benefits - **Abstraction:** A checkout gives access to multiple fintech products (beyond payments). - **Traceability:** Each attempt to complete a checkout is recorded, ensuring traceability and status tracking for every checkout. - **Implementation:** Simplified setup with a single API and web component. ## Checkout Web Component Web components are encapsulated, self-contained units of code (HTML, CSS, and JavaScript), that can be easily reused and combined with other components without external code interference. This leads to more consistent user interfaces, streamlined development, and reduced maintenance, as updates to a component automatically apply across all instances. The Unified Fintech Checkout™ web component provides the easiest way for customers to access multiple fintech products. [Here is an example in our docs](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) ## Implementing Checkout in Your Platform - Please refer to the [Checkout via API](https://docs.justifi.tech/api-spec#tag/Checkout-via-API) documentation for a step-by-step example of how to make a payment using Checkouts. - Please refer to the [Checkout via Component](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) documentation for collecting a payment via checkout using the web component. - Please refer to the [Terminals](https://docs.justifi.tech/api-spec#tag/Terminals) documentation section for our a card present solution. - Review [Create a Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) documentation for more details and parameter options. ## Conclusion Checkouts provide a simple way to access multiple features of the JustiFi platform, allowing businesses to efficiently collect payments and enable other fintech products. By adopting this comprehensive approach, platforms can significantly increase their gross margin and drive growth. --- # Features Source: https://docs.justifi.tech/checkouts/features ## Overview Checkouts offer consolidated payment collection, payment method tokenization into groups, and customizable fee structures in a single workflow. Supported payment types include Card Payments, ACH Payments, Insurance Quote Payments, BNPL (Buy Now Pay Later) Payments (API support pending), and Terminal (Card Reader) Payments. *note: New features will be documented here as they become available.* > **Currency Support** > > Checkouts support both USD and CAD currencies. The currency is determined by the sub-account processing the checkout — each sub-account is scoped to a single currency. To process checkouts in CAD, a dedicated Canada platform account is required. ### Card and ACH Payment - To process a card or ACH payment through this API, refer to [Checkout via API](https://docs.justifi.tech/api-spec#tag/Checkout-via-API) - To process a card or ACH payment using the Unified Fintech Checkout™ Component, refer to [Checkout via Component](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) ### Insurance Quote Payments - To include an insurance quote in a Checkout, first contact to enable insurance payments for your platform. Ensure the required insurance type is available through our provider. - After creating a Checkout, use the [Unified Fintech Checkout™ Component with insurance](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) to collect the insurance payment. ### BNPL Payments - To enable BNPL payments, contact to activate BNPL for your platform and sub account. - After creating a Checkout, use the [Unified Fintech Checkout™ Component](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) with the BNPL option (default). *note: Disable the BNPL option by passing the correspondent prop to the web component: [disable-bnpl](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™)* ### Terminal (Card Reader) Payments - For terminal payments, contact to enable the card-present feature. JustiFi will then provision and configure terminals for your sub accounts. - Find detailed steps in the [Terminals API](https://docs.justifi.tech/api-spec#tag/Terminals) ### Fees Checkouts support flexible fee structures that allow you to specify different fee types. This enables transparent reporting for merchants and selective fee refunds. > **CAD Payments** > > The `payment.fees` and `application_fee_amount` parameters are **not supported for CAD checkouts**. For CAD payments, fees are determined during merchant onboarding and are not configurable via the API. See the [Canadian Payments guide](https://docs.justifi.tech/payments/canadianPayments) for details. #### Using the Fees Array (Recommended) Use the `payment.fees` parameter to specify fee types when creating a checkout: ```json { "amount": 10000, "description": "order_xyz", "payment": { "fees": [ { "type": "processing_fee", "amount": 295 }, { "type": "platform_fee", "amount": 150 } ] } } ``` **Supported fee types:** - `processing_fee` - Fees related to payment processing costs - `platform_fee` - Fees for your platform's services **Benefits of using the fees array:** - **Transparent reporting**: Each fee type appears as a separate line item in merchant balance transactions - **Selective refunds**: When processing refunds, you can choose which fees to return to the merchant For full documentation, see [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management). > **Configurable Fees (v2 Fee Structure)** > > Platforms on the v2 fee structure can use [Configurable Fees](https://docs.justifi.tech/configurableFees/overview) to auto-calculate fees from standard fee configurations on each sub account. The `fees` array does not need to be passed unless overriding the calculated amount. See [Fee Calculation & Examples](https://docs.justifi.tech/configurableFees/examples) for details. > > **Important:** When using Configurable Fees, the checkout response and checkout events (`checkout.created`, `checkout.completed`, `checkout.completion.succeeded`) will **not** include SFC-calculated fees. Fees are calculated after the payment is created. Subscribe to **[payment events](https://docs.justifi.tech/api-spec#tag/Events/operation/paymentEvent)** or use the [Get Payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment) to retrieve the finalized fee breakdown. #### Application Fees (v1 Fee Structure) > **Migrating to Configurable Fees** > > Application Fees are part of the **v1 fee structure**. Platforms on the v2 fee structure use [Configurable Fees](https://docs.justifi.tech/configurableFees/overview) instead, which provide per-payment-type rates, brand-specific pricing, and selective fee refunds. See [Migrating from Application Fees](https://docs.justifi.tech/configurableFees/overview#migrating-from-application-fees) for guidance on transitioning. > **For Existing v1 Integrations** > > The `application_fees` parameter continues to work for platforms on the v1 fee structure. **New integrations** should use `payment.fees` or [Configurable Fees](https://docs.justifi.tech/configurableFees/overview) instead. - Application Fees are configured at the Platform level and can be customized for specific sub accounts. Checkouts add an additional layer of flexibility by allowing the use of the `application_fees` parameter when creating a checkout. - **Create a Checkout:** Use the [Create Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts) with custom application fees (in cents) for card and bank payments, as in the following example: ```json { "amount": 1000, "description": "test checkout application fees", "application_fees": { "card": { "amount": "200" }, "bank_account": { "amount": "100" } } } ``` - The application fee applies based on the selected payment method during checkout. It overwrites the `application_fee_rate` set for the sub account. *note: available for Card, ACH and Terminal (Card Present) only!* **Important**: You cannot use both `application_fees` and `fees` in the same request. ### Payment Method Group - **Create a Payment Method Group:** Use the [Payment Method Group API](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups) to create a group for easy payment method access. - **Create a Checkout:** Use the [Create Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) and pass the `payment_method_group_id`. - **Checkout Web Component:** Use the [Unified Fintech Checkout™ Component](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) and pass the checkout id. This allows the component to display a list of tokenized payment methods in the group, and an option to **Save new payment method** is also available. --- # Lifecycle Source: https://docs.justifi.tech/checkouts/lifecycle ## Overview A Checkout is not a Payment; it has its own data model, lifecycle, and statuses. It contains the information necessary to prepare for possibly multiple payment transactions. During checkout completion a payment is created, processed and linked to the checkout. ### Diagram - When a Checkout is created its status is set to `created`. - If a payment attempt fails, it transitions to the status `attempted` and remains there until it either expires or a payment is successful. - If a payment succeeds, it transitions to the status `completed`. - If not completed within 1 week, it automatically transitions to the status `expired`. - A checkout can have multiple failed payment attempts and/or 1 succeeded payment attempt - see [Checkout Completion Attribute](https://docs.justifi.tech/checkouts/lifecycle#checkout-completion-attribute). ![Checkout Statuses](https://docs.justifi.tech/assets/images/checkout_statuses-bee6de263d7483f7b8d4eb4b6cfe50cc.png) The Checkout states and transitions. ### Datamodel - A checkout has its own attributes set at creation and can be updated if not completed or expired. - Use the [Get Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/GetCheckout) to check the current Checkout state, as in the following example: ```json { "id": "cho_xyz", "type": "checkout", "data": { "id": "cho_xyz", "account_id": "acc_xyz", "platform_account_id": "acc_xyz", "payment_amount": 10000, "payment_currency": "usd", "payment_description": "my_order_xyz", "payment_methods": [], "payment_method_group_id": "pmg_xyz", "status": "created", "mode": "test", "successful_payment_id": "py_xyz", "statement_descriptor": "Big Business", "payment_fees": [ { "type": "processing_fee", "amount": 295 }, { "type": "platform_fee", "amount": 150 } ], "payment_settings": {}, "created_at": "2024-01-01T12:00:00Z", "updated_at": "2024-01-01T12:00:00Z" }, "page_info": "string" } ``` > **Currency** > > The `payment_currency` field reflects the currency of the sub-account processing the checkout (e.g., `usd` or `cad`). Sub-accounts are scoped to a single currency. To process checkouts in CAD, you need a dedicated Canada platform account. > **Fee Structure** > > The `payment_fees` array contains fee objects specifying the fees to be applied when the checkout is completed. Each fee has a `type` (`processing_fee` or `platform_fee`) and an `amount` in cents. See [Fees documentation](https://docs.justifi.tech/checkouts/features#fees) for more details. ### Checkout Completion Attribute - Each attempt to complete a checkout with one of the available payment options is recorded in the `completions` attribute. - The Checkout completion attribute serves as a **history/log** of all completion attempts, including failed attempts and any successful payment. - **Important:** This history is never updated, even if a payment has been refunded. --- # Hosted Checkout Source: https://docs.justifi.tech/checkouts/hosted-checkout Hosted Checkout is the quickest and easiest way to use JustiFi checkouts without the need to build a user interface. Once a checkout is created via API, a link to that checkout can be shared and will take the user to a JustiFi hosted checkout solution. **Note:** JustiFi checkouts expire after 1 week. Please keep this in mind when generating and sharing links to hosted checkouts. ## Getting Started First, create a checkout following our [Create a Checkout API documentation](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout). Upon successful checkout creation, use the checkout ID from the response to create a hosted checkout link: `components.justifi.ai/hosted-checkout/:checkoutId` ## Custom Redirects By default JustiFi Hosted Checkout redirects to a generic `Checkout Complete` page after successful checkout or a `Checkout Session Expired` page if the checkout has expired. If the desired behavior is to redirect back to your application upon completion of the checkout, you can use the `success_redirect_url` parameter to override the default redirect: `components.justifi.ai/hosted-checkout/cho_abc123def456?success_redirect_url=https://yourapp.com/payment-success` --- # Configurable Fees Source: https://docs.justifi.tech/configurableFees/overview ## Overview Configurable Fees allow platforms to set fee rates for each sub account (merchant) via the [Fee Configurations API](https://docs.justifi.tech/configurableFees/managingConfigurations). When a payment is processed, the system automatically calculates the applicable fees based on the payment's characteristics — card brand, payment method type (ecomm, terminal, ACH), and the configured rates. Fee amounts do not need to be passed with every payment request. Each fee rate is stored as a **Standard Fee Configuration** resource. These configurations give platforms centralized control over their fee structure while keeping payment integration simple — configure once, and the fees for every payment for that sub account are handled automatically. > **V1 vs v2 Fee Structure** > > Configurable Fees are part of the **v2 fee structure**, which replaces the legacy Application Fee Rate model (v1). If your platform currently uses `application_fee_amount` or `application_fee_rate`, see [Migrating from Application Fees](#migrating-from-application-fees) for guidance on transitioning to v2. ## Limitations - **USD only.** Configurable Fees are not available for Canadian (CAD) processing. This feature is available for US platform accounts only. - **One active config per fee type per sub account.** Creating a new configuration for the same fee type automatically retires the previous one. - **Base processing configs cannot be retired.** Once a `processing_ecomm`, `processing_card_present`, `processing_ach`, or `processing_ach_expedited` config is created, it cannot have an `effective_end` — it must stay active indefinitely. The only way to change rates is to create a new config, which automatically retires the previous one. See [Chaining Configurations](https://docs.justifi.tech/configurableFees/managingConfigurations#chaining-configurations) for details. - **Brand-specific and platform configs can be retired** at any time by passing an `effective_end` parameter when [creating a new configuration](https://docs.justifi.tech/configurableFees/managingConfigurations#retiring-a-brand-specific-configuration). Payments for that brand will fall back to the base processing config. - **Fee configurations apply to a sub account**, not to the platform. Each sub account is configured individually. - **Cannot be mixed with legacy Application Fees.** Once on v2 fees, the `application_fee_amount` parameter is no longer accepted. ## How It Works 1. **Configure** fee rates for a sub account via the [Create Fee Configuration](https://docs.justifi.tech/configurableFees/managingConfigurations#creating-a-configuration) endpoint or through the JustiFi dashboard 2. **Process payments** as usual — no fee parameters needed in the payment or checkout request 3. **Fees are auto-calculated** based on the payment's characteristics and your configuration 4. **Optionally override** any auto-calculated fee by passing explicit fees in the payment or checkout request ## Fee Configuration Types There are three categories of Standard Fee Configurations. Together, they provide precise control over what is charged per payment. ### Base Processing Fees These define the default fee for each payment method type. You only need to configure the ones relevant to your sub account — for example, if a sub account only processes online card payments, you only need `processing_ecomm`. Once configured, these types cannot be retired (see [Limitations](#limitations)). | Fee Type | When Applied | | -------------------------- | --------------------------------------- | | `processing_ecomm` | Card-not-present (online) card payments | | `processing_card_present` | Card-present (terminal) card payments | | `processing_ach` | ACH (bank account) payments | | `processing_ach_expedited` | Expedited ACH (bank account) payments | ### Brand-Specific Fees These are **optional** and allow different rates for specific card brands. When a brand-specific configuration exists, it **replaces** the base processing fee for that brand — it does not stack on top of it. | Fee Type | When Applied | | ------------------------------- | ---------------------------- | | `visa_brand_ecomm` | Visa online payments | | `visa_brand_card_present` | Visa terminal payments | | `mastercard_brand_ecomm` | Mastercard online payments | | `mastercard_brand_card_present` | Mastercard terminal payments | | `amex_brand_ecomm` | Amex online payments | | `amex_brand_card_present` | Amex terminal payments | | `discover_brand_ecomm` | Discover online payments | | `discover_brand_card_present` | Discover terminal payments | ### Platform Fee This is **optional** and applies to all payments for the sub account, regardless of payment method or card brand. Use this to charge a separate platform service fee alongside the processing fee. | Fee Type | When Applied | | ---------- | ---------------------------- | | `platform` | All payments (if configured) | ## Hierarchical Fee Selection When a payment is processed, the system selects which configuration to use based on a simple hierarchy: 1. **Check for a brand-specific config** that matches the card brand and payment type 2. **If none exists, fall back** to the base processing config for that payment type 3. **Add platform fee** if a `platform` configuration exists > **Brand Configs Replace Base Processing Fees** > > A brand-specific configuration is the **complete** processing rate for that brand and payment type. If you configure `visa_brand_ecomm` at 2.50% + $0.20, that is the full processing fee for Visa online payments — the `processing_ecomm` rate is **not** applied on top of it. ### Example: How Selection Works Suppose a sub account is configured with: - `processing_ecomm`: 2.75% + $0.25 - `amex_brand_ecomm`: 3.25% + $0.25 - `platform`: 1.00% | Incoming Payment | Config Used | Why | | ---------------------- | ------------------ | ------------------------------------------------------------ | | $100 Visa online | `processing_ecomm` | No Visa-specific config exists, base config is applied | | $100 Amex online | `amex_brand_ecomm` | Amex-specific config exists, replaces base config | | $100 Mastercard online | `processing_ecomm` | No Mastercard-specific config exists, base config is applied | In all three cases, the `platform` fee is additionally applied because it is configured. See [Fee Calculation & Examples](https://docs.justifi.tech/configurableFees/examples) for detailed breakdowns with calculated amounts. ## Resulting Payment Fees Regardless of which configuration type is used, the resulting fees on a payment are always one or both of: - **`processing_fee`** — calculated from either a brand-specific or base processing configuration - **`platform_fee`** — calculated from the platform configuration (if it exists) The configuration type determines *how* the fee is calculated. The payment fee type is always `processing_fee` or `platform_fee`. ## Testing and Activation > **Getting Started** > > Configurable Fees are available in test mode for all platforms. To enable configurable fees for live payments, contact . - **Test mode**: Create standard fee configurations via the [create fee configuration API](https://docs.justifi.tech/configurableFees/managingConfigurations#creating-a-configuration) for a test sub account and process test payments with auto-calculated fees. Use this to validate your setup before going live. - **Live mode**: Requires enabling the v2 fee structure on your platform settings. Once enabled, fee configurations take effect for all payments on configured sub accounts. ## Fees in Payment Responses > **Where to Find Fee Data** > > When using Standard Fee Configurations (SFC), fees are calculated and applied by the payment system after the payment is created. This means: > > - **Create Payment and Complete Checkout synchronous responses** may return an empty `fees` array. > - **Checkout events** (`checkout.created`, `checkout.completed`, `checkout.completion.succeeded`) do **not** include SFC-calculated fees. Checkout events only contain fees that were explicitly passed in the checkout creation request. > - **Payment events** (`payment.created`, `payment.succeeded`, etc.) are the authoritative source for the finalized fee breakdown, including which configuration was used and the calculated amounts. > > **Subscribe to [payment events](https://docs.justifi.tech/api-spec#tag/Events/operation/paymentEvent)** (webhooks) or use the [Get Payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment) to retrieve the complete fee details. All payment events (`payment.created`, `payment.succeeded`, etc.) include the `fees` array with each fee's `id`, `type`, `amount`, `remaining_amount`, `currency`, `source_configuration_id`, and `source_fee_type`. ## Refunds and Fee Returns When refunding a payment, platforms can choose exactly which fees to return and how much of each. Fee refunds are **explicit, not automatic** — the fee type and amount to return are specified in the refund request. ```json { "amount": 5000, "fees": [ { "type": "processing_fee", "amount": 175 }, { "type": "platform_fee", "amount": 50 } ] } ``` Each fee on a payment tracks a `remaining_amount` that decreases as fees are returned through refunds. The returned amount cannot exceed the remaining amount on a fee. This provides full control over fee refund policy — return all fees, return only the platform fee, or return nothing. ## Migrating from Application Fees Configurable Fees (v2 fee structure) replace the legacy application fee rate model (v1). The table below summarizes the key differences: | | v1 (Application Fees) | v2 (Configurable Fees) | | ------------------------- | ------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------- | | **How fees are set** | `application_fee_rate` on the sub account, or `application_fee_amount` per payment request | Standard Fee Configurations per sub account, or explicit `fees` array per payment request | | **Fee granularity** | Separate rate by payment method type (card vs ACH) | Separate rates by payment type, card brand, and platform fee | | **Fee on payment record** | `application_fee` field | `fees` array with `processing_fee` and `platform_fee` | | **Refund control** | No fee refund to sub account | Selective — choose which fees to return and how much | ### Migration Steps 1. **Set up fee configurations in test mode.** Create Standard Fee Configurations for each sub account that mirror your current application fee rates. See [Managing Fee Configurations](https://docs.justifi.tech/configurableFees/managingConfigurations) for API details. 2. **Update your payment integration.** Remove any `application_fee_amount` parameters from your payment requests. If you use the `application_fee` field in payment responses and payment events, switch to reading from the `fees` array instead. 3. **Update refund handling.** If you currently rely on automatic proportional fee refunds, update your refund requests to use the explicit `fees` array. See [Refunds and Fee Returns](#refunds-and-fee-returns) above. 4. **Test end-to-end.** Process test payments and refunds to confirm fees are calculated correctly and your integration reads from the right response fields. 5. **Enable v2 for live payments.** Contact to enable the v2 fee structure on your platform. Once enabled, fee configurations take effect for all payments on configured sub accounts. > **Breaking Changes on v2** > > Once a platform is on the v2 fee structure: > > - The `application_fee_amount` parameter is **no longer accepted** on live payment requests — the payment will be rejected with an `application_fee_amount_not_allowed_for_v2_fee_structure` error > - For checkouts, using `application_fees` will cause the underlying payment to fail when it is processed, since the checkout submits `application_fee_amount` to the payments API. Use `payment.fees` on checkouts instead > - The `application_fee` field in payment responses will no longer be populated > - Use the `fees` array for both payments and checkouts instead > > Note: In **test mode**, `application_fee_amount` is still accepted on v2 accounts to support migration testing. This relaxation does not apply to live payments. ## Authentication Fee configuration endpoints require a **platform API key** with admin access. Platforms manage fee configurations for their sub accounts using their platform credentials. See [Authentication](https://docs.justifi.tech/apiFundamentals/authentication) for details on obtaining and using API keys. ## Next Steps - [Managing Fee Configurations](https://docs.justifi.tech/configurableFees/managingConfigurations) — API endpoints for creating, viewing, scheduling, and retiring configurations - [Fee Calculation & Examples](https://docs.justifi.tech/configurableFees/examples) — The fee formula, interactive calculator, and detailed scenario walkthroughs --- # Managing Fee Configurations Source: https://docs.justifi.tech/configurableFees/managingConfigurations ## Overview Standard Fee Configurations are managed through the [Fee Configurations API](#api-endpoints). All configuration management is done at the sub account level — each sub account's configurations are created and managed individually. The API is **fee-type-centric**: a configuration is created for a specific fee type (e.g., `processing_ecomm`), and if one already exists, the new one automatically retires the old one. There are no update or delete operations — to change a rate, you create a replacement configuration. Optional fee types (brand-specific and `platform`) can additionally be **retired** to stop charging them entirely, without a replacement. Base processing fees are required and cannot be retired. See [Retiring an Optional Configuration](#retiring-an-optional-configuration). ## API Endpoints | Method | Endpoint | Description | | ------ | ----------------------------------------------------------- | -------------------------------------------------------------------------- | | `POST` | `/v1/sub_accounts/:id/fee_configurations/:fee_type` | Create a configuration (auto-retires existing config of the same fee type) | | `GET` | `/v1/sub_accounts/:id/fee_configurations` | List all active configurations | | `GET` | `/v1/sub_accounts/:id/fee_configurations/:fee_type` | Get active configuration for a specific fee type | | `GET` | `/v1/sub_accounts/:id/fee_configurations/:fee_type/history` | Get configuration history for a fee type | | `GET` | `/v1/sub_accounts/:id/fee_configurations/scheduled` | List upcoming/scheduled configurations | ## Configuration Parameters | Parameter | Type | Required | Description | | ----------------------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `variable_rate` | number | Yes | Percentage rate. `2.75` = 2.75% | | `transaction_fee_cents` | integer | No | Flat fee in cents added to each transaction. Defaults to `0` | | `fee_cap_cents` | integer | No | Maximum fee amount in cents. If the calculated fee exceeds this amount, the cap is used instead | | `effective_start` | datetime | No | When the configuration takes effect. Defaults to immediately | | `effective_end` | datetime | No | When the configuration expires. Must be later than `effective_start` — the current time or earlier is rejected. Defaults to `null` — which means it stays active indefinitely. Only accepted on optional fee types (brand-specific and platform) | ## Creating a Configuration To set up fees for a sub account, use the [create a fee configuration API](#api-endpoints) for each fee type you want to configure. ### Set a base processing fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.75, "transaction_fee_cents": 25, "fee_cap_cents": 1000 } ``` **Response:** ```json { "id": "sfc_abc123", "type": "standard_fee_configuration", "data": { "id": "sfc_abc123", "account_id": "acc_xxx", "platform_account_id": "acc_yyy", "fee_type": "processing_ecomm", "variable_rate": 2.75, "transaction_fee_cents": 25, "transaction_fee_currency": "usd", "fee_cap_cents": 1000, "effective_start": "2026-02-25T00:00:00Z", "effective_end": null } } ``` This sub account will now be charged 2.75% + $0.25 (capped at $10.00) on every card-not-present payment, unless a brand-specific configuration overrides it. ### Add a brand-specific fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/amex_brand_ecomm ``` ```json { "variable_rate": 3.25, "transaction_fee_cents": 25 } ``` Amex online payments are now charged 3.25% + $0.25 instead of the base 2.75% + $0.25. All other card brands still use `processing_ecomm`. ### Add a platform fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/platform ``` ```json { "variable_rate": 1.00 } ``` Every payment now also includes a 1.00% platform fee, in addition to the processing fee. ## Replacing a Configuration There is no update fee configuration API endpoint. To change a fee rate, use the [create fee configuration API](#creating-a-configuration) to create a new configuration for the same fee type. The previous configuration is **automatically retired** — its `effective_end` is set to the new configuration's `effective_start`. ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.50, "transaction_fee_cents": 30 } ``` The old `processing_ecomm` configuration (2.75% + $0.25) is retired, and the new one (2.50% + $0.30) takes effect immediately. ## Scheduling a Future Configuration To schedule a rate change in advance, set `effective_start` to a future date (in UTC): ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.50, "transaction_fee_cents": 30, "effective_start": "2026-04-01T00:00:00Z" } ``` The current configuration stays active until April 1st, when the new one takes over automatically. The old config's `effective_end` is set to `2026-04-01T00:00:00Z`, and the new config picks up from there with no gap in coverage. Use the scheduled endpoint to view upcoming configurations: ```text GET /v1/sub_accounts/acc_xxx/fee_configurations/scheduled ``` ## Chaining Configurations For base processing fee types, there must always be an active configuration — you cannot leave a gap in coverage, and the chain must always end with a configuration that has no `effective_end` (i.e., it stays active indefinitely). You can schedule temporary configs in between, but the final config in the chain must cover everything going forward. When you POST a new config without `effective_end`, the system automatically retires any existing active config by setting its `effective_end` to the new config's `effective_start`. **Example: Simple rate change on April 1st** Current state: ```text processing_ecomm: 2.75% + $0.25 (effective_start: Feb 1, effective_end: null) ``` POST a new config: ```json { "variable_rate": 2.50, "transaction_fee_cents": 30, "effective_start": "2026-04-01T00:00:00Z" } ``` Result: ```text processing_ecomm: 2.75% + $0.25 (effective_start: Feb 1, effective_end: Apr 1) ← auto-retired processing_ecomm: 2.50% + $0.30 (effective_start: Apr 1, effective_end: null) ← takes over ``` **Example: Temporary promotional rate** To run a promotion from March 1st through March 8th with reduced fees, then return to normal rates, build the chain by creating configs in sequence — each new config auto-retires the previous one: **1. Schedule the promotional rate starting March 1st:** ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.00, "transaction_fee_cents": 15, "effective_start": "2026-03-01T00:00:00Z" } ``` This auto-retires the current config (2.75% + $0.25) by setting its `effective_end` to March 1st. The promotional rate takes over from March 1st with no `effective_end`. **2. Schedule the return to normal rates on March 8th:** ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.75, "transaction_fee_cents": 25, "effective_start": "2026-03-08T00:00:00Z" } ``` This auto-retires the promotional config by setting its `effective_end` to March 8th. The normal rate takes over from March 8th indefinitely. **Result:** ```text processing_ecomm: 2.75% + $0.25 (Feb 1 → Mar 1) ← original, auto-retired by step 1 processing_ecomm: 2.00% + $0.15 (Mar 1 → Mar 8) ← promotional, auto-retired by step 2 processing_ecomm: 2.75% + $0.25 (Mar 8 → forever) ← back to normal ``` The chain is seamless — every moment has exactly one active configuration, and the last one extends indefinitely. There is no need to set `effective_end` explicitly; the system handles it when the next config in the chain is created. > **Base Processing Configs Cannot Have an Effective End Date** > > The following base processing fee types do **not** accept an `effective_end` parameter: > > - `processing_ecomm` > - `processing_card_present` > - `processing_ach` > - `processing_ach_expedited` > > You only need to configure the types relevant to your sub account (e.g., only `processing_ecomm` if you only process online card payments). However, once created, these configurations must stay active indefinitely — they cannot be retired. If you include `effective_end` when creating one of these fee types, the API will reject the request with an `effective_end_must_be_nil_for_fee_type` error. The only way to transition to a new rate is to create a replacement config, which automatically retires the previous one by setting its `effective_end` to the new config's `effective_start`. ## Retiring an Optional Configuration Only **optional** fee types can be retired — turned off entirely, without a replacement: - **Brand-specific** fees (e.g., `amex_brand_ecomm`), which override the base processing rate for a single card brand. - **Platform** fees (`platform`), which add a fee on top of the processing fee. Base processing fees (`processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`) are **required** and cannot be retired — the API rejects `effective_end` on those types (see the warning above). To change one of those, create a replacement configuration instead. To retire an optional configuration, POST the same fee type with an `effective_end`. The configuration stops applying once that time passes. ### Retire a brand-specific fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/amex_brand_ecomm ``` ```json { "variable_rate": 3.25, "transaction_fee_cents": 25, "effective_end": "2026-04-01T00:00:00Z" } ``` After April 1st, Amex online payments fall back to the `processing_ecomm` rate. ### Retire a platform fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/platform ``` ```json { "variable_rate": 1.00, "effective_end": "2026-04-01T00:00:00Z" } ``` After April 1st, payments no longer include a platform fee. ### Retire a fee as soon as possible To turn an optional fee off right away, set `effective_end` to a timestamp just after the current time: ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/platform ``` ```json { "variable_rate": 1.00, "effective_end": "2026-02-25T00:01:00Z" } ``` Once that time passes — typically within a minute — the configuration no longer applies. `variable_rate` is still required, but the rate you pass only applies during the brief window before `effective_end`. > **Note** > > `effective_end` must be later than `effective_start`, which defaults to the time the request is processed. The current time or earlier is rejected, so use a near-future timestamp to retire a configuration as soon as possible. ## Viewing Configurations ### List all active configurations ```text GET /v1/sub_accounts/acc_xxx/fee_configurations ``` **Response:** ```json { "type": "array", "page_info": { "has_previous": false, "has_next": false, "start_cursor": "...", "end_cursor": "..." }, "data": [ { "id": "sfc_abc123", "account_id": "acc_xxx", "platform_account_id": "acc_yyy", "fee_type": "processing_ecomm", "variable_rate": 2.75, "transaction_fee_cents": 25, "transaction_fee_currency": "usd", "fee_cap_cents": null, "effective_start": "2026-02-01T00:00:00Z", "effective_end": null }, { "id": "sfc_def456", "account_id": "acc_xxx", "platform_account_id": "acc_yyy", "fee_type": "amex_brand_ecomm", "variable_rate": 3.25, "transaction_fee_cents": 25, "transaction_fee_currency": "usd", "fee_cap_cents": null, "effective_start": "2026-02-01T00:00:00Z", "effective_end": null } ] } ``` Results are paginated. Use `limit`, `after_cursor`, and `before_cursor` query parameters to page through results. ### Get a specific fee type ```text GET /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` **Response:** ```json { "id": "sfc_abc123", "type": "standard_fee_configuration", "data": { "id": "sfc_abc123", "account_id": "acc_xxx", "platform_account_id": "acc_yyy", "fee_type": "processing_ecomm", "variable_rate": 2.75, "transaction_fee_cents": 25, "transaction_fee_currency": "usd", "fee_cap_cents": null, "effective_start": "2026-02-01T00:00:00Z", "effective_end": null } } ``` Returns the active configuration for that fee type, or 404 if none exists. ### View configuration history ```text GET /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm/history ``` Returns all configurations for that fee type (active, retired, and scheduled), ordered by `effective_start` descending. Useful for auditing rate changes over time. ### List scheduled configurations ```text GET /v1/sub_accounts/acc_xxx/fee_configurations/scheduled ``` Returns configurations with a future `effective_start` that haven't taken effect yet. ## Next Steps - [Fee Calculation & Examples](https://docs.justifi.tech/configurableFees/examples) — See how configurations translate to actual fee amounts on payments - [Overview](https://docs.justifi.tech/configurableFees/overview) — Review the fee hierarchy and selection logic --- # Fee Calculation & Examples Source: https://docs.justifi.tech/configurableFees/examples ## The Fee Formula Every Standard Fee Configuration uses the same calculation: ```text fee = (payment_amount_cents x rate_as_decimal) + transaction_fee_cents ``` Where `rate_as_decimal` = `variable_rate / 100`. A `variable_rate` of `2.75` means 2.75%, so `rate_as_decimal` = `0.0275`. If `fee_cap_cents` is set: ```text fee = min(calculated_fee, fee_cap_cents) ``` ### Breaking it down | Parameter | What It Does | Example | | ----------------------- | ------------------------------- | -------------------------- | | `variable_rate` | Percentage rate. `2.75` = 2.75% | 10000 x 0.0275 = 275 cents | | `transaction_fee_cents` | Flat fee added per transaction | + 25 cents | | `fee_cap_cents` | Maximum fee (if set) | min(300, 1000) = 300 cents | **Example:** A $100.00 payment with a config of `variable_rate: 2.75`, `transaction_fee_cents: 25`: ```text fee = (10000 x 0.0275) + 25 fee = 275 + 25 fee = 300 cents = $3.00 ``` If `fee_cap_cents: 250` were set, the fee would be capped at $2.50 instead. When the variable rate calculation produces a fractional cent, the result is rounded to the nearest cent using standard rounding (half-up). For example, a $33.33 payment at 2.75% produces 91.6575 cents, which rounds to **92 cents**. ## Interactive Fee Calculator Use this calculator to configure fee rates and see exactly which configuration applies for each payment type. Toggle brand-specific configurations on and off to see the hierarchical selection in action. Base Processing Fees \[x]Online payments (processing\_ecomm)Rate:2.75%+ Flat:25centsCap:nonecents \[x]Terminal payments (processing\_card\_present)Rate:2.5%+ Flat:10centsCap:nonecents \[ ]ACH payments (processing\_ach)Rate:%+ Flat:centsCap:cents \[ ]Expedited ACH payments (processing\_ach\_expedited)Rate:%+ Flat:centsCap:cents Brand-Specific Fees (optional) \[ ]Visa online (visa\_brand\_ecomm)Rate:%+ Flat:centsCap:cents \[ ]Visa terminal (visa\_brand\_card\_present)Rate:%+ Flat:centsCap:cents \[ ]Mastercard online (mastercard\_brand\_ecomm)Rate:%+ Flat:centsCap:cents \[ ]Mastercard terminal (mastercard\_brand\_card\_present)Rate:%+ Flat:centsCap:cents \[x]Amex online (amex\_brand\_ecomm)Rate:3.25%+ Flat:25centsCap:nonecents \[ ]Amex terminal (amex\_brand\_card\_present)Rate:%+ Flat:centsCap:cents \[ ]Discover online (discover\_brand\_ecomm)Rate:%+ Flat:centsCap:cents \[ ]Discover terminal (discover\_brand\_card\_present)Rate:%+ Flat:centsCap:cents Platform Fee (optional) \[x]Platform fee (platform)Rate:1%+ Flat:0centsCap:nonecents --- Payment Simulation Payment amount:$100 | Payment Type | Config Used | Processing Fee | Platform Fee | Total Fee | | ------------------- | ----------------------------- | -------------- | ------------ | --------- | | Visa online | processing\_ecommbase | $3.00 | $1.00 | $4.00 | | Visa terminal | processing\_card\_presentbase | $2.60 | $1.00 | $3.60 | | Mastercard online | processing\_ecommbase | $3.00 | $1.00 | $4.00 | | Mastercard terminal | processing\_card\_presentbase | $2.60 | $1.00 | $3.60 | | Amex online | amex\_brand\_ecommbrand | $3.50 | $1.00 | $4.50 | | Amex terminal | processing\_card\_presentbase | $2.60 | $1.00 | $3.60 | | Discover online | processing\_ecommbase | $3.00 | $1.00 | $4.00 | | Discover terminal | processing\_card\_presentbase | $2.60 | $1.00 | $3.60 | > **What to Try** > > 1. Enable `amex_brand_ecomm` and notice how Amex online payments switch from the base `processing_ecomm` to the brand-specific config > 2. Disable it and watch Amex fall back to `processing_ecomm` > 3. Toggle the `platform` fee on and off to see it applied across all payment types > 4. Set a `fee_cap_cents` on a base processing config and increase the payment amount to see the cap in effect ## Walkthrough: Set Fee Configurations on a Sub Account This walkthrough covers a common setup from start to finish. ### Step 1: Configure base processing fees First, set up the rates that will apply to most payments: ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_ecomm ``` ```json { "variable_rate": 2.75, "transaction_fee_cents": 25 } ``` ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/processing_card_present ``` ```json { "variable_rate": 2.50, "transaction_fee_cents": 10 } ``` Now the sub account can process card-not-present payments at 2.75% + $0.25 and terminal payments at 2.50% + $0.10. ### Step 2: Add brand-specific pricing for Amex Amex interchange is typically higher, so platforms often pass that along: ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/amex_brand_ecomm ``` ```json { "variable_rate": 3.25, "transaction_fee_cents": 25 } ``` Amex online payments are now charged 3.25% + $0.25. All other brands still use the base 2.75% + $0.25. ### Step 3: Add a platform fee ```text POST /v1/sub_accounts/acc_xxx/fee_configurations/platform ``` ```json { "variable_rate": 1.00 } ``` Every payment now also includes a 1.00% platform fee. ### Step 4: Process a payment Create a payment without passing any fee parameters in the request and using an Amex payment method (for testing you can use the test card number `378282246310005` - see the [testing section](https://docs.justifi.tech/api-spec#section/Testing) for more test payment method options): ```text POST /v1/payments ``` ```json { "amount": 10000, "currency": "usd", "payment_method": { "token": "pm_xxx" } } ``` The system detects the card brand and applies the right configuration automatically. For a $100 Amex payment: - **Processing fee**: `amex_brand_ecomm` at 3.25% + $0.25 = $3.50 - **Platform fee**: `platform` at 1.00% = $1.00 - **Total fees**: $4.50 > **Fees Are Not in the Create Payment or Checkout Event Responses** > > The fee breakdown is not included in the create payment response or in checkout events (`checkout.created`, `checkout.completed`, `checkout.completion.succeeded`). SFC fees are calculated after the payment is created. Subscribe to **[payment events (webhooks)](https://docs.justifi.tech/api-spec#tag/Events/operation/paymentEvent)** (`payment.created`, `payment.succeeded`, etc.) or use the [get payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment) to receive the finalized fee details. All payment events (`payment.created`, `payment.updated`, etc.) include the fee breakdown: ```json { "id": "py_xxx", "amount": 10000, "fee_amount": 450, "fees": [ { "id": "pyfee_1", "type": "processing_fee", "amount": 350, "remaining_amount": 350, "currency": "usd", "source_configuration_id": "sfc_abc123", "source_fee_type": "amex_brand_ecomm" }, { "id": "pyfee_2", "type": "platform_fee", "amount": 100, "remaining_amount": 100, "currency": "usd", "source_configuration_id": "sfc_def456", "source_fee_type": "platform" } ] } ``` For the same $100 amount with a Visa card (for testing you can use the test card number `4242424242424242` - see the [testing section](https://docs.justifi.tech/api-spec#section/Testing) for more test payment method options): - **Processing fee**: `processing_ecomm` at 2.75% + $0.25 = $3.00 (no Visa-specific config, falls back to base) - **Platform fee**: `platform` at 1.00% = $1.00 - **Total fees**: $4.00 ## Overriding Auto-Calculated Fees Any auto-calculated fee can be overridden by passing explicit fees in the payment request. This is useful for one-off adjustments — for example, waiving the platform fee on a specific payment. Only the fee types you include in the `fees` array are overridden — everything else is calculated based on the fee configurations set on the sub account. Pass the `fees` array with the fee type and amount to override: ```text POST /v1/payments ``` ```json { "amount": 10000, "currency": "usd", "payment_method": { "token": "pm_xxx" }, "fees": [ { "type": "platform_fee", "amount": 0 } ] } ``` In this example, the processing fee is still auto-calculated from the configuration, but the platform fee is explicitly set to $0. The payment event reflects the override: ```json { "id": "py_xxx", "amount": 10000, "fee_amount": 350, "fees": [ { "id": "pyfee_1", "type": "processing_fee", "amount": 350, "remaining_amount": 350, "currency": "usd", "source_configuration_id": "sfc_abc123", "source_fee_type": "amex_brand_ecomm" }, { "id": "pyfee_2", "type": "platform_fee", "amount": 0, "remaining_amount": 0, "currency": "usd", "source_configuration_id": null, "source_fee_type": null } ] } ``` `source_configuration_id` and `source_fee_type` are `null` when the fee was explicitly passed in the payload. ## Scenario Reference ### Card-not-present (ecomm) payments | Card Brand | Brand Config Exists? | Config Used | Result | | ---------- | ---------------------------- | ------------------------ | ------------------ | | Visa | No `visa_brand_ecomm` | `processing_ecomm` | Base rate applied | | Visa | Yes `visa_brand_ecomm` | `visa_brand_ecomm` | Brand rate applied | | Mastercard | No `mastercard_brand_ecomm` | `processing_ecomm` | Base rate applied | | Mastercard | Yes `mastercard_brand_ecomm` | `mastercard_brand_ecomm` | Brand rate applied | | Amex | No `amex_brand_ecomm` | `processing_ecomm` | Base rate applied | | Amex | Yes `amex_brand_ecomm` | `amex_brand_ecomm` | Brand rate applied | | Discover | No `discover_brand_ecomm` | `processing_ecomm` | Base rate applied | | Discover | Yes `discover_brand_ecomm` | `discover_brand_ecomm` | Brand rate applied | ### Card-present (terminal) payments | Card Brand | Brand Config Exists? | Config Used | Result | | ---------- | ----------------------------------- | ------------------------------- | ------------------ | | Visa | No `visa_brand_card_present` | `processing_card_present` | Base rate applied | | Visa | Yes `visa_brand_card_present` | `visa_brand_card_present` | Brand rate applied | | Mastercard | No `mastercard_brand_card_present` | `processing_card_present` | Base rate applied | | Mastercard | Yes `mastercard_brand_card_present` | `mastercard_brand_card_present` | Brand rate applied | | Amex | No `amex_brand_card_present` | `processing_card_present` | Base rate applied | | Amex | Yes `amex_brand_card_present` | `amex_brand_card_present` | Brand rate applied | | Discover | No `discover_brand_card_present` | `processing_card_present` | Base rate applied | | Discover | Yes `discover_brand_card_present` | `discover_brand_card_present` | Brand rate applied | ### ACH payments ACH payments do not have brand-specific configurations. The base processing config is always used. | Payment Type | Config Used | | ------------- | -------------------------- | | Standard ACH | `processing_ach` | | Expedited ACH | `processing_ach_expedited` | ### Platform fee The `platform` configuration applies to **all** payment types when configured. It is added alongside the processing fee, not in place of it. ## Common Mistakes ### Thinking brand configs stack on top of base configs Brand-specific configurations **replace** the base processing config for that brand — they do not add to it. If `processing_ecomm` is 2.75% and `visa_brand_ecomm` is 0.50%, Visa payments are charged 0.50%, not 3.25%. ### Setting brand configs without a base config Brand-specific configs only apply to their specific brand. Every other card brand still needs a base processing config. The API enforces this — if you try to create a brand-specific config (e.g., `amex_brand_ecomm`) without an active base processing config for that payment type (e.g., `processing_ecomm`), the request will fail with a `fee_type_must_be_inside_hierarchy` error. Always set up your base configs (`processing_ecomm`, `processing_card_present`) first. ### Forgetting that fee caps apply per-config If `processing_ecomm` has `fee_cap_cents: 500` and `amex_brand_ecomm` has no cap, the $5.00 cap only applies to non-Amex payments. Each configuration's cap is independent. ## Next Steps - [Managing Fee Configurations](https://docs.justifi.tech/configurableFees/managingConfigurations) — API endpoints for creating and retiring configurations - [Overview](https://docs.justifi.tech/configurableFees/overview) — Review the fee hierarchy and activation requirements --- # Payments Overview in JustiFi API Source: https://docs.justifi.tech/payments/overview ## Overview Welcome to the JustiFi Payments section, where we provide a comprehensive suite of tools and resources to facilitate seamless payment processing. Our API supports a wide range of payment methods and offers advanced features like tokenization and compliance adherence, ensuring a secure and efficient transaction experience. ## Key Features of JustiFi Payments - **Diverse Payment Methods:** Payment Processing through various channels, including ACH and card payments. - **Payment Method Tokenization:** Understand how JustiFi secures payment information using tokenization to enhance data security. - **Robust Payment API:** Explore our Payment API's capabilities, designed to offer flexibility and ease of integration. - **End-to-End Integration:** Discover how to integrate JustiFi's Web Components, including Card Form, Payments Form, and ACH Form, into your platforms. - **Comprehensive Compliance:** Stay informed about PCI Compliance and NACHA Operating Rules, ensuring that your payment processes adhere to industry standards. ## Currency Support JustiFi supports processing payments in USD and CAD. Each sub-account is scoped to a single currency, meaning a sub-account processes payments in only one currency type. - **USD Processing**: Available on US platform accounts - **CAD Processing**: Requires a dedicated Canada platform account. CAD processing differs from USD in fee handling, payout timing, and supported payment methods. See the [Canadian Payments guide](https://docs.justifi.tech/payments/canadianPayments) for details. > **Note** > > ACH payments are available for USD processing only. For CAD payment processing, card-based payment methods are supported. ## Getting Started - **Integration Guides:** Follow our step-by-step guides for integrating various payment methods and JustiFi’s Web Components into your applications. - **Utilizing APIs:** Learn how to use JustiFi's [Payment APIs](https://docs.justifi.tech/payments/paymentsApi) to their fullest potential, from creating payments to handling responses. - **Compliance Practices:** Understand the compliance requirements and best practices to ensure secure and compliant payment processing. Join us in transforming the way businesses handle payments. With JustiFi, you're not just processing transactions; you're creating a seamless, secure, and efficient payment experience for your customers. --- # Understanding PCI-DSS Compliance with JustiFi API Source: https://docs.justifi.tech/payments/compliance ## Disclaimer This document offers guidance on PCI-DSS compliance in the context of using JustiFi's API and web components. It is intended for informational purposes and not as legal advice. Consult with your legal or compliance team for specific advice with your business in mind. ## Overview of PCI-DSS The Payment Card Industry Data Security Standard (PCI-DSS) is a set of security standards designed to ensure that all companies that accept, process, store, or transmit credit card information maintain a secure environment. This compliance is crucial for protecting cardholder data and maintaining customer trust. ## Levels of PCI Compliance There are four levels of PCI compliance, primarily determined by the volume of transactions processed annually. Each level has specific assessment and reporting requirements, with Level 1 being the most stringent. | Level | Thresholds | Requirements | | ----- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | 1 | Merchants processing greater than 6 million card transactions per year | External audit performed by a Qualified Security Assessor (QSA) | | 2 | Merchants processing 1 to 6 million transactions per year | Must submit a Report of Compliance (ROC) completed by and internal evaluation | | 3 | Merchants handling 20,000 to 1 million transactions per year | Not required to perform a ROC, but often do to promote their compliance adherence | | 4 | Merchants handling fewer than 20,000 transactions per year | Not required to provide audits | ## JustiFi's PCI Compliance JustiFi maintains strict compliance with PCI-DSS Level 1 standards. Our infrastructure and services are designed to secure sensitive payment data, leveraging advanced technologies like tokenization, encrypted transmission, and encrypted storage to ensure the highest level of security. ## Specifics of Data Handling JustiFi ensures secure data handling by: - **Tokenization:** Replacing sensitive card details with unique tokens. - **Secure Transmission:** Utilizing encrypted channels for data transfer. - **Annual PCI-DSS Level 1 Audit:** Attestation of Compliance is available for customers to review upon request. - **Quarterly AVS Scans:** Completed by independent and respected auditors. - **Regular Penetration Testing:** Performed by established experts in the field. ## JustiFi's Role in Your Compliance JustiFi aids in supporting your PCI-DSS compliance when you use our Card Form and Payment Form Web Components. These tools use iFrames hosted on JustiFi's infrastructure, ensuring that sensitive card data never passes directly through your application. This approach is widely recognized as a method to potentially avoid entering PCI-DSS scope. ## Your Responsibilities If you choose to collect card data directly and pass it to JustiFi using our Payment API or by creating Card Payment Methods, the card data will be traversing your system. In such cases, JustiFi will require you to provide an annual PCI-DSS Attestation of Compliance to ensure adherence to security standards. ## `full_pan_not_allowed` Error If you attempt to pass a full card number (PAN) directly to the Create Payment or Create Payment Method endpoints without prior PCI approval, the API will return a `400` error: ```json { "error": { "code": "full_pan_not_allowed", "message": "Full card numbers are not accepted on this endpoint. Please use the tokenization iframe to create a payment method token first." } } ``` This restriction exists to protect platforms that have not completed PCI compliance from inadvertently handling raw card data. **To resolve this error**, use the [JustiFi Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) to collect card details securely and obtain a payment method token (`pm_...`), then pass that token to the API. If you are PCI compliant and need to submit full card numbers directly, contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to provide proof of PCI compliance and have this restriction removed for your account. ## Customer’s Compliance Journey To embark on your PCI compliance journey: 1. **Assessment:** Determine your current compliance level. 2. **Implementation:** Apply necessary security measures and practices. 3. **Documentation:** Keep detailed records of compliance efforts. ## Case Scenarios - **Scenario 1:** Using JustiFi's Payment Form for direct card processing and its impact on compliance scope. - **Scenario 2:** Direct API integration for payment processing and its implications on PCI-DSS requirements. ## Resources and Further Reading - [PCI Security Standards Council](https://www.pcisecuritystandards.org) - [PCI Compliance Guide](#) ## Contact Information for Support For more personalized guidance on PCI-DSS compliance when using JustiFi’s services, please contact our support team at . --- # Payment Method Tokenization Source: https://docs.justifi.tech/payments/tokenization ## Overview Tokenization in payment processing is a crucial security measure. JustiFi's API leverages tokenization to protect sensitive payment information such as credit card numbers and bank account details, replacing them with unique identification symbols, or tokens. ## What is Tokenization? Tokenization involves substituting sensitive data with non-sensitive equivalents, known as tokens. These tokens, while not holding any intrinsic value, act as references to the original data securely stored in a token vault. ### Benefits of Tokenization - **Enhanced Security:** Minimizes the risk of data breaches by keeping sensitive information concealed. - **PCI Compliance:** Aids in fulfilling [Payment Card Industry Data Security Standards](https://www.pcisecuritystandards.org) requirements. - **Reduced Liability:** Decreases the volume of sensitive data that your system needs to handle. ## Implementing Tokenization ### Creating Tokens - **API Call:** Instructions on executing an API call to generate a token representing a user’s payment method. - **Data Handling:** Explanation of how tokens are returned in response to successful API calls and can be utilized in future transactions. ### Using Tokens in Transactions - **Processing Payments:** Guidelines on employing tokens to securely process payments. - **Token Management:** Best practices for the storage, retrieval, and management of tokens. ## Example Implementation To provide a practical understanding, here's an example implementation of tokenization in the JustiFi API: #### Card Tokenization Sample ```bash curl -i -X POST \ https://api.justifi.ai/v1/payment_methods \ -H 'Authorization: ' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Sub-Account: ' \ -d '{ "payment_method": { "card": { "name": "Lindsay Whalen", "number": 4242424242421111, "verification": 123, "month": 5, "year": 2042, "address_postal_code": 55555, "metadata": { "new": "info" } } } }' ``` #### Bank Tokenization Sample ```bash curl -i -X POST \ https://api.justifi.ai/v1/payment_methods \ -H 'Authorization: ' \ -H 'Content-Type: application/json' \ -H 'Idempotency-Key: 497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Sub-Account: ' \ -d '{ "payment_method": { "bank_account": { "account_owner_name": "Lindsay Whalen", "routing_number": "110000000", "account_number": "000123456789", "account_type": "checking", "account_owner_type": "individual", "country": "US", "currency": "usd", "metadata": { "new": "info" } } } }' ``` > **Currency** > > When tokenizing bank accounts, the `currency` field must match the currency of the sub-account (e.g., `usd` or `cad`). Sub-accounts are scoped to a single currency. To process payments in CAD, you need a dedicated Canada platform account. Utilize JustiFi's tokenization feature in your payment processes to bolster security and ensure compliance with prevailing industry standards. --- # Payments API Source: https://docs.justifi.tech/payments/paymentsApi ## Overview The JustiFi Payments API is a robust and versatile tool designed to streamline your payment processing. This API facilitates various types of transactions, offering flexibility, security, and ease of integration. ## Capabilities of the Payments API ### Transaction Processing - **Direct Payments:** Process immediate transactions using various payment methods. - **Payment Authorization:** Authorize payments and capture them at a later time, providing flexibility in transaction handling. ### Payment Management - **Refunds and Cancellations:** Manage transaction reversals efficiently. - **Transaction History:** Retrieve historical transaction data for record-keeping and analysis. ## Creating Payments Payment methods must be tokenized before creating a payment. Use the **[JustiFi Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method)** to securely collect and tokenize card or bank account details. The web component returns a payment method token that you can pass to the Create Payment endpoint. ```text POST /v1/payments { "amount": 1000, "currency": "usd", "capture_strategy": "automatic", "payment_method": { "token": "pm_justifi123" } } ``` > **Note:** Passing raw card or bank account details directly to the Payments API requires prior approval. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) if you have a use case that requires direct PAN submission. At minimum, a completed SAQ (Self-Assessment Questionnaire) is required to allow raw PAN submissions. ## Integrating the Payments API ### Getting Started - **API Keys:** Learn how to obtain and use your API keys for secure interactions with the API. - **Endpoint Details:** Overview of the primary endpoints for transaction processing, refunds, and more. ### Making API Calls - **Request Format:** Guidelines on structuring API requests, including required and optional parameters. - **Response Handling:** Understanding the API's response structure and how to interpret different response codes. ## Best Practices ### Compliance Adherence - **Reduced PCI Scope:** By using [JustiFi's Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) to tokenize payment method details, your application avoids directly handling PCI-scoped data like card numbers and bank account numbers. This significantly reduces your PCI compliance burden. > **Important:** If you have prior approval to pass raw payment method details directly to the API, be aware that this places your application within the scope of PCI compliance. At minimum, a completed SAQ (Self-Assessment Questionnaire) is required. By following these best practices, you can effectively use the JustiFi Payments API, ensuring secure, efficient, and compliant financial transactions. --- # Apple Pay Source: https://docs.justifi.tech/payments/applePay Apple Pay is available via the following JustiFi checkout options: - [Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout) - [Unified Fintech Checkout web component](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) - [Modular Checkout web component](https://docs.justifi.tech/web-components/modular-checkout/introduction) Apple Pay is not available in the [Tokenize Payment Method web component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) or via API. ## Prerequisites - Use any **compatible** device, a comprehensive list can be found [here](https://support.apple.com/en-us/102896) - Your application must be served over **HTTPS**. - Ability to host a file under `/.well-known/` in the domain(s) the checkout will be hosted. - Use one of the JustiFi Checkout options ([Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout), [Unified Fintech Checkout](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) or [Modular Checkout](https://docs.justifi.tech/web-components/modular-checkout/introduction) web component) ## Enabling Apple Pay for your account To process Apple Pay payments via JustiFi's checkout your platform needs to be registered with Apple. The following steps describe the registration process. ### Host Apple Merchant Validation Apple requires that each domain you will use to process Apple Pay payments from hosts a specific file (linked below) under the path `/.well-known/apple-developer-merchantid-domain-association`.\ Ensure you have access to host the file under all provided domains.\ **Note:** The FQDN (Fully Qualified Domain Name) is required, wildcard domains are not supported. [Apple Pay merchant validation file](https://components.justifi.ai/.well-known/apple-developer-merchantid-domain-association) ### Provide Platform Domain Names Once you have added the Apple Pay merchant validation file on your platform provide your domain(s) to JustiFi for registration. ### Merchant Registration JustiFi will initiate the registration with Apple for the provided domains.\ After Apple validates the files and confirms the registration JustiFi will enable your platform for Apple Pay.\ If Apple is not able to reach and validate the files the registration will fail. ### Adding new domains If you add the Apple Pay payment options to new domains on your platform at a later point you will need to register these new domains with Apple folling the steps described above. Already registered domains are not impacted by this change. ### Processing Apple Pay Payments Once your platform is successfully registered with Apple you are ready to process Apple Pay payments. If you use Hosted Checkout or the Unified Fintech Checkout web component the Apple Pay button will automatically appear in the checkout form.\ To add Apple Pay to the Modular Checkout web component include the **Apple Pay** sub component in the Modular Checkout as the example below shows. For more details refer to the [Modular Checkout docs](https://docs.justifi.tech/web-components/modular-checkout/introduction) ```html ``` JustiFi will create a payment method record (ID starting with `pm_`) for each transaction processed via Apple Pay. ## Testing your Apple Pay Integration When you use Apple Pay in JustiFi's test environment the Apple Pay checkout process will simulate a live Apple Pay payment with a live Apple Pay payment method. Instead of charging the live payment method used for the test transaction JustiFi will replace it with a test payment method (account number `4111***1111`) and simulate the payment transaction.\ JustiFi will **NOT** charge or save the real credit card for these test transactions. ### Provision Test account To set up your Apple Pay test environment follow these steps: 1. Host the [Apple Pay merchant validation file](https://components.justifi.ai/.well-known/apple-developer-merchantid-domain-association) on your test domain(s) 2. Provide the test domain(s) to JustiFi 3. Provide a JustiFi test account ID you want to use to test Apple Pay **Note:** The test domain needs to be publicly available so Apple Pay can verify the validation file ### Checkout via Apple Pay The easiest and fastest way to see Apple Pay in action is via the JustiFi dashboard: - On desktop use the **Safari** browser to log in to the JustiFi dashboard () - Go to the **"Developers"** section and enable "Test Mode" - From the **"Payments"** section select **"Checkouts"** - Create a checkout via the **"Create Checkout"** button and provide the account ID of the Apple Pay enabled sub account - Open the newly created checkout and click on the **"Hosted Checkout URL"**. This will open the JustiFi **Hosted Checkout** form with the **Apple Pay** button visible - Using Apple Pay will prompt the use of a real Apple Pay wallet on an iPhone - Accepting the payment will simulate a successful payment but will not charge the real Apple Pay card. To provide Apple Pay on your platorm via embedded JustiFi Checkout web components follow this integration guide:\ [Checkout via web component](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) ## See Also - [Google Pay™](https://docs.justifi.tech/payments/googlePay) - Learn about Google Pay™ integration with JustiFi --- # Google Pay™ Source: https://docs.justifi.tech/payments/googlePay Google Pay™ lets users pay with their cards stored in their Google account, providing a fast and secure checkout experience. When offering Google Pay™ as a payment method, you must use the official Google Pay™ logo and button assets in compliance with [Google Pay Web Brand Guidelines](https://developers.google.com/pay/api/web/guides/brand-guidelines), without modifications to the Google Pay™ asset colors, proportions, or appearance. Google Pay™ is available via the following JustiFi checkout options: - [Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout) - [Unified Fintech Checkout web component](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) - [Modular Checkout web component](https://docs.justifi.tech/web-components/modular-checkout/introduction) Google Pay™ is not available in the [Tokenize Payment Method web component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) or via API. ## Prerequisites - Any device **compatible** with Google Pay™, take a look [here](https://developers.google.com/pay/issuers/overview/supported-devices) for a comprehensive list. - Your application must be served over **HTTPS**. - Use one of the JustiFi Checkout options ([Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout), [Unified Fintech Checkout](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) or [Modular Checkout](https://docs.justifi.tech/web-components/modular-checkout/introduction) web component) - If embedding your checkout in a native Android app via `WebView`, see [Android WebView Integration](#android-webview-integration) for additional host-app requirements. ## Implementation Resources For detailed implementation guidance, refer to the following Google Pay documentation: - [Google Pay Web Developer Documentation](https://developers.google.com/pay/api/web/overview) - [Google Pay Web Integration Checklist](https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist) - [Google Pay Web Brand Guidelines](https://developers.google.com/pay/api/web/guides/brand-guidelines) ## Processing Google Pay™ Payments You must complete the following essential steps to enable Google Pay™ functionality: **Adhere to Google policies:** When using Google Pay™ with JustiFi checkout components, merchants must adhere to the [Google Pay and Wallet API's Acceptable Use Policy](https://payments.developers.google.com/terms/aup) and accept the terms defined in the [Google Pay API Terms of Service](https://payments.developers.google.com/terms/sellertos). **Content Security Policy (CSP) settings:** If your application uses Content Security Policy, you may need to update your CSP settings to allow the Google Pay™ SDK to function properly. Ensure your CSP allows connections to Google Pay™ domains and scripts. **Enable Google Pay™ in your account:** Ensure that Google Pay™ is enabled in your JustiFi merchant account dashboard. Contact your account representative if you need assistance enabling this feature. ### Hosted Checkout and Unified Fintech Checkout Once Google Pay™ is enabled in your JustiFi merchant account dashboard, the Google Pay™ button will automatically appear as a payment option in your Hosted Checkout and Unified Fintech Checkout forms. No additional code is required. For more information on setting up hosted checkout, see our [Hosted Checkout documentation](https://docs.justifi.tech/checkouts/hosted-checkout). ### Modular Checkout To add Google Pay™ to the Modular Checkout web component, include the **Google Pay** sub component in the Modular Checkout as the example below shows. For more details refer to the [Modular Checkout docs](https://docs.justifi.tech/web-components/modular-checkout/introduction). ```html ``` JustiFi will create a payment method record (ID starting with `pm_`) for each transaction processed via Google Pay™. ## Android WebView Integration If you are embedding your checkout page inside a native Android application via `WebView`, additional host-app configuration is required. The Payment Request API — which Google Pay™ uses on Android — is disabled by default in `WebView` and must be enabled by the host app. This is **not** required for users accessing your checkout via Android Chrome or other mobile browsers. ### End-user device requirements For Google Pay™ to work in an Android `WebView`, the user's device must have: - **Android System WebView** 137 or newer - **Google Play Services** 25.18.30 or newer ### Manifest configuration Add the following `` entries to your `AndroidManifest.xml` so the `WebView` can resolve the Google Pay payment intents: ```xml ``` ### Enable Payment Request on the WebView Using the [`androidx.webkit`](https://developer.android.com/jetpack/androidx/releases/webkit) compatibility library, opt the `WebView` in to the Payment Request API: ```kotlin import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewFeature webView.settings.javaScriptEnabled = true if (WebViewFeature.isFeatureSupported(WebViewFeature.PAYMENT_REQUEST)) { WebSettingsCompat.setPaymentRequestEnabled(webView.settings, true) } ``` ### Debugging To inspect console errors from inside the JustiFi iframe in your `WebView`, enable remote debugging in your host app: ```kotlin WebView.setWebContentsDebuggingEnabled(true) ``` You can then connect from desktop Chrome via `chrome://inspect` and read the actual error messages emitted from inside the Google Pay iframe. ### Verification order If Google Pay™ is not appearing in your Android `WebView`, verify the integration in this order: 1. **Test in desktop Chrome** at the merchant page URL. If Google Pay™ does not appear or fails here, the issue is in your web integration, not `WebView` configuration. 2. **Test in mobile Chrome** (not the `WebView`). If it works in mobile Chrome but fails in your app, the host-app configuration above is the cause. 3. Use `chrome://inspect` to read the console error from inside the `WebView`. ### References - [Google Pay WebView guide](https://developers.google.com/pay/api/android/guides/recipes/using-android-webview) - [Chrome team's Payment Request in WebViews](https://developer.chrome.com/docs/android/payments-in-webviews) - [Permissions Policy `payment` directive](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy/payment) ## Implementation Details ### Gateway Configuration As a supported payment service provider with the Google Pay™ API, our integration lets you as a merchant use Google Pay™ API's gateway integration type, where we handle all of the decryption on your behalf. When using JustiFi checkout components with Google Pay™, the following values are automatically set in the `TokenizationSpecification` object. **No merchant configuration or code is required** — the checkout component handles this entirely: - **gateway:** Set to `justifi` automatically. - **gatewayMerchantId:** Set using `{sub_account_id}` which is the sub account the checkout is configured to process payments for. Here is an example of what the checkout component passes when initializing the Google Pay™ button: ```json { "tokenizationSpecification": { "type": "PAYMENT_GATEWAY", "parameters": { "gateway": "justifi", "gatewayMerchantId": "acc_m9IjrorZoehPX9BA7kIrn" } } } ``` ### Authorization Methods Google Pay™ provides two different authorization methods: `PAN_ONLY` and `CRYPTOGRAM_3DS`. Our Google Pay™ integration supports both types of card credentials: - **PAN\_ONLY:** Physical card details stored in Google Pay™. - Supported countries: United States - These are cards manually added to a user's Google account - Standard fraud detection and authorization checks apply to all PAN\_ONLY transactions - **CRYPTOGRAM\_3DS:** Tokenized virtual card stored on device. - Authentication is performed by Google Pay™ - Supported countries: United States - These are cards tokenized to Android devices with cryptographic verification - Provides an additional layer of security through device-level authentication **Authentication note:** JustiFi does not currently support standalone 3D Secure (3DS) authentication for PAN\_ONLY credentials. However, CRYPTOGRAM\_3DS transactions include built-in authentication performed by Google Pay™ at the device level. For merchants who require enhanced authentication, we recommend encouraging customers to use device-tokenized cards (CRYPTOGRAM\_3DS) when available, as these provide stronger security guarantees through Google Pay™'s native authentication. ### Supported Card Networks We support the following card networks with the Google Pay™ API. These values are all passed to the `allowedCardNetworks` property automatically and find the appropriate values in [Google Pay's web developer documentation](https://developers.google.com/pay/api/web/guides/test-and-deploy/integration-checklist): - VISA - Mastercard - American Express - Discover ### Billing Address Requirements A billing address is not required for Google Pay™ payments processed through JustiFi checkout components. ## Handling Google Pay™ Payment Data When a customer pays with Google Pay™ through a JustiFi checkout component, the entire payment data lifecycle is handled automatically. The checkout component: 1. Receives the encrypted payment data from Google Pay™ 2. Extracts the token from the `paymentMethodData.tokenizationData.token` property 3. Sends the token securely to the JustiFi backend 4. Tokenizes the payment data into a JustiFi payment method 5. Completes the checkout **No merchant action is required** to process or handle the Google Pay™ payment data. The checkout component manages the complete flow from customer authorization through checkout completion. For more information on completing checkouts, see our [Checkout API documentation](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CompleteCheckout). ## See Also - [Apple Pay](https://docs.justifi.tech/payments/applePay) - Learn about Apple Pay integration with JustiFi --- # Buy Now Pay Later Source: https://docs.justifi.tech/payments/buyNowPayLater ## Overview Buy Now, Pay Later (BNPL) gives customers a flexible way to spread the cost of a purchase over time, typically through short-term installment plans, without the interest charges or lengthy approval processes associated with traditional credit. We partner with Sezzle, so customers can split payments (up to $2,000) into smaller, manageable installments at checkout, with no interest when payments are made on schedule. For your merchants, offering BNPL can increase conversion rates and average order value by lowering the upfront cost barrier for customers, while Sezzle assumes the payment collection and risk, so your merchants still receive full payment upfront. For customers, BNPL provides greater budget control, transparency (fixed payment schedules with no surprise fees when paid on time), and broader access to purchasing power without needing a traditional loan or credit card. ## Prerequisites and Integration - BNPL is only available on the Hosted Checkout and in our embedded checkout web components ([Unified Checkout](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2) and [Modular Checkout](https://docs.justifi.tech/web-components/modular-checkout)) - [see the integration guide](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component). - All these checkout options require the [creation of a checkout via API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) - To enable BNPL payments, contact to activate BNPL for your platform and sub accounts. - If you use Unified Checkout, BNPL will automatically appear as a payment options as soon as BNPL is enabled on the sub account. - If you use Modular Checkout, include the [sezzle Payment Method sub component](https://docs.justifi.tech/web-components/modular-checkout/sub-components/sezzle-payment-method). ## How it works? Once BNPL is enabled on a sub account and available to the web component the Buy Now Pay later option appears as a payment method in the checkout web component. If a customer selects BNPL as their payment method, they're redirected to Sezzle and asked to create an account. With their account in place, they select a payment plan for the purchase amount. Sezzle processes the payment and pays the merchant the full amount upfront. The customer then pays off the balance in installments, following their chosen payment plan. Sezzle handles all communication with the customer about that plan. --- # Insurance Quote Payments Source: https://docs.justifi.tech/payments/insurance ## Overview We partner with Vertical Insure to offer insurance for purchased goods or services at checkout. This offer provides customers with the option to protect their purchase right when its value is top of mind, no separate research or forms required. Coverage is quoted and enrolled in real time, with transparent pricing tied to the specific purchase. For your merchants, this reduces return and refund disputes, builds customer trust, and adds incremental revenue, all within the existing checkout flow. ## Prerequisites and Integration - Insurance quote payments are only available on the Hosted Checkout and in our embedded checkout web components ([Unified Checkout](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2) and [Modular Checkout](https://docs.justifi.tech/web-components/modular-checkout)) - [see the integration guide](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) for details. - All these checkout options require the [creation of a checkout via API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) - To include an insurance quote in a checkout, first contact to enable insurance payments for your platform. Ensure the required insurance type is available through our provider. - If you use Unified Checkout, insurance quote payments will appear as a payment options as soon as the feature is enabled on the sub account. - If you use Modular Checkout, include the specific insurance sub component listed in the [Sub Components section of the docs](https://docs.justifi.tech/web-components/modular-checkout/sub-components). ## How it works Once insurance is enabled for a sub account and available to the web component a tailored insurance quote appears when the checkout component is rendered. If the customer chooses to add the insurance option to their purchase and submits the checkout, an additional insurance payment will be processed on the selected payment method as part of checkout completion. Both payments will be associated with the same checkout record. --- # Bank Account Form Implementation Guide Source: https://docs.justifi.tech/payments/guides/achForm ## Overview Integrating the ACH Form into your application allows for efficient processing of ACH transactions. This guide will walk you through the steps to implement JustiFi's ACH Form, ensuring a seamless bank transfer experience for your users. ## Key Features of the ACH Form - **User-Friendly Interface:** Provides a straightforward form for users to enter their bank details. - **Secure Data Handling:** Ensures sensitive bank information is securely processed and tokenized. - **Customization Options:** Offers flexibility to tailor the form's appearance to match your application's design. ## Integration Steps ### Initial Setup - **API Configuration:** Ensure your JustiFi API setup is ready to handle ACH transactions. - **Form Embedding:** Instructions on embedding the ACH Form into your web application. ### Customizing the ACH Form - **Styling:** Tips on customizing the look and feel of the ACH Form to align with your UI design. - **Field Configuration:** Guide on configuring the input fields based on your requirements. ### Handling Form Submissions - **Capturing Data:** Steps to capture and handle user input from the ACH Form. - **Tokenization:** Implementing the process of tokenizing bank account information for secure transactions. ## Example Code - **Embedding the Form:** Sample code snippet demonstrating how to integrate the ACH Form into your site. - **Handling Submissions:** Example implementation for processing and tokenizing the data submitted via the form. ### Best Practices - **Validation and Error Handling:** Ensure robust validation of user inputs and handle errors gracefully. - **Security Compliance:** Adhere to security standards for processing ACH payments, maintaining the integrity of user data. - **User Experience Optimization:** Recommendations for providing clear instructions and feedback to users within the form. By incorporating JustiFi's ACH Form into your application, you can offer a secure and user-friendly method for customers to make bank transfers, enhancing the overall efficiency and experience of your payment system. ## Component example --- # Card Form Implementation Guide Source: https://docs.justifi.tech/payments/guides/cardForm ## Overview The Card Form is an essential component for processing credit and debit card transactions in JustiFi's API. This document provides a comprehensive guide to implementing the Card Form, ensuring smooth and secure card payments for your users. ## Key Features of the Card Form - **Streamlined User Interface:** Offers an easy-to-use interface for card information entry. - **Enhanced Security:** Incorporates advanced security features, including tokenization, to protect sensitive card data. - **Customization Flexibility:** Allows you to customize the form to fit the look and feel of your application. ## Implementation Steps ### Initial Setup - **API Configuration:** Ensure your JustiFi API is configured for card payments. - **Embedding the Form:** Step-by-step instructions on integrating the Card Form into your web application. ### Customizing the Card Form - **Styling Options:** Tips for customizing the form's appearance. - **Field Configurations:** How to modify the input fields according to your needs. ### Handling Form Submissions - **Data Processing:** Managing the input from the Card Form. - **Secure Tokenization:** Implementing tokenization for card data security. ## Example Code - **Form Integration:** Example code snippet for embedding the Card Form. - **Submission Handling:** Sample implementation for processing form data. ### Best Practices - **Input Validation:** Ensuring accurate data entry and error handling. - **Compliance with Security Standards:** Adhering to PCI DSS and other relevant regulations. - **Optimizing User Experience:** Providing clear instructions and feedback within the form. By integrating JustiFi's Card Form, you enable secure, efficient card transactions, enhancing the payment experience in your application. ## Component example --- # Payment Form Implementation Guide Source: https://docs.justifi.tech/payments/guides/paymentForm ## Overview The Payment Form in JustiFi's API is a versatile tool designed to consolidate the features of both ACH and Card Forms. This all-in-one solution not only processes card and bank transfer payments but also collects the cardholder's billing address, ensuring a comprehensive and secure payment experience. ## Key Features of the Payment Form - **Unified Payment Solution:** Integrates ACH and Card payment options in one form. - **Billing Address Collection:** Includes fields for collecting the cardholder’s billing address, crucial for verifying and securing transactions. - **Customizable Design:** Offers flexibility to tailor the form’s appearance to align with your application’s UI. ## Integrating the Payment Form ### Initial Setup - **API Configuration:** Ensure your JustiFi API setup is prepared to handle both card and ACH transactions. - **Form Integration:** Instructions on embedding the Payment Form into your web application. ### Customizing the Payment Form - **Styling and Layout:** Tips on customizing the look and feel of the Payment Form. - **Field Configurations:** Guide on adjusting input fields, including billing address details. ### Handling Form Submissions - **Data Capture:** Steps to collect and manage user input from the Payment Form. - **Secure Processing:** Implementing tokenization and security measures for handling sensitive payment information. ## Example Code - **Embedding the Form:** Sample code snippet demonstrating how to integrate the Payment Form. - **Processing Submissions:** Example implementation for securely handling the collected data. ### Best Practices - **Comprehensive Validation:** Ensure robust validation of all inputs, including billing address details. - **Enhanced Security Compliance:** Adhere to security standards like PCI DSS, especially when handling card information. - **Optimizing User Experience:** Recommendations for a user-friendly form, providing clear instructions and feedback. By implementing JustiFi's Payment Form, you can offer a streamlined, secure, and efficient method for handling various types of payments, elevating the transaction process in your application. ## Component example --- # Disputes Overview Source: https://docs.justifi.tech/disputes/overview Disputes (also known as chargebacks) occur when a cardholder questions a payment with their card issuer. The [JustiFi Dispute API](https://docs.justifi.tech/api-spec#tag/Disputes) provides comprehensive tools to manage the entire dispute lifecycle, from initial notification through resolution. ## Key Features - **Unified Management**: Handle disputes across all payment gateways through a single API - **Evidence System**: Upload supporting documents via secure S3 presigned URLs using a web component or API - **Real-time Tracking**: Monitor dispute progress with webhook notifications - **Comprehensive Response**: Submit detailed responses with 20+ evidence fields - **Automatic Reversals**: System handles card network dispute reversals - **Test Environment**: Full-featured sandbox for testing dispute workflows ## Getting Started 1. Create an event publisher on the [JustiFi dashboard](https://app.justifi.ai/admin) by navigating to the `Developers` section in the sidebar and select `Event Publishers`, then subscribe to dispute events 2. Set up webhook endpoints in your application to receive dispute notifications 3. Implement dispute response workflows in your application via [Dispute Management Web Component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management) or via [disputes API](https://docs.justifi.tech/api-spec#tag/Disputes) 4. Test the complete dispute lifecycle using the test environment as described below --- # Dispute Lifecycle Source: https://docs.justifi.tech/disputes/lifecycle ## Dispute Creation A dispute (also known as chargeback) is created when a cardholder contacts their card issuer to question a payment. The card issuer opens a chargeback and returns the questioned funds to the cardholder. JustiFi is notified of the chargeback, creates a dispute associated with the payment and pulls the payment funds (and a dispute fee) back from the merchant. As soon as JustiFi has created the dispute: 1. **Notification**: You receive a `payment.dispute.created` webhook event 2. **Timeline**: You have 7-10 business days to respond (varies by card network) ## Response Phase ### Building Your Response During the response phase, you can: - **Upload Evidence**: Add supporting documents via the create [dispute evidence API](https://docs.justifi.tech/api-spec#tag/Disputes/operation/GetDispute) or via [Dispute Management web component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management) - **Update Response Fields**: Fill in detailed information about the transaction ### Response Fields Provide comprehensive information across these categories: #### Customer Information - `customer_name` - Full customer name - `customer_email_address` - Customer email - `customer_billing_address` - Billing address - `customer_purchase_ip_address` - IP address at purchase time #### Transaction Details - `product_description` - Detailed product/service description - `service_date` - Date service was provided - `duplicate_charge_original_payment_id` - Reference for duplicate charges - `duplicate_charge_explanation` - Explanation for duplicate charges #### Shipping Information - `shipping_address` - Delivery address - `shipping_carrier` - Shipping company - `shipping_date` - Ship date - `shipping_tracking_number` - Tracking number #### Policy Information - `refund_policy_disclosure` - Refund policy terms - `cancellation_policy_disclosure` - Cancellation policy terms - `refund_refusal_explanation` - Why refund was refused - `cancellation_rebuttal` - Response to cancellation claims #### Additional Context - `additional_statement` - Free-form additional information ## Evidence Management ### Evidence Categories | Category | Best Used For | | -------------------------------- | -------------------------------- | | `receipt` | Purchase confirmations, invoices | | `shipping_documentation` | Delivery proof, tracking info | | `customer_communication` | Email exchanges, support tickets | | `customer_signature` | Signed delivery receipts | | `refund_policy` | Terms of service, policies | | `cancellation_policy` | Cancellation terms | | `service_documentation` | Proof of service delivery | | `duplicate_charge_documentation` | Duplicate charge evidence | | `activity_log` | System logs, usage data | | `uncategorized_file` | Other supporting documents | ### File Requirements - **Supported formats**: PDF, JPG, JPEG, PNG, ZIP - **Validation**: File extension must match MIME type ## Submission and Review ### Forfeiture Option If you choose not to contest the dispute either use the [submit dispute response API](https://docs.justifi.tech/api-spec#tag/Disputes/operation/SubmitDisputeResponse) with the following body: ```json { "forfeit": true } ``` Or instead forfeit the dispute via [Dispute Management web component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management). This immediately transitions the dispute to `lost` status. ## Resolution Phase ### Possible Outcomes #### Won (`won` status) - **Funds Returned**: Disputed amount returned to your merchant's account. - **Notification**: `payment.dispute.closed` webhook event #### Lost (`lost` status) - **Funds Retained**: No funds are moved. - **Notification**: `payment.dispute.closed` webhook event ### Dispute Reversals Card networks can reverse lost disputes: 1. **Reversal Trigger**: New evidence or network decision 2. **Dispute updated**: Status of dispute is updated to won 3. **Fund Return**: Previously lost funds are returned 4. **Notification**: `payment.dispute.closed` webhook event ## Status Transitions ```text needs_response → under_review → won/lost ↓ forfeited ``` ### Status Descriptions - **`needs_response`** - Initial status, response deadline active - **`under_review`** - Response submitted, card network is reviewing - **`won`** - Dispute resolved in merchant's favor - **`lost`** - Dispute resolved against the merchant ## Webhook Events Monitor these events for real-time updates: - **`payment.dispute.created`** - Lets you know anytime a customer opens a payment dispute - **`payment.dispute.closed`** - Lets you know anytime a payment dispute is closed - **`payment.dispute.funds_returned`** - Lets you know anytime a payment dispute won and funds are returned - **`payment.dispute_evidence.created`** - Lets you know anytime a dispute evidence is created - **`payment.dispute_evidence.uploaded`** - Lets you know anytime a dispute evidence is uploaded - **`payment.dispute.forfeited`** - Lets you know anytime a dispute response is forfeited - **`payment.dispute.submitted`** - Lets you know anytime a dispute response is submitted --- # Payment Methods Source: https://docs.justifi.tech/paymentMethods/overview JustiFi supports a variety of payment methods via API, Hosted Checkout and embedded web components to cater to diverse transactional needs. The following sections provides an overview of the three primary methods: - [Automated Clearing House (ACH) payments](https://docs.justifi.tech/paymentMethods/achPayments) - [Card Not Present (CNP) payments](https://docs.justifi.tech/paymentMethods/cardNotPresent) - [Card Present payments](https://docs.justifi.tech/paymentMethods/cardPresent) --- # ACH Payments Source: https://docs.justifi.tech/paymentMethods/achPayments ACH payments are electronic payments made through the ACH network. They are ideal for direct bank-to-bank transactions, such as direct deposits and bill payments. ## Key Features - **Cost-Effective:** Lower transaction fees compared to other methods. - **Security:** Enhanced safety measures for secure transactions. - **Convenience:** Suitable for recurring payments, consumers without access to cards, and other high value purchases. > **Note** > > ACH payments are available for USD processing only. For Canadian dollar (CAD) payment processing, card-based payment methods are supported through a dedicated Canada platform account. ## Returns An ACH payment can be returned by the customer's bank after it settles, which reverses the payment and charges the merchant a return fee. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns). --- # ACH Returns Source: https://docs.justifi.tech/paymentMethods/achReturns An ACH payment can reach `succeeded` and still be returned by the customer's bank days later, for example for insufficient funds or a closed account. When JustiFi receives the return it: 1. Sets the payment `status` to `failed` and `returned` to `true` 2. Debits the payment amount back from the merchant's balance 3. Returns the fees originally charged on the payment 4. Charges the merchant a flat ACH return fee ## Getting Notified A return arrives as a [`payment.failed`](https://docs.justifi.tech/api-spec#tag/Events/operation/paymentEvent) webhook event whose body is the payment object. There is no dedicated return event, and `payment.failed` also covers card declines and ACH payments rejected before they reach the bank. The payment's `error_description` carries the reason the bank gave for the return. See [ACH Errors](https://docs.justifi.tech/api-spec#section/ACH-Errors) for the values and what to do about each one. ## Reconciling the Payment Object A returned payment reports the reversal on itself: `returned` is `true`, `status` is `failed`, and `amount_returned` equals `amount`. Because the payment amount and its original fees are both reversed, `balance` settles at the negative of the ACH return fee, which is the only amount the merchant is left owing. The ACH return fee is not part of the `application_fee` or `fees` objects, which describe the fees charged when the payment was created. For payments using [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management), `fee_amount` also excludes it; for payments using an application fee, `fee_amount` includes it. ## Finding the Return Fee The fee is always recorded as a balance transaction, which is the reliable place to confirm it. Call [List Balance Transactions](https://docs.justifi.tech/api-spec#tag/Balance-Transactions/operation/ListBalanceTransactions) with `source_payment_id` set to the payment and look for `txn_type` `ach_return_fee_collected`. That filter is scoped to one sub account, so send the `Sub-Account` header with it. A return produces these transactions on the merchant's sub account: | `txn_type` | Meaning | | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | | `ach_return_collected` | Payment amount debited back from the merchant | | `ach_return_fee_collected` | ACH return fee debited from the merchant | | `processing_fee_return`, `platform_fee_return` | Fees from the original payment returned to the merchant, under Enhanced Fee Management | | `application_fee_refund` | Application fee from the original payment returned to the merchant, when the payment used an application fee | [Get Payment Balance Transactions](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPaymentBalanceTransactions) shows the same movements scoped to a single payment, where the fee appears as `payment_balance_txn_type` `ach_return_fee` with a `source_type` of `AchReturnFee`. > **Note** > > Not every returned payment is charged the fee. ACH payments that fail before reaching the bank are also marked `returned`; an `ach_return_fee_collected` balance transaction is what confirms the fee was assessed. ## Payment Methods Invalidated by a Return Some return reasons also mark the stored payment method `invalid` and set `invalid_reason` on it: closed, frozen, missing and non-transaction accounts, bad account or routing numbers, and revoked authorization. Reasons that say nothing about the account, such as insufficient funds, leave it valid. No webhook event is emitted for this change, so re-fetch the payment method with [Get Payment Method](https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/GetPaymentMethod) after a return and read `status` and `invalid_reason`. Reusing an invalid payment method will fail, so check it before retrying or before the customer's next scheduled charge. ## Returned Refunds and Payouts An ACH refund can be returned by the bank in the same way. The refund moves to `status` `failed`, the funds come back to the merchant as a `refund_reversal` balance transaction, and the payment records a `refund_failure` payment balance transaction. This arrives as a [`payment.refund.updated`](https://docs.justifi.tech/api-spec#tag/Events/operation/refundEvent) webhook event. An ACH payout can also be returned. The payout moves to `status` `failed`, the funds return to the merchant's balance as a `payout_failed` balance transaction, and a [`payout.failed`](https://docs.justifi.tech/api-spec#tag/Events/operation/payoutEvent) webhook event is sent. Neither is charged an ACH return fee. ## Testing Failed [ACH test scenarios](https://docs.justifi.tech/testing/ach_payments) run the full return flow, including the return fee and its balance transactions, so you can verify your reconciliation logic before going live. Test returns do not mark the payment method invalid. --- # Card Not Present (CNP) Transactions Source: https://docs.justifi.tech/paymentMethods/cardNotPresent CNP transactions occur when the cardholder is not physically present, typically used for online purchases. This method includes payments made via online forms (also called e-commerce transactions), telephone orders, mail orders, or recurring billing. ## Key Features - **Flexibility:** Facilitates a wide range of online transactions. - **Security:** Requires robust fraud prevention and verification mechanisms. - **Global Reach:** Ideal for e-commerce and international transactions. --- # Card Present (CP) Transactions Source: https://docs.justifi.tech/paymentMethods/cardPresent CP transactions involve the physical use of a credit or debit card at a point of sale. This method is typical in retail or in-person services. ## Key Features - **Immediate Processing:** Real-time transaction authorization. - **Security:** Utilizes EMV chip technology for enhanced security. - **Customer Experience:** Allows for seamless in-person payment experiences. ## JustiFi Card Present Solution View the [Terminals section](https://docs.justifi.tech/category/terminals) of our documentation to find out how you can offer CP payments to your user base --- # Providing Payment Method Options Source: https://docs.justifi.tech/paymentMethods/providingPaymentMethodOptions Payment methods must be tokenized using one of **[JustiFi's web components for payment facilitation](https://docs.justifi.tech/web-components/)** before they can be used for payments. These web components securely collect card or bank account details and return a payment method token. - **[Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method):** Use this embedded web component to securely collect and tokenize card and bank account details for later charge. \*\*[Modular Checkout](https://docs.justifi.tech/web-components/modular-checkout) and [Unified Fintech Checkout](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2) Web Component: Use either of these embedded web components to securely tokenize a payment method and charge it. It offers customization and a variety of payment method options. - **[Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout):** Offer a variety of payment method options to your users for processing a payment via JustiFi Hosted Checkout. It automatically handles tokenization. - **Reduced PCI Scope:** Because the web components handle sensitive payment data, your application never directly touches card numbers or bank account details, significantly reducing your PCI compliance burden. > **Note:** Creating payment methods directly via the API requires prior approval. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) if you have a use case that requires requires direct PAN (Primary Account Number) submission. At minimum, a completed SAQ (Self-Assessment Questionnaire) is required to allow raw PAN submissions. See our [API documentation](https://docs.justifi.tech/api-spec#tag/Payment-Methods) for details. By using JustiFi's web components, your business can cater to various customer preferences and transaction scenarios while maintaining security and efficiency. --- # Payment Method Groups (PMG) Source: https://docs.justifi.tech/paymentMethods/paymentMethodGroups Payment method groups offer a way to organize and filter payment methods of your users. It also allows you to display already save payment methods to a user in the checkout form when using [Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout) or one of the checkout web components ( [Unified Fintech Checkout](https://storybook.justifi.ai/?path=/docs/payment-facilitation-unified-fintech-checkout%E2%84%A2--docs) or [Modular Checkout](https://storybook.justifi.ai/?path=/docs/modular-checkout--docs)). Here is how to use it: 1. Create a payment method group 2. Associate existing payment methods to the payment method group 3. Using a payment method group in a checkout ## Creating PMGs To create a PMG refer to the [Create a Payment Method Group](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/CreatePaymentMethodGroup) specification. ## Associating existing payment methods to a PMG To associate existing payment methods to a PMG refer to the [Update a Payment Method Group](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/PatchPaymentMethodGroup) specification. ## Using a PMG in a checkout Create a checkout via [create checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) and pass the payment method group ID as `payment_method_group_id`. Once you load the Hosted Checkout form or the checkout web component for this checkout any payment methods associated with the PMG will be displayed to the user. --- # Bank Account Verification Source: https://docs.justifi.tech/paymentMethods/bankAccountVerification Bank account verification lets your customer link a bank account by signing in to it, instead of typing an account and routing number. The account details arrive already verified, which makes ACH payments more reliable and cuts down on returns caused by mistyped, closed or invalid accounts. JustiFi provides this through [Plaid](https://plaid.com/), so your customer sees Plaid's branded sign-in window while connecting their bank. Getting it working takes two things: provisioning the business for the bank account verification product, and having JustiFi enable the feature for the account. ## Prerequisites Before a business can be provisioned for bank account verification: - The business must already be provisioned for payments and linked to a sub account - The business legal address country must be the United States, the only country where bank account verification is available - The business must include the following information: - Business Legal Name - Business Website URL - Business Legal Address Add anything missing via the [update business API](https://docs.justifi.tech/api-spec#tag/Business/operation/UpdateBusiness). Bank account verification is available in the following JustiFi checkout options: - [Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout) - [Unified Fintech Checkout web component](https://storybook.justifi.ai/?path=/docs/payment-facilitation-unified-fintech-checkout%E2%84%A2--docs) - [Modular Checkout web component](https://storybook.justifi.ai/?path=/docs/modular-checkout--docs), when the Plaid Payment Method sub component is included It is not available in the [Tokenize Payment Method web component](https://storybook.justifi.ai/?path=/docs/payment-facilitation-tokenize-payment-method--docs) or when creating payment methods directly via the JustiFi API. ## Enabling Bank Account Verification > **Note** > > Bank account verification has to be switched on for your account by JustiFi. Once the business is provisioned, contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have the feature enabled. 1. Determine the business ID of the sub account you want to enable for bank account verification via the [get sub account API](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccount). The business ID is listed in the response. The sub account needs to be enabled for payment processing already. 2. Get the business via the [get business API](https://docs.justifi.tech/api-spec#tag/Business/operation/GetBusiness) and confirm it includes the information listed in [Prerequisites](#prerequisites). Add anything missing via the [update business API](https://docs.justifi.tech/api-spec#tag/Business/operation/UpdateBusiness) before provisioning, otherwise the provisioning request is rejected. 3. Provision the business via the [provisioning API](https://docs.justifi.tech/api-spec#tag/Provisioning), passing the business ID and `bank_account_verification` as the `product_category`. ```bash curl --request POST \ --url https://api.justifi.ai/v1/entities/provisioning \ --header 'authorization: Bearer {{access_token}}' \ --header 'content-type: application/json' \ --data '{ "business_id": "biz_123", "product_category": "bank_account_verification" }' ``` 4. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have bank account verification enabled for the account. Enablement is not immediate. Expect a few business days from the provisioning request until the feature is live on the account, because the business information is reviewed before bank account verification can be switched on. You can confirm the result at any time with [get sub account settings](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccountSettings): `bank_account_verification` reads `true` on the payment settings once the feature is live. ### Platform-Wide Enablement Bank account verification can also be enabled at the platform level, so that every sub account can use it without being provisioned individually. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to set this up, and have a business ready whose legal name matches the name of your platform account, since that business is what JustiFi associates with the platform. ## Using Bank Account Verification Once the feature is live, a bank account verification option appears alongside your other payment methods at checkout. Your customer selects it, signs in to their bank, and chooses the account to pay from. The verified account comes back to the checkout as a tokenized payment method, and the payment is processed as ACH. How the option shows up depends on the checkout you have integrated: - [Hosted Checkout](https://docs.justifi.tech/checkouts/hosted-checkout): appears automatically - [Unified Fintech Checkout](https://storybook.justifi.ai/?path=/docs/payment-facilitation-unified-fintech-checkout%E2%84%A2--docs) web component: appears automatically - [Modular Checkout](https://storybook.justifi.ai/?path=/docs/modular-checkout--docs) web component: include the [Plaid Payment Method sub component](https://storybook.justifi.ai/?path=/docs/modular-checkout-sub-components-plaid-payment-method--docs) A detailed step-by-step walkthrough of the end user flow will be documented separately. ## Testing Bank account verification is available in test mode and uses simulated bank accounts. Hosted Checkout, the Unified Fintech Checkout web component and the Modular Checkout web component all connect to the sandbox automatically when in test mode. Any values are accepted for user credentials and verification codes. > **Note** > > Test accounts do not need the business provisioned for bank account verification, so you can start testing without provisioning anything. The bank account verification setting still has to be enabled for your test account, so contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) if the option does not appear at checkout. ## Troubleshooting These are the errors the provisioning API returns when a business cannot be provisioned for bank account verification: | Status | Cause | Resolution | | ------ | ------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `400` | The business is missing information required for bank account verification. The response lists which fields are missing. | Add the fields via the [update business API](https://docs.justifi.tech/api-spec#tag/Business/operation/UpdateBusiness) and send the provisioning request again | | `400` | The business has no associated sub account, usually because it was never provisioned for payments | Provision the business for payments first, then provision it for bank account verification | | `400` | The business has already been provisioned for bank account verification | No further request is needed. If the option still does not appear at checkout, contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to confirm the feature is enabled | | `400` | The business legal address country is outside the United States | Bank account verification cannot be provisioned for this business | | `502` | JustiFi could not reach the verification provider | Retry the request. If it keeps failing, contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) | --- # Forwarding Source: https://docs.justifi.tech/paymentMethods/forwarding > **Note** > > Forwarding is in beta. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have it enabled for your platform and to get a destination allow-listed. Forwarding allows you to forward any card payment method stored with JustiFi to a third party. You supply the body and headers the destination requires and mark where the card details belong; JustiFi substitutes the real values and sends a request to the destination. Forwarding is asynchronous. Creating a forwarding request returns immediately, before anything leaves JustiFi, and the outcome arrives by webhook or by retrieving the request. ## How it works 1. You have a card payment method in JustiFi — any card payment method, however it was created, including one tokenized by the [Tokenize Payment Method web component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) or the [Checkout web component](https://docs.justifi.tech/web-components/modular-checkout). 2. You [create a forwarding request](https://docs.justifi.tech/api-spec#tag/Forwarding/operation/CreateForwardingRequest) naming the payment method, the destination, and the body and headers the destination expects. Card details are written as `{{card_number}}`, `{{card_expiry_month}}`, `{{card_expiry_year}}` and `{{cardholder_name}}` tags. 3. JustiFi answers `201` with the request in `pending` status, then sends the request to the destination in the background; it swaps each tag for the real value, encodes the body in the format the destination expects, and relays your headers. 4. You get the outcome from the `forwarding_request.completed` or `forwarding_request.failed` event, or by retrieving the forwarding request. ## Prerequisites **The destination must be allow-listed by JustiFi.** Forwarding will only send to destinations JustiFi has approved, matched exactly as a full URL — no trailing slash, casing or query string normalization is applied. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have a destination added, and use exactly the URL you are given. **You supply the destination's credentials.** JustiFi holds no credentials of its own for the destination. Any authorization required by the destination needs to be passed to the `forwarding_request.headers` and is relayed as-is. Only card payments can be forwarded. Bank accounts, card-present payment methods and digital wallets (Apple Pay and Google Pay) are rejected. ## Creating a forwarding request Create the request with [Create a Forwarding Request](https://docs.justifi.tech/api-spec#tag/Forwarding/operation/CreateForwardingRequest). `forwarding_request.body` is the shape the **destination** expects, not a JustiFi shape — JustiFi passes it through, substituting only the tags it finds. ```bash curl --request POST \ --url https://api.justifi.ai/v1/forwarding/requests \ --header 'authorization: Bearer YOUR_ACCESS_TOKEN' \ --header 'content-type: application/json' \ --header 'idempotency-key: YOUR_IDEMPOTENCY_KEY' \ --data '{ "payment_method": "pm_123xyz", "url": "https://api.stripe.com/v1/payment_methods", "forwarding_request": { "body": { "type": "card", "card": { "number": "{{card_number}}", "exp_month": "{{card_expiry_month}}", "exp_year": "{{card_expiry_year}}" }, "billing_details": { "name": "{{cardholder_name}}" }, "metadata": { "reference": "ord_9f21" } }, "headers": { "Authorization": "Bearer sk_live_destination_key" } } }' ``` No `Sub-Account` header is needed — the account is retrieved from the payment method. You always write `forwarding_request.body` as a JSON object. JustiFi encodes it into the format the destination requires — form-encoding it, for instance, when the destination expects form data — and sets `Content-Type` to match, so you do not need to send one. If you do send `Content-Type`, yours is relayed unchanged and you are responsible for it matching the body JustiFi produces. The response is the forwarding request in `pending` status, with `response` still `null`: ```json { "id": "fwd_123xyz", "type": "forwarding_request", "data": { "id": "fwd_123xyz", "account_id": "acc_123xyz", "payment_method_id": "pm_123xyz", "url": "https://api.stripe.com/v1/payment_methods", "http_method": "POST", "provider": "stripe", "status": "pending", "failure_reason": null, "replacements": ["card_number", "card_expiry_month", "card_expiry_year", "cardholder_name"], "request": { "body": { "type": "card", "card": { "number": "4242", "exp_month": 5, "exp_year": 2042 }, "billing_details": { "name": "Lindsay Whalen" }, "metadata": { "reference": "ord_9f21" } }, "headers": { "Authorization": "[FILTERED]" } }, "response": null, "attempted_at": null, "created_at": "2024-01-01T12:00:00Z", "updated_at": "2024-01-01T12:00:00Z" }, "page_info": null } ``` `replacements` lists the tags JustiFi found and will substitute, which is a useful confirmation that your tags were read the way you intended. ### Card tags | Tag | Substituted with | | ----------------------- | ---------------------------------------------------- | | `{{card_number}}` | the full card number | | `{{card_expiry_month}}` | the expiration month, as a number (`5`, not `"05"`) | | `{{card_expiry_year}}` | the expiration year, as a four digit number (`2042`) | | `{{cardholder_name}}` | the cardholder name on the payment method | Three rules apply: - **A tag must be the entire value of its field.** `"number": "{{card_number}}"` works; `"number": "card-{{card_number}}"` is rejected. There is no string interpolation. - **Unknown tags are rejected.** Only the four tags above are supported. - **`{{card_cvc}}` is not supported.** JustiFi does not retain the CVV after the request that collected it. Destinations that require a CVV cannot be reached by forwarding. Braces that are not a whole-value tag are left alone, so a value like `"ref: {{legacy}}"` passes through untouched. A body with no tags at all is accepted, and `replacements` comes back empty. ## Getting the outcome Forwarding requests move through four statuses: | Status | Meaning | | ------------ | --------------------------------------------------------------------- | | `pending` | accepted and queued; nothing has been sent | | `processing` | the request is being sent and the outcome is not yet known | | `completed` | the destination answered — see `response.status_code` for the outcome | | `failed` | the destination could not be reached — see `failure_reason` | > **Note** > > `completed` means the destination **answered**, not that it accepted the request. A `402` from the destination is a `completed` forwarding request with `response.status_code` of `402`. Always check `response.status_code`. When a request `failed`, `response` stays `null` and `failure_reason` says why: | Failure Reason | Meaning | | ------------------ | --------------------------------------------------------- | | `timeout` | the destination did not answer in time | | `connection_error` | the connection or TLS handshake to the destination failed | | `internal_error` | JustiFi failed to send the request | ### Webhooks Subscribe to `forwarding_request.completed` and `forwarding_request.failed`. The event payload is the same object the API returns. Exactly one of the two is published per forwarding request. See [Forwarding Request events](https://docs.justifi.tech/api-spec#tag/Events/operation/forwardingRequestEvent). ### Polling via API If you prefer polling, you can use the [Get a Forwarding Request](https://docs.justifi.tech/api-spec#tag/Forwarding/operation/GetForwardingRequest) API and wait for the `status` to change from `pending` or `processing` to `completed` or `failed`. ```bash curl --request GET \ --url https://api.justifi.ai/v1/forwarding/requests/fwd_123xyz \ --header 'authorization: Bearer YOUR_ACCESS_TOKEN' \ --header 'sub-account: acc_123xyz' ``` Once the destination has answered, `response` is populated: ```json { "status": "completed", "failure_reason": null, "response": { "id": "fwdr_123xyz", "status_code": 200, "body": { "id": "pm_1QabcStripeExample", "object": "payment_method", "card": { "last4": "4242" } }, "headers": { "content-type": "application/json" }, "response_time_ms": 512 }, "attempted_at": "2024-01-01T12:00:01Z" } ``` [List Forwarding Requests](https://docs.justifi.tech/api-spec#tag/Forwarding/operation/ListForwardingRequests) returns a sub account's forwarding requests newest first, and can be filtered by `payment_method_id`, `created_before` and `created_after`. ## What JustiFi stores, and what you can read back Forwarding is designed so that reading a forwarding request back can never expose card data, no matter what you sent or what the destination returned: - **Request body** — stored with the tags still in it, never with the card details. When you read it back, the card number renders as its last four digits; the expiration date and cardholder name render in the clear. This is true wherever you put a tag, including somewhere unexpected like a `metadata` field. - **Request headers** — names are kept so you can confirm what was relayed, but every value renders as `[FILTERED]`. The destination credentials you send are never readable again, so keep your own copy. - **Response body and headers** — anything that looks like a card number is reduced to its last four digits before being stored, so a destination that echoes the card back cannot leak it through JustiFi. ## Idempotency `Idempotency-Key` is required, and works as it does [everywhere else in the JustiFi API](https://docs.justifi.tech/api-spec#section/Idempotent-Requests). Retrying with the same key and the same parameters returns the same forwarding request and never sends a second request to the destination — which matters more here than usual, since the destination may create a record of its own. Reusing a key with different parameters returns `409`. ## Limits - **One attempt.** A forwarding request that fails is not retried. To try again, create a new forwarding request with a new `Idempotency-Key`. - **Timeouts.** JustiFi waits up to 10 seconds to connect and up to 90 seconds for the destination to answer, then records `timeout`. - **JSON request bodies only.** `forwarding_request.body` must be a JSON object; a string or an array is rejected. `forwarding_request.headers`, if present, must be a flat object of string values. JustiFi handles encoding the body into the form the destination expects. - **Cards only.** Bank accounts, card-present payment methods and digital wallet cards cannot be forwarded. ## Errors Every rejection happens before anything is created or sent, so a `400` means nothing reached the destination. | Code | Meaning | | ------------------------------------ | ----------------------------------------------------------------------------------------- | | `forwarding_destination_not_allowed` | the `url` is not on the allow list, or does not match an allow-listed destination exactly | | `payment_method_type_not_supported` | the payment method is not a card | | `digital_wallet_not_supported` | the card is an Apple Pay or Google Pay card | | `invalid_parameter` | a card tag is unknown, or is not the entire value of its field | | `forwarding_request_required` | `forwarding_request` is missing | | `forwarding_request_body_invalid` | `forwarding_request.body` is not a JSON object | | `forwarding_request_headers_invalid` | `forwarding_request.headers` is not an object of string values | | `payment_method_not_found` | no payment method with that id exists (`404`) | | `forwarding_request_not_found` | no forwarding request with that id exists on this sub account (`404`) | | `invalid_id_format` | the `payment_method` id is malformed | | `not_authorized` | your credentials have no admin access to the account that owns the payment method (`403`) | --- # Canadian Payments Source: https://docs.justifi.tech/payments/canadianPayments ## Overview JustiFi supports payment processing in Canadian dollars (CAD) through a dedicated Canada platform. CAD processing differs from USD in fee handling, balance transactions, payout timing, and supported payment methods. ## Platform Setup To process CAD payments, a **separate Canada platform** must be provisioned by JustiFi. This is distinct from your US platform. - Each platform and its sub-accounts are scoped to a **single currency** - A CAD sub-account cannot process USD payments, and vice versa - If your business operates in both the US and Canada, you will have separate platform accounts for each Contact to provision a Canada platform. ## Supported Payment Methods | Payment Method | CAD Support | | --------------------------- | ----------------- | | Card payments (e-commerce) | Supported | | Card present (terminals) | Not yet available | | ACH / bank account payments | Not supported | | Apple Pay | Not yet available | | Google Pay | Not yet available | > **Note** > > ACH and bank account payments are available for USD processing only. Card present (terminal), Apple Pay, and Google Pay support for CAD is planned but not yet available. ## Fees > **Note** > > All CAD processing platform accounts are configured on **interchange plus** pricing. For CAD payments, fees are determined during merchant onboarding and are not configurable by the platform via the API. The following parameters will return validation errors on CAD payments: - `application_fee_amount` on payment or checkout creation - `fees` array on payment or checkout creation - `application_fees` on checkout creation The data for fees applied to a payment is available via the `fees` array on the payment record (available via [Get Payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment) or payment events) as a `processing_fee`. The `application_fee` object will be `null` on CAD payments. Standard fee configurations (`application_fee_rates`) that platforms use for USD processing are not available for CAD. Fee rates for CAD merchants are established during onboarding and cannot be modified through the API. ### Account fees Separate from the per-payment `processing_fee`, the processor withdraws certain merchant-level fees directly from the sub-account's bank account. These include: - Network pass-through assessments (for example, interchange assessments, authorization and connectivity fees, address verification fees) - Periodic membership or service charges (for example, a monthly membership fee) - Per-item chargeback fees These fees are set by the card networks and the processor, not by JustiFi, and they are charged at the account level rather than against an individual payment. Each one appears as an `account_fee` balance transaction on the payout for the period in which it was charged, so your balance reflects the full deduction. The specific fee name appears in the balance transaction's `description` (for example, `CAD account fee: Monthly membership fee` or `CAD account fee: MC Auth Connectivity Fee`). Account fees are not included in `fees_total`; you'll find them in `other_total`. See [What's in `other_total`](#whats-in-other_total). ## Balance Transactions Balance transactions for CAD payments are not created at payment capture time. They are created when settlements are imported asynchronously. There will be a delay between when a payment is captured and when its associated balance transactions appear in the [Balance Transactions API](https://docs.justifi.tech/api-spec#tag/Balance-Transactions). ## Refunds CAD payments can be refunded within 365 days after payment creation the same way as USD payments with the following differences: - Refund transactions are subject to a refund processing fee. To avoid this processing fee try voiding the payment instead (see Voids). - The `fees` parameter on refund requests is not available for CAD payments. Fee returns on CAD refunds are not currently configurable. Create refunds the same way as USD - on the JustiFi dashboard, via the [Refund Payment web component](https://docs.justifi.tech/web-components/payment-facilitation/refund-payment) or via the [refund payment API](https://docs.justifi.tech/api-spec#tag/Refunds/operation/CreateRefund): ```text POST /v1/payments/{id}/refunds { "amount": 5000, "reason": "customer_request" } ``` ## Voids Void a payment transaction to cancel it before it reaches settlement. Unlike a refunded payment, a voided payment does not incur payment and refund processing fees. CAD payments can be voided within 25 minutes of the original transaction via the [void payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/VoidPayment) or by clicking the `Refund` button on the JustiFi dashboard within 25 min of payment transaction. ## Dispute Management To counter a dispute on a CAD payment a merchant (sub account) needs to submit evidence directly to Fiserv Canada via online portal. The [Dispute Management web component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management) is not available for CAD payments. ## Payouts CAD sub-account payouts behave differently from USD payouts in several ways. Both are surfaced through the same [Payouts API](https://docs.justifi.tech/api-spec#tag/Payouts) and JustiFi dashboard, but the creation model, schedule, and a few field values differ. ### What to expect CAD payouts are **net of fees and other deductions** — `Payout.amount` reflects the funds that move to or from the connected bank account, not the gross sum of payments captured. Processing fees appear in `fees_total`; account fees and chargebacks appear in `other_total`. The full breakdown is available on these totals and on the underlying balance transactions. CAD payouts appear in the API once the corresponding settlement has been processed. As a result, a CAD payout's `status` is `paid` and `deposits_at` reflects the date the funds landed. > **Note** > > A CAD payout `amount` can be negative. When a period's deductions exceed its deposits — for example a period whose only activity is an account fee, or one with a chargeback larger than the day's card volume — the payout represents a net amount drawn from the connected bank account rather than deposited to it. ### Schedule CAD payouts are created on **weekdays at approximately 1:00 PM Central Time**, once the day's settlement has been processed. No CAD payouts are created on weekends. ### Field values fixed for CAD payouts The [Payout schema](https://docs.justifi.tech/api-spec#tag/Payouts/operation/GetPayout) covers both USD and CAD payouts, but several fields take a narrower set of values for CAD: | Field | CAD value | Notes | | ----------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `currency` | `cad` | | | `payout_type` | `cc` | `ach` does not occur because ACH isn't a supported CAD payment method | | `status` | `paid` | CAD payouts skip the `scheduled` → `in_transit` lifecycle because the deposit has already settled by the time the payout is created. `failed`, `forwarded`, and `canceled` are not used for CAD. | | `delivery_method` | `standard` | | | `deposits_at` | date the funds landed in the bank | Already in the past at creation time | ### What's in `fees_total` For CAD payouts, `fees_total` is the sum of these balance transaction types on the payout: - `processing_fee` — processing fee on a payment - `refund_processing_fee` — processing fee charged when a refund is issued - `fee_rounding_adjustment` — small reconciliation entry (typically a few cents) for fee calculation rounding **Netted refund pairs**: when a payment is refunded before either the payment or the refund has settled, the two are recorded together with no fees on either side. The `seller_payment` and `seller_payment_refund` balance transactions appear in the payout but no `processing_fee` or `refund_processing_fee` is charged. Refunds of payments that already settled in a prior payout receive a `refund_processing_fee` as normal. ### What's in `other_total` A CAD payout can include balance transactions that fall outside `payments_total`, `refunds_total`, and `fees_total`, so they roll up into `other_total`: - `account_fee` — a merchant-level fee the processor withdrew from the bank account: network pass-through assessments, periodic membership or service charges, and per-item chargeback fees. See [Account fees](#account-fees). - `dispute` — the amount of a chargeback debited in this payout period. See [Dispute Management](#dispute-management). - `seller_payment_void` — the reversal of a voided payment. When a CAD payment is voided it is recorded as a `seller_payment` (positive) paired with a `seller_payment_void` (negative) of the same amount. The positive side is counted in `payments_total` and the negative side lands in `other_total`, so the pair nets to zero and does not change the payout amount. `account_fee` and `dispute` are deductions, so they reduce the net payout and make `other_total` negative. `other_total` is `0` only when a payout has none of these entries. ### Example CAD payout A sub-account on a Canada platform receives a payout covering: - 5 settled card payments totaling **87,500 cents** ($875.00 CAD) - 1 payment + refund netted pair for **20,000 cents** ($200.00 CAD) — neither side settled, so no fees on the pair - 1 standalone refund of **5,000 cents** ($50.00 CAD) for a payment that settled in a prior payout The resulting payout from `GET /v1/payouts/{id}`: ```json { "id": "po_4Ovwaq8yt7AbCdEf", "account_id": "acc_Q4pOABjVAxyz123", "amount": 80098, "currency": "cad", "payout_type": "cc", "status": "paid", "delivery_method": "standard", "deposits_at": "2026-04-20T00:00:00Z", "payments_total": 107500, "payments_count": 6, "refunds_total": -25000, "refunds_count": 2, "fees_total": 2402, "other_total": 0, "description": "Payout", "bank_account": { "id": "ba_abc123", "country": "CA", "currency": "cad", "account_type": "checking", "account_number_last4": "1234", "bank_name": "Royal Bank of Canada" }, "metadata": {}, "created_at": "2026-04-20T18:44:23Z", "updated_at": "2026-04-20T18:44:23Z" } ``` The balance transactions that compose this payout (visible through the [Balance Transactions API](https://docs.justifi.tech/api-spec#tag/Balance-Transactions)): | `txn_type` | `amount` (cents) | Notes | | ------------------------- | ---------------- | ------------------------------------------------------------ | | `seller_payment` | +10,000 | py\_aaa | | `seller_payment` | +20,000 | py\_bbb | | `seller_payment` | +15,000 | py\_ccc | | `seller_payment` | +17,500 | py\_ddd | | `seller_payment` | +25,000 | py\_eee | | `seller_payment` | +20,000 | py\_fff (netted pair) | | `seller_payment_refund` | −20,000 | refund of py\_fff (netted pair — no fee) | | `seller_payment_refund` | −5,000 | standalone refund of py\_ggg (settled in a prior payout) | | `processing_fee` | −270 | py\_aaa | | `processing_fee` | −510 | py\_bbb | | `processing_fee` | −390 | py\_ccc | | `processing_fee` | −450 | py\_ddd | | `processing_fee` | −630 | py\_eee | | `refund_processing_fee` | −150 | refund processing fee, charged on the standalone refund only | | `fee_rounding_adjustment` | −2 | reconciliation entry | | `payout` | −80,098 | the payout itself | `refunds_total` is returned as a negative number (refunds reduce the payout). The full relationship between the totals is: `amount` = `payments_total` + `refunds_total` − `fees_total` + `other_total` This example has no account fees or chargebacks, so `other_total` is `0`: `amount` = 107,500 + (−25,000) − 2,402 + 0 = **80,098 cents** ($800.98 CAD). ### Example CAD payout with account fees and a chargeback When account fees are charged or a chargeback is debited during the period, those amounts appear as `account_fee` and `dispute` balance transactions and reduce your payout through `other_total`. Take the payout above and add, in the same period: - A monthly membership fee of **900 cents** ($9.00 CAD) - Two card network fees: a connectivity fee of **6 cents** and an address verification fee of **2 cents** - A chargeback of **6,000 cents** ($60.00 CAD) These show up as additional balance transactions on the payout, each named in its `description`: | `txn_type` | `amount` (cents) | `description` | | ------------- | ---------------- | ------------------------------------------- | | `account_fee` | −900 | `CAD account fee: Monthly membership fee` | | `account_fee` | −6 | `CAD account fee: MC Auth Connectivity Fee` | | `account_fee` | −2 | `CAD account fee: VI-ADDRESS VER SVC FEE` | | `dispute` | −6,000 | Chargeback debited this period | They do not change `payments_total`, `refunds_total`, or `fees_total`. They sum into `other_total`: `other_total` = (−900) + (−6) + (−2) + (−6,000) = **−6,908 cents** `amount` = `payments_total` + `refunds_total` − `fees_total` + `other_total` = 107,500 + (−25,000) − 2,402 + (−6,908) = **73,190 cents** ($731.90 CAD). ## Technical Integration For information on testing Canadian payments, refer to the [Canadian Payments testing guide](https://docs.justifi.tech/testing/canadian_payments). ## Summary | Feature | USD | CAD | | --------------------------------------- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | Platform | US platform | Separate Canada platform | | Payment methods | Cards + ACH | Cards only | | Digital wallets (Apple Pay, Google Pay) | Supported | Not yet available | | Dynamic fees (`fees` param) | Supported | Not supported | | `application_fee_amount` param | Supported | Not supported | | Fee data on payment | `application_fee` or `fees` array | `fees` array (`processing_fee`) | | Fee configuration via API | Supported | Not supported (set during onboarding) | | Balance transactions | Created at payment capture | Created at settlement import | | Fee returns on refunds | Fully customizable | Not configurable | | Account & network pass-through fees | `account_fee` balance transactions | `account_fee` balance transactions in `other_total` (processor pass-throughs) | | Payout creation | Created before bank deposit | Created after the deposit settles; `amount` is net of fees and other deductions, and can be negative | | Payout schedule | Weekdays | Weekdays, \~1 PM Central | | Payout status lifecycle | `scheduled` → `in_transit` → `paid` (or `failed` / `canceled`) | Always `paid` at creation | | `payout_type` values | `ach`, `cc` | `cc` only | --- # JustiFi Unified Card Present Solution Source: https://docs.justifi.tech/terminals/overview Justifi and Verifone have partnered to deliver industry-leading hardware, software, and terminal management to provide a trusted, end-to-end payment solution from two world-class providers. Together, we’re redefining payments, ensuring frictionless transactions, increased revenue, and exceptional customer experiences. Our unified card present solution brings both card not present and card present transactions into a single system. This not only simplifies processing but also streamlines reporting and support. By doing so, we offer platforms a smoother, more intuitive user experience while also making it easier to gain valuable insights and resolve issues. It's a win-win situation for platforms and their customers alike. ## Terminal Models We offer a variety of terminal models. Here are the most commonly used ones: ### e285 - Companion Device or 3G Standalone Standalone mobile point of sale device with WiFi, Bluetooth and 3G communication options, allowing secure payment acceptance anywhere without dependence on a smart device. The solution features a color touch screen capable of signature capture and is built on the Verifone Engage platform, enabling rich customer interaction at the point of sale. ![terminal model e285](https://docs.justifi.tech/assets/images/terminal-E285-d5339ed8ab135c8cb39ac77ab980306b.png) **Specs**\ 2.8” Touch Display\ 3G / DB WiFi / BT\ **Wired:** USB-C\ **All Card** Acceptance\ **Printer:** None\ **Keypad:** Mechanical\ **Battery:** 3.8V 1800mAh\ **Scanning:** Companion Device\ **ENV:** Indoor mobile\ **Memory:** 1024 MB\ **OS:** V/OS2+ADK ### P400 - Integrated; Food & Beverage, Retail, Supermarket Advanced, high performance pin pad with rich multimedia and commerce capabilities. The P400 is a consumer-facing handheld device. It can also be fix-mounted in some integrated retail scenarios. The product’s design is equally appealing as a handheld PINpad and robust enough to look and function appropriately in a fixed mount setting. ![terminal model P400](https://docs.justifi.tech/assets/images/terminal-P400-07f637da9ee409df5e0840f5cd5d6dff.png) **Specs**\ 3.5” Touch Display\ **Wired:** Ethernet, USB, RS232\ **All Card** Acceptance\ **Printer:** None\ **Keypad:** Mechanical\ **Audio:** Buzzer\ **Battery:** None\ **Scanning:** None\ **ENV:** Indoor Countertop\ **Memory:** 384 MB, micro SD\ **OS:** V/OS2+ADK\\ ## Ready to Get Started? [Get in touch with us](https://docs.justifi.tech/contact) and learn all the ins and outs about the JustiFi Unified Card Present program. --- # Order or Provision Terminal Devices Source: https://docs.justifi.tech/terminals/ordering ## Order Terminals To order terminal devices for your merchants (sub accounts) you can either use the Terminal Orders API, set up the Order Terminals web component on your platform or place the order on the JustiFi dashboard.\ The sub account you intend to order terminals for must be onboarded with JustiFi and enabled for payment processing. The terminals will be automatically shipped to your sub account. ### Via Terminal Orders API Use the [Order Terminals API](https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/terminalsOrder) and pass `"boarding_shipping"` as `order_type` to order one or multiple terminal devices for an enabled sub account.\ Once the order is placed you can retrieve it via [Get Terminals Order API](https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/GetTerminalsOrder).\ To get the necessary `sub_account_id` and `business_id` of the sub account use the [List Sub Accounts API](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/ListSubAccounts) and filter by `enabled` status. ### Via Order Terminals Web Component If you prefer for your sub accounts to directly order terminal devices on your platform you can utilize the [Order Terminals web component](https://docs.justifi.tech/web-components/merchant-tools/order-terminals). The `shipping` prop value you pass to the web component must be `boarding_shipping`. ### Via JustiFi Dashboard Go to and choose **"Terminals"** from the **"Payments"** dropdown. On the **"Terminals"** list select the **"Terminal Orders"** tab. Click the **"Order Terminals"** button and select the business you order devices for. Confirm the **"Shipping Address"** displayed in the dialog is correct. Select the model(s) and the number of devices (up to 20) and submit the order.\ The `created` order will appear in the list of **"Terminal Orders"**. To view the order details click into the order on the list. ## Track Terminal Order After the order was `created` you can track the order progress via the terminal's **"Order Status"** on the JustiFi dashboard or via API.\ The order status will change from `created` to `submitted` as soon as the order was submitted to Verifone. When the order ships the order status will change to `completed`. At that point the Fedex `Tracking Number` will appear on the **"Order Details"** page. In the response of the get terminal order API the tracking number property is called `shipping_tracking_reference`. To get real time updates on status changes of the order you can subsribe to the [terminal order events](https://docs.justifi.tech/api-spec#tag/Events/operation/terminalOrderEvent) `terminal_order.created` and `terminal_order.updated`. Create an event publisher on the JustiFi dashboard to receive these updates: Go to and choose **"Event Publishers"** from the **"Developer"** dropdown. Click `Add Publisher` and select the terminal order events. ## Assign Nickname To simplify identifying and handling a specific terminal device you can assign a nickname to it as soon as the terminal order was created and the ordered terminals appear in the **"Associated Terminals"** list on the bottom of the **"Order Details"** page. To do that use the [Update Terminal API](https://docs.justifi.tech/api-spec#tag/Terminals/operation/updateTerminal). The nickname can be changed at any time via the same methods. ## Provision Terminal Devices If you bulk ordered terminal devices from JustiFi and want to ship them to your merchants (sub accounts) you need to assign them to the specific sub accounts before sending them out. This process is called **"Provisioning"**. You can provision terminals for your sub accounts via the Terminal Orders API, on the JustiFi dashboard or by integrating the Order Terminals web component in your platform.\ The sub account you provision terminals for must be onboarded with JustiFi and enabled for payment processing. Once you have provisioned the devices you can send them to your sub account(s). ### Via Terminal Orders API Use the [Order Terminals API](https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/terminalsOrder) and pass `"boarding_only"` as `order_type`.\ Once the provisioning order is placed you can retrieve it via [Get Terminals Order API](https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/GetTerminalsOrder).\ To get the necessary `sub_account_id` and `business_id` of the sub account use the [List Sub Accounts API](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/ListSubAccounts) and filter by `enabled` status. ### Via JustiFi Dashboard Go to and choose **"Terminals"** from the **"Payments"** dropdown. On the **"Terminals"** list select the **"Terminal Orders"** tab. Click the **"Provision Terminals"** button and select the business you provision devices for. Confirm the business information displayed in the dialog is correct. Select the model(s) and the number of devices and submit.\ The `created` order will appear in the list of **"Terminal Orders"**. To view the order details click into the order on the list. The **"Order Detail"** view shows the assigned terminals on the bottom of the page. Note the **"Device ID"** (or "DID") assigned to each provisioned terminal. Make sure to provide this DID to your sub account when you ship the terminal device to them. They will need to enter that DID into the device after they set up WIFI on the device. See the [Configuration section](https://docs.justifi.tech/terminals/configuration) for details. ### Via Order Terminals Web Component If you prefer for your sub accounts to directly provision terminal devices on your platform you can utilize the [Order Terminals web component](https://docs.justifi.tech/web-components/merchant-tools/order-terminals). The `shipping` prop value you pass to the web component must be `boarding_only` for provisioning. --- # Terminal Device Configuration Source: https://docs.justifi.tech/terminals/configuration ## Overview When you receive your terminal order you will need to connect the device(s) to Wifi and then enter the **device ID (DID**). You can find the 8 digit device ID(s) in the Welcome Email from Verifone and on the **"Terminals"** list in the JustiFi dashboard.\ To view the **"Terminals"** list go to and choose **“Terminals”** from the **"Payments"** dropdown. Filter the list by sub account. Choose a device ID from the list of terminals that match the **"Model Name"** you want to configure and have no assigned **"Serial Number"**. The **"Serial Number"** will be assigned to the device after configuration is finished. #### Follow these steps to configure your device(s): [JustiFi + Verifone: Terminal Configuration](https://player.vimeo.com/video/1085717984?badge=0\&autopause=0\&player_id=0\&app_id=58479) #### The same steps are listed in the following images ![terminal set up guide steps 1 to 6](https://docs.justifi.tech/assets/images/terminal-configuration1-e67d11bf98d93adb7f8dc55e5cab9377.png) ![terminal set up guide steps 7 to 11](https://docs.justifi.tech/assets/images/terminal-configuration2-4571f8c3a3febc2b9e7dd46f8e7da243.png) ![terminal set up guide steps 12 to 17](https://docs.justifi.tech/assets/images/terminal-configuration3-1c06af0bb11ef7f0524e781648e36eb7.png) ## After Configuration You should be able to see any configured terminals in the response of the [List Terminals API response](https://developer.justifi.ai/api-spec#tag/Terminals/operation/listTerminals) and in the **"Terminals List"** on the JustiFi dashboard:\ Go to and choose **“Terminals”** from the **"Payments"** dropdown. Confirm that the device you just configured has an assigned **"Serial Number"** that matches the serial number on the back of your device. ## Check Terminal Status To double check that a terminal is in `CONNECTED` mode call the [Get Terminal Status API](https://developer.justifi.ai/api-spec#tag/Terminals/operation/getTerminalStatus) and pass the terminal ID. Or go to and choose **“Terminals”** from the **"Payments"** dropdown. On the **"Terminals"** list click into a terminal you want to check. On the detail view of a terminal click the **"Check Terminal Status"** button and the latest status will be retrieved. ## Identify Terminal To ping a terminal device and display the nickname or serial number for 20 seconds on its display you can send a request to the [Identify Terminal API](https://docs.justifi.tech/api-spec#tag/Terminals/operation/postIdentifyTerminal). Or go to and choose **“Terminals”** from the **"Payments"** dropdown. On the **"Terminals"** list click into a terminal you want to ping. On the detail view of a terminal click **"Identify Terminal"**. ## Reset a Terminal A terminal is in `ACTIVE` mode when it is processing a payment. It can occasionally get unresponsive. In this case you can reset it by holding down the red **"X"**. Once reset the device will usually be in `CONNECTED` mode. Once your device is configured and you have confirmed it is in `CONNECTED` mode you can [attempt a payment](https://docs.justifi.tech/terminals/payment). ## FAQ **How long will the Device ID screen wait before timeout?**\ The Device ID timeout does not take effect when entering the Device ID. The DID will remain until the form is completed, even after rebooting. **What if I power down the device before entering DID?**\ The terminal will return the device ID screen until the user enters the device ID. **What if I do not enter DID and press OK?**\ After pressing **"OK"**, the terminal will return to the Welcome screen. On the next reboot, it will display the device ID entry screen. **How long does it take to complete the software installation after entering the device ID?**\ After the update job is scheduled by Verifone, it will take 15 to 20 minutes to complete. The download and update usually are complete within 20 to 30 seconds. **What if power is lost during the software installation process?**\ The device will recover from the reboot and continue the software installation process. **Are hidden WIFI networks supported?**\ At this time, hidden networks will require engineering assistance. **What if my device's battery charge level is low before I enter the DID?**\ Please be sure the battery level is above 50% before entering DID. The device will postpone updates if the battery is lower than 20%. It is best practice to attach the terminal to the AC power adapter during the VHQ DID software update process. **What if I cannot find the Welcome email for the terminal?**\ If your package was sent from Verifone, check the packaging list affixed to the terminal's box. The 8 digit DID is listed under “Reference” on the bottom of the packaging list.\ If you can't find either or your package was not sent from Verifone please contact [JustiFi Customer Success](mailto:customer_success@justifi.tech). --- # Process a Card Present Payment Source: https://docs.justifi.tech/terminals/payment Once you have [configured a terminal device](https://docs.justifi.tech/terminals/configuration) and [confirmed its `CONNECTED` status](https://docs.justifi.tech/terminals/configuration#check-the-terminal-status) you can verify the terminal via test payment or attempt a payment via API integration. ## Verify the Terminal To test the device is configured correctly you can process a test payment of $1 via **"Verify Terminal"** on the JustiFi dashboard:\ Go to and choose **"Terminals"** from the **"Payments"** dropdown. Click into the specific terminal you want to test and click **"Verify Terminal"** on the detail view.\ Once you confirm the dialog the terminal device will receive the $1 payment which you can complete with a valid credit card. After the terminal payment has been completed you can view the payment on the JustiFi dashboard:\ Go to and choose **"Payments"** from the **"Payments"** dropdown or retrieve it via the [List Payments API](https://docs.justifi.tech/api-spec#tag/Payments/operation/ListPayments). ## Technical Payment Integration We have outlined how to integrate payment processing via terminals in our [Card Present documentation](https://docs.justifi.tech/api-spec#tag/Terminals). The short version is: [Create a checkout](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout). Pick a terminal and use the [Pay Terminal API](https://docs.justifi.tech/api-spec#tag/Terminals/operation/payTerminal) to process the checkout. If there are errors, the checkout completion record will be updated with information on what error occurred. We recommend listening to the `checkout.completion.succeeded` event to handle successful payments and the `checkout.completion.failed` event to handle a failed or canceled terminal payment.\ See the [Checkout Completion Event documentation](https://docs.justifi.tech/api-spec#tag/Events/operation/checkoutCompletionEvent) for more information. A few other notes: - Terminal payments will time out after 90 seconds - You can click the **"X"** on the device to cancel a terminal payment - The credit card information collected for a terminal payment is stored in a payment method record with the `payment_method_type` `card_present`. This type of payment method is considered "single use" and can currently not be used for other payments. Attempting to create a payment with a `card_present` payment method token returns a `400 Bad Request` with the error code `card_present_payment_method_token_not_supported`. To charge the customer again, collect a new payment method. - Once a payment is successfully collected for a checkout, the payment ID will be added to the checkout record as `successful_payment_id`. To retrieve the checkout or payment use the [Get Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/GetCheckout) or the [Get Payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment).\ The checkout as well as the payment also appear in your JustiFi dashboard:\ Go to and choose **"Checkouts"** or **"Payments"** from the **"Payments"** dropdown. --- # Refund a Terminal Payment Source: https://docs.justifi.tech/terminals/refund You can refund a terminal payment via API or on the JustiFi dashboard. ## Via API We offer 2 different APIs to execute a refund.\ If you want to refund a specific payment use the payment ID from the checkout record and call the [Create Refund API](https://developer.justifi.ai/tag/Refunds#operation/CreateRefund).\ To refund a checkout (which can potentially include multiple payments) send a request to the [Refund Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/RefundCheckout). ## Via JustiFi Dashboard To refund the payment go to and choose **"Payments"** from the **"Payments"** dropdown. If you have the payment ID you can filter the **"Payments"** list by the payment ID. Click into the payment to view the details and click the **"Refund"** button. To refund the checkout go to and choose **"Checkouts"** from the **"Payments"** dropdown. On the **"Checkouts"** list find the specific checkout you want to refund and click on it. If you have the checkout ID click into any checkout in the **"Checkouts"** list and replace the last part of the url with your checkout ID and click enter. On the detail page of your checkout click the **"Refund"** button. --- > **Pre-Release Feature** > > This feature is currently in pre-release. API endpoints and functionality be adjusted before general availability. # Testing JustiFi Integration This guide explains how to test various payment scenarios when integrating with JustiFi's payment processing system. By using specific test scenarios in your API requests, you can simulate different payment outcomes without processing real transactions. ## Overview JustiFi provides a comprehensive testing framework that allows you to simulate various payment scenarios including successful payments, card declines, gateway errors, and other edge cases. This helps you build robust error handling and ensure your integration works correctly in all situations. ## How Testing Works To trigger specific test scenarios, include a metadata field in your [create payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) requests with the following structure: ```json { "metadata": { "payment_test": { "scenario": "scenario_name" } } } ``` Replace `scenario_name` with one of the available test scenarios listed in each resource specific section in the sidebar ### Best Practices for Testing - Test All Scenarios: Ensure your application handles each type of error appropriately - Error Message Display: Test how error messages are displayed to end users - Retry Logic: Implement and test appropriate retry logic for different error types - Logging: Verify that errors are logged properly for debugging - User Experience: Test the complete user flow for both successful and failed payments ### Next Steps Once you've thoroughly tested your integration using these scenarios, you'll be ready to process live payments. To do so create a live API key on the [JustiFi dashboard](https://app.justifi.ai/admin) Developers -> API Keys, and use its credentials to generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials). Remember to remove or modify any test scenario metadata when moving to production. For more information about JustiFi's payment processing capabilities, refer to our Payments API documentation. --- # Card Payment Testing Source: https://docs.justifi.tech/testing/card_payments To simulate different scenarios (success and failure) [create a payment via API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) and pass the test scenario in the metadata property. > **Currency** > > The `currency` field in the examples below uses `usd`. For CAD testing, use `cad` instead. The currency must match the currency configured for the sub-account. Sub-accounts are scoped to a single currency type. Here's an example of how to create a test payment using cURL: ```text curl -X POST https://api.justifi.tech/v1/payments \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "amount": 1000, "currency": "usd", "payment_method": { "card": { "number": "4242424242424242", "exp_month": 12, "exp_year": 2025, "cvc": "123" } }, "metadata": { "payment_test": { "scenario": "insufficient_funds" } } }' ``` ## Successful Card Payment `successful_payment` Simulates a successful payment transaction. **Expected Response Containing:** ```json { "status": "succeeded", "captured": true "success": true } ``` ## Failed Card Payment Scenarios `insufficient_funds` Simulates a payment declined due to insufficient funds on the card. **Expected Response Containing:** ```json { "error": { "code": "card_declined", "decline_code": "insufficient_funds", "message": "Your card has insufficient funds.", "network_error_code": "116" } } ``` \`expired\_card\`\` Simulates a payment with an expired card. **Expected Response Containing:** ```json { "error": { "code": "card_declined", "decline_code": "expired_card", "message": "Your card has expired.", "network_error_code": "101" } } ``` `invalid_card_number` Simulates a payment with an invalid card number. **Expected Response Containing:** ```json { "error": { "code": "card_declined", "decline_code": "invalid_card_number", "message": "The card number is invalid.", "network_error_code": "131" } } ``` `invalid_cvc` Simulates a payment with an invalid CVC/security code. **Expected Response Containing:** ```json { "error": { "code": "card_declined", "decline_code": "invalid_cvc", "message": "Your card's security code is invalid.", "network_error_code": "517" } } ``` `do_not_honor` Simulates a generic card decline from the issuer. **Expected Response Containing:** ```json { "error": { "code": "card_declined", "decline_code": "do_not_honor", "message": "The card was declined.", "network_error_code": "005" } } ``` `restricted_card` Simulates a payment with a restricted card. **Expected Response Containing**: ```json { "error": { "code": "card_declined", "decline_code": "restricted_card", "message": "Your card has been restricted.", "network_error_code": "102" } } ``` `exceeds_card_limit` Simulates a payment that exceeds the card's limit. **Expected Response Containing**: ```json { "error": { "code": "card_declined", "decline_code": "exceeds_card_limit", "message": "The amount exceeds your card's limit.", "network_error_code": "121" } } ``` `gateway_error` Simulates a payment processing error at the gateway level. **Expected Response Containing:** ```json { "error": { "code": "gateway_error", "decline_code": null, "message": "An error occurred while processing your payment. Please try again.", "network_error_code": "963" } } ``` `gateway_timeout` Simulates a gateway timeout error. Expected Response: ```json { "error": { "code": "gateway_timeout_error", "decline_code": null, "message": "The payment gateway timed out. Please try again." } } ``` ### Additional Card Scenarios `card_blocked` Simulates a payment with a blocked card. `incorrect_pin` Simulates a payment with an incorrect PIN. `new_card_issued` Simulates a decline because a new card has been issued. `do_not_retry` Simulates a decline that should not be retried. `account_closed` Simulates a payment with a card from a closed account. `pin_required` Simulates a transaction that requires PIN verification. `pin_tries_exceeded` Simulates a scenario where PIN attempt limit has been exceeded. `amount_too_large` Simulates a payment with an amount that's too large to process. `amount_too_small` Simulates a payment with an amount that's too small to process. `invalid_expiry_month` Simulates a payment with an invalid expiration month. `invalid_expiry_year` Simulates a payment with an invalid expiration year. `invalid_charge_amount` Simulates a payment with an invalid charge amount format. `service_not_allowed` Simulates a transaction type that is not allowed. `issuer_not_available` Simulates when the card issuer is temporarily unavailable. `currency_not_supported` Simulates a payment with an unsupported currency. `three_d_secure_not_supported` Simulates a card that doesn't support 3D Secure authentication. `test_mode_live_card` Simulates the error when trying to use a real card number in test mode. `generic_decline` Simulates a generic payment decline with no specific reason. `generic_error_change_info` Simulates a generic error with a network error category and a message indicating that the card information needs to be updated. `generic_error_do_not_retry` Simulates a generic error with a network error category and a message indicating that the payment should not be retried. `generic_error_please_retry` Simulates a generic error with a network error category and a message indicating that the payment should be retried. ## Webhook Events The events related to each test payment created will be sent to the configured webhooks on the test account. --- # ACH Payment Testing Source: https://docs.justifi.tech/testing/ach_payments An ACH payment will initially have the status `pending` when it was successfully submitted to JustiFi. Only when it was transferred to the bank will the status update to `succeeded` or `failed` which can take a few business days (depending on the chosen settlement strategy). Subscribing to the payment related webhook events is the best way to get notified when the status of an ACH payment changes. The test environment simulates this behavior. In the response of the payment request the status will be `pending`. It will then immediately update to `succeeded` or `failed` depending on the chosen testing scenario. > **Note** > > ACH payments are only available for USD processing on US platform accounts. For Canadian dollar payments, card-based payment methods are supported through a Canada platform account. To simulate different scenarios (success and failure) [create a payment via API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) and pass the test scenario in the metadata property. Here's an example of how to create a test payment using cURL: ```text curl -X POST https://api.justifi.tech/v1/payments \ -H "Authorization: Bearer your_api_key" \ -H "Content-Type: application/json" \ -d '{ "amount": 1000, "currency": "usd", "payment_method": { "bank_account": { "acct_last_four": "1234", "token": "fake_token_for_testing", "account_owner_name": "John Doe", "bank_name": "Test Bank", "payment_method_type": "bank_account" } }, "metadata": { "payment_test": { "scenario": "succeeded" } } }' ``` ## Successful ACH Payment `success` Simulates a successful ACH payment transaction. **Expected Recorded ACH Payment Containing:** ```json { "status": "succeeded", "error": null "error_description": null } ``` ## Failed ACH Payment Scenarios `account_closed` Simulates an ACH payment declined due to account closed **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "account_closed", "error_description": "The customer's bank account has been closed.", } } ``` `account_frozen` Simulates an ACH payment declined due to account frozen **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "account_frozen", "error_description": "The customer's bank account is frozen.", } } ``` `bank_account_restricted` Simulates an ACH payment declined due to bank account restricted **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "bank_account_restricted", "error_description": "This payment could not be processed.", } } ``` `insufficient_funds` Simulates an ACH payment declined due to insufficient\_funds **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "insufficient_funds", "error_description": "The customer's account has insufficient funds to cover this payment.", } } ``` `invalid_account_number` Simulates an ACH payment declined due to invalid account number **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "invalid_account_number", "error_description": "The account number specified does not have the correct number structure.", } } ``` `no_account` Simulates an ACH payment declined due to insufficient\_funds **Expected Recorded ACH payment Containing:** ```json { "error": { "status": "failed", "error_code": "no_account", "error_description": "The customer's bank account could not be located.", } } ``` ## Webhook Events The events related to each test payment created will be sent to the configured webhooks on the test account. The failure scenarios above run the full return flow, so the simulated payment is charged an ACH return fee and records the same balance transactions as a live return. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns). --- # Canadian Payments Testing Source: https://docs.justifi.tech/testing/canadian_payments ## Testing CAD Payments To test CAD payments in the sandbox: 1. Use a **CAD-configured sub-account** (provisioned on your Canada platform) 2. Set `currency` to `cad` in payment requests 3. Use the same [test card scenarios](https://docs.justifi.tech/testing/card_payments) as for payment requests on US sub accounts, substituting the currency ```json { "amount": 1000, "currency": "cad", "capture_strategy": "automatic", "payment_method": { "token": "pm_justifi123" } } ``` ## Testing CAD Payouts CAD test payouts are created **daily** for sub-accounts that have eligible activity. Each payout aggregates any test CAD payments and refunds that haven't yet been included in a payout, and is always created with `status: paid`. The resulting payouts behave the same as live CAD payouts — same fields, same balance transaction breakdown, same `fees_total` composition. See [Canadian Payments → Payouts](https://docs.justifi.tech/payments/canadianPayments#payouts) for the full field reference and an example payout. --- # Payout and Proceeds Testing Source: https://docs.justifi.tech/testing/payouts ## How does it work? Currently the JustiFi testing framework only supports successful payouts. The payouts are automatically created daily at 14:30pm US/Central Time and will succeed. > **CAD Payouts** > > CAD test payouts are also created daily and always succeed. They aggregate test CAD payments and refunds that haven't yet been included in a payout. For CAD-specific behavior, see the [Canadian Payments testing guide](https://docs.justifi.tech/testing/canadian_payments). ## Webhook Events The events related to each test payout created will be sent to the configured webhooks on the test account. --- # Testing Disputes Source: https://docs.justifi.tech/testing/disputes The JustiFi dispute system provides a comprehensive test environment that simulates the complete dispute lifecycle. This allows you to test your dispute handling workflows without affecting live data or moving real money. ## Creating Test Disputes To create a dispute call the [create payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) and pass the `dispute_test_spec` parameter in the metadata property as outlined below. This will create a successful payment with an associated dispute. ```json { "metadata": { "dispute_test_spec": { "expected_result": "won", "reason": "fraudulent", "forfeit": false, "due_date": "2024-02-15", "event_publish_delay_in_seconds": 60 } } } ``` ## Test Workflow 1. **Payment Creation**: A payment with `dispute_test_spec` key inside metadata 2. **Dispute Creation**: System creates dispute with `needs_response` status 3. **Response Building**: Test evidence upload and response field updates 4. **Resolution**: Dispute resolves based on your `expected_result` configuration after `event_publish_delay_in_seconds` seconds 5. **Webhook Events**: Receive all lifecycle events for testing ## Configuration Options The following options are available to customize the dispute details and outcome. ### Expected Results - **`won`** - Dispute resolves in the merchant\`s favor, funds returned to the merchant - **`lost`** - Dispute resolves against the merchant, no funds are moved ### Dispute Reasons - `fraudulent` - Customer claims they didn't authorize the payment - `unrecognized` - Customer doesn't recognize the transaction - `duplicate` - Customer claims they were charged multiple times - `subscription_canceled` - Customer claims they canceled their subscription - `product_unacceptable` - Customer claims the product was defective - `product_not_received` - Customer claims they never received the product - `processing_error` - Customer claims there was a processing error - `credit_not_processed` - Customer claims a refund wasn't processed - `general` - General dispute reason - `debit_not_authorized` - The debit was not authorized - `incorrect_account` - The account is not correct ### Timing Configuration - **`due_date`** - Response deadline in YYYY-MM-DD format (typically 7-10 business days) - **`event_publish_delay_in_seconds`** - Delay before dispute creation event (default: 60) ## Testing Evidence Upload To upload evidence for the dispute you can either use the [Dispute Management web component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management) or the [create dispute evidence API](https://docs.justifi.tech/api-spec#tag/Disputes/operation/UpdateDispute) and submit [Dispute Response API](https://docs.justifi.tech/api-spec#tag/Disputes/operation/UpdateDisputeResponse) ### Supported File Types | File Type | Extensions | MIME Types | | --------- | ----------------------- | ------------------------------------------------- | | Images | `.jpg`, `.jpeg`, `.png` | `image/jpeg`, `image/png` | | Documents | `.pdf` | `application/pdf` | | Archives | `.zip` | `application/zip`, `application/x-zip-compressed` | ### Evidence Categories Choose the appropriate category for each piece of evidence: - **`receipt`** - Purchase receipts and invoices - **`shipping_documentation`** - Tracking numbers, delivery confirmations - **`customer_communication`** - Email exchanges, chat logs - **`customer_signature`** - Signed delivery receipts - **`refund_policy`** - Terms of service, refund policies - **`cancellation_policy`** - Cancellation terms and conditions - **`service_documentation`** - Proof of service delivery - **`duplicate_charge_documentation`** - Evidence for duplicate charge disputes - **`activity_log`** - System activity logs - **`uncategorized_file`** - Other supporting documents ## Testing Response Scenarios ### Comprehensive Response Example ```json { "customer_name": "John Doe", "customer_email_address": "john@example.com", "customer_billing_address": "123 Main St, Anytown, ST 12345", "customer_purchase_ip_address": "192.168.1.1", "product_description": "Premium software subscription with advanced features", "service_date": "2024-01-15", "shipping_address": "123 Main St, Anytown, ST 12345", "shipping_carrier": "FedEx", "shipping_date": "2024-01-16", "shipping_tracking_number": "1234567890", "refund_policy_disclosure": "Customer agreed to no-refund policy during checkout", "additional_statement": "Customer received and actively used the service as confirmed by login logs and feature usage analytics." } ``` ### Testing Forfeiture If you choose not to contest the dispute either use the [submit dispute response API](https://docs.justifi.tech/api-spec#tag/Disputes/operation/SubmitDisputeResponse) with the following body: ```json { "forfeit": true } ``` Or instead forfeit the dispute via [Dispute Management web component](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management). This immediately transitions the dispute to `lost` status. ## Status Flow Testing Test each status transition: 1. **`needs_response`** - Initial status after dispute creation 2. **`under_review`** - Automatic after response submission 3. **`won`** or **`lost`** - Based on `expected_result` configuration ## Webhook Testing Test disputes generate all standard webhook events: - **`payment.dispute.created`** - Lets you know anytime a customer opens a payment dispute - **`payment.dispute.closed`** - Lets you know anytime a payment dispute is closed - **`payment.dispute.funds_returned`** - Lets you know anytime a payment dispute won and funds are returned - **`payment.dispute_evidence.created`** - Lets you know anytime a dispute evidence is created - **`payment.dispute_evidence.uploaded`** - Lets you know anytime a dispute evidence is uploaded - **`payment.dispute.forfeited`** - Lets you know anytime a dispute response is forfeited - **`payment.dispute.submitted`** - Lets you know anytime a dispute response is submitted Configure webhook endpoints in your test account to receive and process these events. --- # Introduction to JustiFi Web Component Library Source: https://docs.justifi.tech/web-components/introduction Welcome to the JustiFi Web Component Library. These web components are framework-agnostic and can be used in modern frameworks like React, Vue, Angular, or plain HTML. Examples in this documentation use the npm package `@justifi/webcomponents` at version 6.13.0. ## Usage ### HTML Web Components The simplest way to use the Web Components is to include the following script within your HTML. This loads all the components into the browser's custom component registry. ```html ``` Then, you can use the custom elements as normal `HTML` tags. ```html ``` It can also be installed as a package with `npm` or `pnpm`: ```bash npm install --save @justifi/webcomponents # or pnpm add @justifi/webcomponents ``` and import the component module using ES modules. ```javascript import '@justifi/webcomponents/dist/module/justifi-checkout.js'; ``` ## Styling ### How Parts Stack for Efficient Global Styling Parts are designed hierarchically to let you apply global styles like `color` or `font-family` universally, while components inherit these settings without repetitive targeting. ### Core Parts and Inheritance 1. **Base Parts**: `color`, `font-family`, and `background-color` define foundational styles. - These propagate into higher-level parts like `text`, `button`, and `input`. 2. **Higher-Level Parts**: - **`text`**: Combines `color` and `font-family` for typography. - **`input`, `button`, `label`**: Inherit `text`, ensuring consistent styles across components. ### Global Styling in Action #### Universal Font Set the font for all components using `font-family`: ```css ::part(font-family) { font-family: 'Inter', system-ui, sans-serif; } ``` #### Universal Text Color Set the text color once via `color`: ```css ::part(color) { color: #1d1b2f; } ``` These apply to all components that rely on `text`, including buttons, inputs, and headings. ### Component-Specific Overrides After defining global styles, customize specific components using their higher-level parts: #### Buttons ```css ::part(button-primary) { background-color: #0d3b66; color: #fff; /* Overrides `color` */ } ``` #### Input States ```css ::part(input-focused) { border-color: #0d3b66; background-color: #f0f8ff; } ``` To view the full list of available parts for styling, consult the source file [here](https://github.com/justifi-tech/web-component-library/blob/main/packages/webcomponents/src/styles/parts.ts). ### Best Practices 1. **Style Base Parts First**: Focus on `color` and `font-family` for global consistency. 2. **Override as Needed**: Use component-specific parts (e.g., `button-primary`) sparingly for deviations. 3. **Inspect and Leverage Stacking**: Ensure you understand how parts like `text` layer to avoid redundant styles. This hierarchy ensures maintainable, reusable styles across all components with minimal effort. ## Report Issues For bugs and issues, please: 1. Go to our [GitHub Issues](https://github.com/justifi-tech/web-component-library/issues). 2. Click "New Issue" and describe the problem. --- # Changelog Source: https://docs.justifi.tech/web-components/changelog We keep the authoritative changelog in GitHub so every commit that ships to npm stays auditable. - [Browse the `packages/webcomponents/CHANGELOG.md` file](https://github.com/justifi-tech/web-component-library/blob/main/packages/webcomponents/CHANGELOG.md) - [Install the newest version from npm](https://www.npmjs.com/package/@justifi/webcomponents) > Looking for upgrade guidance? Each release entry documents breaking changes, deprecations, and migration notes so you can copy the relevant snippets into your internal runbooks. --- # Frameworks Source: https://docs.justifi.tech/web-components/frameworks Examples in this documentation use the npm package `@justifi/webcomponents` at version 6.13.0. Pick the framework-specific guide that matches your host app. 1. [Angular](https://docs.justifi.tech/web-components/frameworks/angular) 2. [React](https://docs.justifi.tech/web-components/frameworks/react) 3. [Vue 3](https://docs.justifi.tech/web-components/frameworks/vue) --- # React Source: https://docs.justifi.tech/web-components/frameworks/react React treats JustiFi web components like any other custom element. Load the bundle, optionally declare types, and use refs for method calls or event wiring. Examples in this documentation use the npm package `@justifi/webcomponents` at version 6.13.0. ## Usage ### Load the components ```html ``` Or install the package: ```bash npm install --save @justifi/webcomponents ``` Then import the module you need: ```javascript import '@justifi/webcomponents/dist/module/justifi-checkout.js'; ``` ### Render inside JSX ```jsx export function CheckoutExample() { return ( ); } ``` ## TypeScript integration Let TypeScript know about the generated intrinsic elements so JSX understands attributes and custom events. ```ts // register-web-components.ts import { JSX as LocalJSX } from '@justifi/webcomponents/dist/loader'; import { HTMLAttributes } from 'react'; type StencilToReact = { [K in keyof T]?: T[K] & Omit, 'className'> & { class?: string; }; }; declare global { export namespace JSX { interface IntrinsicElements extends StencilToReact {} } } ``` Import that file once at the edge of your application (for example inside `src/main.tsx`) so the declarations register globally. ## Calling methods with refs ```tsx import { useRef } from 'react'; export default function CheckoutWithRef() { const checkoutRef = useRef(null); const fillBillingForm = () => { checkoutRef.current?.fillBillingForm({ name: 'John Doe', address_line1: '123 Main St', address_city: 'Minneapolis', address_state: 'MN', address_postal_code: '55401', }); }; return ( <> ); } ``` ## Listening to events Attach listeners with `addEventListener` inside `useEffect` or via inline handlers if you wrap the component. ```tsx import { useEffect, useRef } from 'react'; export function CheckoutWithEvents() { const checkoutRef = useRef(null); useEffect(() => { const element = checkoutRef.current; if (!element) { return; } const handleSubmit = (event: CustomEvent) => { console.log('Submit payload', event.detail); }; element.addEventListener('submit-event', handleSubmit); return () => element.removeEventListener('submit-event', handleSubmit); }, []); return ( ); } ``` --- # Angular Source: https://docs.justifi.tech/web-components/frameworks/angular Angular can render the JustiFi custom elements once you load the library and allow custom schemas. Examples in this documentation use the npm package `@justifi/webcomponents` at version 6.13.0. ## Usage ### Load the bundle ```html ``` Or install locally: ```bash npm install --save @justifi/webcomponents ``` Import specific elements where needed: ```ts import '@justifi/webcomponents/dist/module/justifi-checkout.js'; ``` ### Allow custom elements ```ts import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { AppComponent } from './app.component'; @NgModule({ declarations: [AppComponent], imports: [BrowserModule], providers: [], bootstrap: [AppComponent], schemas: [CUSTOM_ELEMENTS_SCHEMA], }) export class AppModule {} ``` ## Props and event handling Use Angular bindings for attributes and `(event)` syntax for emitted events. ```html ``` ## Calling methods Leverage `ViewChild` to call public methods on the web component. ```html ``` ```ts // app.component.ts import { AfterViewInit, Component, ElementRef, ViewChild } from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.component.html', }) export class AppComponent implements AfterViewInit { @ViewChild('checkoutForm') checkoutForm!: ElementRef; ngAfterViewInit() { // Safe place to call component methods } fillBillingForm() { const billing = { name: 'John Doe', address_line1: 'Main St', address_city: 'Beverly Hills', address_state: 'CA', address_postal_code: '90210', }; this.checkoutForm.nativeElement.fillBillingForm(billing); } } ``` > `HTMLJustifiCheckoutElement` is available from `@justifi/webcomponents/dist/components` if you want stronger typing. --- # Vue 3 Source: https://docs.justifi.tech/web-components/frameworks/vue Vue treats the JustiFi custom elements like native HTML tags. Load the script, import what you need, and wire up refs/events. Examples in this documentation use the npm package `@justifi/webcomponents` at version 6.13.0. ## Integration steps ### Load the components ```html ``` Or install locally and import the desired module: ```bash npm install --save @justifi/webcomponents ``` ```ts import '@justifi/webcomponents/dist/module/justifi-checkout.js'; ``` ### Use inside templates ```html ``` ## Event handling Leverage Vue's `@event-name` syntax for the custom events we emit. ```html ``` ## Calling methods Grab a ref to the element and call the public APIs directly. ```html ``` --- # Entities Source: https://docs.justifi.tech/web-components/entities Use the Entities toolkit to collect and maintain compliance-ready business records. - [BusinessDetails](https://docs.justifi.tech/web-components/entities/business-details) – guided intake for legal and tax profiles. - [Payment Provisioning](https://docs.justifi.tech/web-components/entities/payment-provisioning) – connect verified businesses to the rails they need to accept funds. > Pair these components with back-office workflows so underwriting teams can review submissions without bouncing between tools. --- # Business Details Source: https://docs.justifi.tech/web-components/entities/business-details ## Overview Component to render detailed information about a business. You will need to first create a business via [Business API](https://docs.justifi.tech/api-spec#tag/Business) to get the business-id required for this component. ## Usage ```html justifi-business-details ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------- | -------- | -------- | ------- | ----------- | | `auth-token` | `string` | Yes | — | | | `business-id` | `string` | Yes | — | | ### Events - `error-event`: Emits when API requests fail or validation errors occur; payload includes field-level hints. ## Theming & Layout | Part | Description | DOM target | | ------------------ | ----------- | ---------- | | `::part(skeleton)` | | — | | `::part(heading1)` | | — | | `::part(heading2)` | | — | | `::part(link)` | | — | | `::part(text)` | | — | # Example Usage --- --- --- # Payment Provisioning Source: https://docs.justifi.tech/web-components/entities/payment-provisioning ## Overview Component to render a business onboarding form, segmented into multiple steps. You will need to first create a business via [Business API](https://docs.justifi.tech/api-spec#tag/Business) to get the business-id required for this component. ## Usage ```html ``` ## Props & Events | Name | Type | Required | Default | Description | | ----------------------- | --------- | -------- | ------------------------ | ----------- | | `allow-optional-fields` | `boolean` | No | `false` | | | `auth-token` | `string` | Yes | — | | | `business-id` | `string` | Yes | — | | | `form-title` | `string` | No | `'Business Information'` | | ### Events - `submit-event`: Fires when payout information is collected and saved. Payload includes the API response or error details. - `click-event`: Fires on button interactions (Previous/Next step navigation). Payload includes the action name. - `error-event`: Fires when errors occur, including: - Missing required props (`auth-token` or `business-id`) - API failures during business data fetch or provisioning submission - When provisioning has already been requested for the business Payload includes `message`, `errorCode`, and `severity` properties. ### Public Methods This component does not expose any public methods. Form submission is handled automatically through the multi-step form flow. ## Validation Rules The form enforces the following rules before a step can be submitted. They apply to both US and Canadian businesses. ### Business Information - **Date of Registration** is required and must be a date in the past — today's date is not accepted. ### Business Owners - **Ownership percentage** is required for every owner and must be at least **25%** (and at most 100%). Owners with less than 25% ownership should not be registered; the form displays an informational alert reminding that all owners with 25% or more ownership of the business must be registered. - **Combined ownership** across all owners cannot exceed **100%**. Totals under 100% are allowed. - **Email addresses** must be unique across owners. Submitting duplicate emails blocks the step and flags the offending field with an error. ## Theming & Layout | Part | Description | DOM target | | ------------------------------------- | ----------- | ---------- | | `::part(text)` | | — | | `::part(skeleton)` | | — | | `::part(heading1)` | | — | | `::part(heading2)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(inputAdornment)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputGroup)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(input)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | | `::part(radioListItem)` | | — | | `::part(buttonSecondary)` | | — | | `::part(alert)` | | — | | `::part(buttonLoading)` | | — | | `::part(buttonPrimary)` | | — | | `::part(buttonSuccess)` | | — | | `::part(buttonDanger)` | | — | | `::part(buttonWarning)` | | — | | `::part(buttonInfo)` | | — | | `::part(buttonLight)` | | — | | `::part(buttonDark)` | | — | | `::part(buttonLink)` | | — | | `::part(buttonOutlinePrimary)` | | — | | `::part(buttonOutlineSecondary)` | | — | | `::part(heading3)` | | — | | `::part(card)` | | — | | `::part(table)` | | — | | `::part(tableCell)` | | — | | `::part(tableHeadCell)` | | — | | `::part(inputCheckbox)` | | — | | `::part(inputCheckboxChecked)` | | — | | `::part(inputCheckboxCheckedFocused)` | | — | | `::part(inputCheckboxFocused)` | | — | | `::part(inputCheckboxInvalid)` | | — | # Example Usage --- --- --- # Merchant Tools Source: https://docs.justifi.tech/web-components/merchant-tools Merchant Tools components expose the same operational insights that platforms use internally. Mix and match them to build tailored portals: 1. [Checkouts List](https://docs.justifi.tech/web-components/merchant-tools/checkouts-list) – monitor in-flight checkout sessions and states. 2. [Payments List](https://docs.justifi.tech/web-components/merchant-tools/payments-list) / [Payment Details](https://docs.justifi.tech/web-components/merchant-tools/payment-details) – audit every transaction from authorization through settlement. 3. [Payment Transactions List](https://docs.justifi.tech/web-components/merchant-tools/payment-transactions-list) – deep dive into ledger-level events. 4. [Payouts List](https://docs.justifi.tech/web-components/merchant-tools/payouts-list), [Payout Details](https://docs.justifi.tech/web-components/merchant-tools/payout-details), and [Payout Transactions List](https://docs.justifi.tech/web-components/merchant-tools/payout-transactions-list) – reconcile disbursements end to end. 5. [Gross Payments Chart](https://docs.justifi.tech/web-components/merchant-tools/gross-payments-chart) – visualize trends. 6. [Order Terminals](https://docs.justifi.tech/web-components/merchant-tools/order-terminals), [Terminal Orders List](https://docs.justifi.tech/web-components/merchant-tools/terminal-orders-list), and [Terminals List](https://docs.justifi.tech/web-components/merchant-tools/terminals-list) – manage hardware fulfillment. > Most teams embed just a handful of these components per view. Keep pages focused so operators can answer one question without sifting through noise. --- # Checkouts List Source: https://docs.justifi.tech/web-components/merchant-tools/checkouts-list ## Overview Component to render a formated list of checkouts for the requested account. ### Custom columns Pass a comma-separated list to the `columns` prop (`created_at,payment_amount,status`) to match the data points your operators expect. ## Props, Events & Methods | Name | Type | Required | Default | Description | | ---------------- | -------- | -------- | -------------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | | `sub-account-id` | `string` | No | — | | ### Events - `click-event`: Emitted when a row or control is clicked. `event.detail.name` indicates the source. - `error-event`: Fires when the list cannot load data due to network/auth issues. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | - Filters component emits custom events; ensure both components share the same container so spacing stays consistent. # Example Usage --- --- ```html justifi-checkouts-list ``` --- # Payment Details Source: https://docs.justifi.tech/web-components/merchant-tools/payment-details ## Overview Component to display detailed information about a specific payment. ## Usage ```html justifi-payment-details ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | ------- | ----------- | | `auth-token` | `string` | Yes | — | | | `payment-id` | `string` | Yes | — | | ### Events - `error-event`: Surfaces API or token errors for logging. - `record-click-event`: Emitted when users click on a related record (e.g., refund, dispute). ## Theming & Layout | Part | Description | DOM target | | ------------------------ | ----------- | ---------- | | `::part(skeleton)` | | — | | `::part(heading1)` | | — | | `::part(heading2)` | | — | | `::part(link)` | | — | | `::part(text)` | | — | | `::part(badge)` | | — | | `::part(badgePrimary)` | | — | | `::part(badgeSecondary)` | | — | | `::part(badgeSuccess)` | | — | | `::part(badgeDanger)` | | — | | `::part(badgeWarning)` | | — | | `::part(badgeInfo)` | | — | | `::part(badgeLight)` | | — | | `::part(badgeDark)` | | — | # Example Usage --- --- --- # Payments List Source: https://docs.justifi.tech/web-components/merchant-tools/payments-list ## Overview Component to render a formated list of payments for the requested account. ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | ### Events - `click-event`: emitted when users select a row or click an inline action; `event.detail` surfaces `payment_id`. - `error-event`: surfaces API or token errors for logging. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Example Usage --- --- ```html justifi-payments-list ``` --- # Payment Transactions List Source: https://docs.justifi.tech/web-components/merchant-tools/payment-transactions-list ## Overview Component to display a list of payment transactions for a specific payment. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | | `payment-id` | `string` | Yes | — | | ### Events - `click-event`: Emitted when a row is clicked; surfaces `transaction_id`. - `error-event`: Surfaces API or token failures. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Usage Example --- --- ```html justifi-payment-transactions-list ``` --- # Payouts List Source: https://docs.justifi.tech/web-components/merchant-tools/payouts-list ## Overview Component to render a formated list of payouts for the requested account. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | ### Events - `click-event`: Fires when a row is clicked; `detail.payout_id` indicates which payout to drill into. - `error-event`: Surfaces API or token errors for logging. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Usage Example --- --- ```html justifi-payouts-list ``` --- # Payout Details Source: https://docs.justifi.tech/web-components/merchant-tools/payout-details ## Overview Component to display detailed information about a specific payout. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | --------------------- | --------- | -------- | ------- | ----------- | | `auth-token` | `string` | Yes | — | | | `enable-record-click` | `boolean` | No | `false` | | | `payout-id` | `string` | Yes | — | | ### Events - `error-event`: Emits when payout data cannot be loaded. - `record-click-event`: Emitted when users click on a related record. ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(skeleton)` | | — | | `::part(heading1)` | | — | | `::part(heading2)` | | — | | `::part(link)` | | — | | `::part(text)` | | — | | `::part(buttonLoading)` | | — | | `::part(buttonPrimary)` | | — | | `::part(buttonSecondary)` | | — | | `::part(buttonSuccess)` | | — | | `::part(buttonDanger)` | | — | | `::part(buttonWarning)` | | — | | `::part(buttonInfo)` | | — | | `::part(buttonLight)` | | — | | `::part(buttonDark)` | | — | | `::part(buttonLink)` | | — | | `::part(buttonOutlinePrimary)` | | — | | `::part(buttonOutlineSecondary)` | | — | | `::part(badge)` | | — | | `::part(badgePrimary)` | | — | | `::part(badgeSecondary)` | | — | | `::part(badgeSuccess)` | | — | | `::part(badgeDanger)` | | — | | `::part(badgeWarning)` | | — | | `::part(badgeInfo)` | | — | | `::part(badgeLight)` | | — | | `::part(badgeDark)` | | — | # Usage Example --- --- ```html justifi-payout-details ``` --- # Payout Transactions List Source: https://docs.justifi.tech/web-components/merchant-tools/payout-transactions-list ## Overview Component to display a list of payout transactions for a specific payout. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | | `payout-id` | `string` | Yes | — | | ### Events - `click-event`: Row selection event that surfaces `transaction_id`. - `error-event`: Surfaces API or token failures. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Usage Example --- --- ```html justifi-payout-transactions-list ``` --- # Gross Payments Chart Source: https://docs.justifi.tech/web-components/merchant-tools/gross-payments-chart ## Overview Component to render chart displaying last 30 days of gross payment data. ## Usage ### Chart monthly volume ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | ------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | ### Events - `error-event`: Surfaces API or token errors for logging. ## Theming & Layout | Part | Description | DOM target | | ------------------------ | ----------- | ---------- | | `::part(loadingSpinner)` | | — | ## Usage Example --- --- ```html justifi-gross-payment-chart ``` --- # Order Terminals Source: https://docs.justifi.tech/web-components/merchant-tools/order-terminals ## Overview Component to render a form for terminal order requests. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------------------- | --------- | -------- | ---------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `business-id` | `string` | Yes | — | | | `shipping` | `boolean` | No | `false` | | | `submit-button-text` | `string` | No | `'Submit Order'` | | ### Events - `submit-event`: Fires when an order is placed; includes order ID and device list. - `error-event`: Emits network or validation errors. ## Theming & Layout | Part | Description | DOM target | | ----------------------- | ----------- | ---------- | | `::part(buttonPrimary)` | | — | | `::part(heading4)` | | — | | `::part(heading5)` | | — | | `::part(text)` | | — | | `::part(skeleton)` | | — | | `::part(buttonLink)` | | — | | `::part(card)` | | — | | `::part(image)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | # Usage Example --- --- ```html justifi-order-terminals ``` --- # Terminal Orders List Source: https://docs.justifi.tech/web-components/merchant-tools/terminal-orders-list ## Overview Component to render a formated list of terminal device orders for the requested account. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | ### Events - `click-event`: Surfaces the order ID for navigation. - `error-event`: Surfaces API or token errors for logging. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Usage Example --- --- ```html justifi-terminal-orders-list ``` --- # Terminals List Source: https://docs.justifi.tech/web-components/merchant-tools/terminals-list ## Overview Component to render a formated list of terminals for the requested account. ## Usage ```html ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | -------------------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `columns` | `string` | No | `defaultColumnsKeys` | | ### Events - `click-event`: Row click event that surfaces `terminal_id`. - `error-event`: Surfaces API or token errors for logging. ## Theming & Layout | Part | Description | DOM target | | -------------------------------------- | ----------- | ---------- | | `::part(table)` | | — | | `::part(tableRow)` | | — | | `::part(tableFoot)` | | — | | `::part(tableFootRow)` | | — | | `::part(tableFootCell)` | | — | | `::part(tableHead)` | | — | | `::part(tableHeadRow)` | | — | | `::part(tableCell)` | | — | | `::part(loadingSpinner)` | | — | | `::part(tableEmpty)` | | — | | `::part(tableError)` | | — | | `::part(paginationButton)` | | — | | `::part(paginationButtonDisabled)` | | — | | `::part(paginationButtonIconNext)` | | — | | `::part(paginationButtonIconPrevious)` | | — | | `::part(paginationButtonText)` | | — | # Usage Example --- --- ```html justifi-terminals-list ``` --- # Modular Checkout Source: https://docs.justifi.tech/web-components/modular-checkout Modular Checkout stitches every payment surface, summary view, and auxiliary experience into one cohesive flow. Use this hub to jump into the right phase of the journey: - [Introduction](https://docs.justifi.tech/web-components/modular-checkout/introduction) for architecture, props, events, and theming guidance. - [Donation Form Example](https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-1) for a donation flow with Card, Bank account, and Apple Pay toggle. - [E-commerce Checkout Example](https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-2) for a two-column page with header, shipping, payment, and cart summary. - [Stripe-style Two-Column Example](https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-3) for an order summary and payment form side by side with `preCompleteHook` demo. - [Sub-components](https://docs.justifi.tech/web-components/modular-checkout/sub-components) for deep dives on each child element (card form, bank form, payment method picker, etc.). --- # Modular Checkout Source: https://docs.justifi.tech/web-components/modular-checkout/introduction ## Overview The `justifi-modular-checkout` wrapper component serves as a container for checkout-related sub components. It manages the tokenization of payment methods, billing information, insurance, and overall form submission to complete the checkout. It also supports saving a payment method to a payment method group for future use. ## Supported sub components Required for checkout completion (add at least one of the following sub components): - [justifi-card-form](https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-form) - [justifi-bank-account-form](https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-form) - [justifi-saved-payment-methods](https://docs.justifi.tech/web-components/modular-checkout/sub-components/saved-payment-methods) - [justifi-sezzle-payment-method](https://docs.justifi.tech/web-components/modular-checkout/sub-components/sezzle-payment-method) - [justifi-plaid-payment-method](https://docs.justifi.tech/web-components/modular-checkout/sub-components/plaid-payment-method) Optional: - [justifi-checkout-summary](https://docs.justifi.tech/web-components/modular-checkout/sub-components/summary) - [justifi-season-interruption-insurance](https://docs.justifi.tech/web-components/modular-checkout/sub-components/season-interruption-insurance) - [justifi-billing-form-full](https://docs.justifi.tech/web-components/modular-checkout/sub-components/billing-form-full) - [justifi-card-billing-form-simple](https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-billing-form-simple) - [justifi-bank-account-billing-form-simple](https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-billing-form-simple) - [justifi-apple-pay](https://docs.justifi.tech/web-components/modular-checkout/sub-components/apple-pay) - [justifi-google-pay](https://docs.justifi.tech/web-components/modular-checkout/sub-components/google-pay) > **Note:** In addition to the supported sub components, you can add any custom HTML elements or markup inside the justifi-modular-checkout. This allows you to render headings, descriptions, disclaimers, or other layout elements as needed. ## Providing Billing Information Billing information is **required when collecting a new card or bank account** and can be provided in one of the following ways: - Using the `` sub component for complete billing address collection - Using the `` sub component for ZIP code only (card payments) - Using the `` sub component for account owner name only (ACH payments) - Passing a `billingInformation` object directly to the `submitCheckout` method For checkouts that use a saved payment method or a wallet/BNPL sub component (for example, ``, ``, ``, or ``), billing information is optional and is not validated by the modular checkout flow. The `billingInformation` object can take one of two forms: **Full billing address:** ```javascript { name: string; address_line1: string; address_line2?: string; address_city: string; address_state: string; address_postal_code: string; } ``` **Only postal code:** ```javascript { address_postal_code: string; } ``` ### Card Form Billing Information When using ``, billing information **must be provided** through either: - `` sub component for complete billing address - `` sub component for ZIP code only - Passing the full `billingInformation` object directly to the `submitCheckout` method - Passing the `billingInformation` object with only `address_postal_code` to the `submitCheckout` method ### Bank Account Form Billing Information When using ``, billing information **must be provided** through either: - `` sub component for complete billing address - `` sub component for account owner name only - Passing the full `billingInformation` object directly to the `submitCheckout` method ## Pre-filling Billing Information Use `fillBillingForm()` to programmatically pre-populate billing fields, e.g. from saved customer data. Values persist when the user switches between payment methods. ```javascript const modularCheckout = document.querySelector('justifi-modular-checkout'); modularCheckout.fillBillingForm({ name: 'John Doe', address_line1: '123 Main St', address_city: 'Anytown', address_state: 'NY', address_postal_code: '12345', }); ``` All fields are optional except `address_postal_code`: ```typescript interface BillingFormFields { name?: string; address_line1?: string; address_line2?: string; address_city?: string; address_state?: string; address_postal_code: string; // required } ``` ## Completing Checkout To finalize the checkout process, include a submit button that calls the `submitCheckout` method on the `justifi-modular-checkout` wrapper component. This method: - handles validation, form submission and payment method tokenization - optionally accepts a `billingInformation` object (useful when not using a billing component) - executes `preCompleteHook` (if provided) after validation and tokenization (including Plaid exchange) and before checkout completion - emits a `submit-event` when the submission is successful - returns a promise (`Promise`) and you should listen for `submit-event` to handle completion > If you passed a `payment_method_group_id` to the [create checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) and you want to give the user the option to save a newly entered payment method to that payment method group for future use, set the `savePaymentMethod` prop to true on the `justifi-modular-checkout`. This will automatically save the payment method to that payment method group after successful checkout. ## Props, Events & Methods | Name | Type | Required | Default | Description | | ----------------- | ------------------------------------------------------------------------------------------- | -------- | ------- | ----------- | | `auth-token` | `string` | Yes | — | | | `checkout-id` | `string` | Yes | — | | | `preCompleteHook` | `(data: CheckoutState, resolve: (data: CheckoutState) => void, reject: () => void) => void` | No | — | | ### Events - **`error-event`**: Emitted when validation fails or an error occurs. Detail shape: `{ message: string; errorCode: string; severity?: 'info' | 'warning' | 'error' }`. When the error originates from `justifi-apple-pay`, `errorCode` will be prefixed with `APPLE_PAY_` (e.g. `APPLE_PAY_NOT_SUPPORTED`, `APPLE_PAY_PAYMENT_FAILED`). - **`submit-event`**: Emitted when checkout completes successfully. Detail shape: `{ checkout: any; message: string }`. - **`checkout-changed`**: Emitted when checkout state changes. Detail shape: `{ availablePaymentMethodTypes: PAYMENT_METHODS[]; selectedPaymentMethod: { id?: string; type: PAYMENT_METHODS }; savedPaymentMethods: SavedPaymentMethod[] }`. ### Public methods 1. `fillBillingForm(fields)` – Pre-populate billing form fields from saved customer data. 2. `submitCheckout(billingInformation?)` – Validate, tokenize, and complete the checkout. Optionally accepts a `billingInformation` object. 3. `validate()` – Validate all sub-component form fields; returns a promise resolving to `boolean`. 4. `setSelectedPaymentMethod(method)` – Programmatically set the active payment method. ## Pre-Complete Hook You can provide a `preCompleteHook` function to inspect the checkout state before submission proceeds. This is useful for implementing custom validation, user confirmation dialogs, or conditional payment restrictions based on business rules. The hook runs after validation and payment method tokenization (including Plaid exchange when applicable), and before the checkout is completed, so the state includes the latest values such as `paymentToken` when available. The hook receives three parameters: - `state`: A `CheckoutState` object containing the current checkout information - `resolve`: A function to call to proceed with submission - `reject`: A function to call to stop submission ```javascript const checkout = document.querySelector('justifi-modular-checkout'); /** * CheckoutState example (shape): * { * selectedPaymentMethod: { id?: string, type: 'new_card' | 'apple_pay' | 'google_pay' | ... } | undefined, * paymentAmount: 5000, * totalAmount: 5000, * paymentCurrency: 'USD', * paymentDescription: 'Order #123', * savedPaymentMethods: [], * savePaymentMethod: false, * bnplEnabled: false, * applePayEnabled: true, * insuranceEnabled: false, * disableBankAccount: false, * disableCreditCard: false, * disablePaymentMethodGroup: false, * paymentToken: 'pm_123' // tokenized payment method id; Apple Pay, Google Pay and Plaid set this too (paymentMethodId) * } */ checkout.preCompleteHook = (state, resolve, reject) => { // Example: Require confirmation for large payments if (state.totalAmount > 100000) { const confirmed = confirm( `Confirm payment of $${(state.totalAmount / 100).toFixed(2)}?`, ); if (confirmed) { resolve(state); } else { reject(); } } else { resolve(state); } }; ``` > Important: Assign the hook as a JavaScript property on the element (e.g., `checkout.preCompleteHook = fn`). Do not pass it as an HTML attribute (e.g., `pre-complete-hook="..."`); functions must be set on properties, not attributes. See the `CheckoutState` type definition in the [Public Types](#public-types) section below for the complete structure of the state object. ## Validation When `submitCheckout` is called, the `justifi-modular-checkout` wrapper component automatically validates all included sub components. If any required fields are missing or invalid, submission is blocked and validation errors will appear inline. You can also trigger validation manually by calling the `validate` method on the `justifi-modular-checkout` wrapper component. This returns a promise that resolves to a `boolean` indicating whether the form is valid. ## Setting Payment Method Programmatically You can programmatically set the selected payment method by calling the `setSelectedPaymentMethod` method on the `justifi-modular-checkout` wrapper component. This method accepts either a saved payment method object or an object with a `type` field. > Important: The wrapper does not automatically select a default payment method. If you want a default to be selected (for example, the first saved method or a new card), explicitly call `setSelectedPaymentMethod` after initialization (e.g., on the first `checkout-changed` event). ```javascript import { PAYMENT_METHODS } from '@justifi/webcomponents'; const modularCheckout = document.querySelector('justifi-modular-checkout'); // Set to new card payment method modularCheckout.setSelectedPaymentMethod({ type: PAYMENT_METHODS.NEW_CARD }); // Set to new bank account payment method modularCheckout.setSelectedPaymentMethod({ type: PAYMENT_METHODS.NEW_BANK_ACCOUNT, }); // Set to a saved payment method by id modularCheckout.setSelectedPaymentMethod({ id: 'pm_123', type: PAYMENT_METHODS.SAVED_CARD, }); ``` ## Checkout Changed Event The `justifi-modular-checkout` wrapper component emits a `checkout-changed` event whenever any internal checkout state changes. The event detail includes `availablePaymentMethodTypes`, `selectedPaymentMethod`, and `savedPaymentMethods`. ```javascript const modularCheckout = document.querySelector('justifi-modular-checkout'); modularCheckout.addEventListener('checkout-changed', (event) => { const { availablePaymentMethodTypes, selectedPaymentMethod, savedPaymentMethods, } = event.detail; console.log('Available:', availablePaymentMethodTypes); console.log('Selected:', selectedPaymentMethod); console.log('Saved methods:', savedPaymentMethods); }); ``` `availablePaymentMethodTypes` includes: - `saved_card`, `saved_bank_account`: Saved methods from `payment_method_group`. Bank-related types are omitted when the checkout has `payment_settings.ach_payments === false` or when `disableBankAccount` is true on checkout state. - `new_card`, `new_bank_account`: Entry forms for new payment methods. `new_bank_account` is omitted when `payment_settings.ach_payments === false` or when `disableBankAccount` is true. - `sezzle`: BNPL is available when enabled by the account and not disabled. - `plaid`: Plaid is available when `payment_settings.bank_account_verification === true`, `payment_settings.ach_payments` is enabled for the checkout, and `disableBankAccount` is false. ## ACH payments When the checkout's `payment_settings.ach_payments` is `false`, modular checkout does not offer `new_bank_account`, `saved_bank_account`, or `plaid` as available payment method types. If `justifi-bank-account-form` remains in the DOM, it renders nothing and logs a console warning: `[bank-account-form] ACH payments are disabled for this checkout (payment_settings.ach_payments=false).` ## Insurance Integration The `justifi-modular-checkout` wrapper component automatically integrates the `justifi-season-interruption-insurance` component. - **Automatic Refresh**: When insurance values change the checkout data is automatically refreshed when insurance values are updated - **Feature Flag**: If the checkout's `payment_settings.insurance_payments` is `false`, the wrapper will skip validating the insurance component. The `justifi-season-interruption-insurance` component will also render nothing and log a console warning indicating that insurance is disabled for the checkout. ```html ``` ## Public Types ```ts import { PAYMENT_METHODS } from '@justifi/webcomponents'; import type { SelectedPaymentMethod, SavedPaymentMethod, CheckoutChangedEventDetail, CheckoutState, } from '@justifi/webcomponents'; ``` ## Authorization Authorization is performed by passing a web component token as `auth-token`. - **Web Component Token**: These tokens are generated by your backend services using the [Web Component Tokens API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens/operation/CreateWebComponentToken). Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the roles: `write:checkout:checkout_id` and `write:tokenize:account_id`. Make sure the value for `account_id` matches the account associated with the checkout. --- ```html justifi-modular-checkout ``` --- # Layout 1 — Donation Form Source: https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-1 A complete checkout form example that demonstrates a donation payment flow with a clean, modern design. This example showcases how to combine the `justifi-modular-checkout` wrapper with `justifi-card-form`, `justifi-bank-account-form`, and `justifi-card-billing-form-simple` components to create a professional payment experience. The layout includes: - A donation total header - A main payment form container - Payment method selection buttons (Card, Bank account, Apple Pay) with toggle functionality - Card form with secure iframe inputs - Bank account form for ACH payments - Country dropdown and ZIP code form (using justifi-card-billing-form-simple) - A prominent "Donate Now" submit button This example uses CSS parts to style the web components consistently with the overall design theme. The payment method cards allow users to switch between card and bank account payment methods, with the Apple Pay option available for future implementation. ## Example Usage Donation Total $10.00 Card Bank account Apple Pay Country United States ```html justifi-modular-checkout
Donation Total $10.00
Card
Bank account
``` --- # Layout 2 — E-commerce Checkout Source: https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-2 A complete checkout page example featuring a modern e-commerce layout with a two-column design. This example demonstrates how to integrate the modular checkout components within a full page layout including header, shipping information, payment methods, and shopping cart summary. The layout includes: - **Header**: Brand logo and navigation with shopping cart icon - **Shipping Section**: Pre-filled shipping information with edit functionality - **Payment Method Section**: Apple Pay button and credit card form with postal code - **Shopping Cart**: Order summary with item details and totals This example uses the `justifi-card-form` and `justifi-card-billing-form-simple` components within the `justifi-modular-checkout` wrapper, styled with CSS parts to match the design system. ## Example Usage JustiFi BREW [SHOP](#) [LEARN](#) 🛒 1 # Checkout --- ## Shipping [Edit](#) John Doe 123 Main St, Anytown, USA Standard Shipping: Free Arrive Thursday, October 31st --- ## Payment Method or By clicking Place Order you agree to the [Terms & Conditions.](#) ## Shopping Cart [Edit](#) Subtotal $38.00 Shipping Fee Free Tax $4.00 Order Total $42.00 ITEM QTY PRICE Drip Coffee Funnel 8 cups / 64 ounces 1 $38.00 ```html justifi-modular-checkout
JustiFi BREW

Checkout


Shipping

Edit
John Doe
123 Main St, Anytown, USA
Standard Shipping: Free
Arrive Thursday, October 31st

Payment Method

or
By clicking Place Order you agree to the{' '} Terms & Conditions.

Shopping Cart

Edit
Subtotal $38.00
Shipping Fee Free
Tax $4.00
Order Total $42.00
ITEM QTY PRICE
Drip Coffee Funnel
8 cups / 64 ounces
1
$38.00
``` --- # Layout 3 — Stripe-style Two-Column Source: https://docs.justifi.tech/web-components/modular-checkout/complete-examples/layout-3 A complete checkout form example that demonstrates a modern two-column payment layout with order summary and payment form side by side. This example showcases how to integrate the `justifi-modular-checkout` wrapper with `justifi-card-form` and `justifi-card-billing-form-simple` components to create a professional payment experience. The layout includes: - **Header Bar**: Back arrow, brand name, and test mode indicator - **Left Column**: Order summary with product details, pricing breakdown, and footer - **Right Column**: Payment form with email, card details, billing address, and submit button - **Card Form**: Secure iframe inputs for card number, expiration, and CVV - **Billing Form**: ZIP code input for billing information (using justifi-card-billing-form-simple) This example uses CSS parts to style the web components consistently with the overall design theme and demonstrates proper integration of the modular checkout components, including the `preCompleteHook` for custom validation or server updates before submission. ## Example Usage ← JustiFi Store # Pay JustiFi Store $39.99 📚 Fintech Deployhandbook Test How to deploy Fintech app... $39.99 Subtotal $39.99 Tax ⓘ Enter address to calculate Total due $39.99 Powered by JustiFi [Terms](#) [Privacy](#) ## Pay with card Email [Enter your email]() Name on card Enter cardholder name Billing address United States Address [Enter address manually](#) ```html justifi-modular-checkout
← JustiFi Store

Pay JustiFi Store

$39.99
📚
Fintech Deployhandbook Test
How to deploy Fintech app...
$39.99
Subtotal $39.99
Tax ⓘ
Enter address to calculate
Total due $39.99

Pay with card

Enter address manually
``` --- # Modular Checkout Sub-components Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components Each sub-component inherits authentication context from the parent checkout and can be slotted wherever your layout requires. Dive into the dedicated docs for implementation details: - [Card form](https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-form) - [Bank account form](https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-form) - [Billing form full](https://docs.justifi.tech/web-components/modular-checkout/sub-components/billing-form-full) - [Card billing form simple](https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-billing-form-simple) - [Bank account billing form simple](https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-billing-form-simple) - [Plaid payment method](https://docs.justifi.tech/web-components/modular-checkout/sub-components/plaid-payment-method) - [Sezzle payment method](https://docs.justifi.tech/web-components/modular-checkout/sub-components/sezzle-payment-method) - [Apple Pay](https://docs.justifi.tech/web-components/modular-checkout/sub-components/apple-pay) - [Google Pay](https://docs.justifi.tech/web-components/modular-checkout/sub-components/google-pay) - [Saved payment methods](https://docs.justifi.tech/web-components/modular-checkout/sub-components/saved-payment-methods) - [Season interruption insurance](https://docs.justifi.tech/web-components/modular-checkout/sub-components/season-interruption-insurance) - [Summary](https://docs.justifi.tech/web-components/modular-checkout/sub-components/summary) > Looking for additional rails? Duplicate any of these MDX files, adjust the front matter `id`, and follow the existing documentation scaffolding. --- # Card Form Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-form ## Overview Renders a form for collecting credit and debit card details as part of a checkout flow. This component is **designed to be used within** the `justifi-modular-checkout` and **does not accept props directly**. Instead, it relies on shared state passed through the Stencil Store, managed by the wrapper component. > **Note:** If you are using the card payment method, you also need to provide billing information. This can be done by using either the `justifi-billing-form-full` component for complete billing address, the `justifi-card-billing-form-simple` component for ZIP code only, or by passing the `billingInformation` object as an argument to the `submitCheckout` method called on the wrapper. The `billingInformation` object can contain all the fields or just the `address_postal_code` field. **Authorization** and business context are also handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. This component exposes **no public methods or properties** and is not intended for standalone use. ## Usage ```html justifi-card-form ``` ## Props, Events & Methods ### Events All submit and error events bubble through the parent ``, so no additional listeners are required on the card form. ## Theming & Layout - When embedded inside cards, wrap the host element in your layout container and scope typography overrides via the parts listed below. | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(skeleton)` | | — | | `::part(input)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(label)` | | — | | `::part(textDanger)` | | — | - Use the `card-form` CSS part (`::part(card-form)`) to apply box shadows or wrapper padding. --- # Apple Pay Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/apple-pay ## Overview Renders an Apple Pay button for eligible devices and orchestrates the Apple Pay flow. Designed to be used within `justifi-modular-checkout`. ## Usage ```html justifi-apple-pay ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | --------------------------------------------- | ----------- | | `button-style` | `ApplePayButtonStyle.BLACK \| ApplePayButtonStyle.WHITE \| ApplePayButtonStyle.WHITE_OUTLINE` | No | `ApplePayButtonStyle.BLACK` | | | `button-type` | `ApplePayButtonType.BOOK \| ApplePayButtonType.BUY \| ApplePayButtonType.CHECK_OUT \| ApplePayButtonType.DONATE \| ApplePayButtonType.PLAIN \| ApplePayButtonType.SET_UP \| ApplePayButtonType.SUBSCRIBE` | No | `ApplePayButtonType.PLAIN` | | | `country-code` | `string` | No | `"US"` | | | `disabled` | `boolean` | No | `false` | | | `height` | `string` | No | `"48px"` | | | `initiative-context` | `string` | No | `"dev-checkout.justifi-staging.com"` | | | `merchant-display-name` | `string` | No | `"JustiFi Checkout"` | | | `merchant-identifier` | `string` | No | `"merchant.com.staging-justifi.checkout-dev"` | | | `width` | `string` | No | `"100%"` | | ### Events - `applePayStarted`: Fires when the Apple Pay sheet is presented. - `applePayCompleted`: Fires when payment completes; includes success status and payment method details. - `applePayCancelled`: Fires when the user dismisses the Apple Pay sheet. - `applePayError`: Surfaces tokenization failures (network issues, validation errors, etc.). ### Public methods 1. `isSupported()` – Check if Apple Pay is available on the current device/browser. 2. `getPaymentMethods()` – Returns available payment method types. 3. `abort()` – Programmatically cancel an in-progress Apple Pay session. ## Theming & Layout - Styling is intentionally limited to keep Apple compliance. | Part | Description | DOM target | | ------------------ | ----------- | ---------- | | `::part(skeleton)` | | — | --- # Google Pay Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/google-pay ## Overview Renders a Google Pay button for eligible devices/browsers and orchestrates the Google Pay flow. Designed to be used within `justifi-modular-checkout`. ## Usage ```html justifi-google-pay ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ----------------------------------------------------------------------- | ------------------------ | -------- | -------------------- | ------------------------------------------------------------------------------------------ | | `environment` | `"PRODUCTION" \| "TEST"` | No | — | If not provided, the environment will be determined by the account mode: 'test' or 'live'. | | `merchant-display-name` | `string` | No | `"JustiFi Checkout"` | | | `use-native-payment-request` | `boolean` | No | `false` | Set to true when embedding inside an Android WebView so the iframe uses the | | W3C Payment Request API (native Google Pay sheet) instead of pay.js's | | | | | | loadPaymentData popup, which Google blocks in WebViews (OR\_BIBED\_15). | | | | | ### Events - `googlePayStarted`: Fires when the user clicks the Google Pay button, immediately before the payment sheet opens. - `googlePayCompleted`: Fires when payment completes; includes success status, payment method ID, card network, and card details (last 4 digits). - `googlePayCancelled`: Fires when the user dismisses the Google Pay sheet. ### Event Payloads **googlePayCompleted (success)** ```typescript { success: true, paymentMethodId: "pm_xxx", // JustiFi payment method ID cardNetwork: "VISA", // Card network (VISA, MASTERCARD, etc.) cardDetails: "1234" // Last 4 digits } ``` **googlePayCompleted (error)** ```typescript { success: false, error: { code: "PAYMENT_FAILED", message: "Error description" } } ``` ## Flow 1. Component checks device/browser eligibility for Google Pay 2. If eligible, Google Pay button renders 3. User clicks button → `googlePayStarted` fires → Google Pay sheet opens 4. User completes payment → `googlePayCompleted` event fires with `paymentMethodId` 5. Modular checkout automatically completes the checkout ## Theming & Layout - Styling is intentionally limited to keep Google Pay compliance. - Button renders at 48px height, 100% width. | Part | Description | DOM target | | ------------------ | ----------- | ---------- | | `::part(skeleton)` | | — | --- # Plaid Payment Method Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/plaid-payment-method ## Overview Renders a radio input for selecting the Plaid bank account payment method, and orchestrates the Plaid Link flow to securely connect a bank account when selected. This component is designed to be used within the `justifi-modular-checkout` and does not accept props directly. It relies on the shared state and context managed by `justifi-modular-checkout` (auth token, account ID, and checkout ID). Saving a new payment method is controlled via the `justifi-save-new-payment-method` checkbox when a payment method group is available. It exposes no public properties for configuration, but does emit Plaid-specific events for error handling and recovery. > Note: This component renders nothing and logs a console warning when bank account verification is not enabled for the checkout (`payment_settings.bank_account_verification !== true`), or when ACH payments are disabled for the checkout (`payment_settings.ach_payments !== true`). The same `payment_settings` apply to other ACH rails in modular checkout (for example `new_bank_account` and `saved_bank_account` in `availablePaymentMethodTypes`). ## Usage ```html justifi-plaid-payment-method ``` ## Props, Events & Methods ### Events - `plaidError`: Surfaces integration failures (expired link token, network issues, user errors). - `plaidErrorRecovered`: Fires when a previous Plaid error has been resolved and the flow can continue. ## Theming & Layout - Styling is limited to the wrapper since Plaid controls the Link modal. - Provide fallback instructions for devices where Plaid is unavailable. --- # Sezzle Payment Method Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/sezzle-payment-method ## Overview Renders a radio input for selecting the Sezzle payment method, if BNPL (Buy Now Pay Later) is enabled for the sub account. This component is **designed to be used within** the `justifi-modular-checkout` and **does not accept props directly**. Instead, it relies on the shared state passed through the Stencil Store, managed by the `justifi-modular-checkout` component. **Authorization** and business context are also handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. This component exposes **no public methods or properties** and is not intended for standalone use. ## Usage ```html justifi-sezzle-payment-method ``` ## Props, Events & Methods ### Events - `paymentMethodOptionSelected`: Emits when Sezzle is selected as the payment method. ## Theming & Layout - Respect Sezzle's branding by keeping the provided colors and logos intact. --- # Season Interruption Insurance Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/season-interruption-insurance ## Overview Component to render a formated list of season interruption insurance for the requested account. ## Usage ```html justifi-season-interruption-insurance ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | ------------------------------------ | -------- | -------- | ------- | ----------- | | `auth-token` | `string` | No | — | | | `checkout-id` | `string` | No | — | | | `covered-identity-first-name` | `string` | No | — | | | `covered-identity-last-name` | `string` | No | — | | | `policy-attributes-end-date` | `string` | No | — | | | `policy-attributes-insurable-amount` | `number` | Yes | — | | | `policy-attributes-start-date` | `string` | No | — | | | `primary-identity-country` | `string` | Yes | — | | | `primary-identity-email-address` | `string` | Yes | — | | | `primary-identity-first-name` | `string` | Yes | — | | | `primary-identity-last-name` | `string` | Yes | — | | | `primary-identity-postal-code` | `string` | Yes | — | | | `primary-identity-state` | `string` | Yes | — | | ### Events - `insurance-updated`: Fires after the component successfully toggles coverage via the insurance API. - `error-event`: Emits a `ComponentErrorEvent` if required props are missing or an API call fails. ### Public methods 1. `validate()` – Returns `{ isValid: boolean }` indicating whether the customer selected accept or decline. Uses the shared insurance validation helpers. ## Theming & Layout - The host inherits the same typography tokens as other Modular Checkout rails via `StyledHost`, so it naturally matches surrounding content. - Use the exposed parts to restyle copy or validation messaging without affecting the radios themselves. | Part | Description | DOM target | | ---------------------------------- | ----------- | ---------- | | `::part(text)` | | — | | `::part(textDanger)` | | — | | `::part(skeleton)` | | — | | `::part(heading2)` | | — | | `::part(inputRadio)` | | — | | `::part(inputRadioChecked)` | | — | | `::part(inputRadioCheckedFocused)` | | — | | `::part(inputRadioFocused)` | | — | | `::part(inputRadioInvalid)` | | — | | `::part(label)` | | — | | `::part(input)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(inputInvalidAndFocused)` | | — | --- # Saved Payment Methods Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/saved-payment-methods ## Overview Renders a radio input list of saved payment methods as part of a checkout flow. > Note: This sub component will only display saved payment methods if a `payment_method_group_id` with associated payment methods was passed to the [create checkout](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) API request. Saved **bank** methods are not offered as selectable options when ACH is disabled for the checkout (`payment_settings.ach_payments === false`), even if the payment method group contains bank accounts. This component is **designed to be used within** the `justifi-modular-checkout` and **does not accept props directly**. Instead, it relies on shared state passed through the Stencil Store, managed by the wrapper component. **Authorization** and business context are also handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. This component exposes **no public methods or properties** and is not intended for standalone use. ## Usage ```html justifi-saved-payment-methods ``` ## Props, Events & Methods ### Events This component does not emit any events directly. Events are handled by the parent `justifi-modular-checkout` component. ## Theming & Layout | Part | Description | DOM target | | ---------------------------------- | ----------- | ---------- | | `::part(radioListItem)` | | — | | `::part(inputRadio)` | | — | | `::part(inputRadioChecked)` | | — | | `::part(inputRadioCheckedFocused)` | | — | | `::part(inputRadioFocused)` | | — | | `::part(inputRadioInvalid)` | | — | | `::part(label)` | | — | | `::part(input)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(inputInvalidAndFocused)` | | — | --- # Checkout Summary Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/summary ## Overview Renders a summary of checkout details consisting of the checkout description and amount passed in the [create checkout API request](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) as part of a checkout flow. This component is **designed to be used within** the `justifi-modular-checkout` and **does not accept props directly**. Instead, it relies on the shared state passed through the Stencil Store, managed by the `justifi-modular-checkout` component. **Authorization** and business context are also handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. This component exposes **no public methods or properties** and is not intended for standalone use. ## Usage ```html justifi-checkout-summary ``` ## Props, Events & Methods ### Events No custom events; summary listens to the parent checkout for updates automatically. ### Public methods 1. `refresh()` – Fetch updated totals (useful if you change the checkout server-side). ## Theming & Layout | Part | Description | DOM target | | -------------- | ----------- | ---------- | | `::part(text)` | | — | --- # Bank Account Form Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-form ## Overview Renders a form for collecting bank account details as part of a checkout flow. This subcomponent is **designed to be used within** the `justifi-modular-checkout` and **does not accept props directly**. Instead, it relies on the shared state passed through the Stencil Store, managed by the `justifi-modular-checkout` component. > **Note:** If you are using this sub component, you also need to provide billing information. This can be done by adding the `justifi-billing-form-full` sub component for complete billing address, the `justifi-bank-account-billing-form-simple` sub component for account owner name only, or by passing the `billingInformation` object as an argument to the `submitCheckout` method called on the `justifi-modular-checkout`. See the [modular checkout docs](https://docs.justifi.tech/web-components/modular-checkout/introduction) for more information. > **Note:** If the checkout's `payment_settings.ach_payments` is `false`, this component does not render the form and logs a console warning (`[bank-account-form] ACH payments are disabled for this checkout (payment_settings.ach_payments=false).`). Prefer omitting the sub-component when ACH is off, or use `checkout-changed` / `availablePaymentMethodTypes` so your layout does not reserve an empty slot. **Authorization** and business context are also handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. This component exposes **no public methods or properties** and is not intended for standalone use. ## Usage ```html justifi-bank-account-form ``` ## Props, Events & Methods ### Events - Emits the same `submit` / `error` events as other modular rails via the parent checkout; no direct listeners required. ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(skeleton)` | | — | | `::part(input)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(label)` | | — | | `::part(textDanger)` | | — | --- # Billing Form Full Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/billing-form-full ## Overview Renders a form for collecting a complete billing address (name, address line 1 & 2, city, state, postal code) as part of a checkout flow. This component is **designed to be used within** the `justifi-modular-checkout` and works with both card and bank account payment methods. The wrapper component reads billing values during `submitCheckout` validation and tokenization. **Authorization** and business context are handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. ## Usage ```html justifi-billing-form-full ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------- | -------- | -------- | ------- | ----------- | | `legend` | `string` | No | — | | ### Events All submit and error events bubble through the parent ``, so no additional listeners are required on the billing form. ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(billingForm)` | | — | | `::part(heading3)` | | — | | `::part(input)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | | `::part(radioListItem)` | | — | --- # Card Billing Form Simple Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/card-billing-form-simple ## Overview Renders a minimal billing form that collects only the postal code (ZIP code). Intended for use with the `justifi-card-form` when a full billing address is not required. This component is **designed to be used within** the `justifi-modular-checkout` alongside `justifi-card-form`. The wrapper component reads billing values during `submitCheckout` validation and tokenization. **Authorization** and business context are handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. ## Usage ```html justifi-card-billing-form-simple ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------- | -------- | -------- | ------- | ----------- | | `legend` | `string` | No | — | | ### Events All submit and error events bubble through the parent ``, so no additional listeners are required on the billing form. ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(billingForm)` | | — | | `::part(input)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | --- # Bank Account Billing Form Simple Source: https://docs.justifi.tech/web-components/modular-checkout/sub-components/bank-account-billing-form-simple ## Overview Renders a minimal billing form that collects only the account holder name. Intended for use with the `justifi-bank-account-form` when a full billing address is not required for ACH payments. This component is **designed to be used within** the `justifi-modular-checkout` alongside `justifi-bank-account-form`. The wrapper component reads billing values during `submitCheckout` validation and tokenization. **Authorization** and business context are handled by `justifi-modular-checkout`, which manages authentication tokens and related configuration. ## Usage ```html justifi-bank-account-billing-form-simple ``` ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------- | -------- | -------- | ------- | ----------- | | `legend` | `string` | No | — | | ### Events All submit and error events bubble through the parent ``, so no additional listeners are required on the billing form. ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(billingForm)` | | — | | `::part(input)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | --- # Payment Facilitation Source: https://docs.justifi.tech/web-components/payment-facilitation Build an end-to-end payment experience by combining these focused guides: 1. [Unified Fintech Checkout™](https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™) – the full-stack checkout shell for authorization and capture. 2. [Tokenize Payment Method](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method) – vault cards or bank accounts for future use. 3. [Refund Payment](https://docs.justifi.tech/web-components/payment-facilitation/refund-payment) – return funds with audit-friendly status updates. 4. [Dispute Management](https://docs.justifi.tech/web-components/payment-facilitation/dispute-management) – monitor chargebacks and submit compelling evidence. > Once your payment-facilitation configuration is live, tie it into `[Entities](../entities)` and `[Merchant Tools](../merchant-tools)` to keep back-office teams in sync. --- # Tokenize Payment Method Source: https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method ## Overview Component to render an entire form including a switch to use a credit card or bank account, a submit button and all fields required for proper use. This component can be used standalone or as part of the modular checkout system. ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------------------------------- | --------- | -------- | ---------- | ----------- | | `account-id` | `string` | No | — | | | `auth-token` | `string` | No | — | | | `disable-bank-account` | `boolean` | No | — | | | `disable-credit-card` | `boolean` | No | — | | | `hide-bank-account-billing-form` | `boolean` | No | — | | | `hide-card-billing-form` | `boolean` | No | — | | | `hide-submit-button` | `boolean` | No | — | | | `payment-method-group-id` | `string` | No | — | | | `save-payment-method-label` | `string` | No | — | | | `submit-button-text` | `string` | No | `'Submit'` | | ### Events - `submit-event`: fires when tokenization completes; `event.detail.response` is the full payload (see [Response payload](#response-payload)). - `error-event`: fires if tokenization fails; payload includes `code`, `message`, and validation hints. ### Public methods 1. `tokenizePaymentMethod()` – programmatically trigger submission (returns a promise that resolves to the same payload emitted by `submit-event`). 2. `fillBillingForm(partialBillingDetails)` – prefill customers' billing information from saved data. 3. `validate()` – validate the form fields and return validation result. ### Response payload Both `submit-event` (`event.detail.response`) and the `tokenizePaymentMethod()` promise resolve to the **full payment method object**, not just the token: ```typescript interface PaymentMethodPayload { token?: string; // convenience: the payment method token (e.g. "pm_...") data?: { data?: { signature: string; customer_id: string; account_id: string; invalid_reason: string; // present for card payment methods: card?: { id: string; name: string; acct_last_four: number; brand: string; token: string; month: string; year: string; metadata: any; address_line1_check: string; address_postal_code_check: string; // BIN lookup details (when available): bin_details?: { type: 'Credit' | 'Debit' | 'Prepaid' | 'Unknown'; card_brand: string; card_class: string; country: string; issuer: string; funding_source: | 'Charge' | 'Credit' | 'Debit' | 'Deferred Debit (Visa Only)' | 'Network Only' | 'Prepaid'; }; }; // present for bank account payment methods: bank_account?: { id: string; account_owner_name: string; account_type: 'checking' | 'savings'; bank_name: string; acct_last_four: number; token: string; metadata: any; }; }; }; error?: { code: string; message: string; decline_code: string }; validationError?: boolean; } ``` > **Note:** `bin_details` is only populated for card payment methods and may be absent depending on the BIN lookup result. Always null-check before reading it (e.g. `response.data?.data?.card?.bin_details`). Bank accounts do not include `bin_details`. # Authorization --- Authorization is performed by passing a web component token as `auth-token`. - **Web Component Token**: These tokens are generated by your backend services using the [Web Component Tokens API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens/operation/CreateWebComponentToken). Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the role: `write:tokenize:account_id`. Make sure the value for `account_id` matches the prop you also pass separately. # Security --- The api endpoint associated with this component has the following security measures in place: 1. **Rate Limiting**: POST requests to are limited to 2 requests per 10 seconds. 2. **Token-based Request Limiting**: POST requests using web component token authentication are limited to 10 attempts per token. These measures are in place to prevent abuse and ensure the security of the payment processing system. **Note:** While `client-id` is still supported, we now recommend using web component tokens (`auth-token`) for enhanced security and flexibility. # Usage Patterns --- ## Standalone Usage When used standalone, the component provides its own submit button and handles all tokenization internally: ```html ``` ## External Control Hide the built-in submit button and control tokenization externally: ```html ``` ## Pre-filling Billing Information Use `fillBillingForm()` to programmatically pre-populate billing fields, e.g. from saved customer data. Values persist when the user switches between payment methods. ```javascript const tokenizer = document.querySelector('justifi-tokenize-payment-method'); tokenizer.fillBillingForm({ name: 'John Doe', address_line1: '123 Main St', address_city: 'Anytown', address_state: 'NY', address_postal_code: '12345', }); ``` All fields are optional except `address_postal_code`: ```typescript interface BillingFormFields { name?: string; address_line1?: string; address_line2?: string; address_city?: string; address_state?: string; address_postal_code: string; // required } ``` # Integration with Modular Checkout --- When used within the `justifi-modular-checkout` wrapper component, this component automatically adapts its behavior: - **Auto-detection**: The component automatically detects if it's slotted within a modular checkout - **Submit button hiding**: The submit button is automatically hidden when inside modular checkout - **Shared authentication**: Uses authentication tokens from the parent modular checkout component - **Coordinated validation**: Validation is coordinated by the modular checkout wrapper ```html ``` # Example Usage --- --- ```html justifi-tokenize-payment-method ``` ## Theming & Layout | Part | Description | DOM target | | ------------------------------------- | ----------- | ---------- | | `::part(radioListItem)` | | — | | `::part(inputRadio)` | | — | | `::part(inputRadioChecked)` | | — | | `::part(inputRadioCheckedFocused)` | | — | | `::part(inputRadioFocused)` | | — | | `::part(inputRadioInvalid)` | | — | | `::part(label)` | | — | | `::part(input)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(billingForm)` | | — | | `::part(inputDisabled)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(textDanger)` | | — | | `::part(heading3)` | | — | | `::part(inputCheckbox)` | | — | | `::part(inputCheckboxChecked)` | | — | | `::part(inputCheckboxCheckedFocused)` | | — | | `::part(inputCheckboxFocused)` | | — | | `::part(inputCheckboxInvalid)` | | — | | `::part(text)` | | — | | `::part(skeleton)` | | — | | `::part(buttonLoading)` | | — | | `::part(buttonPrimary)` | | — | | `::part(buttonSecondary)` | | — | | `::part(buttonSuccess)` | | — | | `::part(buttonDanger)` | | — | | `::part(buttonWarning)` | | — | | `::part(buttonInfo)` | | — | | `::part(buttonLight)` | | — | | `::part(buttonDark)` | | — | | `::part(buttonLink)` | | — | | `::part(buttonOutlinePrimary)` | | — | | `::part(buttonOutlineSecondary)` | | — | --- # Unified Fintech Checkout™ Source: https://docs.justifi.tech/web-components/payment-facilitation/unified-fintech-checkout™ ## Overview Component to render the necessary fields to enter proper payment method information and process a payment. You will need to first create a checkout via [Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts) to get the `checkout-id` required for this component. # Props, events and methods --- | Name | Type | Required | Default | Description | | -------------------------------- | ------------------------------------------------------------------------------------------- | -------- | ------- | --------------------------------------------------------------------------------------- | | `auth-token` | `string` | Yes | — | | | `checkout-id` | `string` | Yes | — | | | `disable-bank-account` | `boolean` | No | `false` | | | `disable-bnpl` | `boolean` | No | `false` | | | `disable-credit-card` | `boolean` | No | `false` | | | `disable-payment-method-group` | `boolean` | No | `false` | | | `google-pay-env` | `"PRODUCTION" \| "TEST"` | No | — | Passed to `justifi-google-pay` as `environment`. Omit to let the child use its default. | | `hide-bank-account-billing-form` | `boolean` | No | `false` | | | `hide-card-billing-form` | `boolean` | No | `false` | | | `preCompleteHook` | `(data: CheckoutState, resolve: (data: CheckoutState) => void, reject: () => void) => void` | No | — | | ### Events - `submit-event`: Emits when payment succeeds; payload includes the server response. - `error-event`: Fires if payment processing fails; includes error codes for analytics. - `loaded`: Emits when the checkout form is fully loaded. ### Public methods 1. `fillBillingForm(fields)` – Pre-populate billing form fields from saved customer data. 2. `validate()` – Validates all form fields and returns `{ isValid: boolean }`. # Pre-Complete Hook --- You can provide a `preCompleteHook` function to inspect the checkout state before submission proceeds. This is useful for implementing custom validation, user confirmation dialogs, or conditional payment restrictions based on business rules. The hook runs after validation and payment method tokenization (including Plaid exchange when applicable), and before the checkout is completed, so the state includes the latest values such as `paymentToken` when available. The hook receives three parameters: - `state`: A `CheckoutState` object containing the current checkout information - `resolve`: A function to call to proceed with submission - `reject`: A function to call to stop submission ```javascript const checkout = document.querySelector('justifi-checkout'); /** * CheckoutState example (shape): * { * selectedPaymentMethod: { id?: string, type: 'new_card' | 'apple_pay' | 'google_pay' | ... } | undefined, * paymentAmount: 5000, * totalAmount: 5000, * paymentCurrency: 'USD', * paymentDescription: 'Order #123', * savedPaymentMethods: [], * savePaymentMethod: false, * bnplEnabled: false, * applePayEnabled: true, * insuranceEnabled: false, * disableBankAccount: false, * disableCreditCard: false, * disablePaymentMethodGroup: false, * paymentToken: 'pm_123' // tokenized payment method id; Apple Pay, Google Pay and Plaid set this too (paymentMethodId) * } */ checkout.preCompleteHook = (state, resolve, reject) => { // Example: Require confirmation for large payments if (state.totalAmount > 100000) { const confirmed = confirm( `Confirm payment of $${(state.totalAmount / 100).toFixed(2)}?`, ); if (confirmed) { resolve(state); } else { reject(); } } else { resolve(state); } }; ``` > Important: Assign the hook as a JavaScript property on the element (e.g., `checkout.preCompleteHook = fn`). Do not pass it as an HTML attribute (e.g., `pre-complete-hook="..."`); functions must be set on properties, not attributes. # Pre-filling Billing Information --- Use `fillBillingForm()` to programmatically pre-populate billing fields, e.g. from saved customer data. Values persist when the user switches between payment methods. ```javascript const checkout = document.querySelector('justifi-checkout'); checkout.fillBillingForm({ name: 'John Doe', address_line1: '123 Main St', address_city: 'Anytown', address_state: 'NY', address_postal_code: '12345', }); ``` All fields are optional except `address_postal_code`: ```typescript interface BillingFormFields { name?: string; address_line1?: string; address_line2?: string; address_city?: string; address_state?: string; address_postal_code: string; // required } ``` # Payment methods --- The Unified Checkout automatically displays additional payment method options when they are enabled in your account settings and when device/browser or other eligibility constraints are met: - **Apple Pay**: Must be enabled in account settings. It renders automatically only on eligible devices/browsers; otherwise it will not appear. - **Sezzle (BNPL)**: Must be enabled in account settings. It displays automatically when available for the account. - **Plaid (Bank account verification)**: Bank and ACH-related options (including Plaid where applicable) depend on the checkout’s payment settings: ACH or bank payments and Plaid verification must both be enabled in account/checkout configuration, consistent with `payment_settings` on the [Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts). When those settings are off or ineligible, those options are not shown. No extra component configuration is required beyond enabling these features on the account. When unavailable or ineligible, these options are simply not shown. # Authorization --- Web Component Token: These tokens are generated by your backend services using the [Web Component Tokens API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens). Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the following roles: - `write:checkout:checkout_id` - use the `checkout_id` you receive when you create a checkout via [Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts) - `write:tokenize:account_id` - use the `account_id` you pass to the checkout API # Security --- The api endpoint associated with this component has the following security measures in place: 1. **Rate Limiting**: POST requests to are limited to 2 requests per 10 seconds. 2. **Token-based Request Limiting**: POST requests using web component token authentication are limited to 10 attempts per token. These measures are in place to prevent abuse and ensure the security of the payment processing system. # Example Usage --- --- ```html justifi-checkout
``` ## Theming & Layout | Part | Description | DOM target | | ------------------------- | ----------- | ---------- | | `::part(checkoutSummary)` | | — | | `::part(text)` | | — | | `::part(radioListItem)` | | — | --- # Refund Payment Source: https://docs.justifi.tech/web-components/payment-facilitation/refund-payment ## Overview Component to render a form for partially or fully refunding a payment based on a provided payment ID. ## Props, Events & Methods | Name | Type | Required | Default | Description | | -------------------- | --------- | -------- | ------- | ----------- | | `account-id` | `string` | Yes | — | | | `auth-token` | `string` | Yes | — | | | `hide-submit-button` | `boolean` | No | `false` | | | `payment-id` | `string` | Yes | — | | ### Events - `submit-event`: Emits when the refund is created; payload includes `refund_id` and amount. - `error-event`: Fires when validation or network calls fail. ### Public methods 1. `refundPayment()` – Trigger the refund flow programmatically (useful if the component is inside a modal with custom buttons). # Authorization --- Authorization is performed by passing a web component token as `auth-token`. - **Web Component Token**: These tokens are generated by your backend services using the [Web Component Tokens API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens/operation/CreateWebComponentToken). Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the role: `write:account:account_id`. Make sure the value for `account_id` matches the prop you also pass separately. # Example Usage --- --- ```html justifi-refund-payment ``` ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(input)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(inputAdornment)` | | — | | `::part(text)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(radioListItem)` | | — | | `::part(buttonLoading)` | | — | | `::part(buttonPrimary)` | | — | | `::part(buttonSecondary)` | | — | | `::part(buttonSuccess)` | | — | | `::part(buttonDanger)` | | — | | `::part(buttonWarning)` | | — | | `::part(buttonInfo)` | | — | | `::part(buttonLight)` | | — | | `::part(buttonDark)` | | — | | `::part(buttonLink)` | | — | | `::part(buttonOutlinePrimary)` | | — | | `::part(buttonOutlineSecondary)` | | — | --- # Dispute Management Source: https://docs.justifi.tech/web-components/payment-facilitation/dispute-management ## Overview Component to render notification of disputed payments and allow platform to respond to dispute via form submission. # Props, events and methods --- | Name | Type | Required | Default | Description | | ------------ | -------- | -------- | ------- | ----------- | | `auth-token` | `string` | Yes | — | | | `dispute-id` | `string` | Yes | — | | ### Events - `submit-event`: Fires when the dispute response is submitted or when a dispute is accepted. - `complete-form-step-event`: Fires when a form step is completed; includes server response and completed form step. - `click-event`: Fires when users click on actions; `event.detail.name` indicates the action (e.g., `nextStep`, `previousStep`, `cancelDispute`, `respondToDispute`, `submit`). - `error-event`: Captures upload or API issues. # Authorization --- Authorization is performed by passing a web component token as `auth-token`. - **Web Component Token**: These tokens are generated by your backend services using the [Web Component Tokens API](https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens/operation/CreateWebComponentToken). Each token can be scoped to perform a set number of actions and is active for 60 minutes. When creating a web component token for this specific component you'll need to use the role: `read:dispute:dispute_id` or `write:dispute:dispute_id`. Make sure the value for `dispute_id` matches the prop you also pass separately. # Events usage --- ```html ``` # Example Usage --- --- ```html justifi-dispute-management ``` ## Theming & Layout | Part | Description | DOM target | | -------------------------------- | ----------- | ---------- | | `::part(heading4)` | | — | | `::part(text)` | | — | | `::part(skeleton)` | | — | | `::part(heading2)` | | — | | `::part(tooltip)` | | — | | `::part(tooltipIcon)` | | — | | `::part(tooltipInner)` | | — | | `::part(inputAdornment)` | | — | | `::part(inputDisabled)` | | — | | `::part(inputFocused)` | | — | | `::part(inputGroup)` | | — | | `::part(inputInvalid)` | | — | | `::part(label)` | | — | | `::part(input)` | | — | | `::part(inputInvalidAndFocused)` | | — | | `::part(textDanger)` | | — | | `::part(radioListItem)` | | — | | `::part(buttonLoading)` | | — | | `::part(buttonPrimary)` | | — | | `::part(buttonSecondary)` | | — | | `::part(buttonSuccess)` | | — | | `::part(buttonDanger)` | | — | | `::part(buttonWarning)` | | — | | `::part(buttonInfo)` | | — | | `::part(buttonLight)` | | — | | `::part(buttonDark)` | | — | | `::part(buttonLink)` | | — | | `::part(buttonOutlinePrimary)` | | — | | `::part(buttonOutlineSecondary)` | | — | | `::part(heading5)` | | — | --- # JustiFi API Documentation reference Reference: https://docs.justifi.tech/api-spec Base URL: `https://api.justifi.ai/v1` ## Introduction The JustiFi API is a REST-based payment processing API. Our API has predictable, resource-oriented URLs, accepts JSON, and returns JSON. We use HTTP status codes and supply detailed error codes whenever possible. We'll provide you with both a `test` and `live` account with which to use our API. Each account will have its own API key, and the key you use to authenticate each request will determine whether to use your `test` or `live` account. When you use your `test` account, it won't affect your `live` data or move any real money. ## Getting Started To process a payment with JustiFi, follow these steps - [Get Your Accounts](#get-your-accounts) - [Get Your API Keys](#get-your-api-keys) - [Authenticate With JustiFi](#authenticate-with-justifi) - For Platforms, [Create and Onboard Your Sub Accounts](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) - [Create a Payment](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) ### Get Your Accounts Our customer onboarding team will work with you to create your `test` and `live` accounts. For platforms, our team will also guide you through setting up your sub accounts onboarding. Once you're up and running, you'll have access to the JustiFi API as well as the admin features at https://app.justifi.ai where you can see your account overview, payments, payouts, issue refunds, etc. ### Get Your API Keys Once your `test` and `live` accounts have been created, you'll have access to generate your API keys in the Developer Tools section of the app. You'll need a `test` key and a `live` key. Each key will provide you with a client id and a client secret, which you'll use to authenticate your API requests. Requests authenticated with your `test` key will use your `test` account; requests authenticated with your `live` key will use your `live` account. Make sure to store your client secrets somewhere secure (like a password manager) because this is the only time they'll display in the UI. Additionally, we can provide access to a sandbox environment upon request. ### Authenticate With JustiFi ##### Example OAuth Client Credentials Grant Request ```sh curl -X POST https://api.justifi.ai/oauth/token \ -H 'Content-Type: application/json' \ --data '{"client_id":"[your client id]","client_secret":"[your client secret]"}' ``` ##### Example Authenticated Response ```json { "access_token": "... this will be a very long string and is valid for 24 hours" } ``` ##### Example Authenticated Request ```sh curl -X POST https://api.justifi.ai/v1/payments \ -H 'Authorization: Bearer [access_token]' \ -H 'Content-Type: application/json' -H 'Idempotency-Key: a-unique-string-for-the-transaction' ``` JustiFi uses the OAuth Client Credentials authentication flow. To access, use your JustiFi client id and client secret to POST to https://api.justifi.ai/oauth/token. These are valid for 24 hours. The test key is prepended with `test_` and the live key is prepended with `live_`. Next, take the access token in that response and pass it in all subsequent requests as the `Authorization` header. This token is valid for 24 hours, so be sure to handle a `401 - Unauthorized` response by getting a new access token via the client credentials grant API. ## Idempotent Requests ##### Example Request with Idempotency-Key Header ```sh curl -X POST https://api.justifi.ai/v1/payments \ -H 'Authorization: Bearer [access_token]' \ -H 'Accept: application/json' -H 'Idempotency-Key: a-unique-string-for-the-transaction' ``` In order to guarantee that payments and other important transactions are only ever processed a single time, we leverage the `Idempotency-Key` header in our payments APIs. This means that you MUST provide an `Idempotency-Key` header along with your request, otherwise you'll receive an error. If a second request with same idempotent key is processed concurrently, it will result in a `409` error instead of double processing. If these requests fail with a network timeout or a `5XX` error, they should be retried with the same exact parameters. Once they're fully successful, you'll receive a `2XX` response. If you POST the same request and `Idempotency-Key` again, you'll get the response you originally received back. If you receive a `4XX` error, do not retry the request, unless the response code is a `409`. If you try the same `Idempotency-Key` with different parameters, your request will error and won't be possible to process. The `Idempotency-Key` header is only meant for a single transaction; it's there to protect against processing the same exact thing more than once. Once the parameters change, a request is considered distinct from the original request. You may use any string up to 100 characters long to identify your `Idempotency-Key`; we generally recommend using a generated uuid, but you may use any unique string. ## Pagination ##### Example Paginated Request ```sh curl -X GET https://api.justifi.ai/v1/payments?limit=25&after_cursor=token-from-page-info \ -H 'Authorization: Bearer [access_token]' \ -H 'Accept: application/json' ``` ##### Example Paginated Response ```sh { "id": null, "type": "array", "data":[ { "id":"py_438xBom2Drh55kE1WfyGLg", "amount": 1000, ... additional response attributes based on resource schema } ], "page_info": { "has_previous": false, "has_next": true, "start_cursor": "WyIyMDIyLTAxLTExIDE1OjI3OjM2LjAyNzc3MDAwMCIsImNhNjQwMTk1LTEzYzMtNGJlZi1hZWQyLTU3ZjA1MzhjNjNiYSJd", "end_cursor": "WyIyMDIyLTAxLTExIDEyOjU5OjQwLjAwNTkxODAwMCIsImQ0Njg5MGE2LTJhZDItNGZjNy1iNzdkLWFiNmE3MDJhNTg3YSJd" } } ``` All top-level API resources have support for bulk fetches via `array` API methods. JustiFi uses cursor-based pagination, which supports `limit`, `before_cursor` and `after_cursor`. Each response will have a `page_info` object that contains the `has_next` and `has_previous` fields, which tells you if there are more items before or after the current page. The `page_info` object also includes `start_cursor` and `end_cursor` values which can be used in conjunction with `before_cursor` and `after_cursor` to retrieve items from the API one page at a time. #### Standard `array` API Request Parameters
Parameter Description
limit The number of resources to retrieve. type: integer default: 25 minimum: 1 maximum: 100
after_cursor Token to fetch the next page of a list. type: string
before_cursor Token to fetch the previous page of a list. type: string
The `after_cursor`/`before_cursor` parameter determines which page of results will be returned. If `after_cursor` is the encoded `id` of the last record in the collection `has_next` will be false and you'll get an empty array response. If `before_cursor` is the encoded `id` of the first record in the collection `has_previous` will be false and you'll get an empty array response. The `limit` parameter determines the maximum number of results included in each response. If there are fewer records available than the `limit` value, the response will include all available records. The maximum value allowed is 100 with a default value of 25. If the `limit` value is an invalid type, the default value of 25 is used. #### Standard API Response Structure All of our responses are contained in the same envelope, for arrays the id field will be null and the object will be an array.
Attribute Description
id The id of the object returned. Will be null for arrays. type: string default: "a uuid"
type The type of object returned. type: string default: "array"
data The resource OR an array of the requested resources. type: array | object Notes: May be an empty array [] if no resources are available.
page_info The object containing pagination information. type: object Notes: Contains has_previous, has_next, start_cursor and end_cursor
## Testing Use these card numbers to test successful transactions as well as various error scenarios. Make sure to authenticate your requests using your `test` API key (these cards won't work for `live` payments). #### Successful Test Cards
Number Brand CVC Date
4242424242424242 Visa Any 3 digits Any future date
4000056655665556 Visa (debit) Any 3 digits Any future date
5555555555554444 Mastercard Any 3 digits Any future date
2223003122003222 Mastercard (2-series) Any 3 digits Any future date
5200828282828210 Mastercard (debit) Any 3 digits Any future date
5105105105105100 Mastercard (prepaid) Any 3 digits Any future date
378282246310005 American Express Any 4 digits Any future date
371449635398431 American Express Any 4 digits Any future date
6011000990139424 Discover Any 3 digits Any future date
#### Declined Test Cards
Number Description Tokenization Succeeds
4000000000000101 If a CVC number is provided, the cvc_check fails. true
4000000000000341 Tokenizing this card succeeds, but attempts to make a payment fail. true
4000000000000002 Payment is declined with a card_declined code. true
4000000000009995 Payment is declined with a card_declined code. The decline_code attribute is insufficient_funds. true
4000000000009987 Payment is declined with a card_declined code. The decline_code attribute is lost_card. true
4000000000009979 Payment is declined with a card_declined code. The decline_code attribute is stolen_card. true
4000000000000069 Payment is declined with an expired_card code. true
4000000000000127 Payment is declined with an invalid_cvc code. true
4000000000000119 Payment is declined with a gateway_error code. true
4242424242424241 Payment is declined with an card_number_invalid code as the card number fails the Luhn check. false
#### Successful Bank Account (ACH)
Routing Number Account Number
110000000 000123456789
#### Declined Bank Accounts (ACH)
Routing Number Account Number Payment Error
110000000 000222222227 Insufficient Funds
110000000 000333333335 The account doesn't support debits
110000000 000111111113 The account is closed
110000000 000111111116 The account doesn't exist
## HTTP Errors The JustiFi API may return a number of standard HTTP errors due to invalid requests. Some common errors are described below to help you build with JustiFi. #### Bad Request The server cannot process the request. This error is most likely due to malformed request syntax. - code: `400` - status: `Bad Request` #### Unauthorized Similar to a `403 Forbidden`, but specifically when authentication is provided and has failed, or has not been provided. This error is most likely due to not including your API key in the request header. - code: `401` - status: `Unauthorized` #### Payment Required There was an error processing the payment. This response is returned when errors occur while tokenizing the payment method, such as an invalid cvc or an expiration date in the past. This can also occur when making a payment and the card is declined. In that case, the error message will provide more specific information about why the request was declined. - code: `402` - status: `Payment Required` #### Forbidden The request was valid, but you are unable to execute the request. This error is most likely due to the API key that was used not having the necessary permissions, or attempting a prohibited action such as creating a duplicate record where one already exists. - code: `403` - status: `Forbidden` #### Not Found The requested resource could not be found, but may be available in the future. This error is most likely due to requesting a resource by `id` that doesn't exist. You'll want to double check that you're referencing the correct `id` and that it exists on your account. - code: `404` - status: `Not Found` #### Concurrent Request Error The request has an identical `Idempotency-Key` header for another request which either failed OR is processing at the same time. You can retry these requests without risk of double processing. - code: `409` - status: `Conflict` #### Unprocessable Entity The request was well-formed, but was unable to be processed due to semantic errors. This error is most likely due to including invalid data in `POST`, `PATCH`, and `PUT` requests. Double check the request documentation to make sure you're supplying the required attributes, and that the attribute types are correct. - code: `422` - status: `Unprocessable Entity` #### Internal Server Error An internal server error occurred due to an unexpected condition. This error is most likely due to an issue with our servers. - code: `500` - status: `Internal Server Error` #### Error Codes Many of our `4XX` errors will provide an error code in addition to their HTTP status. Here is a list of our error codes and a brief description of the error to provide more context when applicable.
Error Code Description
acct_last_four_required Missing required parameter: acct_last_four
amount_below_minimum Amount must be greater than 50
amount_must_be_an_integer Amount must be an integer
amount_required Missing required parameter: amount
amount_above_maximum Amount must be lower than 100000000 ($1,000,000.00)
amount_below_minimum Amount must be greater than 50
application_fee_rate_id_required Missing required parameter: application_fee_rate_id
application_fee_required Missing required parameter: application_fee
brand_required Missing required parameter: brand
capture_strategy_invalid Format is invalid for parameter: capture_strategy
card_decline_rate_limit_exceeded This card has been declined too many times. You can try to charge this card again after 24 hours. We suggest reaching out to your customer to make sure they have entered all of their information correctly and that there are no issues with their card.
card_declined The card has been declined. When a card is declined, the error includes a decline_code attribute specifying the reason for the decline, and a network_decline_code provided by the card network, if available.
card_name_required Missing required parameter: card_name
card_number_invalid Format is invalid for parameter: card_number
card_number_required Missing required parameter: card_number
card_present_payment_method_token_not_supported card_present payment method tokens cannot be used to create a payment. Payment methods with the payment_method_type card_present are recorded from terminal transactions and are single use. To charge the customer again, collect a new payment method.
charge_expired_for_capture The charge cannot be captured as the authorization has expired. Auth and capture charges must be captured within 7 days.
country_invalid Format is invalid for parameter: country
currency_invalid Format is invalid for parameter: currency
currency_required Missing required parameter: currency
customer_id_required Missing required parameter: customer_id
customer_max_payment_methods The maximum number of PaymentMethods for this Customer has been reached. Either detach some PaymentMethods from this Customer or proceed with a different Customer.
email_invalid The email address is invalid (e.g., not properly formatted). Check that the email address is properly formatted and only includes allowed characters.
email_required Missing required parameter: email
expired_card The card has expired. Please check the expiration date or try a different card or payment method.
gateway_account_id_required Missing required parameter: gateway_account_id
gateway_authentication_error The payment network returned an authentication error
gateway_error There was an issue processing your payment with the gateway. Please try again later.
gateway_idempotency_error The gateway detected concurrent requests using this idempotency key
gateway_rate_limit_error Too many requests hit the API too quickly. We recommend an exponential back-off of your requests.
gateway_ref_id_required Missing required parameter: gateway_ref_id
gateway_timeout_error There was a timeout with the gateway, we recommend retrying using the Should-Retry header
idempotency_concurrent_request We detected concurrent requests using this idempotency key
idempotency_key_required Idempotency-Key is a required header
idempotency_params_mismatch The request parameters do not match those of a previous request using this idempotency key
idempotency_request_in_progress Another request using this idempotency key is currently in progress
internal_server_error An unexpected error has occurred. JustiFi engineers will investigate the error and contact you if any remediation steps are necessary.
invalid_address The card’s address is incorrect. Please check the address or try a different card or payment method.
invalid_card_number The card’s number is incorrect. Please check the number or try a different card or payment method.
invalid_card_brand The card’s brand is not supported. Please use Visa, Mastercard, American Express, or Discover, or try a different payment method.
invalid_characters This value provided to the field contains characters that are unsupported by the field.
invalid_charge_amount Your transaction was declined because the payment amount is outside the limits set by your card issuer. Please try a different card or payment method.
invalid_cvc The card’s security code is incorrect. Please check the security code or try a different card or payment method.
invalid_expiry_month The card’s expiration month is incorrect. Please check the expiration date or try a different card or payment method.
invalid_expiry_year The card’s expiration year is incorrect. Please check the expiration date or try a different card or payment method.
invalid_expiry_date The provided expiration date is invalid. Please check the expiration date or try a different card or payment method.
invalid_zip_code The card’s postal code is incorrect. Please check the postal code or try a different card or payment method.
month_invalid Format is invalid for parameter: month
not_authenticated Not authenticated
not_authorized Not authorized
parameter_missing Missing required parameter
payment_fully_refunded The refund cannot be processed because the associated payment is fully refunded
payment_intent_cannot_be_captured Payment Intent status is '%{status}' so it cannot be captured
payment_intent_not_found Payment intent not found
payment_intent_unexpected_state You cannot provide a new payment method to a PaymentIntent when it has a status of requires_capture, canceled, or succeeded
payment_method_not_found Payment method not found
payment_method_required Missing required parameter: payment_method
payment_method_token_required Missing required parameter: payment_method_token
payment_outside_refund_window The refund cannot be processed because the associated payment is outside the refund window
postal_code_invalid Format is invalid for parameter: postal_code
refund_error An error occurred during refunding your payment, JustiFi engineers have been alerted and are working on a solution
refund_exceeds_amount_available The refund cannot be processed because the refund amount exceeds the available funds
refund_exceeds_payment_amount The refund cannot be processed because the refund amount exceeds the associated payment amount
refund_reason_invalid Refund reason must be one of the following: %{Refund::REASONS}
resource_not_found Resource not found
state_invalid Format is invalid for parameter: state
token_already_used The token provided has already been used. You must create a new token before you can retry this request.
token_in_use The token provided is currently being used in another request. This occurs if your integration is making duplicate requests simultaneously.
transfer_required Missing required parameter: transfer
unexpected_parameter Unexpected parameter for this request
verification_invalid Format is invalid for parameter: verification
year_invalid Format is invalid for parameter: year
service_not_allowed This account is not permitted to process the type of transaction being requested, or the surcharge amount is invalid
do_not_honor This card has been rejected by the issuing bank. Please try a different card or payment method.
do_not_retry This card has been rejected. Please try a different card or payment method.
refund_in_progress A refund for this payment is already in progress
invalid_sub_account The sub account cannot process a payment for this card. Please contact customer support.
new_card_issued The transaction was denied because the issuing bank has issued a new card. Please try a different card or payment method.
account_closed The account associated with this payment method is been closed. Please try a different card or payment method.
restricted_card This card has a restriction preventing approval for this transaction. Please try a different card or payment method.
restricted_card This card has a restriction preventing approval for this transaction. Please try a different card or payment method.
insufficient_funds This card has insufficient funds. Please try a different card or payment method.
exceeds_card_limit The payment amount would exceed a limit placed on this card.
pin_tries_exceeded The number of PIN retries has been exceeded.
incorrect_pin The entered PIN is incorrect.
pin_required A PIN is required.
payment_outside_void_window The void cannot be processed because the associated payment is outside the void window. Try a refund instead.
issuer_not_available The card issuer is not available. Please try again later.
amount_too_small The specified amount is less than the minimum amount allowed. Use a higher amount and try again.
amount_too_large The specified amount is less than the minimum amount allowed. Use a higher amount and try again.
gateway_error_please_retry There was a temporary issue processing this payment. Please try again.
checkout_invalid_currency The currency parameter does not match the currency this account is configured to process.
## Network Errors We provide the network error code, and the network error category to help inform you how to handle a decline. These are only returned when a transaction fails while trying to process on the card network. Please take a look at each section. The network error category is especially relevant for recurring payments. It can reduce retries on transactions which will never succeed. ### Network Error Codes In addition to the standard error codes provided by JustiFi, some errors may include a `network_error_code` that provides more specific information about the error from the payment network. Here's a list of common `network_error_code` values and their meanings: | Code | Description | Customer Impact & Suggested Actions | | ---- | ----------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 005 | Do not honor (Declined by card association) | The payment was declined by the card association. The customer should try a different payment method or contact the card issuer for more information. | | 100 | Do not honor (Declined by card association) | The payment was declined by the card association. The customer should try a different payment method or contact the card issuer for more information. | | 101 | Expired card | The provided card has expired. The customer needs to update with a new, non-expired card or provide a different payment method. | | 102 | Suspected Fraud | The payment was flagged as potentially fraudulent activity. The customer should contact the card issuer to verify the transaction. | | 104 | Restricted card | The provided card is restricted and cannot be used for this transaction type. The customer needs to use a different payment method or contact the card issuer. | | 106 | Allowable PIN tries exceeded | The maximum allowable PIN entry attempts have been exceeded. The customer should verify the PIN and try again, or use a different payment method. | | 110 | Invalid amount | The payment amount entered is invalid. The customer needs to recheck the amount and retry the transaction. | | 116 | Not sufficient funds | There are insufficient funds in the account to cover this payment. The customer should add funds to the account or use a different payment method. | | 117 | Incorrect PIN or PIN length error | The entered PIN is incorrect or has an invalid length. The customer should re-enter the correct PIN and try again. | | 119 | Transaction not permitted to cardholder | This transaction is not permitted for the provided card/account. The customer should contact the card issuer or use a different payment method. | | 121 | Exceeds withdrawal amount limit | The payment amount exceeds the maximum allowed withdrawal limit. The customer should try a smaller amount or use a different payment method. | | 122 | Security violation | A security violation was detected with this payment. The customer should contact the card issuer for assistance. | | 123 | Exceeds withdrawal frequency limit | The maximum number of allowed withdrawals within the set time period has been exceeded. The customer should try again later or use a different payment method. | | 124 | Violation of law | This payment violates applicable laws or regulations and cannot be processed. The customer needs to use a different payment method. | | 129 | Suspected counterfeit card | The card has been flagged as potentially counterfeit. The customer should contact the card issuer immediately. | | 131 | Invalid account number | The provided account number is invalid. The customer needs to verify the account details and try again with the correct information. | | 132 | Unmatched card expiry date | The provided expiration date does not match the card issuer's records. The customer should confirm the correct expiry date and retry. | | 134 | Not sufficient funds | There are insufficient funds in the account to cover this payment. The customer should add funds to the account or use a different payment method. | | 152 | Exceeds limit | The payment amount exceeds the maximum limit allowed. The customer should try a smaller amount or use a different payment method. | | 154 | Over monthly limit | The maximum monthly payment limit has been exceeded. The customer should try again next month or use a different payment method. | | 208 | Lost Card / Lost Check | The card or check was reported as lost. The customer needs to use a different, valid payment method. | | 209 | Stolen card | The card was reported as stolen. The customer should contact the card issuer immediately and use a different payment method. | | 213 | Invalid account number for card type | The provided account number is invalid for the specified card type. The customer needs to verify the account details and retry with the correct information. | | 231 | Stop payment requested for all payments | A stop payment has been requested on this account, so no payments can be processed. The customer should contact the card issuer for assistance. | | 232 | Stop all payments – account closed | This account has been closed, so no payments can be processed. The customer needs to use a different payment method or contact support to update the account details. | | 237 | Deny – new card issued | A new card has been issued for this account. The customer needs to update the payment method with the new card details and retry. | | 302 | Account closed | The account the customer is trying to pay from is closed and cannot be used. The customer needs to update with a different, valid payment method. | | 317 | Max balance exceeded | This payment would cause the account balance to exceed the maximum allowed limit. The customer should try a smaller amount or use a different payment method. | | 351 | Customer PIN authentication required | The customer must authenticate this payment by entering the PIN. The customer should follow the prompts to complete PIN authentication. | | 414 | Void/Full Reversal request unable to process due to network cut-off window elapsed | The void or reversal request could not be processed because the network cut-off time has passed. A refund may be required instead. | | 500 | Generic error | A generic error occurred while processing this payment. The customer should try again later or use a different payment method. | | 503 | New Account Information | New account information is available for this payment method. The customer needs to update the account details and retry the payment. | | 504 | Do not try again | This payment was declined and should not be retried with this payment method. The customer needs to use an alternative method. | | 505 | Please retry | There was a temporary issue processing this payment. The customer should retry the same payment again. | | 512 | Service not allowed or invalid surcharge amount | This service or surcharge amount is not permitted for the account. The customer needs to verify the account details or try a different payment type. | | 516 | Please retry – Reasons include: Format Error, Unable to route transaction, Switch or issuer unavailable, System Busy, Timeout | A temporary issue caused this payment to fail, the customer should retry. If it continues to fail, the card issuer should be contacted. | | 517 | CVV2 Declined | The entered CVV2/CVC security code was declined. The customer should verify the code and retry with the correct information. | | 531 | Retry with 3DS data - 3D Secure authentication is required for this transaction, but not supported at this time | This card requires 3D Secure authentication which is not currently supported. The customer should use an alternative payment method or contact the card issuer. | | 528 | Debit/EBT transaction count exceeds pre-determined limit in specified time/ Withdrawal limit exceeded | The maximum allowed debit/EBT transaction count or withdrawal limit for the given time period has been exceeded. The customer should try again later or use a different payment method. | | 902 | Invalid Transaction | The payment transaction data was invalid and could not be processed. The customer needs to verify the payment details and retry. | | 907 | Card issuer or switch inoperative or processor not available | There was an issue with the card issuer's systems or payment processor during this transaction. The customer should retry later or use another payment method. | ### Network Error Category Both Visa and Mastercard send additional information about how to handle a declined payment for recurring payments. Effective May 30th, 2025 we pass through this information to help handle failures. We have added the `network` and `network_error_category` attributes to declined payments, when we get the additional information from the card networks. We are working on further classification of errors, for now please only respond to those documented here. | network | network_error_category | Definition | | ---------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | VISA | 1 | Issuer will never approve. Do not attempt again. This indicates the card is invalid, never existed or block. Cardholders can contact their bank for more information. | | VISA | 2 | Issuer cannot approve at this time. They may try again at another time. This could be related to credit risk, velocity controls, or system issues. | | VISA | 3 | Issuer cannot approve based on the details provided. This might be an invalid cvv, expiration date, etc. Do not try again without attempting to obtain additional information. | | VISA | R00/R01 | Recurring payment not allowed on card. Do not attempt again. | | MASTERCARD | 01 | Updated information needed. Similar to Visa code 3. | | MASTERCARD | 02 | Try again later. Similar to Visa code 2. | | MASTERCARD | 03 | Do not try again. Do not attempt again. Similar to Visa code 1. | | ALL | R0 | Stop this payment. Stops one specific recurring payment for one merchant and a specific card account. | | ALL | R1 | Stop all future payments. Stops all eligible transactions for one merchant and a specific card account. | | ALL | R3 | Stop all merchants. Stops all payments on a specific card account. | ## ACH Errors ACH (Automated Clearing House) transactions are transfers from the payer's bank account to the seller's bank account. If the funds can't be transferred we receive an error from the banking partners. Most of these errors are returned within 2 business days after the payment was submitted but can occur later. In the case of an error JustiFi will update the payment status to `failed` and populate the `error_description` property on the payment. To get real time notification about a failure [subscibe to the `payment.failed` event](https://docs.justifi.tech/api-spec#tag/Events). The most common ACH errors are described below. | Description | Customer Impact & Suggested Actions | |------------------------------------|-------------------------------------------------------------------------------------------------------- | | ACCOUNT_CLOSED | The cutsomer's bank account is closed and cannot be used. The customer needs to retry the payment with a different, valid payment method. | | ACCOUNT_FROZEN_OR_RETURNED_OFAC_INSTRUCTION | The customer's bank rejected the transaction because the debit was not approved by the customer. Reach out to the customer. | | ACCOUNT_NOT_FOUND | The receiving bank rejected the transaction because the account number entered does not match an active or existing bank account. The customer needs to verify the account details and try again with the correct information. | | BENEFICIARY_OR_ACCOUNT_HOLDER_DECEASED | The transaction was rejected because the account holder has passed away. | | CHECK_TRUNCATION_EARLY_RETURN | The electronically deposited check was not deposited successfully. The customer needs to attempt payment again. | | CORPORATE_CUSTOMER_ADVISES_NOT_AUTHORIZED | The corporate account holder has notified their bank that the attempted ACH debit was not authorized. Reach out to the customer. | | CUSTOMER_ADVISE_INVALID_TRANSACTION | The customer's bank rejected the debit because the account holder disputed the payment. The customer either claimed the charge was unauthorized, outside the terms of authorization, or improperly processed. | | CUSTOMER_REVOKED_AUTHORIZATION | The account holder explicitly instructed their bank to cancel the permission they previously gave to draft funds from their bank account. Reach out to the customer. | | DUPLICATE_ENTRY | The receiving bank has identified the transaction as a repeat of a previously processed payment and has rejected or reversed it. | | INSUFFICIENT_FUNDS | The bank account has insufficient funds to cover this payment. The customer should add funds to the account or use a different payment method. | INVALID_ACCOUNT_NUMBER | The provided bank account number is invalid. The customer needs to verify the account details and try again with the correct information. | | INVALID_ACH_ROUTING_NUMBER | The provided bank routing number is invalid. The customer needs to verify the account details and try again with the correct information. | | NON_TRANSACTION_ACCOUNT | The customer's bank account is restricted from processing electronic payments; it might be a savings account, money market account, loan account, etc. The customer needs to try again with a different payment method. | | PAYMENT_STOPPED | The bank account holder formally requested to cancel a specific pending or recurring transaction. Reach out to the customer. | | UNAUTHORIZED_DEBIT | The customer's bank flagged the transaction because it lacked the proper preauthorization, the amount pulled was incorrect, or funds were taken at a time the customer did not agree to. Reach out to the customer. | | UNCOLLECTED_FUNDS | The customer's account has enough total funds, but a portion of it is still processing and can't be released for the withdrawal of the payment. The payment should be retried when the account holds sufficient available funds. | | VALIDATION_ERROR | The provided transaction data fails technical or formatting requirements and the payment request was blocked by the gateway, processor, or bank before it entered the ACH network. The customer needs to verify the account details and try again with the correct information. | | ## Enhanced Fee Management JustiFi's enhanced fee management gives platforms granular control over how fees are charged and—importantly—how they are returned when processing refunds. > **New Integrations**: If you're building a new integration, use the `fees` array described below. This is the recommended approach for all new implementations. > > **Existing Integrations**: The `application_fee_amount` field continues to work unchanged. You can migrate to the new structure at your own pace—we'll provide migration support in a future release. ### Overview The enhanced fee structure separates your fees into distinct types, each tracked independently: | Fee Type | Description | |----------|-------------| | `processing_fee` | Fees related to payment processing costs | | `platform_fee` | Fees for your platform's services | This separation enables: - **Selective refunds**: Return the processing fee while keeping your platform fee, or vice versa - **Clear reporting**: Each fee type appears as a separate line item in balance transactions - **Remaining amount tracking**: Track how much of each fee can still be refunded ### Supported Endpoints | Endpoint | Request Field | Description | |----------|---------------|-------------| | [Create Payment](#tag/Payments/operation/CreatePayment) | `fees` | Specify fees when creating a payment | | [Refund a Payment](#tag/Payments/operation/CreateRefund) | `fees` | Choose which fees to return to the merchant | | [Create Checkout](#tag/Checkouts/operation/CreateCheckout) | `payment.fees` | Specify fees for the checkout | | [Refund a Checkout](#tag/Checkouts/operation/RefundCheckout) | `fees` | Choose which fees to return | ### Creating Payments with Fees **Request:** ```json POST /v1/payments { "amount": 10000, "currency": "usd", "capture_strategy": "automatic", "fees": [ { "type": "processing_fee", "amount": 350 }, { "type": "platform_fee", "amount": 500 } ], "payment_method": { "token": "pm_xyz" } } ``` **Response (Create):** > **Important:** The `fees` array will be **empty** in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects once they are available. Alternatively, you can poll with a [Get Payment](#tag/Payments/operation/GetPayment) request. ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "amount": 10000, "fee_amount": 850, "fees": [] } } ``` **Response (Webhook Events / Get Payment):** When receiving a payment webhook event or fetching a payment, the `fees` array is populated with the full fee objects: ```json { "fees": [ { "id": "pyfee_abc", "type": "processing_fee", "amount": 350, "remaining_amount": 350, "currency": "usd" }, { "id": "pyfee_xyz", "type": "platform_fee", "amount": 500, "remaining_amount": 500, "currency": "usd" } ] } ``` ### Refunding Payments with Selective Fee Return You control exactly which fees are returned to the merchant. This enables flexible refund policies. **Request:** ```json POST /v1/payments/{id}/refunds { "amount": 5000, "reason": "customer_request", "fees": [ { "type": "processing_fee", "amount": 175 } ] } ``` In this example: - $50.00 is refunded to the customer - $1.75 processing fee is returned to the merchant - The platform fee is retained **Response:** ```json { "id": "re_xyz", "type": "refund", "data": { "id": "re_xyz", "amount": 5000, "status": "succeeded", "returned_fees": [ { "id": "rtfee_xyz", "payment_fee_id": "pyfee_abc", "type": "processing_fee", "returned_amount": 175, "original_amount": 350, "remaining_amount": 175, "currency": "usd" } ] } } ``` After this refund, fetching the payment shows the updated `remaining_amount`: ```json { "fees": [ { "id": "pyfee_abc", "type": "processing_fee", "amount": 350, "remaining_amount": 175, "currency": "usd" }, { "id": "pyfee_xyz", "type": "platform_fee", "amount": 500, "remaining_amount": 500, "currency": "usd" } ] } ``` > **Note**: If no `fees` array is provided in the refund request, no fees are returned to the merchant. ### Creating Checkouts with Fees For checkouts, use the `payment.fees` field: **Request:** ```json POST /v1/checkouts { "amount": 10000, "description": "Order #12345", "payment": { "fees": [ { "type": "processing_fee", "amount": 295 }, { "type": "platform_fee", "amount": 150 } ] } } ``` **Response:** ```json { "id": "cho_xyz", "type": "checkout", "data": { "id": "cho_xyz", "payment_amount": 10000, "status": "created", "payment": { "fees": [ { "type": "processing_fee", "amount": 295 }, { "type": "platform_fee", "amount": 150 } ] } } } ``` When the checkout is completed, the fees are passed to the payment and tracked with `remaining_amount`. ### Refunding Checkouts with Fee Return **Request:** ```json POST /v1/checkouts/{id}/refunds { "amount": 5000, "fees": [ { "type": "processing_fee", "amount": 147 } ] } ``` **Response:** ```json { "id": "chr_xyz", "type": "checkout_refund", "data": { "id": "chr_xyz", "checkout_id": "cho_xyz", "status": "succeeded", "refund_amount": 5000, "returned_fees": [ { "type": "processing_fee", "amount": 147 } ] } } ``` ### Validation Rules | Rule | Error Code | Description | |------|------------|-------------| | Fee type required | `fees_invalid` | Fee type must be `processing_fee` or `platform_fee` | | Amount required | `fee_amount_greater_than_zero` | Fee amount must be an integer greater than 0 | | No duplicate types | `multiple_of_same_fee_type` | Only one fee per type is allowed | | Fees within limit | `fee_amount_greater_than_payment_amount` | Total fees cannot exceed the payment amount | | No mixing fee types | `fee_and_application_fee_declared` | Cannot use both `fees` and `application_fee_amount` | | Fee type exists | `fee_type_must_exist_on_payment_fees` | Refund fee type must exist on the original payment | | Within remaining | `returned_fee_exceeds_remaining_amount` | Refund amount cannot exceed the fee's remaining amount | ### Fee Lifecycle When using the enhanced fee structure (`fees` array), fees are handled as follows throughout the payment lifecycle: | Event | Fee Behavior | |-------|--------------| | **Payment captured** | Fees are charged and appear as separate balance transactions by type | | **Refund** | You control which fees (if any) to return via the `fees` array in the refund request | | **ACH return** | All fees are automatically returned to the merchant | | **Void** | All fees are automatically returned to the merchant | For refunds, if no `fees` array is provided in the refund request, no fees are returned—giving you full control over your refund policy. For ACH returns and voids, fee returns happen automatically since the original payment is reversed. > **Note**: Payments created with `application_fee_amount` (legacy structure) continue to behave as before—this fee lifecycle applies only to payments using the `fees` array. ### Balance Transactions Each fee type creates separate balance transaction entries for clear tracking: **When a payment is captured:** | Transaction Type | Account | Description | |------------------|---------|-------------| | `seller_payment` | Merchant | Payment amount credited | | `processing_fee` | Merchant | Processing fee deducted | | `processing_fee_credit` | Platform | Processing fee credited | | `platform_fee` | Merchant | Platform fee deducted | | `platform_fee_credit` | Platform | Platform fee credited | **When fees are returned (refund/ACH return/void):** | Transaction Type | Account | Description | |------------------|---------|-------------| | `processing_fee_return` | Merchant | Processing fee returned (credit) | | `processing_fee_return` | Platform | Processing fee return (debit) | | `platform_fee_return` | Merchant | Platform fee returned (credit) | | `platform_fee_return` | Platform | Platform fee return (debit) | ### Reporting Each fee type appears as a separate line item in: - Balance transactions for both merchants and platforms - Subaccount payout reports - Platform proceeds reports This gives merchants clear visibility into their true processing costs versus platform charges, and gives platforms detailed revenue breakdowns by fee type. ### CAD (Canadian Dollar) Payments The enhanced fee management features described above — including the `fees` array, `application_fee_amount`, and selective fee returns on refunds — are **not available for CAD payments**. For Canadian dollar payments, fees are determined during merchant onboarding and are not configurable via the API: - The `fees`, `application_fee_amount`, and `application_fees` parameters are not supported on CAD payment or checkout requests - Fee data is available via the `fees` array on the payment record (available via Get Payment API or payment events) as a `processing_fee`. The `application_fee` object will be `null` - **Balance transactions** are created when settlements are imported — not at payment capture time - The `fees` parameter on refund requests is not supported for CAD payments - When a refund incurs a processing fee, it appears in the payment's `fees` array as a `refund_processing_fee` whose `refund_id` links it to the associated refund For more details, see the [Canadian Payments guide](https://docs.justifi.tech/payments/canadianPayments). ### For Existing Integrations The `application_fee_amount` field continues to work unchanged for existing integrations. When you're ready to adopt the enhanced fee structure: 1. Replace `application_fee_amount` with the `fees` array 2. Decide how to split your fee between `processing_fee` and `platform_fee` 3. Update your refund logic to specify which fees to return You cannot use both `application_fee_amount` and `fees` in the same request. --- # API Credentials Reference: https://docs.justifi.tech/api-spec#tag/API-Credentials Exchange your client credentials for an access token to authenticate API requests. ## Generate Access Token `POST https://api.justifi.ai/v1/oauth/token` Reference: https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken To get an access token, post your `client_id` and `client_secret`. The request responds with an access token, which is valid for 24 hours. Pass the token as the `Authorization` header with `Bearer` appended before the token, e.g. `Bearer {access_token}`. **Note: These access tokens are meant only for backend-to-backend calls. If you are looking to authorize a web component, please see the Web Component Token API** ### Request body Content type: `application/json` - `client_id` (string): the client id for your (live or test) account Example: `"test_clientId"`. - `client_secret` (string): the client secret for your (live or test) account Example: `"test_clientSecret"`. ```json { "client_id": "test_clientId", "client_secret": "test_clientSecret" } ``` ### Responses #### 200: An access token has been granted Content type: `application/json` - `access_token` (string): an access token to pass to our API as the `Authorization` header with `Bearer` appended before the token, e.g. `Bearer {access_token}` --- # Web Component Tokens Reference: https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens ## Generate A Token `POST https://api.justifi.ai/v1/web_component_tokens` Reference: https://docs.justifi.tech/api-spec#tag/Web-Component-Tokens/operation/CreateWebComponentToken The web component token provides permission to render a web component on your frontend. To get a web component token post your [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken) in the header and the `business_id` or `account_id` as part of the `resources` array in the body. For a list of resources needed for each web component please refer to [Roles need for each component](https://docs.justifi.tech/infrastructure/webComponentTokens#roles-need-for-each-component). The token will be valid for 60 minutes. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `resources` (array of string): Build an array of concatenated role (read/write), resource (account/business) and resource id which you need the web component to access. For example ["write:business:biz_123"] ```json { "resources": [ "write:business:biz_abc", "write:account:account_123" ] } ``` ### Responses #### 200: A web component token has been created Content type: `application/json` - `access_token` (string): Use this field in the `auth-token` parameter of the web component you would like to render - `expires_in` (number): The amount of seconds until the token expires - `token_type` (string): Type of token, this will always return Bearer --- # Sub Accounts Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts Sub Accounts are the representation of your platform's customers for payment processing in JustiFi and are associated with your platform account. To gain approval for payment processing each of your customers need to be onboarded as a business via [web compoenent](https://docs.justifi.tech/api-spec#tag/Onboarding-via-Component), [hosted onboarding](https://docs.justifi.tech/api-spec#tag/Hosted-Onboarding) or [API](https://docs.justifi.tech/api-spec#tag/Onboarding-via-API). During the onboarding process a sub account is automatically created for each business and updated along the way. Payments can be processed through a sub account once it's status is `enabled`. | Status | Description | | ----------- | ----------- | | created | this sub account has been created (via Sub Accounts API), but we haven't received their onboarding entry yet | | submitted | we've received this sub account's onboarding entry (via hosted onboarding or API) and we're reviewing their information | | information_needed | we reviewed this sub account's onboarding entry and found an issue; we need more information before we can enable this account | | enabled | this sub account is approved to process payments _note: test accounts are automatically enabled_ | | rejected | this sub account didn't pass approval, so they won't be able to process payments | | disabled | this sub account was previously approved, but has since become ineligible to process payments (e.g. due to fraud) | | archived | this sub account has been archived; they won't be able to process payments (but their record will remain for historical reasons) | ## List Sub Accounts `GET https://api.justifi.ai/v1/sub_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/ListSubAccounts List the sub accounts for your platform. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). *Note: By default, all sub accounts which are not archived will be returned. To list archived sub accounts, use the optional status parameter set to `archived`* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `status` | query | string | no | Return accounts with specific status One of: `created`, `submitted`, `information_needed`, `rejected`, `enabled`, `disabled`, `archived`. | | `business_id` | query | string | no | Filter accounts associated with a business record | ### Responses #### 200: Successfully list sub accounts Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `SubAccount`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Sub Account (deprecated) `POST https://api.justifi.ai/v1/sub_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/CreateSubAccount **We no longer allow new platforms to use this API. To onboard a customer so they can process payments use [Hosted Onboarding](https://docs.justifi.tech/api-spec#tag/Hosted-Onboarding) or [Onboarding via API](https://docs.justifi.tech/api-spec#tag/Onboarding-via-API) instead. During the onboarding process a sub account will automatically created for your customer.** Create a JustiFi account for your customer, so they can process payments (once approved by JustiFi). The sub account will be created as part of your platform. If you use your test credentials, the sub account you create will have one account with the `account_type` of `test`. If you use your live credentials, the sub account you create will have two accounts -- one with the `account_type` of `test` and another with the `account_type` of `live`. This allows you to perform test operations on your real accounts by using their `test` account. When viewing the data payload for any sub account, you can reference the `related_accounts` attribute to get the `test_account_id` and `live_account_id` (if present) for that sub account. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `name` (string, required): name for the sub account *note: the name must be unique in your platform* Example: `"Sub account name"`. ### Responses #### 201: Sub account was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"sub_account"`. - `data` (object): the attributes for the object - `id` (string (uuid)): sub account id Example: `"acc_xyz"`. - `name` (string): sub account name Example: `"The Shire Haberdashery"`. - `account_type` (string): sub account type (live or test) Example: `"live"`. - `status` (string): sub account status One of: `created`, `submitted`, `information_needed`, `rejected`, `enabled`, `disabled`, `archived`. Example: `"enabled"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `platform_account_id` (string (uuid)): id of associated platform account Example: `"acc_xyz"`. - `payout_account_id` (string (uuid)): id of active payout bank account Example: `"ba_xyz"`. - `business_id` (string (uuid)): id of associated business Example: `"biz_xyz"`. - `application_fee_rates` (array): list of associated application fee rates - `processing_ready` (boolean): sub account ready for processing Example: `false`. - `payout_ready` (boolean): sub account ready for payouts Example: `false`. - `related_accounts` (object): when a live sub account is created, a related test account is automatically created; this provides both ids - `live_account_id` (string (uuid)): live sub account id (this will be nil if a sub account was created with test credentials) Example: `"acc_xyz"`. - `test_account_id` (string (uuid)): test sub account id Example: `"acc_xyz"`. - `payments_activated_on` (string (date-time), nullable): date and time when the first successful payment was processed on this sub account Example: `"2021-01-15T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Sub Account `GET https://api.justifi.ai/v1/sub_accounts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccount Get information about a sub account. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a sub account Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"sub_account"`. - `data` (object): the attributes for the object - `id` (string (uuid)): sub account id Example: `"acc_xyz"`. - `name` (string): sub account name Example: `"The Shire Haberdashery"`. - `account_type` (string): sub account type (live or test) Example: `"live"`. - `status` (string): sub account status One of: `created`, `submitted`, `information_needed`, `rejected`, `enabled`, `disabled`, `archived`. Example: `"enabled"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `platform_account_id` (string (uuid)): id of associated platform account Example: `"acc_xyz"`. - `payout_account_id` (string (uuid)): id of active payout bank account Example: `"ba_xyz"`. - `business_id` (string (uuid)): id of associated business Example: `"biz_xyz"`. - `application_fee_rates` (array): list of associated application fee rates - `processing_ready` (boolean): sub account ready for processing Example: `false`. - `payout_ready` (boolean): sub account ready for payouts Example: `false`. - `related_accounts` (object): when a live sub account is created, a related test account is automatically created; this provides both ids - `live_account_id` (string (uuid)): live sub account id (this will be nil if a sub account was created with test credentials) Example: `"acc_xyz"`. - `test_account_id` (string (uuid)): test sub account id Example: `"acc_xyz"`. - `payments_activated_on` (string (date-time), nullable): date and time when the first successful payment was processed on this sub account Example: `"2021-01-15T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Payout Account `GET https://api.justifi.ai/v1/sub_accounts/{id}/payout_account` Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetPayoutAccount Get information about the currently active payout bank account of a sub account. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get the active payout bank account a sub account Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payout_bank_account"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique bank account id - `full_name` (string): account holder's full name - `bank_name` (string): name of bank - `account_number_last4` (string): last 4 digits of the account number Example: `1111`. - `routing_number` (string) - `country` (string): One of: `US`, `CA`. Example: `"US"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `nickname` (string) - `account_type` (string): One of: `checking`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get Sub Account Settings `GET https://api.justifi.ai/v1/sub_accounts/{id}/settings` Reference: https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccountSettings Get information about sub account settings. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get sub account settings Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"sub_account_settings"`. - `data` (object): the attributes for the object - `payments` (object) - `id` (string): unique payment settings id Example: `"stpy_7KRQzIYhUGxNscgLJP0Aum"`. - `account_id` (string): unique sub account id this setting is applied to Example: `"acc_123xyz"`. - `mcc_code` (string): merchant category code configured Example: `"5045"`. - `credit_card_payments` (boolean): credit card payments enabled for processing Example: `true`. - `ach_payments` (boolean): ach payments enabled for processing Example: `true`. - `card_present` (boolean): card present feature enabled for processing Example: `false`. - `bnpl_payments` (boolean): buy now pay later feature enabled Example: `false`. - `apple_payments` (boolean): apple payments feature enabled Example: `false`. - `google_payments` (boolean): google payments feature enabled Example: `false`. - `bank_account_verification` (boolean): bank account verification feature enabled Example: `false`. - `insurance_payments` (boolean): insurance feature enabled Example: `false`. - `platform_wallet_account` (boolean): platform_wallet_account feature enabled Example: `false`. - `payouts` (object) - `id` (string): unique payout settings id Example: `"stpo_1FrQmV9ByJEKjpKf5diaA4"`. - `enabled` (boolean): payouts enabled for the sub account Example: `true`. - `statement_descriptor` (string): statement descriptor for the payout Example: `"JustiFi"`. - `settlement_priority` (enum[standard expedited]): Example: `"standard"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### SubAccount - `id` (string (uuid)): sub account id Example: `"acc_xyz"`. - `name` (string): sub account name Example: `"The Shire Haberdashery"`. - `account_type` (string): sub account type (live or test) Example: `"live"`. - `status` (string): sub account status One of: `created`, `submitted`, `information_needed`, `rejected`, `enabled`, `disabled`, `archived`. Example: `"enabled"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `platform_account_id` (string (uuid)): id of associated platform account Example: `"acc_xyz"`. - `payout_account_id` (string (uuid)): id of active payout bank account Example: `"ba_xyz"`. - `business_id` (string (uuid)): id of associated business Example: `"biz_xyz"`. - `application_fee_rates` (array): list of associated application fee rates - `processing_ready` (boolean): sub account ready for processing Example: `false`. - `payout_ready` (boolean): sub account ready for payouts Example: `false`. - `related_accounts` (object): when a live sub account is created, a related test account is automatically created; this provides both ids - `live_account_id` (string (uuid)): live sub account id (this will be nil if a sub account was created with test credentials) Example: `"acc_xyz"`. - `test_account_id` (string (uuid)): test sub account id Example: `"acc_xyz"`. - `payments_activated_on` (string (date-time), nullable): date and time when the first successful payment was processed on this sub account Example: `"2021-01-15T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Platform Wallet Accounts Reference: https://docs.justifi.tech/api-spec#tag/Platform-Wallet-Accounts A Platform Wallet Account allows you to store payment methods centrally and use them across multiple sub accounts within your platform. This feature enables you to maintain a single source of stored payment methods while processing payments through different sub accounts. ## Enable a Platform Wallet Account *Note: You can choose a sub account as your platform_wallet_account once it is underwritten and enabled for payments.* Contact us at [customer_success@justifi.tech](mailto:customer_success@justifi.tech) to enable the `platform_wallet_account` setting for your designated platform wallet account. ## Key Features Once enabled, you can: - Store payment methods in the designated platform wallet account - Use these payment methods across your platform's sub accounts - Group payment methods for easier management using [PaymentMethodGroups](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups), to associate multiple payment methods to your customer ## Using Platform Wallet Payment Methods *Note: While the PaymentMethods and Payments API allow you to tokenize a payment method we strongly suggest using the [Unified Fintech Checkout](/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2) or [Tokenize Payment Method](/web-components/payment-facilitation/tokenize-payment-method) web components instead to avoid PCI scope* ### 1. Manage Payment Methods Create and organize payment methods in your platform wallet account. All payment method operations require the platform wallet account ID in the Sub-Account header. ``` // Example: Create payment method group const group = await fetch('https://api.justifi.ai/v1/payment_method_groups', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Sub-Account': platformWalletAccountId, // Platform wallet account 'Content-Type': 'application/json' } }); // Example: Add payment methods to group const updatedGroup = await fetch(`https://api.justifi.ai/v1/payment_method_groups/${groupId}`, { method: 'PATCH', headers: { 'Authorization': `Bearer ${token}`, 'Sub-Account': platformWalletAccountId, // Platform wallet account 'Content-Type': 'application/json' }, body: JSON.stringify({ "payment_method_ids": ["pm_walletaccxyz", "pm_walletaccabc"] }) }); ``` ### 2. Process Payments You can process payments using wallet payment methods either through the [Unified Fintech Checkout web component](/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2) or via API #### Via Checkout Component [Checkout via Component Walkthrough](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) ``` // Create checkout const checkout = await fetch('https://api.justifi.ai/v1/checkouts', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Sub-Account': processingSubAccountId, // Processing sub account 'Content-Type': 'application/json' }, body: JSON.stringify({ "amount": 1799, "description": "Example item", "payment_method_group_id": "pmg_walletGroupId", // Group from wallet account "origin_url": "http://localhost:3000" // Required for component }) }); // Render component ``` #### Via API ``` // Create checkout const checkout = await fetch('https://api.justifi.ai/v1/checkouts', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Sub-Account': processingSubAccountId, // Processing sub account 'Content-Type': 'application/json' }, body: JSON.stringify({ "amount": 1799, "description": "Example item", "payment_method_group_id": "pmg_walletGroupId" // Group from wallet account }) }); // Complete checkout with wallet payment method const completion = await fetch(`https://api.justifi.ai/v1/checkouts/${checkoutId}/complete`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Sub-Account': processingSubAccountId, // Processing sub account 'Content-Type': 'application/json' }, body: JSON.stringify({ "payment_token": "pm_walletPaymentMethodToken" }) }); ``` ## Updating Wallet Payment Methods - You can update a payment method via the [payment methods API](https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/UpdatePaymentMethod) - Updates should always be made to the payment method in the platform wallet account - Any changes made to the platform wallet payment method automatically propagate to all cloned payment methods across sub accounts - Available update options include: - Card expiration date - Payment method metadata - The system maintains consistency by: - Automatically syncing updates to all cloned versions of the payment method ## Important Notes - Header Requirements: - Use **platform wallet account ID** for: - Creating/managing payment methods - Creating/managing payment method groups - Use **processing sub account ID** for: - Creating checkouts - Completing payments - The system automatically: - Validates wallet payment method access - Creates payment method clones for processing sub accounts - Returns new sub account specific tokens in responses - All sub accounts must be on the same platform as the platform wallet account For complete details on specific endpoints, see: - [Checkout via Component](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) - [Checkout via API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) - [Payments API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) --- # Onboarding via Component Reference: https://docs.justifi.tech/api-spec#tag/Onboarding-via-Component In order to process payments, each of your customers must be onboarded on the JustiFi platform. Once they are added they go through an approval process. JustiFi's [PaymentProvisioning web component](/web-components/entities/payment-provisioning) allows you to collect the required business and financial information from each of your customers. Once approved, your customer can process payments through JustiFi. To onboard a new business via PaymentProvisioning web component 1. Get an access token 2. Create a business 3. Generate a web component token 4. Render the Payment Provisioning web component 5. Handle success/failure events of the web component 6. Check the sub account's status ### Get an access token On your backend, using your client id and client secret from the Developer > API keys section of the JustiFi dashboard, generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken). ``` function getToken() { return fetch('https://api.justifi.ai/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "client_id": "YOUR CLIENT ID", "client_secret": "YOUR CLIENT SECRET" }) }) .then(response => response.json()) .then(data => data.access_token); } const token = await getToken(); ``` ### Create a business From your backend create a business using the [Business API](https://docs.justifi.tech/api-spec#tag/Business/operation/CreateBusiness). A business only requires one parameter (e.g. `legal_name`) but you can pass as much information about your customer as you have. When you render the web component all the data you passed to the business will be pre-filled in the form and can be updated by your customer. ``` async function createBusiness(token) { const response = await fetch('https://api.justifi.ai/v1/entities/business', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "legal_name": "First Business" }) }); const data = await response.json(); return data; } const business = await createBusiness(token); ``` ### Generate a web component token To render the PaymentProvisioning web component, you must generate a web component token. This is a short lived token which is meant to grant short term, fine grained access. The web component requires the role of `write:business:${businessId}` with the id of the business you created in the previous step. ``` async function getWebComponentToken(token, businessId) { const response = await fetch('https://api.justifi.ai/v1/web_component_tokens', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "resources": [`write:business:${businessId}`] }) }); const data = await response.json(); return data.access_token; } const webComponentToken = await getWebComponentToken(token, business.id); ``` ### Render the PaymentProvisioning web component Using the web component token generated above and the business id, render the [PaymentProvisioning web component](/web-components/entities/payment-provisioning). This will allow your customer to provide all business information required for payment processing ``` ``` ### Handle success/failure events of the web component The web component makes an API request every time the user moves to a `Next` step and when the user submits the form. Whenever the web component receives an API response it emits a `submitted` event that contains the API response. When the form is submitted we provision the business and create a sub account for the business. The `submitted` event data will contain the response from the [Provisioning API request](https://docs.justifi.tech/api-spec#tag/Provisioning/operation/ProductProvisioning). If the provisioning request was successful the response will include the `sub_account_id` attribute of that newly created sub account. Otherwise, an error message can be presented to the user. Our example below covers both. The `error` event means there was an issue with the PaymentProvisioning form connecting to the network, etc. ``` ``` ### Check the sub account's status Once your business submits the onboarding form 1. We will provision your business for payment processing and create a `sub account` for this business as mentioned above. This sub account is the representation of your business for payment processing. 2. We'll review the submitted information. This underwriting process can take up to a few business days. Once approved the status of the sub account will be updated to `enabled` and payments can be processed. In order to check the account's onboarding status, call the [Get a Sub Account endpoint](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccount) or use an event publisher to subscribe to the [`sub_account.updated` events](https://docs.justifi.tech/api-spec#tag/Events/operation/subAccountEvent) #### Retrieve a sub account ``` async function getBusiness(token, accountId) { const response = await fetch(`https://api.justifi.ai/v1/sub_accounts/${accountId}`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` } }); const data = await response.json(); return data; } const business = await getBusiness(toke, account.id); ``` --- # Hosted Onboarding Reference: https://docs.justifi.tech/api-spec#tag/Hosted-Onboarding In order to process payments, each of your customers (whom we refer to as `businesses`) will have to be onboarded on our platform. Once they are added they go through an approval process. JustiFi's hosted onboarding provides you with an easy-to-implement, user-friendly way to collect the required business and financial information from each business within your platform. Once approved, your business can process payments through JustiFi. To onboard a new business via hosted onboarding: 1. Get an access token 2. Create a business 3. Generate a web component token 4. Include JustiFi Hosted Onboarding in your application 5. (optional) Listen to success/fail message 6. Check the underwriting status of the sub account connected to the business ### 1. Get an access token On your backend, using your client id and client secret from the Developer > API keys section of the JustiFi dashboard, generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken). ``` function getToken() { return fetch('https://api.justifi.ai/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "client_id": "YOUR CLIENT ID", "client_secret": "YOUR CLIENT SECRET" }) }) .then(response => response.json()) .then(data => data.access_token); } const token = await getToken(); ``` ### 2. Create a business From your backend create a business using the [Business API](https://docs.justifi.tech/api-spec#tag/Business/operation/CreateBusiness). A business only requires one parameter (e.g. `legal_name`) but you can pass as much information about your customer as you have. When you render the web component all the data you passed to the business will be pre-filled in the form and can be updated by your customer. ``` async function createBusiness(token) { const response = await fetch('https://api.justifi.ai/v1/entities/business', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "legal_name": "First Business" }) }); const data = await response.json(); return data; } const business = await createBusiness(token); ``` ### 3. Generate a web component token To render the Hosted Onboarding form, you must generate a web component token. This is a short-lived token intended to grant temporary, fine-grained access. The web component requires the role `write:business:${businessId}`, with the ID of the business created in the previous step. _Note:The web component token expires after 60 minutes. If the onboarding flow takes longer than that to complete, you’ll need to generate a new web component token and reinitialize the component with the refreshed token._ ``` async function getWebComponentToken(token, businessId) { const response = await fetch('https://api.justifi.ai/v1/web_component_tokens', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "resources": [`write:business:${businessId}`] }) }); const data = await response.json(); return data.access_token; } const webComponentToken = await getWebComponentToken(token, business.id); ``` ### 4. Include JustiFi Hosted Onboarding in your application To present the JustiFi hosted onboarding form to your user, create an iframe with with the following source:\ `https://components.justifi.ai/onboarding?business_id=BUSINESS_ID&web_component_token=WEB_COMPONENT_TOKEN`,\ where `BUSINESS_ID` is the `business_id` that was created in step 2 and `WEB_COMPONENT_TOKEN` is the `access_token` that was created in step 3.\ This iframe will present your user with a multi-step form where they can enter the business and financial information needed for approval. Upon submission, a success message will display. ### 5. (optional) Listen to success/fail message #### Listen to success/fail message ```js const handleOnboardingCompletion = (e) => { const { eventType } = e.data; if (eventType === 'submitSuccess') { // Handle successful onboarding } if (eventType === 'submitFailure') { // Handle failed onboarding } }; window.addEventListener('message', handleOnboardingCompletion); ``` When the onboarding is completed, success or failure, the JustiFi iframe will send a postMessage. This allows your platform to take a next step, for example closing a modal, or redirecting to another page. ### 6. Check the underwriting status of the sub account connected to the business Once your business submits the onboarding form 1. We will provision your business for payment processing and create a `sub account` for this business. This sub account is the representation of your business for payment processing. 2. We'll review the submitted information. This approval process can take up to a few business days. In order to check the account's onboarding status, call the [Get a Sub Account endpoint](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccount) or use an event publisher to subscribe to the [`sub_account.updated` events](https://docs.justifi.tech/api-spec#tag/Events/operation/subAccountEvent) #### Retrieve a sub account ```sh curl -X GET https://api.justifi.ai/v1/sub_accounts/ACCOUNT_ID \ -H 'Authorization: Bearer [access_token]' \ -H 'Accept: application/json' ``` ### Canada Onboarding When using a Canadian platform, the hosted onboarding form automatically adapts to collect Canada-specific information. The flow follows the same steps described above, but certain fields and requirements change based on the business's country of establishment. | Area | United States | Canada | |------|--------------|--------| | Tax ID / Business Number | Required | Optional | | SSN / SIN | Required (SSN) | Optional (SIN) | | Postal code format | 5-digit ZIP | A1A 1A1 | | State / Province | US states | Canadian provinces | | Bank identification | Routing number (9 digits) | Transit number (5 digits) + Institution number (3 digits) | | Financial documents | Voided check or bank statement | Voided check or bank letter | | Business documents | Not required | Required (articles of incorporation or business registration) | | Identity documents | Not required | Required — two per owner (one Group 1 + one Group 2) | #### Document requirements for Canada Canadian onboarding requires three categories of documents: **Financial document** — one of the following: - Voided check - Bank letter **Business document** — one of the following: - Articles of incorporation - Business registration **Identity documents** — each business owner must provide two identity documents, one from each group: *Group 1 (government-issued photo ID) — one per owner:* - Canadian passport - Canadian driver's license - Canadian government-issued ID card - Permanent resident card - Certificate of Indian Status - US state-issued driver's license *Group 2 (supporting identity document) — one per owner:* - Nexus Card (photo ID) - Canadian citizenship/naturalization card or certificate - Foreign passport - Canadian birth certificate - Social Insurance Number (SIN) card - Social Security Number (SSN) card For example, if a business has two owners, the onboarding form will require two Group 1 documents and two Group 2 documents (one of each per owner). --- # Onboarding via API Reference: https://docs.justifi.tech/api-spec#tag/Onboarding-via-API In order to process payments, each of your customers (whom we refer to as `businesses`) will have to be onboarded on the JustiFi platform. Once they are added they go through an approval process. JustiFi's onboarding API allows you to utilize your own onboarding frontend to collect the required business and financial information from each of your businesses. Once approved, your business can process payments through JustiFi. To onboard a new business via the API 1. Create a business 2. Create a bank account 3. Upload documents 4. Accept terms and conditions 5. Provision the business 6. Check the sub account's status ### Create a business #### Create a business ```sh curl -X POST \ https://api.justifi.ai/v1/entities/business \ -H 'Authorization: Bearer {access_token}' \ -H 'Content-Type: application/json' \ -d '{ "legal_name": "Business name" }' ``` Use the business API to [create a business](https://docs.justifi.tech/api-spec#tag/Business/operation/CreateBusiness) on JustiFi that is associated with your platform. The create business API endpoint does not require any parameters but they will be required when the business is provisioned (see step 5). You will need the ID from the business you create for the next steps. ### Create a bank account Use the bank account API to [create a bank account](https://docs.justifi.tech/api-spec#tag/Bank-Account/operation/CreateBankAccount). This bank account will be used to pay out earnings for payment processing to the business. ### Upload documents Use the document API to [upload a document](https://docs.justifi.tech/api-spec#tag/Document/operation/CreateDocument). The minimum document requirement (for small businesses and sole proprietors) is a voided check. ### Accepte terms and conditions Use the terms and conditions API to [accept terms for payment processing](https://docs.justifi.tech/api-spec#tag/Terms-and-Conditions/operation/TermsAndConditions). ### Provision the business #### Provision the business for payment processing ```sh curl -X POST \ https://api.justifi.ai/v1/entities/provisioning \ -H 'Authorization: Bearer {access_token}' \ -H 'Content-Type: application/json' \ -d '{ "business_id": "biz_123", "product_category": "payment" }' ``` Once you have submitted all business related information use the provisioning API to [provision the business for payment processing](https://docs.justifi.tech/api-spec#tag/Provisioning/operation/ProductProvisioning). At this point all required parameters for payment processing are validated. An error is returned if any fields are missing. If successful, the product provisioning request will create a sub account associated with the business. The response will include the ID of that associated sub account. It is required for any payment processing related API requests. ### Check the sub account status #### Retrieve a sub account ```sh curl -X GET https://api.justifi.ai/v1/sub_accounts/ACCOUNT_ID \ -H 'Authorization: Bearer [access_token]' \ -H 'Accept: application/json' ``` Once you have provisioned the busiess, we'll review their information. This approval process can take up to a few business days. In order to check the associated sub account's onboarding status, call the [Get a Sub Account endpoint](https://docs.justifi.tech/api-spec#tag/Sub-Accounts/operation/GetSubAccount) or use an event publisher to subscribe to the `sub_account.updated` events. --- # Fee Configurations Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations Standard Fee Configurations allow platforms to set per-sub-account fee rates that are automatically applied at payment time. Configurations are managed per fee type — creating a new configuration for the same fee type automatically retires the previous one. For a detailed guide on configurable fees, including the fee hierarchy, calculation formula, and examples, see the [Configurable Fees documentation](https://docs.justifi.tech/configurableFees/overview). ## List Fee Configurations `GET https://api.justifi.ai/v1/sub_accounts/{id}/fee_configurations` Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations/operation/ListFeeConfigurations List all active Standard Fee Configurations for a sub account. Returns configurations where the current time is between `effective_start` and `effective_end` (or `effective_end` is null). This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `limit` | query | integer | no | the number of resources to retrieve | | `after_cursor` | query | string | no | token to fetch the next page of a list | | `before_cursor` | query | string | no | token to fetch the previous page of a list | ### Responses #### 200: Successfully list fee configurations Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `StandardFeeConfiguration`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## List Scheduled Fee Configurations `GET https://api.justifi.ai/v1/sub_accounts/{id}/fee_configurations/scheduled` Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations/operation/ListScheduledFeeConfigurations List Standard Fee Configurations with a future `effective_start` that haven't taken effect yet. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `limit` | query | integer | no | the number of resources to retrieve | | `after_cursor` | query | string | no | token to fetch the next page of a list | | `before_cursor` | query | string | no | token to fetch the previous page of a list | ### Responses #### 200: Successfully list scheduled fee configurations Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `StandardFeeConfiguration`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Fee Configuration `GET https://api.justifi.ai/v1/sub_accounts/{id}/fee_configurations/{fee_type}` Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations/operation/GetFeeConfiguration Get the active Standard Fee Configuration for a specific fee type on a sub account. Returns 404 if no active configuration exists for that fee type. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `fee_type` | path | string | yes | the fee type to retrieve One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. | ### Responses #### 200: Successfully retrieve a fee configuration Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"standard_fee_configuration"`. - `data` (object): the attributes for the object - `id` (string): unique identifier for the fee configuration Example: `"sfc_abc123"`. - `account_id` (string (uuid)): the sub account this configuration applies to Example: `"acc_xyz"`. - `platform_account_id` (string (uuid), nullable): the platform account that created this configuration Example: `"acc_yyy"`. - `fee_type` (string): the type of fee this configuration applies to: - `processing_ecomm` — card-not-present (online) payments - `processing_card_present` — card-present (terminal) payments - `processing_ach` — ACH payments - `processing_ach_expedited` — expedited ACH payments - `visa_brand_ecomm` — Visa online payments - `visa_brand_card_present` — Visa terminal payments - `mastercard_brand_ecomm` — Mastercard online payments - `mastercard_brand_card_present` — Mastercard terminal payments - `amex_brand_ecomm` — Amex online payments - `amex_brand_card_present` — Amex terminal payments - `discover_brand_ecomm` — Discover online payments - `discover_brand_card_present` — Discover terminal payments - `platform` — platform service fee applied to all payments One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. - `variable_rate` (number): percentage rate applied to the payment amount. `2.75` = 2.75% Example: `2.75`. - `transaction_fee_cents` (integer): flat fee in cents added to each transaction Example: `25`. - `transaction_fee_currency` (string): currency of the transaction fee One of: `usd`. Example: `"usd"`. - `fee_cap_cents` (integer, nullable): maximum fee amount in cents; if the calculated fee exceeds this, the cap is used instead Example: `1000`. - `effective_start` (string (date-time)): when this configuration takes effect (UTC) Example: `"2026-02-25T00:00:00Z"`. - `effective_end` (string (date-time), nullable): when this configuration expires (UTC); `null` means it stays active indefinitely - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Create a Fee Configuration `POST https://api.justifi.ai/v1/sub_accounts/{id}/fee_configurations/{fee_type}` Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations/operation/CreateFeeConfiguration Create a Standard Fee Configuration for a specific fee type on a sub account. If an active configuration already exists for the same fee type, it is automatically retired — its `effective_end` is set to the new configuration's `effective_start`. There is no update or delete operation. To change a fee rate, create a new configuration for the same fee type. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `fee_type` | path | string | yes | the fee type to configure One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. | ### Request body Content type: `application/json` - `variable_rate` (number, required): percentage rate applied to the payment amount. `2.75` = 2.75% Example: `2.75`. - `transaction_fee_cents` (integer): flat fee in cents added to each transaction (defaults to `0`) Example: `25`. - `fee_cap_cents` (integer, nullable): maximum fee amount in cents; if the calculated fee exceeds this, the cap is used instead Example: `1000`. - `effective_start` (string (date-time)): when the configuration takes effect (UTC); defaults to immediately Example: `"2026-04-01T00:00:00Z"`. - `effective_end` (string (date-time), nullable): when the configuration expires (UTC); must be later than `effective_start`, so the current time or earlier is rejected; `null` means it stays active indefinitely. Only accepted on optional fee types (brand-specific and `platform`). ### Responses #### 201: Fee configuration was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"standard_fee_configuration"`. - `data` (object): the attributes for the object - `id` (string): unique identifier for the fee configuration Example: `"sfc_abc123"`. - `account_id` (string (uuid)): the sub account this configuration applies to Example: `"acc_xyz"`. - `platform_account_id` (string (uuid), nullable): the platform account that created this configuration Example: `"acc_yyy"`. - `fee_type` (string): the type of fee this configuration applies to: - `processing_ecomm` — card-not-present (online) payments - `processing_card_present` — card-present (terminal) payments - `processing_ach` — ACH payments - `processing_ach_expedited` — expedited ACH payments - `visa_brand_ecomm` — Visa online payments - `visa_brand_card_present` — Visa terminal payments - `mastercard_brand_ecomm` — Mastercard online payments - `mastercard_brand_card_present` — Mastercard terminal payments - `amex_brand_ecomm` — Amex online payments - `amex_brand_card_present` — Amex terminal payments - `discover_brand_ecomm` — Discover online payments - `discover_brand_card_present` — Discover terminal payments - `platform` — platform service fee applied to all payments One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. - `variable_rate` (number): percentage rate applied to the payment amount. `2.75` = 2.75% Example: `2.75`. - `transaction_fee_cents` (integer): flat fee in cents added to each transaction Example: `25`. - `transaction_fee_currency` (string): currency of the transaction fee One of: `usd`. Example: `"usd"`. - `fee_cap_cents` (integer, nullable): maximum fee amount in cents; if the calculated fee exceeds this, the cap is used instead Example: `1000`. - `effective_start` (string (date-time)): when this configuration takes effect (UTC) Example: `"2026-02-25T00:00:00Z"`. - `effective_end` (string (date-time), nullable): when this configuration expires (UTC); `null` means it stays active indefinitely - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get Fee Configuration History `GET https://api.justifi.ai/v1/sub_accounts/{id}/fee_configurations/{fee_type}/history` Reference: https://docs.justifi.tech/api-spec#tag/Fee-Configurations/operation/GetFeeConfigurationHistory List all Standard Fee Configurations for a specific fee type on a sub account, including active, retired, and scheduled configurations. Results are ordered by `effective_start` descending. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `fee_type` | path | string | yes | the fee type to retrieve history for One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. | | `limit` | query | integer | no | the number of resources to retrieve | | `after_cursor` | query | string | no | token to fetch the next page of a list | | `before_cursor` | query | string | no | token to fetch the previous page of a list | ### Responses #### 200: Successfully list fee configuration history Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `StandardFeeConfiguration`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Schemas ### StandardFeeConfiguration - `id` (string): unique identifier for the fee configuration Example: `"sfc_abc123"`. - `account_id` (string (uuid)): the sub account this configuration applies to Example: `"acc_xyz"`. - `platform_account_id` (string (uuid), nullable): the platform account that created this configuration Example: `"acc_yyy"`. - `fee_type` (string): the type of fee this configuration applies to: - `processing_ecomm` — card-not-present (online) payments - `processing_card_present` — card-present (terminal) payments - `processing_ach` — ACH payments - `processing_ach_expedited` — expedited ACH payments - `visa_brand_ecomm` — Visa online payments - `visa_brand_card_present` — Visa terminal payments - `mastercard_brand_ecomm` — Mastercard online payments - `mastercard_brand_card_present` — Mastercard terminal payments - `amex_brand_ecomm` — Amex online payments - `amex_brand_card_present` — Amex terminal payments - `discover_brand_ecomm` — Discover online payments - `discover_brand_card_present` — Discover terminal payments - `platform` — platform service fee applied to all payments One of: `processing_ecomm`, `processing_card_present`, `processing_ach`, `processing_ach_expedited`, `visa_brand_ecomm`, `visa_brand_card_present`, `mastercard_brand_ecomm`, `mastercard_brand_card_present`, `amex_brand_ecomm`, `amex_brand_card_present`, `discover_brand_ecomm`, `discover_brand_card_present`, `platform`. Example: `"processing_ecomm"`. - `variable_rate` (number): percentage rate applied to the payment amount. `2.75` = 2.75% Example: `2.75`. - `transaction_fee_cents` (integer): flat fee in cents added to each transaction Example: `25`. - `transaction_fee_currency` (string): currency of the transaction fee One of: `usd`. Example: `"usd"`. - `fee_cap_cents` (integer, nullable): maximum fee amount in cents; if the calculated fee exceeds this, the cap is used instead Example: `1000`. - `effective_start` (string (date-time)): when this configuration takes effect (UTC) Example: `"2026-02-25T00:00:00Z"`. - `effective_end` (string (date-time), nullable): when this configuration expires (UTC); `null` means it stays active indefinitely ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Proceeds Reference: https://docs.justifi.tech/api-spec#tag/Proceeds Proceeds represent your platform's take-home portion of the fees from your sub account's financial transactions. Proceeds are batched together according to the payout schedule configured on your account, then transferred to your active bank account. Each proceeds payout also breaks down the fees behind its amount. `platform_fees_total` is what your platform charged its sub accounts, `justifi_fees_total` is what JustiFi charged your platform, and `interchange_network_fees` is the interchange and card network fees passed through to you. For most payouts, `amount` equals `platform_fees_total` minus `justifi_fees_total` plus `interchange_network_fees`. Less common entries, such as a previously failed payout being forwarded or a fee adjustment, also move the amount. JustiFi calculates these three fields shortly after the payout is created, so they are null in the `proceeds.payout.created` event. Fetch the payout again to read them. ## List Proceeds `GET https://api.justifi.ai/v1/proceeds` Reference: https://docs.justifi.tech/api-spec#tag/Proceeds/operation/ListProceeds List the proceeds payouts for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `deposits_before` | query | string (date-time) | no | filter records which deposit before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `deposits_after` | query | string (date-time) | no | filter records which deposit after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | ### Responses #### 200: Successfully list proceeds Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Proceed`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Proceeds Payout `GET https://api.justifi.ai/v1/proceeds/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Proceeds/operation/GetProceeds Get information about a proceeds payout. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a proceeds payout Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"payout"`. - `data` (array of `Proceed`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Proceeds Report `GET https://api.justifi.ai/v1/reports/proceeds/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Proceeds/operation/GetProceedsReport **Deprecated.** [DEPRECATION WARNING] This endpoint will be deprecated, please use [Reports API](#tag/Reports). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a link to a csv and json report for a proceeds payout Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"procceds"`. - `data` (object): the attributes for the object - `id` (string): unique proceeds payout id Example: `"po_xyz"`. - `csv_url` (string): url that links to downloadable CSV report for proceeds payout Example: `"https://justifi-test-platform-proceeds-reports.s3.amazonaws.com/acc_1234lkj/po_23jdfi36dqhj.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test"`. - `report_url` (string): url that links to downloadable JSON report for proceeds payout Example: `"https://justifi-test-platform-proceeds-reports.s3.amazonaws.com/acc_1234lkj/po_23jdfi36dqhj.json?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Proceed - `id` (string): unique proceeds payout id Example: `"po_xyz"`. - `account_id` (string (uuid)): id of the account associated with the proceeds payout - `amount` (number): proceeds payout amount in cents Example: `100000`. - `bank_account` (`PayoutBankAccount`) - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `delivery_method` (string): how the proceeds payout is delivered One of: `standard`. - `description` (string, nullable) - `deposits_at` (string (date-time)): in UTC, the date and time of the proceeds payout deposit (or in rare cases, withdrawal) Example: `"2021-01-01T12:00:00Z"`. - `refunds_count` (number): number of refunds that impacted the proceeds payout Example: `5`. - `refunds_total` (number): sum deducted from the proceeds payout as a result of accounts' refunds, in cents Example: `10000`. - `payments_count` (number): number of payments that impacted the proceeds payout Example: `50`. - `payments_total` (number): sum added to the proceeds payout as a result of accounts' payments, in cents Example: `110000`. - `payout_type` (string): proceeds payouts are always of the type "proceeds" (other types apply only to sub accounts payouts) One of: `proceeds`. - `other_total` (number): sum of other less common transactions that impacted the proceeds payout, in cents Example: `100`. - `platform_fees_total` (number, nullable): gross fees your platform charged its sub accounts in the proceeds payout, in cents, before JustiFi's processing fees, null until calculated shortly after the payout is created Example: `271961`. - `justifi_fees_total` (number, nullable): processing fees JustiFi charged your platform in the proceeds payout, in cents, always positive, null until calculated shortly after the payout is created Example: `703`. - `interchange_network_fees` (number, nullable): interchange and card network fees passed through to your platform in the proceeds payout, in cents, negative when charged and positive when refunds credit interchange back, null until calculated shortly after the payout is created Example: `-10318`. - `status` (string): status of the proceeds payout One of: `scheduled paid failed pending in_transit canceled`. Example: `"scheduled"`. - `metadata` (object (json)): any useful information you'd like to store alongside this proceeds payout - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### PayoutBankAccount - `id` (string (uuid)): unique bank account id - `full_name` (string): account holder's full name - `bank_name` (string): name of bank - `account_number_last4` (string): last 4 digits of the account number Example: `1111`. - `routing_number` (string) - `country` (string): One of: `US`, `CA`. Example: `"US"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `nickname` (string) - `account_type` (string): One of: `checking`. --- # Reports Reference: https://docs.justifi.tech/api-spec#tag/Reports Reports can be used to pull data for various different resources. They are CSV format, and can be filtered by date and sub account. Once a the create endpoint is called via POST, a report will be in `created` status. The report will move to `processing` status once it is being generated. Finally, when the report is generated, and the CSV file is available, the report will be in `completed` status. To download a report, you can use the `download_url` provided in the response when retrieving a report. We use presigned URLs to allow you to download the report directly from our S3 bucket. ## Report Types ### Payout Report Contains balance transaction data for payouts. | Column | Description | | ------ | ----------- | | id | Balance transaction ID | | type | Transaction type | | currency | Currency | | amount | Amount in cents | | fee | Fee amount in cents | | net | Net amount in cents | | source_id | Source object ID | | source_account_id | Source account ID | | source_type | Source object type | | source_amount | Source amount in cents | | available_on | When funds become available | | payment_id | Associated payment ID | | created_at | Creation timestamp | | payment_method_name | Payment method name | | source_payment_id | Payment ID associated with the source | | payout_id | Associated payout ID | | payout_created_at | Payout creation timestamp | | payout_deposits_at | Expected payout deposit date | ### Proceeds Report Contains platform proceeds data. | Column | Description | | ------ | ----------- | | id | Balance transaction ID | | type | Transaction type | | currency | Currency code | | amount | Amount in cents | | fee | Fee amount in cents | | net | Net amount in cents | | source_id | Source object ID | | source_account_id | Source account ID | | source_type | Source object type | | source_amount | Source amount in cents | | application_fee_amount | Application fee in cents | | platform_fee_amount | Platform fee in cents | | proceeds | Calculated proceeds in cents | | available_on | When funds become available | | created_at | Creation timestamp | | fee_major_category | Fee major category | | fee_minor_category | Fee minor category | | fee_description | Fee description | | fee_product_code | Fee product code | | fee_batch_date | Fee batch date | | payment_method_type | Payment method type | | payment_method_brand | Payment method brand | | source_payment_id | Payment ID associated with the source | | payout_id | Associated payout ID | | payout_created_at | Payout creation timestamp | | payout_deposits_at | Expected payout deposit date | ## List Reports `GET https://api.justifi.ai/v1/reports` Reference: https://docs.justifi.tech/api-spec#tag/Reports/operation/ListSubAccounts List all generated reports ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `nickname` | query | string | no | the nickname of the report | ### Responses #### 200: Successfully list reports Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Report`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a report `POST https://api.justifi.ai/v1/reports` Reference: https://docs.justifi.tech/api-spec#tag/Reports/operation/CreateReport Create a report for any of the available report types ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Request body Content type: `application/json` Schema: one of `ReportInterchangeFeeParameters` | `ReportProceedsParameters` | `ReportPayoutParameters` | `ReportSubAccountSummaryParameters` | `ReportPaymentListParameters` ### Responses #### 200: Report was queued successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"report"`. - `data` (object): the attributes for the object - `id` (string): report unique id Example: `"rpt_xyz"`. - `report_type` (`ReportType`): which report was generated One of: `proceeds`, `payout`, `interchange_fee`, `sub_account_summary`, `payment_list`. Example: `"proceeds"`. - `nickname` (string, nullable): the report nickname Example: `"My Report"`. - `status` (string): the report status One of: `scheduled`, `processing`, `completed`, `failed`, `canceled`, `expired`. Example: `"scheduled"`. - `scheduled_at` (string (date)): when the report was scheduled Example: `"2025-12-25T14:44:45.026Z"`. - `run_at` (string (date)): when the report started processing Example: `"2025-12-30T14:44:45.026Z"`. - `created_at` (string (date)): when the report was created Example: `"2025-12-31T14:44:45.026Z"`. - `error_description` (string): error description in case of errors - `account_id` (string): the account id the report was created for Example: `"acc_xyz"`. - `presigned_url` (string (url)): the url to download the report when completed - `platform_account_id` (string): the platform account id the report was created for Example: `"acc_xyz"`. - `parameters` (`ReportParameters`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a report `GET https://api.justifi.ai/v1/reports/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Reports/operation/GetReport Get and generate the download url for a report ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `id` | path | string (uuid) | yes | | ### Responses #### 200: Successfully get a report Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"refund"`. - `data` (object): the attributes for the object - `id` (string): report unique id Example: `"rpt_xyz"`. - `report_type` (`ReportType`): which report was generated One of: `proceeds`, `payout`, `interchange_fee`, `sub_account_summary`, `payment_list`. Example: `"proceeds"`. - `nickname` (string, nullable): the report nickname Example: `"My Report"`. - `status` (string): the report status One of: `scheduled`, `processing`, `completed`, `failed`, `canceled`, `expired`. Example: `"scheduled"`. - `scheduled_at` (string (date)): when the report was scheduled Example: `"2025-12-25T14:44:45.026Z"`. - `run_at` (string (date)): when the report started processing Example: `"2025-12-30T14:44:45.026Z"`. - `created_at` (string (date)): when the report was created Example: `"2025-12-31T14:44:45.026Z"`. - `error_description` (string): error description in case of errors - `account_id` (string): the account id the report was created for Example: `"acc_xyz"`. - `presigned_url` (string (url)): the url to download the report when completed - `platform_account_id` (string): the platform account id the report was created for Example: `"acc_xyz"`. - `parameters` (`ReportParameters`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Report - `id` (string): report unique id Example: `"rpt_xyz"`. - `report_type` (`ReportType`): which report was generated One of: `proceeds`, `payout`, `interchange_fee`, `sub_account_summary`, `payment_list`. Example: `"proceeds"`. - `nickname` (string, nullable): the report nickname Example: `"My Report"`. - `status` (string): the report status One of: `scheduled`, `processing`, `completed`, `failed`, `canceled`, `expired`. Example: `"scheduled"`. - `scheduled_at` (string (date)): when the report was scheduled Example: `"2025-12-25T14:44:45.026Z"`. - `run_at` (string (date)): when the report started processing Example: `"2025-12-30T14:44:45.026Z"`. - `created_at` (string (date)): when the report was created Example: `"2025-12-31T14:44:45.026Z"`. - `error_description` (string): error description in case of errors - `account_id` (string): the account id the report was created for Example: `"acc_xyz"`. - `presigned_url` (string (url)): the url to download the report when completed - `platform_account_id` (string): the platform account id the report was created for Example: `"acc_xyz"`. - `parameters` (`ReportParameters`) ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### ReportInterchangeFeeParameters - `report_type` (string, required): One of: `interchange_fee`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. ### ReportProceedsParameters - `report_type` (string, required): One of: `proceeds`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. ### ReportPayoutParameters - `report_type` (string, required): One of: `payout`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. ### ReportSubAccountSummaryParameters - `report_type` (string, required): One of: `sub_account_summary`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. ### ReportPaymentListParameters - `report_type` (string, required): One of: `payment_list`. - `payment_status` (string): the payment status to filter by One of: `authorized`, `failed`, `succeeded`, `canceled`. Example: `"succeeded"`. - `payment_method_id` (string): the payment method id to filter by Example: `"pm_xyz"`. - `terminal_id` (string): the terminal_id to filter by Example: `"trm_xyz"`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. ### ReportType which report was generated Type: string ### ReportParameters - Option 1: - `report_type` (string, required): One of: `proceeds`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 2: - `report_type` (string, required): One of: `payout`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 3: - `report_type` (string, required): One of: `interchange_fee`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 4: - `report_type` (string, required): One of: `sub_account_summary`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 5: - `report_type` (string, required): One of: `payment_list`. - `payment_status` (string): the payment status to filter by One of: `authorized`, `failed`, `succeeded`, `canceled`. Example: `"succeeded"`. - `payment_method_id` (string): the payment method id to filter by Example: `"pm_xyz"`. - `terminal_id` (string): the terminal_id to filter by Example: `"trm_xyz"`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. --- # Payments Reference: https://docs.justifi.tech/api-spec#tag/Payments To charge a payment method the desired amount, you'll use a payment. You can choose whether to charge a payment method that's already been tokenized or tokenize a new one when you create the payment. If a payment fails, the status will reflect it and an error code will be returned. You can retrieve information about your payments and refund them if needed. ## List Payments `GET https://api.justifi.ai/v1/payments` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/ListPayments List the payments for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `payment_method_id` | query | string | no | filter records which are associated with a payment method. | | `void_id` | query | string | no | filter records which are associated with a void. | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `payment_status` | query | string | no | filter to payments which have request payment_status One of: `succeeded`, `failed`, `pending`, `authorized`, `refunded`, `disputed`. | ### Responses #### 200: Successfully list payments Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `CardPayment` | `BankAccountPayment`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Payment `POST https://api.justifi.ai/v1/payments` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment Authorize, capture, and charge a payment method. We limit concurrency to 10 concurrent requests per platform. This is due to the nature of the payments API, to reduce rejections, and false positive fraud detection during bulk payment processing. **Payment methods must be tokenized before creating a payment.** Tokenize payment methods use the embedded **[JustiFi Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method)** to securely collect and tokenize card or bank account details. Once you have a payment method token (e.g. `pm_justifi123`), pass it in the `payment_method.token` field to create a payment. > **Note:** Passing raw card or bank account details directly to this endpoint requires prior approval. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) if you have a use case that requires direct PAN submission. At minimum, a completed SAQ (Self-Assessment Questionnaire) is required to allow raw PAN submissions. *Note: If the sub account status is not `enabled`, `400` will be returned.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | yes | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Request body Content type: `application/json` - `amount` (number, required): amount to charge in cents Example: `10000`. - `currency` (string, required): One of: `usd`, `cad`. Example: `"usd"`. - `capture_strategy` (string, required): automatic will authorize and capture the payment in the same request; manual will only authorize the payment. An authorized payment will need to be captured in a subsequent capture payment request. If not captured within 7 days the payment will be canceled. Not supported by bank account (ACH) payment methods. One of: `automatic`, `manual`. Example: `"automatic"`. - `email` (string (email)): email address to associate with payment method - `payment_method` (object, required) - `token` (string, required): A payment method token obtained from the JustiFi Tokenize Payment Method Web Component. Example: `"pm_xyz"`. - `application_fee_amount` (integer): Sets a custom application fee amount that applies to this payment, instead of relying on application fee rates configured at the platform account level (*only Platforms may set application_fee_amount*). Must be greater than zero. **New integrations** should use the `fees` array instead for granular control over fee types and selective refunds. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). Cannot be used together with `fees`. > **CAD Payments:** This parameter is not available for CAD payments. Fees for Canadian dollar payments are determined during merchant onboarding and are not configurable via the API. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. Example: `400`. - `fees` (array of `Fee`): Array of fee objects to charge on this payment. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. Each fee object specifies: - `type`: `processing_fee` or `platform_fee` (required) - `amount`: Fee amount in cents (required) **Benefits over `application_fee_amount`:** - Separate fee types for clear reporting - Selective refunds: Choose which fees to return - Each fee type appears as a separate balance transaction Cannot be used together with `application_fee_amount`. > **Note:** The `fees` array will be empty in the create response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee details, or poll with a subsequent [Get Payment](#tag/Payments/operation/GetPayment) request. > **CAD Payments:** This parameter is not available for CAD payments. Fees for Canadian dollar payments are determined during merchant onboarding and are not configurable via the API. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"order_xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement, must have between 5-22 alphanumeric characters and can include dash or underscore - `metadata` (object (json)): Any useful information you'd like to store alongside this payment. **Testing Disputes**: Include `dispute_test_spec` to create test disputes: - `expected_result`: `"won"` or `"lost"` - Final dispute outcome - `reason`: Dispute reason (`"fraudulent"`, `"unrecognized"`, `"duplicate"`, `"subscription_canceled"`, `"product_unacceptable"`, `"product_not_received"`, `"processing_error"`, `"credit_not_processed"`, `"general"`) - `due_date`: Response deadline in YYYY-MM-DD format - `event_publish_delay_in_seconds`: Delay before dispute creation (default: 0) - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments ```json { "amount": 1000, "currency": "usd", "capture_strategy": "automatic", "email": "example@test.com", "description": "Charging $10 to a tokenized payment method", "payment_method": { "token": "pm_justifi123" } } ``` ### Responses #### 201: Payment was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payment"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "my order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "checkout_id": "cho_123", "refunded": false, "returned": false, "status": "succeeded", "payment_mode": "ecom", "terminal_id": "trm_123_xyz", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": "4242", "brand": "visa", "digital_wallet": null, "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "bin_details": { "type": "Debit", "card_brand": "Visa", "card_class": "Consumer", "country": "United States of America", "issuer": "WELLS FARGO BANK", "funding_source": "Debit" }, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": "null", "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "transaction_hold": { "id": "th_123xyz", "financial_transaction_id": "ft_123xyz" }, "refunds": [], "disputes": [] }, "page_info": null } ``` #### 400: Full card number submitted without PCI approval Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "full_pan_not_allowed", "message": "Full card numbers are not accepted on this endpoint. Please use the tokenization iframe to create a payment method token first." } } ``` #### 402: Error when processing the payment Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "card_declined", "decline_code": "do_not_retry", "message": "This card has been rejected. Please try a different card or payment method", "network": "MASTERCARD", "network_error_category": "03", "network_error_code": "504" } } ``` ## Get a Payment `GET https://api.justifi.ai/v1/payments/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment Get information about a payment. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a payment Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "my order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "checkout_id": "cho_123", "refunded": false, "returned": false, "status": "succeeded", "payment_mode": "ecom", "terminal_id": "trm_123_xyz", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": "4242", "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "fees": [ { "id": "pyfee_abc", "type": "processing_fee", "amount": 150, "currency": "usd", "remaining_amount": 150, "source_configuration_id": null, "source_fee_type": null, "refund_id": null } ], "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "transaction_hold": { "id": "th_123xyz", "financial_transaction_id": "ft_123xyz" }, "refunds": [], "disputes": [] }, "page_info": null } ``` ## Update a Payment `PATCH https://api.justifi.ai/v1/payments/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/UpdatePayment Change a payment's description or metadata. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"order_xyz new description"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment; when you update metadata, any previous metadata will be overwritten ### Responses #### 200: Payment update was successful Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_refunded": 0, "amount_disputed": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "order xyz new description", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "checkout_id": "cho_123", "refunded": false, "returned": false, "status": "succeeded", "payment_mode": "ecom", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": "4242", "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "refunds": [], "disputes": [] }, "page_info": null } ``` ## Capture a Payment `POST https://api.justifi.ai/v1/payments/{id}/capture` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/CapturePayment To charge a payment method and capture a previously authorized payment. Returns a `payment_already_captured` error if the payment is in a captured state. If not captured an authorized payment will be canceled after 7 days. *Note: If the sub account status is not `enabled`, `400` will be returned.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Payment with identical idempotency key was captured Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "checkout_id": "cho_123", "refunded": false, "returned": false, "status": "succeeded", "payment_mode": "ecom", "terminal_id": "trm_123_xyz", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": "4242", "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "bin_details": { "type": "Debit", "card_brand": "Visa", "card_class": "Consumer", "country": "United States of America", "issuer": "WELLS FARGO BANK", "funding_source": "Debit" }, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "transaction_hold": { "id": "th_123xyz", "financial_transaction_id": "ft_123xyz" }, "refunds": [], "disputes": [] }, "page_info": null } ``` #### 201: Payment was captured successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "checkout_id": "cho_123", "refunded": false, "returned": false, "status": "succeeded", "payment_mode": "ecom", "terminal_id": "trm_123_xyz", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": 4242, "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "bin_details": { "type": "Debit", "card_brand": "Visa", "card_class": "Consumer", "country": "United States of America", "issuer": "WELLS FARGO BANK", "funding_source": "Debit" }, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "transaction_hold": { "id": "th_123xyz", "financial_transaction_id": "ft_123xyz" }, "refunds": [], "disputes": [] }, "page_info": null } ``` ## Refund a Payment `POST https://api.justifi.ai/v1/payments/{id}/refunds` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/CreateRefund Issue a refund for a payment. You may refund the full payment amount or just a portion. When refunding a portion, multiple refunds are supported up until the full payment amount has been refunded. *Note: If the sub account status is not `enabled`, `400` will be returned.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `amount` (number): amount to refund; must be less than or equal to the `amount_refundable` on the payment Example: `10000`. - `description` (string): an optional note about this refund - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `fees` (array of object): Array of fee objects to return to the merchant as part of this refund. If omitted, no fees are returned (current behavior preserved). Each fee object specifies: - `type`: The fee type to refund (`processing_fee` or `platform_fee`) - `amount`: Amount to return in cents **Validation:** - The requested amount cannot exceed the `remaining_amount` for that fee type on the original payment - The fee type must exist on the original payment > **CAD Payments:** This parameter is not available for CAD payments. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `type` (string, required): The type of fee to refund One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Amount to refund in cents Example: `175`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund ```json { "amount": 10000, "reason": "customer_request", "description": "Customer requested full refund" } ``` ### Responses #### 201: Refund was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"refund"`. - `data` (object): the attributes for the object - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Void a Payment `POST https://api.justifi.ai/v1/payments/{id}/void` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/VoidPayment Void an ecom card or ACH payment transaction to cancel the payment before it reaches settlement. Payment transactions are voidable within 25 minutes of the original transaction. This includes `authorized` payments (that were created with `capture_strategy` manual and have not been captured yet). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Payment was voided successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ```json { "id": "py_123xyz", "type": "payment", "data": { "id": "py_123xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "refunded": false, "returned": false, "status": "canceled", "payment_mode": "ecom", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": 4242, "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "refunds": [], "disputes": [] }, "page_info": null } ``` ## Get Payment Balance Transactions `GET https://api.justifi.ai/v1/payments/{id}/payment_balance_transactions` Reference: https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPaymentBalanceTransactions Get information about the payment-balance-transactions associated with a payment. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully retrieve the payment-balance-transactions for a payment Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `PaymentBalanceTransaction`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Schemas ### CardPayment - `id` (string): unique payment id Example: `"py_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): payment amount in cents Example: `10000`. - `amount_disputed` (number): sum of open or lost disputes for this payment, in cents Example: `0`. - `amount_refunded` (number): sum of refunds for this payment, in cents Example: `0`. - `amount_refundable` (number): amount of this payment currently able to be refunded, in cents Example: `10000`. - `balance` (number): sum of debits and credits for this payment, in cents (reflects the amount this account has earned from this payment). Compiled and calculated value, eventually consistent. To see all changes affecting the payment's balance call [Get Balance Transactions](#operation/GetPaymentBalanceTransactions) Example: `99850`. - `fee_amount` (number): sum of fees for this payment Example: `150`. - `financial_transaction_id` (string): associated financial transaction id Example: `"ft_123xyz"`. - `captured` (boolean): whether or not this payment is captured Example: `true`. - `capture_strategy` (string): One of: `automatic`, `manual`. Example: `"automatic"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my_order_xyz"`. - `disputed` (boolean): whether or not this payment has any open or lost disputes Example: `false`. - `disputes` (array): list of associated disputes - `error_code` (string): error code if the payment fails Example: `"credit_card_number_invalid"`. - `error_description` (string): text description of the error code Example: `"Credit Card Number Invalid (Failed LUHN checksum)"`. - `is_test` (boolean): whether or not this payment was made using the test account Example: `true`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment - `payment_intent_id` (string): unique id of associated payment intent Example: `"pi_123xyz"`. - `checkout_id` (string): unique id of associated checkout Example: `"cho_123xyz"`. - `payment_method` (`CardPaymentMethod`) - `application_fee` (`ApplicationFee`) - `application_fee_rate_id` (string): unique id of application fee rate applied to this payment, if any Example: `"afr_123xyz"`. - `fees` (array of `FeeResponse`): Array of fee objects showing the fees charged on this payment with their remaining refundable amounts. Populated whether the fees were provided via the `fees` array in the payment request or calculated automatically (for example, from a Standard Fee Configuration, or the `processing_fee` on a CAD payment). **Note:** This array is empty in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects (with `id`, `remaining_amount`, and `currency`), or poll with a subsequent Get Payment request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `refunded` (boolean): whether or not this payment has any refunds Example: `false`. - `status` (string): status of the payment One of: `pending`, `authorized`, `canceled`, `succeeded`, `failed`, `partially_refunded`, `fully_refunded`, `disputed`. - `payment_mode` (string): One of: `ecom`, `ach`, `card_present`. Example: `"ecom"`. - `terminal_id` (string): id of terminal used to process the card payment, if any Example: `"trm_123xyz"`. - `transaction_hold` (object) - `id` (string): unique transaction hold id Example: `"th_123xyz"`. - `financial_transaction_id` (string (uuid)): financial transaction id the transaction hold is associated to Example: `"ft_123xyz"`. - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### BankAccountPayment - `id` (string): unique payment id Example: `"py_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): payment amount in cents Example: `10000`. - `amount_disputed` (number): sum of open or lost disputes for this payment, in cents Example: `0`. - `amount_refunded` (number): sum of refunds for this payment, in cents Example: `0`. - `amount_refundable` (number): amount of this payment currently able to be refunded, in cents Example: `10000`. - `amount_returned` (number): amount of this payment reversed by an ACH return, in cents. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns) Example: `0`. - `balance` (number): Sum of debits and credits for this payment, in cents (reflects the amount this account has earned from this payment). Compiled and calculated value, eventually consistent. To see all changes affecting the payment's balance see [Get Payment Balance Transactions](#operation/GetPaymentBalanceTransactions). When an ACH payment is returned, the payment amount and its original fees are both reversed, so any remaining negative `balance` is the ACH return fee. Example: `99850`. - `fee_amount` (number): Sum of fees for this payment. Payments using an application fee include the ACH return fee here once the payment is returned; payments using [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) do not. Either way the return fee is recorded as a balance transaction. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns). Example: `150`. - `financial_transaction_id` (string): associated financial transaction id Example: `"ft_123xyz"`. - `captured` (boolean): whether or not this payment is captured Example: `true`. - `capture_strategy` (string): One of: `automatic`, `manual`. Example: `"automatic"`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my_order_xyz"`. - `disputed` (boolean): whether or not this payment has any open or lost disputes Example: `false`. - `disputes` (array): list of associated disputes - `error_code` (string): error code if the payment fails Example: `"credit_card_number_invalid"`. - `error_description` (string): text description of the error code Example: `"Credit Card Number Invalid (Failed LUHN checksum)"`. - `is_test` (boolean): whether or not this payment was made using the test account Example: `true`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment - `payment_intent_id` (string): unique id of associated payment intent Example: `"pi_123xyz"`. - `checkout_id` (string): unique id of associated checkout Example: `"cho_123"`. - `payment_method` (`BankAccountPaymentMethod`) - `application_fee` (`ApplicationFee`) - `application_fee_rate_id` (string): unique id of application fee rate applied to this payment, if any Example: `"afr_123xyz"`. - `fees` (array of `FeeResponse`): Array of fee objects showing the fees charged on this payment with their remaining refundable amounts. Populated whether the fees were provided via the `fees` array in the payment request or calculated automatically (for example, from a Standard Fee Configuration). **Note:** This array is empty in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects (with `id`, `remaining_amount`, and `currency`), or poll with a subsequent Get Payment request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `refunded` (boolean): whether or not this payment has any refunds Example: `false`. - `returned` (boolean): whether or not this payment was reversed by an ACH return Example: `false`. - `status` (string): status of the payment One of: `pending`, `authorized`, `canceled`, `succeeded`, `failed`, `partially_refunded`, `fully_refunded`, `disputed`. - `payment_mode` (string): One of: `ecom`, `ach`, `card_present`. Example: `"ecom"`. - `terminal_id` (string): id of terminal used to process a card payment, null for bank account payments Example: `"trm_123xyz"`. - `transaction_hold` (object) - `id` (string): unique transaction hold id Example: `"th_123xyz"`. - `financial_transaction_id` (string (uuid)): financial transaction id the transaction hold is associated to Example: `"ft_123xyz"`. - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments Example: `true`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### Fee A fee object specifying type and amount - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. ### PaymentError - `error` (object) - `code` (string): error code if the payment fails Example: `"card_declined"`. - `decline_code` (string): decline code if the payment fails Example: `"do_not_retry"`. - `message` (string): text description of the error code Example: `"This card has been rejected. Please try a different card or payment method"`. - `network` (string, nullable): card network used for payment Example: `"MASTERCARD"`. - `network_error_category` (string, nullable): network error category code Example: `"03"`. - `network_error_code` (string, nullable): network error code Example: `"504"`. ### ReturnedFeeResponse A returned fee object showing fee details returned to the merchant with a refund - `id` (string, required): Unique identifier for this returned fee Example: `"rtfee_xyz"`. - `payment_fee_id` (string, required): Unique identifier for the original payment fee that was partially or fully returned Example: `"pyfee_abc"`. - `type` (string, required): The type of fee that was returned: - `processing_fee`: Processing fee returned to merchant - `platform_fee`: Platform fee returned to merchant One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `returned_amount` (integer, required): Amount returned to the merchant in cents Example: `175`. - `original_amount` (integer, required): Original fee amount in cents from the payment Example: `350`. - `currency` (string, required): Currency of the fee amounts Example: `"usd"`. - `remaining_amount` (integer, required): Amount still available for refund on the original payment fee in cents Example: `175`. ### PaymentBalanceTransaction - `id` (string (uuid)): unique payment balance transaction id Example: `"pbt_123xyz"`. - `amount` (number): payment balance transaction amount, in cents Example: `40145`. - `balance` (number): balance amount of the payment balance transaction, in cents Example: `53550`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `financial_transaction_id` (string (uuid)): id of the financial transaction associated with the payment balance transaction Example: `"ft_123xyz"`. - `payment_id` (string (uuid)): id of the payment associated with the payment balance transaction Example: `"py_123xyz"`. - `payment_balance_txn_type` (string): Type of the transaction object associated with the payment balance transaction. - `payment`: Payment amount credited to the merchant - `payment_fee`: Application fee charged on the payment - `processing_fee`, `platform_fee`: Fees charged on the payment under [Enhanced Fee Management](#section/Enhanced-Fee-Management) - `refund`, `refund_failure`, `fee_refund`, `refund_processing_fee`: Refund and the fees returned or charged with it - `void`: Payment voided before settlement - `dispute`, `dispute_fee`, `dispute_refund`, `dispute_fee_refund`: Dispute amount and fee, and their reversals - `ach_return`: Payment amount reversed when an ACH payment is returned - `ach_return_fee`: Flat fee charged when an ACH payment is returned by the bank - `application_fee_returned`, `processing_fee_return`, `platform_fee_return`: Fees from the original payment returned on an ACH return See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns) for how these combine on a returned ACH payment. One of: `payment`, `payment_fee`, `processing_fee`, `platform_fee`, `payout`, `refund`, `refund_failure`, `refund_processing_fee`, `fee_refund`, `void`, `dispute`, `dispute_fee`, `dispute_fee_refund`, `dispute_refund`, `ach_return`, `ach_return_fee`, `application_fee_returned`, `processing_fee_return`, `platform_fee_return`. Example: `"fee_refund"`. - `source_id` (string (uuid)): id of the source object associated with the payment balance transaction Example: `"fee_123xyz"`. - `source_type` (string): type of the source object associated with the payment balance transaction (for example `Payment`, `ApplicationFee`, `PaymentFee`, `Refund`, `Dispute`, `AchReturnFee`) Example: `"ApplicationFee"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### CardPaymentMethod - `card` (`Card`) - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### ApplicationFee - `id` (string (uuid)): unique application fee id Example: `"fee_123xyz"`. - `amount` (number): application fee amount, in cents Example: `150`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### FeeResponse A fee object in API responses. The `fees` array is empty in the Create Payment response — subscribe to payment webhook events (recommended) to receive the full fee objects, or poll with a subsequent Get Payment request. - `id` (string): Unique identifier for this fee. Present when fetching a payment. Example: `"pyfee_xyz"`. - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services - `refund_processing_fee`: A processing fee charged when a refund is processed. Currently applies to CAD payments only. One of: `processing_fee`, `platform_fee`, `refund_processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. - `currency` (string): Currency of the fee amount. Present when fetching a payment. One of: `usd`, `cad`. Example: `"usd"`. - `remaining_amount` (integer): Amount still available for refund in cents. Updates after each partial refund. Present when fetching a payment. Example: `350`. - `source_configuration_id` (string, nullable): The public ID of the Standard Fee Configuration used to calculate this fee. Null when the fee was explicitly provided in the payment request rather than auto-calculated. Example: `"sfc_abc123"`. - `source_fee_type` (string, nullable): The fee type from the Standard Fee Configuration that generated this fee (e.g., `processing_ecomm`, `amex_brand_ecomm`, `platform`). Null when the fee was explicitly provided in the payment request. Example: `"amex_brand_ecomm"`. - `refund_id` (string, nullable): The public ID of the refund this fee is associated with. Populated for `refund_processing_fee` fees (currently CAD payments only); null for all other fees. Present when fetching a payment. Example: `"re_xyz"`. ### BankAccountPaymentMethod - `bank_account` (`BankAccount`) - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### Card - `id` (string (uuid)): unique card id Example: `"pm_123xyz"`. - `acct_last_four` (string): last 4 digits of the card number Example: `4242`. - `brand` (any): card brand or bank name Example: `"Visa"`. - `digital_wallet` (string, nullable): which digital wallet provider the card is tied to One of: `apple_pay`, `google_pay`, `null`. Example: `"apple_pay"`. - `name` (string, nullable): card or account holder name Example: `"Amanda Kessel"`. - `token` (any): same value as unique card id; can be saved and used to process multiple payments with the same card Example: `"pm_123xyz"`. - `month` (any): expiration date month Example: `"5"`. - `year` (any): expiration date year Example: `"2042"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this card - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `address_line1_check` (string): Result of the address line 1 verification check. `pass` — matches the cardholder's address on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no address was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. - `address_postal_code_check` (string): Result of the postal code verification check. `pass` — matches the cardholder's postal code on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no postal code was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. ### BankAccount - `id` (string (uuid)): unique bank account payment method id Example: `"pm_123xyz"`. - `account_owner_name` (string): account owner name Example: `"Lindsay Whalen"`. - `account_type` (string): type of account (checking, savings, etc.) Example: `"checking"`. - `bank_name` (string, nullable): bank name Example: `"Wells Fargo"`. - `acct_last_four` (string): last 4 digits of the account number Example: `1111`. - `token` (any): same value as unique bank account id; can be saved and used to process multiple payments with the same bank account Example: `"pm_123xyz"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this bank account --- # Payment Methods Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods Payment methods refer to the specific form of payment each customer uses (e.g. their credit card). Payment methods are tokenized, then charged at time of payment. ## List Payment Methods `GET https://api.justifi.ai/v1/payment_methods` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/ListPaymentMethods List the payment methods for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `customer_id` | query | string | no | Note: customer_id is a deprecated field. Please use our payment method groups instead. filter records which are associated with a customer. | | `payment_method_group_id` | query | string | no | filter records which are associated with a payment method group. | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | ### Responses #### 200: Successfully list payment methods Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of one of `CardPaymentMethodWithBinDetails` | `BankAccountPaymentMethodWithStatus` | `CardPresentPaymentMethod`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Payment Method `POST https://api.justifi.ai/v1/payment_methods` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/CreatePaymentMethod **This endpoint requires prior approval.** New integrations should use the **[JustiFi Tokenize Payment Method Web Component](https://docs.justifi.tech/web-components/payment-facilitation/tokenize-payment-method)** to securely collect and tokenize payment method details. The web component handles PCI-scoped data collection and returns a payment method token that you can pass to the [Create Payment](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment) endpoint. If you have a use case that requires creating payment methods directly via the API, contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) for approval. At minimum, a completed SAQ (Self-Assessment Questionnaire) is required to allow raw PAN submissions. *Note: If the sub account status is not `enabled`, `400` will be returned.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | yes | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Request body Content type: `application/json` - `payment_method` (one of object, required) - Option 1: - `payment_method_group_id` (string): When present this payment method will be associated with the given payment method group - `card` (`CreateCard`) - `bank_account` (`CreateBankAccount`): Bank Account - `email` (string (email)): email address to associate with the payment method - `force_tokenize` (boolean): Optional. If set to true in the request payload, allows for tokenization even if validations and authorization fail during the creation of the payment method ```json { "payment_method": { "payment_method_group_id": "pmg_123xyz", "card": { "name": "Lindsay Whalen", "number": 4242424242421111, "verification": 123, "month": 5, "year": 2042, "address_postal_code": 55555, "metadata": { "new": "info" } } } } ``` ### Responses #### 201: Payment method was created successfully Content type: `application/json` Schema: one of `CardResponse` | `BankAccountResponse` | `CardPresentResponse` #### 400: Full card number submitted without PCI approval Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "full_pan_not_allowed", "message": "Full card numbers are not accepted on this endpoint. Please use the tokenization iframe to create a payment method token first." } } ``` ## Get a Payment Method `GET https://api.justifi.ai/v1/payment_methods/{token}` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/GetPaymentMethod Get information about a payment method. *Note: This is the primary endpoint recommended for retrieving bin_details related to a card payment method. bin_details are not guaranteed to be present on every card — availability depends on the card network and issuer. When unavailable, the bin_details field will be null.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `token` | path | string | yes | | ### Responses #### 200: Successfully get a payment method Content type: `application/json` Schema: one of `CardResponse` | `BankAccountResponse` | `CardPresentResponse` ## Update a Payment Method `PATCH https://api.justifi.ai/v1/payment_methods/{token}` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/UpdatePaymentMethod Change a payment method's expiration date, address, or metadata. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `token` | path | string | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `card` (`UpdateCard`) ### Responses #### 200: Payment method update was successful Content type: `application/json` Schema: one of `CardResponse` | `BankAccountResponse` | `CardPresentResponse` ## Clone a Payment Method `POST https://api.justifi.ai/v1/payment_methods/{token}/clone` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/ClonePaymentMethod Copy a payment method from one sub account to another sub account. This allows one to share payment methods between accounts without having to collect the card information again. The original payment method's id / token should be provided in the path. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `token` | path | string | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `destination_account_id` (string): The sub account id to which the payment method should be cloned Example: `"acc_xyz123"`. ### Responses #### 200: Payment method clone was successful Content type: `application/json` Schema: one of `CardResponse` | `BankAccountResponse` | `CardPresentResponse` ## Schemas ### CardPaymentMethodWithBinDetails - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"nil"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `card` (`CardWithBinDetails`) - `customer_id` (string, nullable): id of the customer associated with the payment method Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### BankAccountPaymentMethodWithStatus - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"nil"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `bank_account` (`BankAccount`) - `customer_id` (string, nullable): id of the customer associated with the payment method Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### CardPresentPaymentMethod - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"nil"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `card_present` (object) - `id` (string (uuid)): unique card present payment method id Example: `"cp_7SdSRKRMADOn2Yi5expjej"`. - `brand` (string): card brand or institution Example: `"visa"`. - `cardholder_name` (string): name of the cardholder Example: `"CARDHOLDER/VISA"`. - `last4` (string): last 4 digits of the card number Example: `"2970"`. - `expiry` (string): card expiration date in MM/YY format Example: `"11/30"`. - `type` (string): the payment method type Example: `"card_present"`. - `customer_id` (string, nullable): id of the customer associated with the payment method Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### CreateCard - `name` (string, required): cardholder full name Example: `"Kevin Garnett"`. - `number` (string, required): card number Example: `4242424242424242`. - `verification` (string): card verification number Example: `123`. - `month` (string, required): card expiration month Example: `5`. - `year` (string, required): card expiration year Example: `2042`. - `address_line1` (string): card address street Example: `"123 Fake St"`. - `address_line2` (string): card address apartment, suite, etc. Example: `"Suite 101"`. - `address_city` (string): card address city Example: `"Cityville"`. - `address_state` (string): card address state Example: `"MN"`. - `address_postal_code` (string, required): card address ZIP Example: `55555`. - `address_country` (string): card address 2-character country code Example: `"US"`. - `brand` (string): card brand or institution Example: `"Visa"`. - `metadata` (object (json)): any useful information you'd like to store alongside this card ### CreateBankAccount Bank Account - `account_owner_name` (string, required): account owner name Example: `"Lindsay Whalen"`. - `routing_number` (string, required): routing number Example: `"110000000"`. - `account_number` (string, required): bank account number Example: `"000123456789"`. - `account_type` (string, required): type of account One of: `checking`, `savings`. Example: `"checking"`. - `account_owner_type` (string, required): type of account holder One of: `individual`, `company`. Example: `"individual"`. - `country` (string, required): country associated with the bank account Example: `"US"`. - `currency` (string, required): currency of the bank account One of: `usd`, `cad`. Example: `"usd"`. - `bank_name` (string): bank name Example: `"Wells Fargo"`. - `metadata` (object (json)): any useful information you'd like to store alongside this bank account ### CardResponse - `id` (number): the object id Example: `"pm_123xyz"`. - `type` (string): the object type, or array of objects Example: `"payment_method"`. - `data` (object): the attributes for the object - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `signature` (string, nullable): unique signature associated with the payment_method Example: `"3aGWnUznQ"`. - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_123abc"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"INVALID_ACCOUNT_NUMBER"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `card` (object): the card associated with the payment_method - `id` (string (uuid)): unique card payment method id Example: `"pm_123xyz"`. - `name` (string, nullable): card holder name Example: `"Lindsay Whalen"`. - `acct_last_four` (string): last 4 digits of the account number Example: `1111`. - `brand` (string): card brand or institution Example: `"visa"`. - `digital_wallet` (string, nullable): which digital wallet provider the card is tied to One of: `apple_pay`, `google_pay`, `null`. Example: `"apple_pay"`. - `token` (any): same value as unique bank account id; can be saved and used to process multiple payments with the same bank account Example: `"pm_123xyz"`. - `month` (any): expiration date month Example: `"5"`. - `year` (any): expiration date year Example: `"2042"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this card - `address_line1_check` (string): Result of the address line 1 verification check. `pass` — matches the cardholder's address on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no address was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"pass"`. - `address_postal_code_check` (string): Result of the postal code verification check. `pass` — matches the cardholder's postal code on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no postal code was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"pass"`. - `bin_details` (`BinDetails`, nullable): BIN details for this card. Not guaranteed to be present — availability depends on the card network and issuer. - `page_info` (string, nullable): information for cursor style pagination, is null for single records ### BankAccountResponse - `id` (number): the object id Example: `"pm_123xyz"`. - `type` (string): the object type, or array of objects Example: `"payment_method"`. - `data` (object): the attributes for the object - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `signature` (string, nullable): unique signature associated with the payment_method Example: `"3aGWnUznQ"`. - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_123abc"`. - `account_id` (string): account id associated with payment method Example: `"acc_123"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"nil"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `bank_account` (object): the bank account associated with the payment_method - `id` (string (uuid)): unique bank account payment method id Example: `"pm_123xyz"`. - `account_owner_name` (string): account owner name Example: `"Lindsay Whalen"`. - `account_type` (string): type of account (checking, savings, etc.) Example: `"checking"`. - `bank_name` (string, nullable): bank name Example: `"Wells Fargo"`. - `acct_last_four` (string): last 4 digits of the account number Example: `1111`. - `token` (any): same value as unique bank account id; can be saved and used to process multiple payments with the same bank account Example: `"pm_123xyz"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this bank account - `page_info` (string, nullable): information for cursor style pagination, is null for single records ### CardPresentResponse - `id` (number): the object id Example: `"pm_123xyz"`. - `type` (string): the object type, or array of objects Example: `"payment_method"`. - `data` (object): the attributes for the object - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `signature` (string, nullable): unique signature associated with the payment_method Example: `"3aGWnUznQ"`. - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_123abc"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. - `status` (string): signals whether the payment method is valid or invalid Example: `"valid"`. - `invalid_reason` (string, nullable): informs reason that the payment method has been marked invalid, if status is invalid Example: `"INVALID_ACCOUNT_NUMBER"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `card_present` (object): the card present payment method - `id` (string (uuid)): unique card present payment method id Example: `"cp_7SdSRKRMADOn2Yi5expjej"`. - `brand` (string): card brand or institution Example: `"visa"`. - `cardholder_name` (string): name of the cardholder Example: `"CARDHOLDER/VISA"`. - `last4` (string): last 4 digits of the card number Example: `"2970"`. - `expiry` (string): card expiration date in MM/YY format Example: `"11/30"`. - `type` (string): the payment method type Example: `"card_present"`. - `page_info` (string, nullable): information for cursor style pagination, is null for single records ### PaymentError - `error` (object) - `code` (string): error code if the payment fails Example: `"card_declined"`. - `decline_code` (string): decline code if the payment fails Example: `"do_not_retry"`. - `message` (string): text description of the error code Example: `"This card has been rejected. Please try a different card or payment method"`. - `network` (string, nullable): card network used for payment Example: `"MASTERCARD"`. - `network_error_category` (string, nullable): network error category code Example: `"03"`. - `network_error_code` (string, nullable): network error code Example: `"504"`. ### UpdateCard - `month` (string): new expiration month Example: `5`. - `year` (string): new expiration year Example: `2042`. - `address_line1` (string): new card address street Example: `"123 Fake St"`. - `address_line2` (string): new card address apartment, suite, etc. Example: `"Suite 101"`. - `address_city` (string): new card address city Example: `"Cityville"`. - `address_state` (string): new card address state Example: `"MN"`. - `address_postal_code` (string): new card address ZIP Example: `55555`. - `address_country` (string): new card address 2-character country code Example: `"US"`. - `metadata` (object (json)): any useful information you'd like to store alongside this card; when you update metadata, any previous metadata will be overwritten ### CardWithBinDetails - `id` (string (uuid)): unique card id Example: `"pm_123xyz"`. - `acct_last_four` (string): last 4 digits of the card number Example: `4242`. - `brand` (any): card brand or bank name Example: `"Visa"`. - `digital_wallet` (string, nullable): which digital wallet provider the card is tied to One of: `apple_pay`, `google_pay`, `null`. Example: `"apple_pay"`. - `name` (string, nullable): card or account holder name Example: `"Amanda Kessel"`. - `token` (any): same value as unique card id; can be saved and used to process multiple payments with the same card Example: `"pm_123xyz"`. - `month` (any): expiration date month Example: `"5"`. - `year` (any): expiration date year Example: `"2042"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this card - `address_line1_check` (string): Result of the address line 1 verification check. `pass` — matches the cardholder's address on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no address was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. - `address_postal_code_check` (string): Result of the postal code verification check. `pass` — matches the cardholder's postal code on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no postal code was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. - `bin_details` (`BinDetails`, nullable): BIN details for this card. Not guaranteed to be present — availability depends on the card network and issuer. ### BankAccount - `id` (string (uuid)): unique bank account payment method id Example: `"pm_123xyz"`. - `account_owner_name` (string): account owner name Example: `"Lindsay Whalen"`. - `account_type` (string): type of account (checking, savings, etc.) Example: `"checking"`. - `bank_name` (string, nullable): bank name Example: `"Wells Fargo"`. - `acct_last_four` (string): last 4 digits of the account number Example: `1111`. - `token` (any): same value as unique bank account id; can be saved and used to process multiple payments with the same bank account Example: `"pm_123xyz"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this bank account ### BinDetails BIN (Bank Identification Number) details for a card. bin_details are not guaranteed to be present on every card payment method — availability depends on the card network and issuer. When unavailable, this field will be null. - `type` (string): Type of card issued, values include Credit, Debit, Prepaid, Unknown Example: `"Credit"`. - `card_brand` (string): Brand or network associated with card. Possible values include Visa, Mastercard, American Express, Discover Example: `"Visa"`. - `card_class` (string): Example: `"Consumer"`. - `country` (string): Long form country name which issued the card Example: `"United States of America"`. - `issuer` (string): Issuing bank Example: `"WELLS FARGO BANK, N.A."`. - `funding_source` (string): Source of funds defined by BIN for a given card. Values include Charge, Credit, Debit, Deferred Debit (Visa Only), Network Only, Prepaid Example: `"Credit"`. --- # Tokenize via Component Reference: https://docs.justifi.tech/api-spec#tag/Tokenize-via-Component The Tokenize Payment Method web component allows you to securely collect your customers' credit card and ACH (bank accout) payment methods without any sensitive data entering your system. The following guide takes you through the few simple steps of integrating the [Tokenize Payment Method web component](/web-components/payment-facilitation/tokenize-payment-method) on your platform. We assume you have an activated sub account for payment processing. *Note: If you want to charge a payment at time of payment method tokenization consider using the [Unified Fintech Checkout™ web component](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component) instead.* 1. Get an access token 2. Generate a web component token 3. Render the web component 4. Handle success/failure events 5. Listen to payment method events ### Get an access token On your backend, using your client id and client secret from the Developer > API keys section of the JustiFi dashboard, generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken). ``` function getToken() { return fetch('https://api.justifi.ai/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "client_id": "YOUR CLIENT ID", "client_secret": "YOUR CLIENT SECRET" }) }) .then(response => response.json()) .then(data => data.access_token); } const token = await getToken(); ``` ### Generate a web component token To render the web component you need to generate a web component token. This is a short lived token which is meant to grant short term, fine grained access. The Tokenize Payment Method web component requires the role of `write:tokenize:{accountId}` with the sub account id you are saving the payment method for. *Note: Consider setting up a [Platform Wallet Account](https://docs.justifi.tech/api-spec#tag/Platform-Wallet-Accounts) if your customers will use payment methods accross different sub accounts on your platform.* ``` async function getWebComponentToken(token, accountId) { const response = await fetch('https://api.justifi.ai/v1/web_component_tokens', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "resources": [`write:tokenize:${accountId}] }) }); const data = await response.json(); return data.access_token; } const webComponentToken = await getWebComponentToken(token, subAccountId); ``` ### Render the web component Use the web component token generated above and the sub account id passed to the web component token API to render the [Tokenize Payment Method web component](/web-components/payment-facilitation/tokenize-payment-method). This will allow you to collect a customer's credit card or ACH payment method. It will not process a payment. ``` ``` ### Handle success/failure events The web component will emit a `submitted` event when a payment method is submitted. This event will contain the response of the [Create Payment Method API](https://docs.justifi.tech/api-spec#tag/Payment-Methods/operation/CreatePaymentMethod) which includes the payment method `token` attribute. To charge a payment to the newly tokenized payment method pass this token as payment method token to the [Payments API](https://docs.justifi.tech/api-spec#tag/Payments/operation/CreatePayment). An `error` event means there was an issue with the Tokenize Payment Method web component, connecting to the network, etc. ``` ``` At this point, the payment method has been tokenized and can be used for future payments! ### Listen to payment method events In addition to the web component events you can listen to [payment method specific events](https://docs.justifi.tech/api-spec#tag/Events) via event publisher. To set up an event publisher go to the Developer > Event Pubslisher section of the JustiFi dashboard. --- # Payment Method Groups Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups Payment method groups are a way to associate payment methods to a single group for easy access. ## List Payment Method Groups `GET https://api.justifi.ai/v1/payment_method_groups` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/ListPaymentMethodGroup List payment method groups associated to an account ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Responses #### 200: Successfully list payment method groups Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `PaymentMethodGroupResponse`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Payment Method Group `POST https://api.justifi.ai/v1/payment_method_groups` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/CreatePaymentMethodGroup You can create payment methods groups ahead of time, then associate payment methods and easily filter them. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | yes | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Responses #### 201: Payment method group was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payment_method_group"`. - `data` (object): the attributes for the object - `id` (string): the object id Example: `"pm_123xyz"`. - `account_id` (string): the account_id associated with the object Example: `"acc_123xyz"`. - `platform_account_id` (string): the account_id for the platform account associated with the object Example: `"acc_321abc"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Payment Method Group `GET https://api.justifi.ai/v1/payment_method_groups/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/GetPaymentMethodGroup Get payment method group associated to an account ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `id` | path | string (uuid) | yes | | ### Responses #### 200: Successfully get payment method group Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payment_method_group"`. - `data` (object): the attributes for the object - `id` (string): the object id Example: `"pm_123xyz"`. - `account_id` (string): the account_id associated with the object Example: `"acc_123xyz"`. - `platform_account_id` (string): the account_id for the platform account associated with the object Example: `"acc_321abc"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Payment Method Group `PATCH https://api.justifi.ai/v1/payment_method_groups/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/PatchPaymentMethodGroup Updates a payment method group to associate payment methods ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `id` | path | string (uuid) | yes | | ### Request body Content type: `application/json` - `payment_method_ids` (array of uuid): Payment method ids to be associated with the payment method group ### Responses #### 200: Payment method group update successful ## Remove a Payment Method from a Payment Method Group `DELETE https://api.justifi.ai/v1/payment_method_groups/{id}/payment_methods/{payment_method_id}` Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups/operation/RemovePaymentMethodFromGroup Removes a payment method from a payment method group ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `id` | path | string (uuid) | yes | | | `payment_method_id` | path | string (uuid) | yes | ID of the payment method to remove Example: `"pm_123xyz"`. | ### Responses #### 200: Payment method successfully removed from group ## Schemas ### PaymentMethodGroupResponse - `id` (string): the object id Example: `"pm_123xyz"`. - `account_id` (string): the account_id associated with the object Example: `"acc_123xyz"`. - `platform_account_id` (string): the account_id for the platform account associated with the object Example: `"acc_321abc"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Refunds Reference: https://docs.justifi.tech/api-spec#tag/Refunds When you refund a payment, a refund object is created. You can retrieve information about the refunds you've issued. ## Refund a Payment `POST https://api.justifi.ai/v1/payments/{id}/refunds` Reference: https://docs.justifi.tech/api-spec#tag/Refunds/operation/CreateRefund Issue a refund for a payment. You may refund the full payment amount or just a portion. When refunding a portion, multiple refunds are supported up until the full payment amount has been refunded. *Note: If the sub account status is not `enabled`, `400` will be returned.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `amount` (number): amount to refund; must be less than or equal to the `amount_refundable` on the payment Example: `10000`. - `description` (string): an optional note about this refund - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `fees` (array of object): Array of fee objects to return to the merchant as part of this refund. If omitted, no fees are returned (current behavior preserved). Each fee object specifies: - `type`: The fee type to refund (`processing_fee` or `platform_fee`) - `amount`: Amount to return in cents **Validation:** - The requested amount cannot exceed the `remaining_amount` for that fee type on the original payment - The fee type must exist on the original payment > **CAD Payments:** This parameter is not available for CAD payments. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `type` (string, required): The type of fee to refund One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Amount to refund in cents Example: `175`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund ```json { "amount": 10000, "reason": "customer_request", "description": "Customer requested full refund" } ``` ### Responses #### 201: Refund was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"refund"`. - `data` (object): the attributes for the object - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## List Refunds `GET https://api.justifi.ai/v1/refunds` Reference: https://docs.justifi.tech/api-spec#tag/Refunds/operation/ListRefunds List the refunds for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Responses #### 200: Successfully list refunds Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Refund`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Refund `GET https://api.justifi.ai/v1/refunds/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Refunds/operation/GetRefund Get information about a refund. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a refund Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"refund"`. - `data` (object): the attributes for the object - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Refund `PATCH https://api.justifi.ai/v1/refunds/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Refunds/operation/UpdateRefund Update the refund metadata. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `metadata` (object (json)): any useful information you'd like to store alongside this refund; when you update metadata, any previous metadata will be overwritten ### Responses #### 200: Refund update was successful Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"refund"`. - `data` (object): the attributes for the object - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### ReturnedFeeResponse A returned fee object showing fee details returned to the merchant with a refund - `id` (string, required): Unique identifier for this returned fee Example: `"rtfee_xyz"`. - `payment_fee_id` (string, required): Unique identifier for the original payment fee that was partially or fully returned Example: `"pyfee_abc"`. - `type` (string, required): The type of fee that was returned: - `processing_fee`: Processing fee returned to merchant - `platform_fee`: Platform fee returned to merchant One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `returned_amount` (integer, required): Amount returned to the merchant in cents Example: `175`. - `original_amount` (integer, required): Original fee amount in cents from the payment Example: `350`. - `currency` (string, required): Currency of the fee amounts Example: `"usd"`. - `remaining_amount` (integer, required): Amount still available for refund on the original payment fee in cents Example: `175`. ### Refund - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Disputes Reference: https://docs.justifi.tech/api-spec#tag/Disputes A customer may dispute their payment with the card issuer/bank if they believe the charge is erroneous. When this happens, a dispute record is created and associated with their original payment. ## List Disputes `GET https://api.justifi.ai/v1/disputes` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/ListDisputes Any disputes associated with a payment are also included in the response of the [get payment API](https://docs.justifi.tech/api-spec#tag/Payments/operation/GetPayment) and the [list payments API](https://docs.justifi.tech/api-spec#tag/Payments/operation/ListPayments) response ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Responses #### 200: Successfully list disputes Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Dispute`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Dispute `GET https://api.justifi.ai/v1/disputes/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/GetDispute Get information about a dispute. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a dispute Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"dispute"`. - `data` (object): the attributes for the object - `id` (string): unique dispute id Example: `"dp_xyz"`. - `payment_id` (string (uuid)): the disputed payment Example: `"py_xyz"`. - `account_id` (string (uuid)): id of the account associated with the dispute Example: `"acc_xyz"`. - `amount` (number): amount disputed in cents Example: `100`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `reason` (string): the reason this payment was disputed Example: `"fraudulent"`. - `due_date` (string (date)): due date for evidence submission to counter the dispute Example: `"2025-02-23"`. - `status` (string): status of the dispute One of: `needs_response`, `under_review`, `won`, `lost`. Example: `"won"`. - `metadata` (object (json)): any useful information you'd like to store alongside this dispute - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `dispute_response` (object) - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `dispute_reversal` (object, nullable): present when dispute gets reversed from lost to won - `description` (string): Example: `"Dispute was reversed"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Dispute `PATCH https://api.justifi.ai/v1/disputes/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/UpdateDispute Change a dispute's metadata. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `metadata` (object (json)): any useful information you'd like to store alongside this dispute; when you update metadata, any previous metadata will be overwritten ### Responses #### 200: Dispute update was successful Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"dispute"`. - `data` (object): the attributes for the object - `id` (string): unique dispute id Example: `"dp_xyz"`. - `payment_id` (string (uuid)): the disputed payment Example: `"py_xyz"`. - `account_id` (string (uuid)): id of the account associated with the dispute Example: `"acc_xyz"`. - `amount` (number): amount disputed in cents Example: `100`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `reason` (string): the reason this payment was disputed Example: `"fraudulent"`. - `due_date` (string (date)): due date for evidence submission to counter the dispute Example: `"2025-02-23"`. - `status` (string): status of the dispute One of: `needs_response`, `under_review`, `won`, `lost`. Example: `"won"`. - `metadata` (object (json)): any useful information you'd like to store alongside this dispute - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `dispute_response` (object) - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `dispute_reversal` (object, nullable): present when dispute gets reversed from lost to won - `description` (string): Example: `"Dispute was reversed"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Create dispute evidence `PUT https://api.justifi.ai/v1/disputes/{id}/evidence` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/CreateDisputeEvidence Creates dispute evidence and generate presigned url > ⚠️ **Not available for Canada accounts** > > The dispute response and evidence endpoints are not available for Canada accounts. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `file_name` (string, required): dispute evidence file name Example: `"receipt.pdf"`. - `file_type` (string, required): dispute evidence file type One of: `image/jpeg`, `image/png`, `application/pdf`, `application/zip`, `application/x-zip-compressed`. Example: `"application/pdf"`. - `dispute_evidence_type` (string, required): dispute evidence type matching the file that will be uploaded One of: `cancellation_policy`, `customer_communication`, `customer_signature`, `duplicate_charge_documentation`, `receipt`, `refund_policy`, `service_documentation`, `shipping_documentation`, `uncategorized_file`. Example: `"receipt"`. - `description` (string): description of the dispute evidence file that will be uploaded - `metadata` (object (json)): any useful information you'd like to store alongside the dispute evidence ### Responses #### 201: Dispute evidence created and presigned url generated Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"dispute evidence"`. - `data` (object): the attributes for the object - `id` (string): unique dispute evidence id Example: `"dpe_xyz"`. - `file_name` (string): dispute evidence file name Example: `"receipt.pdf"`. - `file_type` (string): dispute evidence file type One of: `image/jpeg`, `image/png`, `application/pdf`, `application/zip`, `application/x-zip-compressed`. Example: `"application/pdf"`. - `dispute_evidence_type` (string): dispute evidence type matching the file that will be uploaded One of: `cancellation_policy`, `customer_communication`, `customer_signature`, `duplicate_charge_documentation`, `receipt`, `refund_policy`, `service_documentation`, `shipping_documentation`, `uncategorized_file`. Example: `"receipt"`. - `status` (string): dispute evidence status One of: `pending`, `uploaded`. - `description` (string): description of the dispute evidence file that will be uploaded - `presigned_url` (string): url that should be used to submit a put request to upload the evidence file - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Submit dispute response `POST https://api.justifi.ai/v1/disputes/{id}/response` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/SubmitDisputeResponse Submits the dispute response > ⚠️ **Not available for Canada accounts** > > The dispute response and evidence endpoints are not available for Canada accounts. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `forfeit` (boolean, required): when true forfeits the dispute and all other parameters passed in are ignored - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge ### Responses #### 200: Dispute response submitted Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"dispute"`. - `data` (object): the attributes for the object - `id` (string): unique dispute id Example: `"dp_xyz"`. - `payment_id` (string (uuid)): the disputed payment Example: `"py_xyz"`. - `account_id` (string (uuid)): id of the account associated with the dispute Example: `"acc_xyz"`. - `amount` (number): amount disputed in cents Example: `100`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `reason` (string): the reason this payment was disputed Example: `"fraudulent"`. - `due_date` (string (date)): due date for evidence submission to counter the dispute Example: `"2025-02-23"`. - `status` (string): status of the dispute One of: `needs_response`, `under_review`, `won`, `lost`. Example: `"won"`. - `metadata` (object (json)): any useful information you'd like to store alongside this dispute - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `dispute_response` (object) - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `dispute_reversal` (object, nullable): present when dispute gets reversed from lost to won - `description` (string): Example: `"Dispute was reversed"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update dispute response `PATCH https://api.justifi.ai/v1/disputes/{id}/response` Reference: https://docs.justifi.tech/api-spec#tag/Disputes/operation/UpdateDisputeResponse Updates the dispute response > ⚠️ **Not available for Canada accounts** > > The dispute response and evidence endpoints are not available for Canada accounts. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge ### Responses #### 200: Dispute response updated Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"dispute response"`. - `data` (object): the attributes for the object - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Dispute - `id` (string): unique dispute id Example: `"dp_xyz"`. - `payment_id` (string (uuid)): the disputed payment Example: `"py_xyz"`. - `account_id` (string (uuid)): id of the account associated with the dispute Example: `"acc_xyz"`. - `amount` (number): amount disputed in cents Example: `100`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `reason` (string): the reason this payment was disputed Example: `"fraudulent"`. - `due_date` (string (date)): due date for evidence submission to counter the dispute Example: `"2025-02-23"`. - `status` (string): status of the dispute One of: `needs_response`, `under_review`, `won`, `lost`. Example: `"won"`. - `metadata` (object (json)): any useful information you'd like to store alongside this dispute - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `dispute_response` (object) - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `dispute_reversal` (object, nullable): present when dispute gets reversed from lost to won - `description` (string): Example: `"Dispute was reversed"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Payouts Reference: https://docs.justifi.tech/api-spec#tag/Payouts Each day, a payout containing that day's funds is automatically created for the purpose of distributing those funds to the active bank account. Payout amounts are calculated by summing the associated balance transactions for that specific day. Payouts are processed each day at 11:30am US/Central time. A Platform can also configure each sub account to have an expedited payout priority. If this is enabled, the payout will be settled on the day the payout is generated. Otherwise, standard payouts will settle the next business day. ## List Payouts `GET https://api.justifi.ai/v1/payouts` Reference: https://docs.justifi.tech/api-spec#tag/Payouts/operation/ListPayouts ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `deposits_before` | query | string (date-time) | no | filter records which deposit before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `deposits_after` | query | string (date-time) | no | filter records which deposit after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | ### Responses #### 200: Successfully list payouts Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Payout`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Payout `GET https://api.justifi.ai/v1/payouts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payouts/operation/GetPayout Get information about a payout. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a payout Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payout"`. - `data` (object): the attributes for the object - `id` (string): unique payout id Example: `"po_xyz"`. - `account_id` (string (uuid)): id of the account associated with the payout - `amount` (number): payout amount in cents Example: `100000`. - `bank_account` (`PayoutBankAccount`) - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `delivery_method` (string): how the payout is delivered One of: `standard`. - `description` (string, nullable) - `deposits_at` (string (date-time)): in UTC, the estimated date and time of the payout deposit (or in rare cases, withdrawal) Example: `"2021-01-01T12:00:00Z"`. - `fees_total` (number): sum of fees in the payout, in cents Example: `5000`. - `refunds_count` (number): number of refunds in the payout Example: `5`. - `refunds_total` (number): sum of refunds in the payout, in cents Example: `10000`. - `payments_count` (number): number of payments in the payout Example: `50`. - `payments_total` (number): sum of payments in the payout, in cents Example: `110000`. - `payout_type` (string): type of payment method used for the payments in the payout (funds from different types of payment methods settle at different intervals; in order to pay out your funds ASAP, we batch separate payouts for each payment method type) One of: `ach cc`. - `other_total` (number): sum of other less common transactions in the payout, in cents Example: `100`. - `platform_fees_total` (number, nullable): gross fees your platform charged its sub accounts in a proceeds payout, in cents, null for sub account payouts - `justifi_fees_total` (number, nullable): processing fees JustiFi charged your platform in a proceeds payout, in cents, always positive, null for sub account payouts - `interchange_network_fees` (number, nullable): interchange and card network fees passed through to your platform in a proceeds payout, in cents, usually negative, null for sub account payouts - `status` (string): status of the payout One of: `paid failed forwarded scheduled in_transit canceled`. Example: `"paid"`. - `settlement_priority` (string): settlement priority of the payout, either standard or expedited. One of: `standard expedited`. Example: `"standard"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payout - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Payout `PATCH https://api.justifi.ai/v1/payouts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payouts/operation/UpdatePayout Change a payout's metadata. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `metadata` (object (json)): any useful information you'd like to store alongside this payout; when you update metadata, any previous metadata will be overwritten ### Responses #### 200: Payout update was successful Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payout"`. - `data` (object): the attributes for the object - `id` (string): unique payout id Example: `"po_xyz"`. - `account_id` (string (uuid)): id of the account associated with the payout - `amount` (number): payout amount in cents Example: `100000`. - `bank_account` (`PayoutBankAccount`) - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `delivery_method` (string): how the payout is delivered One of: `standard`. - `description` (string, nullable) - `deposits_at` (string (date-time)): in UTC, the estimated date and time of the payout deposit (or in rare cases, withdrawal) Example: `"2021-01-01T12:00:00Z"`. - `fees_total` (number): sum of fees in the payout, in cents Example: `5000`. - `refunds_count` (number): number of refunds in the payout Example: `5`. - `refunds_total` (number): sum of refunds in the payout, in cents Example: `10000`. - `payments_count` (number): number of payments in the payout Example: `50`. - `payments_total` (number): sum of payments in the payout, in cents Example: `110000`. - `payout_type` (string): type of payment method used for the payments in the payout (funds from different types of payment methods settle at different intervals; in order to pay out your funds ASAP, we batch separate payouts for each payment method type) One of: `ach cc`. - `other_total` (number): sum of other less common transactions in the payout, in cents Example: `100`. - `platform_fees_total` (number, nullable): gross fees your platform charged its sub accounts in a proceeds payout, in cents, null for sub account payouts - `justifi_fees_total` (number, nullable): processing fees JustiFi charged your platform in a proceeds payout, in cents, always positive, null for sub account payouts - `interchange_network_fees` (number, nullable): interchange and card network fees passed through to your platform in a proceeds payout, in cents, usually negative, null for sub account payouts - `status` (string): status of the payout One of: `paid failed forwarded scheduled in_transit canceled`. Example: `"paid"`. - `settlement_priority` (string): settlement priority of the payout, either standard or expedited. One of: `standard expedited`. Example: `"standard"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payout - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Payout CSV Report `GET https://api.justifi.ai/v1/reports/payouts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payouts/operation/GetPayoutCsvReport **Deprecated.** [DEPRECATION WARNING] This endpoint will be deprecated, please use [Reports API](#tag/Reports). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a link to a csv report for a payout Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payout"`. - `data` (object): the attributes for the object - `id` (string): unique payout id Example: `"po_xyz"`. - `csv_url` (string): url that links to downloadable CSV report for payout. Example: `"https://justifi-test-payouts-reports.s3.amazonaws.com/acc_1234lkj/po_23jdfi36dqhj.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=test"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Payout - `id` (string): unique payout id Example: `"po_xyz"`. - `account_id` (string (uuid)): id of the account associated with the payout - `amount` (number): payout amount in cents Example: `100000`. - `bank_account` (`PayoutBankAccount`) - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `delivery_method` (string): how the payout is delivered One of: `standard`. - `description` (string, nullable) - `deposits_at` (string (date-time)): in UTC, the estimated date and time of the payout deposit (or in rare cases, withdrawal) Example: `"2021-01-01T12:00:00Z"`. - `fees_total` (number): sum of fees in the payout, in cents Example: `5000`. - `refunds_count` (number): number of refunds in the payout Example: `5`. - `refunds_total` (number): sum of refunds in the payout, in cents Example: `10000`. - `payments_count` (number): number of payments in the payout Example: `50`. - `payments_total` (number): sum of payments in the payout, in cents Example: `110000`. - `payout_type` (string): type of payment method used for the payments in the payout (funds from different types of payment methods settle at different intervals; in order to pay out your funds ASAP, we batch separate payouts for each payment method type) One of: `ach cc`. - `other_total` (number): sum of other less common transactions in the payout, in cents Example: `100`. - `platform_fees_total` (number, nullable): gross fees your platform charged its sub accounts in a proceeds payout, in cents, null for sub account payouts - `justifi_fees_total` (number, nullable): processing fees JustiFi charged your platform in a proceeds payout, in cents, always positive, null for sub account payouts - `interchange_network_fees` (number, nullable): interchange and card network fees passed through to your platform in a proceeds payout, in cents, usually negative, null for sub account payouts - `status` (string): status of the payout One of: `paid failed forwarded scheduled in_transit canceled`. Example: `"paid"`. - `settlement_priority` (string): settlement priority of the payout, either standard or expedited. One of: `standard expedited`. Example: `"standard"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payout - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### PayoutBankAccount - `id` (string (uuid)): unique bank account id - `full_name` (string): account holder's full name - `bank_name` (string): name of bank - `account_number_last4` (string): last 4 digits of the account number Example: `1111`. - `routing_number` (string) - `country` (string): One of: `US`, `CA`. Example: `"US"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `nickname` (string) - `account_type` (string): One of: `checking`. --- # Payout Holds Reference: https://docs.justifi.tech/api-spec#tag/Payout-Holds A payout hold is a resource that temporarily hold or pause payouts for a sub account. This feature is used for risk management, compliance, or business rule enforcement. Holds can be created automatically by the system (e.g., for first payments) or manually by JustiFi staff.. ## List Payout Holds `GET https://api.justifi.ai/v1/payout_holds` Reference: https://docs.justifi.tech/api-spec#tag/Payout-Holds/operation/ListPayoutHolds List the payout holds that belong to this account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `start_date_before` | query | string (date) | no | Filter by start date before the specified date (ISO 8601 format) | | `start_date_after` | query | string (date) | no | Filter by start date after the specified date (ISO 8601 format) | | `end_date_before` | query | string (date) | no | Filter by end date before the specified date (ISO 8601 format) | | `end_date_after` | query | string (date) | no | Filter by end date after the specified date (ISO 8601 format) | ### Responses #### 200: Successfully list payout holds Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `PayoutHold`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Payout Hold `GET https://api.justifi.ai/v1/payout_holds/{payout_hold_id}` Reference: https://docs.justifi.tech/api-spec#tag/Payout-Holds/operation/GetPayoutHold Retrieve a specific payout hold by ID. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `payout_hold_id` | path | string | yes | Payout hold public ID with poh_ prefix | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a payout hold Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"payout_hold"`. - `data` (object): the attributes for the object - `id` (string): Example: `"poh_abc123xyz"`. - `account_id` (string): Example: `"acc_sub123"`. - `hold_type` (string): One of: `first_payment`, `manual`. Example: `"manual"`. - `issued_by` (string): One of: `system`, `platform`. Example: `"platform"`. - `start_date` (string (date)): Example: `"2024-01-01"`. - `end_date` (string (date), nullable): Example: `"2024-01-31"`. - `active` (boolean): Example: `true`. - `created_at` (string (date-time)): Example: `"2024-01-01T10:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T10:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### PayoutHold - `id` (string): Example: `"poh_abc123xyz"`. - `account_id` (string): Example: `"acc_sub123"`. - `hold_type` (string): One of: `first_payment`, `manual`. Example: `"manual"`. - `issued_by` (string): One of: `system`, `platform`. Example: `"platform"`. - `start_date` (string (date)): Example: `"2024-01-01"`. - `end_date` (string (date), nullable): Example: `"2024-01-31"`. - `active` (boolean): Example: `true`. - `created_at` (string (date-time)): Example: `"2024-01-01T10:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T10:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Balance Transactions Reference: https://docs.justifi.tech/api-spec#tag/Balance-Transactions Balance transactions are the reflection of any movement of funds that affects the balance of an account. Oftentimes, a single financial transaction (like a payment) will result in the creation of many balance transactions in order to document the flow of funds between multiple accounts. Other financial transactions that result in balance transactions include refunds, disputes, and payouts. ## List Balance Transactions `GET https://api.justifi.ai/v1/balance_transactions` Reference: https://docs.justifi.tech/api-spec#tag/Balance-Transactions/operation/ListBalanceTransactions List the balance transactions for your account. This API is limited to a single sub account or payout. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `payout_id` | query | string | no | Filter records which are part of the payout with the specified id | | `source_payment_id` | query | string | no | Filter records which are associated with the payment with the specified id | ### Responses #### 200: Successfully list balance transactions Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `BalanceTransaction`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Balance Transaction `GET https://api.justifi.ai/v1/balance_transactions/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Balance-Transactions/operation/GetBalanceTransaction Get information about a balance transaction. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a balance transaction Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"balance_transaction"`. - `data` (object): the attributes for the object - `id` (string): unique balance transaction id Example: `"bt_xyz"`. - `account_id` (string (uuid)): id of the account associated with the balance transaction Example: `"acc_xyz"`. - `amount` (number): balance transaction amount, in cents Example: `100000`. - `available_on` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `description` (string, nullable) - `fee` (number): amount of fees deducted from the balance transaction amount, in cents Example: `5000`. - `financial_transaction_id` (string (uuid)): id of the financial transaction associated with the balance transaction Example: `"ft_xyz"`. - `net` (number): net amount of the balance transaction (after fees are deducted), in cents Example: `600`. - `payout_id` (string (uuid)): id of the payout associated with the balance transaction Example: `"po_xyz"`. - `source_id` (string (uuid)): id of the source object associated with the balance transaction Example: `"py_xyz"`. - `source_type` (string): type of source object associated with the balance transaction (for example payment, refund, dispute, payout) Example: `"payment"`. - `source_payment_id` (string, nullable): id of the payment associated with the source of the balance transaction Example: `"py_xyz"`. - `txn_type` (string): Type of transaction object associated with the balance transaction. Common types include: - `seller_payment`: Payment amount credited to merchant - `seller_payment_refund`: Payment refund debited from merchant - `processing_fee`: Processing fee deducted from merchant - `processing_fee_credit`: Processing fee credited to platform - `platform_fee`: Platform fee deducted from merchant - `platform_fee_credit`: Platform fee credited to platform - `processing_fee_return`: Processing fee returned on refund/void/ACH return - `platform_fee_return`: Platform fee returned on refund/void/ACH return - `partner_platform_discount_fee`: JustiFi basis point fee deducted from platform - `partner_platform_transaction_fee`: JustiFi per-transaction fee deducted from platform - `payout`: Payout to bank account - `refund`: Refund transaction - `ach_return_collected`: Returned ACH payment amount debited from merchant - `ach_return_fee_collected`: ACH return fee debited from merchant - `application_fee_refund`: Application fee returned to merchant on refund/void/ACH return - `dispute_amount_collected`: Disputed payment amount debited from merchant - `dispute_fee_collected`: Dispute fee debited from merchant - `refund_reversal`: Returned ACH refund credited back to merchant - `payout_failed`: Returned payout credited back to merchant A `_collected` suffix means the amount was taken from this account to fund a recovery, so it is recorded as a debit. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for details on fee-related transaction types, and [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns) for the transactions a returned ACH payment produces. Example: `"seller_payment"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### BalanceTransaction - `id` (string): unique balance transaction id Example: `"bt_xyz"`. - `account_id` (string (uuid)): id of the account associated with the balance transaction Example: `"acc_xyz"`. - `amount` (number): balance transaction amount, in cents Example: `100000`. - `available_on` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `description` (string, nullable) - `fee` (number): amount of fees deducted from the balance transaction amount, in cents Example: `5000`. - `financial_transaction_id` (string (uuid)): id of the financial transaction associated with the balance transaction Example: `"ft_xyz"`. - `net` (number): net amount of the balance transaction (after fees are deducted), in cents Example: `600`. - `payout_id` (string (uuid)): id of the payout associated with the balance transaction Example: `"po_xyz"`. - `source_id` (string (uuid)): id of the source object associated with the balance transaction Example: `"py_xyz"`. - `source_type` (string): type of source object associated with the balance transaction (for example payment, refund, dispute, payout) Example: `"payment"`. - `source_payment_id` (string, nullable): id of the payment associated with the source of the balance transaction Example: `"py_xyz"`. - `txn_type` (string): Type of transaction object associated with the balance transaction. Common types include: - `seller_payment`: Payment amount credited to merchant - `seller_payment_refund`: Payment refund debited from merchant - `processing_fee`: Processing fee deducted from merchant - `processing_fee_credit`: Processing fee credited to platform - `platform_fee`: Platform fee deducted from merchant - `platform_fee_credit`: Platform fee credited to platform - `processing_fee_return`: Processing fee returned on refund/void/ACH return - `platform_fee_return`: Platform fee returned on refund/void/ACH return - `partner_platform_discount_fee`: JustiFi basis point fee deducted from platform - `partner_platform_transaction_fee`: JustiFi per-transaction fee deducted from platform - `payout`: Payout to bank account - `refund`: Refund transaction - `ach_return_collected`: Returned ACH payment amount debited from merchant - `ach_return_fee_collected`: ACH return fee debited from merchant - `application_fee_refund`: Application fee returned to merchant on refund/void/ACH return - `dispute_amount_collected`: Disputed payment amount debited from merchant - `dispute_fee_collected`: Dispute fee debited from merchant - `refund_reversal`: Returned ACH refund credited back to merchant - `payout_failed`: Returned payout credited back to merchant A `_collected` suffix means the amount was taken from this account to fund a recovery, so it is recorded as a debit. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for details on fee-related transaction types, and [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns) for the transactions a returned ACH payment produces. Example: `"seller_payment"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Ach Return Fees Reference: https://docs.justifi.tech/api-spec#tag/Ach-Return-Fees ACH return fees are fees charged by financial institutions when an ACH (Automated Clearing House) transaction is returned due to insufficient funds or other reasons. If an ACH transaction is returned for any reason, the financial institution may charge a fee to the sender of the transaction. These fees can vary depending on the policies of the financial institution and the reason for the return. ## Get an Ach Return Fee `GET https://api.justifi.ai/v1/ach_return_fees/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Ach-Return-Fees/operation/GetAchReturnFee Get information about ach return fee. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get an ach return fee Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"account_ach_return_fee"`. - `data` (object): the attributes for the object - `id` (string): unique ach return fee id Example: `"arf_123xyz"`. - `payment_id` (string): the payment for which this ach return fee is being issued Example: `"py_123xyz"`. - `amount` (number): ach return fee amount, in cents Example: `150`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records --- # Payment Method Migration Reference: https://docs.justifi.tech/api-spec#tag/Payment-Method-Migration ## Data Import JustiFi enables you to transfer your existing customer data and payment methods. Please contact our [Customer Success Department](mailto:customer_success@justifi.tech) to begin work with your existing processor to securely transfer your information. ### PGP Encryption Many processors utilize PGP to encrypt sensative data. You can find useful information about PGP by looking over the [GPG](http://gnupg.org/) documentation. Once you understand the basics, you will want to [import a public key](http://www.gnupg.org/gph/en/manual.html#AEN84). Please contact our [Customer Success Department](mailto:customer_success@justifi.tech) if you have any questions. #### JusitiFi's PGP migration key | | | |--|--| |**Key ID** |`A4546473910D638E`| |**User ID**|`JustiFi Import Key (PCI) support-migrations@justifi.tech`| |**Fingerprint**|`0E7C 2E45 F62D 98D7 F7B8 776B A454 6473 910D 638E`| |**Key Type**|`RSA`| |**Key Size**|4096| **PGP Public Key File**: [https://docs.justifi.tech/security/pgp-public-key.asc](/security/pgp-public-key.asc) ##### Public Key ```bash -----BEGIN PGP PUBLIC KEY BLOCK----- mQINBGS+8MwBEACibKFR3bZb4huE7piU0fX3zbLpIq+Jnvs79v5ywVMYvu1kgzbb XcA0Td2IO0PXuG/cgH4JxH1qVG+cSGjSQ0rOpoQWG5hwOrvRVH17SUQMkZxgDwQb pCo1N44L+Ij23wW3JlyVb/FbVTK6uctjPmOoonFtzMG2ObKyeTqc1yWFqaIypjvG AUG2SzgLVqTTLIE5AySyOIpHTnQUwky4J/yCaWhcEJcsQ9GFHx/e+gAlReydMxfa WhTlMf9Cjm/WaOKVVKrTVicOtfVsFSWmxgtVMK5Smo0YGyF57Oz36Axy63g3QyYs 6XhWiuqCYpnH9EYHNDZaD6G1tZMyczon/rQNtCemUJeM96eyoVi8zK9wCDQT0fQ3 06JqqQtJqI3pAdzQ/VNYwm57XzZPXpFQ7ZGW+0JWb0UfGiwHgnOd/NHsy8imMQiK FLQjsFnDKVpRgXjqiRUX2/2Qs22XKprKmr6ptNweFLwU1dW0qBkmeM2GBaq7hAdq Kx6zoPwhYMe7ZxzKO2brvBcxMexhIBYAgdZR3AIdqLWnkGBHY4A3rXYAXqBOiryA SFK9r6VKr8CihdF4sasdf0uALEOiSYzcXarc5k1rlPxD9ldXduv+RdoodoHVW//+ ID+kvQQSwVOMSF8In+9j+Hhu2Ma3BLDRAqz/Vip9vB9frUn/YyqxjoZQxQARAQAB tDpKdXN0aUZpIEltcG9ydCBLZXkgKFBDSSkgPHN1cHBvcnQtbWlncmF0aW9uc0Bq dXN0aWZpLnRlY2g+iQJXBBMBCABBAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4H AheAFiEEDnwuRfYtmNf3uHdrpFRkc5ENY44FAmiEAzcFCQlorOsACgkQpFRkc5EN Y443phAAgqY1md2ygY4m/Sdrk/GaN82N7IQDx+okFrSKxtckSK2rcEz5m0GcB4fD TWAgSCgEnUz391c/Cu0KA1/r3CdmGGrLMnUeNisCYH83i+dvCVqGBsZcWn3+04Il MG14E1zgtrO3gP48sBowD8hrz1lSdz+YgfHcohrJvp7Dr/Wr78yyULcXeXZvLUsR NhAczwpQlHJi/cpGSefUidpSbAMKmgC2NNS+LvazZBikgYIZ27hLqT0nVv2nY+wd qWp4EkWNkVoNNkvpMYEzVEY7U1eb8rEH5hIibtdTPwfiaRJh0joUrAM2TjaVGzle wKOHdTc9uWxb2IN/Nh2lT2CKdRWak33Jt5rWwOaLGpP+qD2FsU0CgibrO9qDDMYt kjH8WDx78bXj9WHmvjolJT2pe6LELCxzUDPChlXmDu3jjdUYpESJdAvE17cGU28o uLkU9QgFQY5TwKfFaIqrStuSwhc+7FTdLwDObpOqfoC98J47UebE7gtLmddif/0p FLREzLdWE1sAQQnR+Ml8Vsb1+3vCE/vxusS8gx5pyscupE8H35OTe8MA36BmsQfM fbcgtt7xJ+v3EKKeJf+SNEs8xXEw5lXxngMKUXC3f2KA/Lp3pY5HixN+moDi2AdF c4Yr5B9veuHpVnCeuV64/Bzbr6OJRJYIaXON88WrRSI4uokq2V25Ag0EZL7wzAEQ AMF7UzULBsQmK4LwiuwVOcrYnN0ORQ/AXqDt09cOksDON4UzPrZxvq0FTggi9mzj U83onhtOv9mjoLYmgdaHUEhhzw167lmWbpwmD/w8PoLgmssrqUcnZH8nYsdYXpkR ZCTsd68nJdhBQLHjpnH9Ok6nB3ApiPaktIF1Z5Lu8pdPKQVSVHsEUOJ+qZM4cGXk WsqZLhmjycXnoF5ezSrUik8KwJL13fVFT7NCKagZazcCP57dNMF+sN6VZQSsvCOC jGjErIGJ6jZ4Qwdd9XVgygxtT5AEj0UakLZJZJfvO9o1ssxQ0TqOQyIj4n/45fRQ nNSWR03LubksurvduZxpaI1s8p5G3WH2mSVocV+AZV2vmcz/GAFLOS1Ik6EalRDh DVfGy5o/0D+rURs1zpcCwn1C3bib+LES9S6rnahkhzfqn1J456CxXzVtaqKJrfYq l2oYd7C18kbarzBLIlEsygWf3yJi/VnsE/2beV2fa7BtQwvdongq9w8IMPzNyXEU I/7QycB6+YURvt51bhmulSDcFcy6zL1AphLcn/2HQcQs9CMTpwc6QxBuOevgd4Hx zRIweYzwND+a8pEzIoHIsfpPkWNFOzGWTj5apE9IwbrQ4oVk+Yd7KrcbZHDLTmtd /yfAQtgGeiO7ns6APdggzKhGMTuTsLPla9zrY1aLSVOLABEBAAGJAjwEGAEIACYC GwwWIQQOfC5F9i2Y1/e4d2ukVGRzkQ1jjgUCaIQEhgUJCWiuOgAKCRCkVGRzkQ1j jkEyD/95ukg4C3XHuNLnx6D4cvCa+MCMhKL4LXH4nhRf40ChJSt88OsImE9XOhwz zWwsvfqvdzn4szitraUzK8AyYoJ5bQ4mw5KB0flw4qBbo7OZVKpLC9pP4ZDy3Z9D bGQY17uz+KMtzdMdsSgewkYpVcxS9hAqmt4CaQ2X+CWf37c4U/ljs8AOWcUYZ/s+ s9IAP+7wYmIgToqizAfFOHFiFfRbLqA3wbCJD7fiMRJqMLWY4CuMVhRY8k6erDpr HiuXBwb/f7y8Srdtq5kX5fEHw20DsVsSF5zB3rZ/smLeMTJmNWG55iLf7GPhTXA5 m36N+EhbjCYdoMPyEdBGbC2r1In/PgJuyeBX+kteD4aqY7W8QwEHFtCNVRuR3qB1 OA/fuJlKamN5N4OaCTDjNud/iWMeCi9BXdBOpGHf0iH3Un+ZyjicH2D0KaGA8FKX v8oHgP4sTR4dwkHGibvPYKX+1RwQ5/9vkJ6OpqtyuPONAjWbkz7geXPRBtQw+yg9 8aNKlI3D1nLCxDBD5nvFrl7mkK1nh/IbdOw7adRYq+8qGSOBaWCRhBmdAhCf8nz8 yKo41dXUSqDDCGBdzkc4CMMSirF63SJI6qnlvof1apzbwN3JQGSmaL1ROcIviHjs 8M9w1S9P69JkFyMzGYZExD+cHWYA10DHjM4mSWCBxZ+tC3UirA== =SSDk -----END PGP PUBLIC KEY BLOCK----- ``` #### Importing and using our key 1. Copy JustiFi's migration key into a new file named `public.key` 2. Run the GPG command to import the key. ```sh gpg --import public.key ``` 3. Encrypt your file using the newly imported key. This will create an encrypted file named `import_file.json.gpg`. ```sh gpg --encrypt --recipient A4546473910D638E import_file.json ``` --- # Forwarding (Beta) Reference: https://docs.justifi.tech/api-spec#tag/Forwarding Forwarding sends a request to a third party in the shape that destination expects, with card details filled in from a payment method JustiFi already holds. You describe the body the destination expects and mark where card details go with `{{card_number}}`, `{{card_expiry_month}}`, `{{card_expiry_year}}` and `{{cardholder_name}}`. JustiFi substitutes the real values at send time, relays the headers you supply, and stores a masked copy of what was sent alongside the destination's response. Forwarding is asynchronous: creating a forwarding request returns immediately with a `pending` status, and the outcome arrives via the [`forwarding_request.completed` or `forwarding_request.failed` event](https://docs.justifi.tech/api-spec#tag/Events/operation/forwardingRequestEvent) or by retrieving the request. Destinations must be allow-listed by JustiFi before they can be used. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have one added. See the [Forwarding guide](https://docs.justifi.tech/paymentMethods/forwarding) for a full walkthrough. ## List Forwarding Requests `GET https://api.justifi.ai/v1/forwarding/requests` Reference: https://docs.justifi.tech/api-spec#tag/Forwarding/operation/ListForwardingRequests List the forwarding requests for a sub account, newest first. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `payment_method_id` | query | string | no | filter records which are associated with a payment method. | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | ### Responses #### 200: Successfully list forwarding requests Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `ForwardingRequest`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Forwarding Request `POST https://api.justifi.ai/v1/forwarding/requests` Reference: https://docs.justifi.tech/api-spec#tag/Forwarding/operation/CreateForwardingRequest Send a request to an allow-listed destination with card details filled in from a payment method JustiFi already holds. You describe the request the destination expects, and write `{{card_number}}`, `{{card_expiry_month}}`, `{{card_expiry_year}}` or `{{cardholder_name}}` wherever card details belong. JustiFi substitutes them at send time. A tag must be the **entire** value of its field. A tag inside a longer string (`"num:{{card_number}}"`), an unknown tag (`{{card_expiry}}`) and `{{card_cvc}}`, which JustiFi does not store, are all rejected with `invalid_parameter`. **This endpoint responds before anything leaves JustiFi.** The forwarding request is created with `status` `pending` and a `null` `response`. Poll [Get a Forwarding Request](https://docs.justifi.tech/api-spec#tag/Forwarding/operation/GetForwardingRequest) or listen for the [`forwarding_request.completed` and `forwarding_request.failed` events](https://docs.justifi.tech/api-spec#tag/Events/operation/forwardingRequestEvent) for the outcome. Destinations are allow-listed by JustiFi and matched exactly — no trailing slash, casing or query normalization is applied. Contact [JustiFi Customer Success](mailto:customer_success@justifi.tech) to have a destination added. Only card payment methods can be forwarded. Bank accounts and card-present payment methods are rejected with `payment_method_type_not_supported`, and digital wallet cards with `digital_wallet_not_supported`. *Note: no `Sub-Account` header is needed. The account is inferred from the payment method.* ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `payment_method` (string, required): the id of the card payment method whose details are substituted into the request body Example: `"pm_123xyz"`. - `url` (string, required): the destination to send the request to. Must match an allow-listed destination exactly Example: `"https://api.stripe.com/v1/payment_methods"`. - `forwarding_request` (object, required): the request to send to the destination - `body` (object, required): the request body the destination expects, as a JSON object. Use `{{card_number}}`, `{{card_expiry_month}}`, `{{card_expiry_year}}` and `{{cardholder_name}}` where card details belong; each tag must be the entire value of its field. JustiFi encodes the body in the format the destination expects - `headers` (object): headers to relay to the destination, including the credentials it requires. Values must be strings. JustiFi stores none of its own credentials for the destination and adds only `Content-Type`, and only when you leave it out ```json { "payment_method": "pm_123xyz", "url": "https://api.stripe.com/v1/payment_methods", "forwarding_request": { "body": { "type": "card", "card": { "number": "{{card_number}}", "exp_month": "{{card_expiry_month}}", "exp_year": "{{card_expiry_year}}" }, "billing_details": { "name": "{{cardholder_name}}" }, "metadata": { "reference": "ord_9f21" } }, "headers": { "Authorization": "Bearer sk_live_destination_key" } } } ``` ### Responses #### 201: The forwarding request was accepted and queued. Nothing has been sent to the destination yet, so `status` is `pending` and `response` is `null`. Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"forwarding_request"`. - `data` (object): the attributes for the object - `id` (string): unique id of the forwarding request Example: `"fwd_123xyz"`. - `account_id` (string, nullable): the sub account that owns the payment method the request was created from Example: `"acc_123xyz"`. - `payment_method_id` (string, nullable): the payment method whose card details are substituted into the request body Example: `"pm_123xyz"`. - `url` (string): the allow-listed destination the request is sent to Example: `"https://api.stripe.com/v1/payment_methods"`. - `http_method` (string): the HTTP method used to reach the destination, determined by the destination itself One of: `POST`. Example: `"POST"`. - `provider` (string): the destination provider, determined by the destination itself One of: `stripe`. Example: `"stripe"`. - `status` (string): `pending` — accepted and queued, nothing has been sent yet; `processing` — the request is being sent and the outcome is not known yet; `completed` — the destination answered, see `data.response.status_code` for the outcome; `failed` — the destination could not be reached, see `failure_reason`. One of: `pending`, `processing`, `completed`, `failed`. Example: `"completed"`. - `failure_reason` (string, nullable): why the destination could not be reached, `null` unless `status` is `failed`. `timeout` — the destination did not answer in time; `connection_error` — the connection or TLS handshake failed; `internal_error` — JustiFi failed to send the request. One of: `timeout`, `connection_error`, `internal_error`. Example: `"timeout"`. - `replacements` (array of string): the card tags JustiFi found in the request body and substituted before sending - `request` (object): what was sent to the destination, masked - `body` (object, nullable): the request body as it was sent, with card details masked. The card number renders as its last four digits; the expiration date and cardholder name render in the clear. - `headers` (object): the headers as they were sent, with every value replaced by `[FILTERED]`. Header names are kept so you can confirm what was relayed; values are never stored in readable form. - `response` (object, nullable): the destination's response, `null` until the destination has answered - `id` (string): unique id of the forwarding response Example: `"fwdr_123xyz"`. - `status_code` (integer): the HTTP status code the destination answered with Example: `200`. - `body` (any, nullable): the response body, scrubbed of anything that looks like a card number - `headers` (any, nullable): the response headers, scrubbed of anything that looks like a card number - `response_time_ms` (integer, nullable): how long the destination took to answer, in milliseconds Example: `512`. - `attempted_at` (string (date-time), nullable): when JustiFi started sending the request (in UTC), `null` while the request is still queued Example: `"2024-01-01T12:00:01Z"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:02Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records #### 400: The request was rejected. Nothing was created and nothing was sent. Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "forwarding_destination_not_allowed", "message": "That destination is not on the forwarding allow list" } } ``` #### 404: No payment method with that id exists. Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "payment_method_not_found", "message": "Payment method not found" } } ``` ## Get a Forwarding Request `GET https://api.justifi.ai/v1/forwarding/requests/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Forwarding/operation/GetForwardingRequest Retrieve a forwarding request, and the destination's response once there is one. While `status` is `pending` or `processing`, `response` is `null`. Once `status` is `completed`, `response` holds the status code, body and headers the destination answered with — a `completed` forwarding request means the destination answered, not that it accepted the request, so check `response.status_code`. Once `status` is `failed`, `response` stays `null` and `failure_reason` explains why the destination could not be reached. Card details are never returned in readable form. The card number renders as its last four digits in `request.body`, every value in `request.headers` renders as `[FILTERED]`, and anything in the destination's response that looks like a card number is reduced to its last four digits. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `id` | path | string (uuid) | yes | | ### Responses #### 200: Successfully get forwarding request Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"forwarding_request"`. - `data` (object): the attributes for the object - `id` (string): unique id of the forwarding request Example: `"fwd_123xyz"`. - `account_id` (string, nullable): the sub account that owns the payment method the request was created from Example: `"acc_123xyz"`. - `payment_method_id` (string, nullable): the payment method whose card details are substituted into the request body Example: `"pm_123xyz"`. - `url` (string): the allow-listed destination the request is sent to Example: `"https://api.stripe.com/v1/payment_methods"`. - `http_method` (string): the HTTP method used to reach the destination, determined by the destination itself One of: `POST`. Example: `"POST"`. - `provider` (string): the destination provider, determined by the destination itself One of: `stripe`. Example: `"stripe"`. - `status` (string): `pending` — accepted and queued, nothing has been sent yet; `processing` — the request is being sent and the outcome is not known yet; `completed` — the destination answered, see `data.response.status_code` for the outcome; `failed` — the destination could not be reached, see `failure_reason`. One of: `pending`, `processing`, `completed`, `failed`. Example: `"completed"`. - `failure_reason` (string, nullable): why the destination could not be reached, `null` unless `status` is `failed`. `timeout` — the destination did not answer in time; `connection_error` — the connection or TLS handshake failed; `internal_error` — JustiFi failed to send the request. One of: `timeout`, `connection_error`, `internal_error`. Example: `"timeout"`. - `replacements` (array of string): the card tags JustiFi found in the request body and substituted before sending - `request` (object): what was sent to the destination, masked - `body` (object, nullable): the request body as it was sent, with card details masked. The card number renders as its last four digits; the expiration date and cardholder name render in the clear. - `headers` (object): the headers as they were sent, with every value replaced by `[FILTERED]`. Header names are kept so you can confirm what was relayed; values are never stored in readable form. - `response` (object, nullable): the destination's response, `null` until the destination has answered - `id` (string): unique id of the forwarding response Example: `"fwdr_123xyz"`. - `status_code` (integer): the HTTP status code the destination answered with Example: `200`. - `body` (any, nullable): the response body, scrubbed of anything that looks like a card number - `headers` (any, nullable): the response headers, scrubbed of anything that looks like a card number - `response_time_ms` (integer, nullable): how long the destination took to answer, in milliseconds Example: `512`. - `attempted_at` (string (date-time), nullable): when JustiFi started sending the request (in UTC), `null` while the request is still queued Example: `"2024-01-01T12:00:01Z"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:02Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records #### 404: No forwarding request with that id exists on this sub account. Content type: `application/json` Schema: `PaymentError` ```json { "error": { "code": "forwarding_request_not_found", "param": "forwarding_request_id" } } ``` ## Schemas ### ForwardingRequest - `id` (string): unique id of the forwarding request Example: `"fwd_123xyz"`. - `account_id` (string, nullable): the sub account that owns the payment method the request was created from Example: `"acc_123xyz"`. - `payment_method_id` (string, nullable): the payment method whose card details are substituted into the request body Example: `"pm_123xyz"`. - `url` (string): the allow-listed destination the request is sent to Example: `"https://api.stripe.com/v1/payment_methods"`. - `http_method` (string): the HTTP method used to reach the destination, determined by the destination itself One of: `POST`. Example: `"POST"`. - `provider` (string): the destination provider, determined by the destination itself One of: `stripe`. Example: `"stripe"`. - `status` (string): `pending` — accepted and queued, nothing has been sent yet; `processing` — the request is being sent and the outcome is not known yet; `completed` — the destination answered, see `data.response.status_code` for the outcome; `failed` — the destination could not be reached, see `failure_reason`. One of: `pending`, `processing`, `completed`, `failed`. Example: `"completed"`. - `failure_reason` (string, nullable): why the destination could not be reached, `null` unless `status` is `failed`. `timeout` — the destination did not answer in time; `connection_error` — the connection or TLS handshake failed; `internal_error` — JustiFi failed to send the request. One of: `timeout`, `connection_error`, `internal_error`. Example: `"timeout"`. - `replacements` (array of string): the card tags JustiFi found in the request body and substituted before sending - `request` (object): what was sent to the destination, masked - `body` (object, nullable): the request body as it was sent, with card details masked. The card number renders as its last four digits; the expiration date and cardholder name render in the clear. - `headers` (object): the headers as they were sent, with every value replaced by `[FILTERED]`. Header names are kept so you can confirm what was relayed; values are never stored in readable form. - `response` (object, nullable): the destination's response, `null` until the destination has answered - `id` (string): unique id of the forwarding response Example: `"fwdr_123xyz"`. - `status_code` (integer): the HTTP status code the destination answered with Example: `200`. - `body` (any, nullable): the response body, scrubbed of anything that looks like a card number - `headers` (any, nullable): the response headers, scrubbed of anything that looks like a card number - `response_time_ms` (integer, nullable): how long the destination took to answer, in milliseconds Example: `512`. - `attempted_at` (string (date-time), nullable): when JustiFi started sending the request (in UTC), `null` while the request is still queued Example: `"2024-01-01T12:00:01Z"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:02Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### PaymentError - `error` (object) - `code` (string): error code if the payment fails Example: `"card_declined"`. - `decline_code` (string): decline code if the payment fails Example: `"do_not_retry"`. - `message` (string): text description of the error code Example: `"This card has been rejected. Please try a different card or payment method"`. - `network` (string, nullable): card network used for payment Example: `"MASTERCARD"`. - `network_error_category` (string, nullable): network error category code Example: `"03"`. - `network_error_code` (string, nullable): network error code Example: `"504"`. --- # Checkouts Reference: https://docs.justifi.tech/api-spec#tag/Checkouts Checkouts can be used to collect payments directly via API, or using our Checkout component. You can use a checkout to complete a payment via JustiFi, via BNPL, via terminal, and to purchase insurance in a single transaction. All attempts to complete a payment will be recorded, along with the outcome of a payment. ## List Checkouts `GET https://api.justifi.ai/v1/checkouts` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/ListCheckouts List Checkouts for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `payment_mode` | query | string | no | the mode in which the checkout was completed One of: `bnpl`, `ecom`, `card_present`, `apple_pay`. | | `status` | query | string | no | the checkout status One of: `created`, `completed`, `attempted`, `expired`. | | `payment_status` | query | string | no | the status of the payment which was use to complete the checkout One of: `succeeded`, `failed`, `canceled`, `skipped`, `pending`. | ### Responses #### 200: Successfully list checkouts Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (object): the list of objects - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Checkout `POST https://api.justifi.ai/v1/checkouts` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout Create a checkout to initiate the collection of a Card Payment, ACH Payment, Insurance Quote Payment, BNPL Payment (not yet available via API), or Card Reader payment in a single flow. Checkouts have the following statuses: `created` after creating a checkout, `attempted` when a checkout payment is attempted, `completed` when a payment is collected for a checkout, `expired` when a checkout has not been completed after one week since being created ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | yes | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Request body Content type: `application/json` - `amount` (number, required): amount to charge in cents, must be an integer greater than 50 (equivalent to $0.50) Example: `10000`. - `description` (string, required): your meaningful description of the checkout (e.g. an order number or other value from your system) Example: `"order_xyz"`. - `origin_url` (string): the domain on which the web component will be rendered, required for web component usage only Example: `"http://localhost:3000"`. - `payment_method_group_id` (string): payment method group to associate with the checkout Example: `"pmg_xyz123"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement, must have between 5-22 alphanumeric characters and can include dash or underscore Example: `"Big Business"`. - `metadata` (object (json)): any useful information you'd like to store alongside this checkout - `application_fees` (object): Sets a custom application fee amount by payment method type. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). (card/ach and card present only, not available for bnpl). **Not available for CAD payments** — fees are determined during merchant onboarding. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments). - `card` (object) - `amount` (number): custom application fee amount that applies to card payment method. Example: `300`. - `bank_account` (object) - `amount` (number): custom application fee amount that applies to bank account payment method. Example: `150`. - `payment` (object): Overrides the information saved on the Payment when a checkout is paid via JustiFi card/ach payment - `description` (string): Overrides the default payment description of "Checkout [checkout id]" Example: `"Pay David for great work"`. - `metadata` (object (json)): Adds metadata to the payment record - `expedited` (boolean): settlement priority of the payment, only applies to ACH payments - `fees` (array of `Fee`): *Recommended for new integrations.* Fees to apply to the payment. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. Each fee object specifies: - `type`: `processing_fee` or `platform_fee` (required) - `amount`: Fee amount in cents (required) Cannot be used together with `application_fees`. > **Note:** The `fees` array will be empty in the create response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee details, or poll with a subsequent Get Payment request. > **CAD Payments:** This parameter is not available for CAD payments. Fees for Canadian dollar payments are determined during merchant onboarding and are not configurable via the API. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. ### Responses #### 201: Checkout was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"checkout"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get Checkout `GET https://api.justifi.ai/v1/checkouts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/GetCheckout Get information about a checkout ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | ### Responses #### 200: Successfully get a checkout Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"checkout"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Checkout `PATCH https://api.justifi.ai/v1/checkouts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/UpdateCheckout Change a checkout's amount or description ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `amount` (number): amount to charge in cents, must be an integer greater than 50 (equivalent to $0.50) Example: `10000`. - `description` (string): your meaningful description of the checkout (e.g. an order number or other value from your system) Example: `"order_xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement, must have between 5-22 alphanumeric characters and can include dash or underscore Example: `"Big Business"`. - `metadata` (object (json)): any useful information you'd like to store alongside this checkout; when you update metadata, any previous metadata will be overwritten - `application_fees` (object): (card/ach and card present only, not available for bnpl) sets a custom application fee amount that applies to this payment, instead of relying on application fee rates configured at the platform account level. Must be greater than zero. - `card` (object) - `amount` (number): custom application fee amount that applies to card payment method. Example: `300`. - `bank_account` (object) - `amount` (number): custom application fee amount that applies to bank account payment method. Example: `150`. - `payment` (object): Overrides the information saved on the Payment when a checkout is paid via JustiFi card/ach payment - `description` (string): Overrides the default payment description of "Checkout [checkout id]" Example: `"Pay David for great work"`. - `metadata` (object (json)): Adds metadata to the payment record - `expedited` (boolean): settlement priority of the payment, only applies to ACH payments - `fees` (array of `Fee`): *Recommended for new integrations.* Fees to apply to the payment. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. Each fee object specifies: - `type`: `processing_fee` or `platform_fee` (required) - `amount`: Fee amount in cents (required) Cannot be used together with `application_fees`. > **Note:** The `fees` array will be empty in the create response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee details, or poll with a subsequent Get Payment request. > **CAD Payments:** This parameter is not available for CAD payments. Fees for Canadian dollar payments are determined during merchant onboarding and are not configurable via the API. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. ### Responses #### 200: Checkout update was successful Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"object"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Complete a Checkout `POST https://api.justifi.ai/v1/checkouts/{id}/complete` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CompleteCheckout Use to complete a checkout and capture a payment, requires an idempotency key for payment processing ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `payment_token` (string, required): Payment Method token which you want to use to complete the payment Example: `"pm_asdfakjsd23"`. - `payment_mode` (string): The mode in which the checkout is being completed. If not provided, defaults to `ecom` One of: `ecom`, `bnpl`, `card_present`, `apple_pay`. Example: `"ecom"`. ```json { "payment_token": "pm_asdfakjsd23", "payment_mode": "ecom" } ``` ### Responses #### 201: Checkout was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"checkout_completion"`. - `data` (object): the attributes for the object - `id` (string): unique checkout completion id Example: `"chc_xyz"`. - `payment_mode` (string): One of: `ecom`, `bnpl`, `card_present`. Example: `"ecom"`. - `payment_token` (string): the payment method token used to process the payment, only for ecom payments Example: `"pm_xyz123"`. - `status` (string): the status of the completion, only succeeded or failed One of: `succeeded`, `failed`, `processing`. Example: `"succeeded"`. - `payment_status` (string): depending upon payment mode, the status of the payment API call, bnpl transaction, or card reader transaction. One of: `succeeded`, `failed`, `pending`, `canceled`, `skipped`. Example: `"succeeded"`. - `payment_error_code` (string): when payment fails, related error code Example: `"card_declined"`. - `payment_error_description` (string): when payment fails, related error description Example: `"Your card was declined"`. - `payment_response` (object) - `id` (string): unique payment id, same as id in data object Example: `"py_xyz"`. - `type` (string): the object type Example: `"payment"`. - `data` (`CardPayment`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records - `checkout_id` (string (uuid)): id of the checkout for this completion Example: `"cho_xyz123"`. - `additional_transactions` (array of objects): legacy attribute, other transactions processed during checkout completion. For example, insurance payments - `checkout` (`Checkout`) - `payment_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"py_xyz123"`. - `payment_method_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"pm_xyz123"`. - `terminal_id` (string (uuid)): id of the terminal used for this checkout, when mode is card present Example: `"trm_xyz123"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Refund a Checkout `POST https://api.justifi.ai/v1/checkouts/{id}/refunds` Reference: https://docs.justifi.tech/api-spec#tag/Checkouts/operation/RefundCheckout Use to refund a checkout. You may refund the full amount or just a portion. When refunding a portion, multiple refunds are supported up until the full payment amount has been refunded. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Idempotency-Key` | header | string (uuid) | yes | a string to identify your request (we recommend using a generated uuid, but you may use any unique string) see [Idempotent Requests](https://docs.justifi.tech/api-spec#section/Idempotent-Requests) | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `amount` (integer): Amount to be refunded. If missing, the total amount will be used. Example: `4900`. - `fees` (array of object): Fees to return to the merchant as part of this refund. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. Each fee object specifies: - `type`: The fee type to return (`processing_fee` or `platform_fee`) - `amount`: Amount to return in cents If omitted, no fees are returned. Only supported for card/ach and card present payments completed with the `fees` array. > **CAD Payments:** This parameter is not available for CAD payments. See [Canadian Payments](https://docs.justifi.tech/payments/canadianPayments) for details. - `type` (string, required): The type of fee to return One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Amount to return in cents Example: `175`. ```json { "amount": 1000, "fees": [ { "type": "processing_fee", "amount": 100 }, { "type": "platform_fee", "amount": 100 } ] } ``` ### Responses #### 200: Refund was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"checkout_completion"`. - `data` (object): the attributes for the object - `id` (string): unique checkout refund id Example: `"chr_xyz"`. - `checkout_id` (string (uuid)): id of the checkout for this refund - `status` (string): the status of the refund, only succeeded or failed One of: `succeeded`, `failed`. Example: `"succeeded"`. - `refund_response` (string): when refund fails, related error description. when refund succeeded additional refund info (or null). Example: `"invalid_amount"`. - `refund_amount` (integer): the amount requested to refund (or full checkout amount) Example: `4900`. - `returned_fees` (array of object): Fees returned to the merchant as part of this refund. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `type` (string): The type of fee that was returned One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer): Amount returned in cents Example: `175`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Fee A fee object specifying type and amount - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. ### CheckoutCompletionAttempt - `id` (string): unique checkout completion id Example: `"chc_xyz123"`. - `payment_mode` (string): One of: `ecom`, `bnpl`, `card_present`. Example: `"ecom"`. - `payment_token` (string): the payment method token used to process the payment, only for ecom payments Example: `"pm_xyz123"`. - `status` (string): the status of the completion, only succeeded or failed One of: `succeeded`, `failed`, `processing`. Example: `"succeeded"`. - `payment_status` (string): depending upon payment mode, the status of the payment API call, bnpl transaction, or card reader transaction. One of: `succeeded`, `failed`, `pending`, `canceled`, `skipped`. Example: `"succeeded"`. - `payment_error_code` (string): when payment fails, related error code Example: `"card_declined"`. - `payment_error_description` (string): when payment fails, related error description Example: `"Your card was declined"`. - `payment_response` (object) - `id` (string): unique payment id, same as id in data object Example: `"py_xyz"`. - `type` (string): the object type Example: `"payment"`. - `data` (`CardPayment`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records - `checkout_id` (string (uuid)): id of the checkout for this completion Example: `"cho_xyz123"`. - `additional_transactions` (array of objects): legacy attribute, any other transactions processed during checkout completion. For example, insurance payments - `payment_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"py_xyz123"`. - `payment_method_id` (string (uuid)): id of the payment method associated with this checkout, when successful Example: `"pm_xyz123"`. - `terminal_id` (string (uuid)): id of the terminal used for this checkout, when mode is card present Example: `"trm_xyz123"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### CardPayment - `id` (string): unique payment id Example: `"py_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): payment amount in cents Example: `10000`. - `amount_disputed` (number): sum of open or lost disputes for this payment, in cents Example: `0`. - `amount_refunded` (number): sum of refunds for this payment, in cents Example: `0`. - `amount_refundable` (number): amount of this payment currently able to be refunded, in cents Example: `10000`. - `balance` (number): sum of debits and credits for this payment, in cents (reflects the amount this account has earned from this payment). Compiled and calculated value, eventually consistent. To see all changes affecting the payment's balance call [Get Balance Transactions](#operation/GetPaymentBalanceTransactions) Example: `99850`. - `fee_amount` (number): sum of fees for this payment Example: `150`. - `financial_transaction_id` (string): associated financial transaction id Example: `"ft_123xyz"`. - `captured` (boolean): whether or not this payment is captured Example: `true`. - `capture_strategy` (string): One of: `automatic`, `manual`. Example: `"automatic"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my_order_xyz"`. - `disputed` (boolean): whether or not this payment has any open or lost disputes Example: `false`. - `disputes` (array): list of associated disputes - `error_code` (string): error code if the payment fails Example: `"credit_card_number_invalid"`. - `error_description` (string): text description of the error code Example: `"Credit Card Number Invalid (Failed LUHN checksum)"`. - `is_test` (boolean): whether or not this payment was made using the test account Example: `true`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment - `payment_intent_id` (string): unique id of associated payment intent Example: `"pi_123xyz"`. - `checkout_id` (string): unique id of associated checkout Example: `"cho_123xyz"`. - `payment_method` (`CardPaymentMethod`) - `application_fee` (`ApplicationFee`) - `application_fee_rate_id` (string): unique id of application fee rate applied to this payment, if any Example: `"afr_123xyz"`. - `fees` (array of `FeeResponse`): Array of fee objects showing the fees charged on this payment with their remaining refundable amounts. Populated whether the fees were provided via the `fees` array in the payment request or calculated automatically (for example, from a Standard Fee Configuration, or the `processing_fee` on a CAD payment). **Note:** This array is empty in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects (with `id`, `remaining_amount`, and `currency`), or poll with a subsequent Get Payment request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `refunded` (boolean): whether or not this payment has any refunds Example: `false`. - `status` (string): status of the payment One of: `pending`, `authorized`, `canceled`, `succeeded`, `failed`, `partially_refunded`, `fully_refunded`, `disputed`. - `payment_mode` (string): One of: `ecom`, `ach`, `card_present`. Example: `"ecom"`. - `terminal_id` (string): id of terminal used to process the card payment, if any Example: `"trm_123xyz"`. - `transaction_hold` (object) - `id` (string): unique transaction hold id Example: `"th_123xyz"`. - `financial_transaction_id` (string (uuid)): financial transaction id the transaction hold is associated to Example: `"ft_123xyz"`. - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### Checkout - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any ### CardPaymentMethod - `card` (`Card`) - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### ApplicationFee - `id` (string (uuid)): unique application fee id Example: `"fee_123xyz"`. - `amount` (number): application fee amount, in cents Example: `150`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### FeeResponse A fee object in API responses. The `fees` array is empty in the Create Payment response — subscribe to payment webhook events (recommended) to receive the full fee objects, or poll with a subsequent Get Payment request. - `id` (string): Unique identifier for this fee. Present when fetching a payment. Example: `"pyfee_xyz"`. - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services - `refund_processing_fee`: A processing fee charged when a refund is processed. Currently applies to CAD payments only. One of: `processing_fee`, `platform_fee`, `refund_processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. - `currency` (string): Currency of the fee amount. Present when fetching a payment. One of: `usd`, `cad`. Example: `"usd"`. - `remaining_amount` (integer): Amount still available for refund in cents. Updates after each partial refund. Present when fetching a payment. Example: `350`. - `source_configuration_id` (string, nullable): The public ID of the Standard Fee Configuration used to calculate this fee. Null when the fee was explicitly provided in the payment request rather than auto-calculated. Example: `"sfc_abc123"`. - `source_fee_type` (string, nullable): The fee type from the Standard Fee Configuration that generated this fee (e.g., `processing_ecomm`, `amex_brand_ecomm`, `platform`). Null when the fee was explicitly provided in the payment request. Example: `"amex_brand_ecomm"`. - `refund_id` (string, nullable): The public ID of the refund this fee is associated with. Populated for `refund_processing_fee` fees (currently CAD payments only); null for all other fees. Present when fetching a payment. Example: `"re_xyz"`. ### Card - `id` (string (uuid)): unique card id Example: `"pm_123xyz"`. - `acct_last_four` (string): last 4 digits of the card number Example: `4242`. - `brand` (any): card brand or bank name Example: `"Visa"`. - `digital_wallet` (string, nullable): which digital wallet provider the card is tied to One of: `apple_pay`, `google_pay`, `null`. Example: `"apple_pay"`. - `name` (string, nullable): card or account holder name Example: `"Amanda Kessel"`. - `token` (any): same value as unique card id; can be saved and used to process multiple payments with the same card Example: `"pm_123xyz"`. - `month` (any): expiration date month Example: `"5"`. - `year` (any): expiration date year Example: `"2042"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this card - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `address_line1_check` (string): Result of the address line 1 verification check. `pass` — matches the cardholder's address on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no address was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. - `address_postal_code_check` (string): Result of the postal code verification check. `pass` — matches the cardholder's postal code on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no postal code was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. --- # Checkout via Component Reference: https://docs.justifi.tech/api-spec#tag/Checkout-via-Component A checkout is used to initiate the collection of a credit card payment, ACH payment, insurance quote payment, BNPL payment, or card reader payment in a single flow. This walk through will take you through collecting a payment via checkout using the [Unified Fintech Checkout™ web component](/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2). We assume you have an activated sub account for payment processing. For a more customized checkout experience refer to the [Modular Checkout](/web-components/modular-checkout) web component docs. 1. Get an access token 2. Create a Checkout 3. Generate a Web Component Token 4. Render the checkout component 5. Handle success/failure events ### Get an access token On your backend, using your client id and client secret from the Developer > API keys section of the JustiFi dashboard. Using those, generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken). ``` function getToken() { return fetch('https://api.justifi.ai/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "client_id": "YOUR CLIENT ID", "client_secret": "YOUR CLIENT SECRET" }) }) .then(response => response.json()) .then(data => data.access_token); } const token = await getToken(); ``` ### Create a checkout From your backend create a checkout using the [Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout). A checkout requires a payment `amount` and `descripton`. You can also pass a [Payment Method Group](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups) if you want a customer's pre-entered card information to be shown on the checkout. To render the checkout component, you must set the `origin_url` parameter to be the domain on which you will render the component. For example, to develop locally you could specify "http://localhost:3000" if you're developing on port 3000. ``` async function makeCheckout(token, subAccountId) { const response = await fetch('https://api.justifi.ai/v1/checkouts', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'Sub-Account': `${subAccount}`, }, body: JSON.stringify({ "amount": 1799, "description": "One Chocolate Donut", "payment_method_group_id": "(optional)", "origin_url": http://localhost:3000 }) }); const data = await response.json(); return data; } const subAccountId = "acc_5Et9iXrSSAZR2KSouQGAWi const checkout = await makeCheckout(token, subAccountId); ``` ### Generate a Web Component Token To render the checkout component, you must generate a web component token. This is a short lived token which is meant to grant short term, fine grained access. The checkout component requires the role of `write:checkout:{checkout id}` for the checkout you want to process and `write:tokenize:{account id}` with the sub account id you are processing the payment for. ``` async function getWebComponentToken(token, checkoutId, accountId) { const response = await fetch('https://api.justifi.ai/v1/web_component_tokens', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ "resources": [`write:checkout:${checkoutId}`, `write:tokenize:${accountId}] }) }); const data = await response.json(); return data.access_token; } const webComponentToken = await getWebComponentToken(token, checkout.id, subAccountId); ``` ### Render the checkout component Using the web component token generated above and the checkout id, render the [checkout web component](/web-components/payment-facilitation/unified-fintech-checkout%E2%84%A2). This will allow a customer to complete a checkout via credit card payment, ACH payment, or BNPL payment depending upon the sub account configuration. It will also process payments for attached insurance quotes, if the Insurance components were used. ``` ``` ### Handle success/failure events The web component will emit a `submitted` event when a payment is submitted for a checkout. This event will have a `payment_status` attribute. If the payment succeeded, your app can proceed to a successful checkout state. Otherwise, an error message can be presented to the user. Our example below covers both. If there are insurance quotes being processed, the `additional_transactions` section will contain the results of the insurance payments. An `error` event means there was an issue with the payment form, connecting to the network, etc. ``` ``` At this point, your checkout is completed and you have successfully collected a payment! --- # Checkout via API Reference: https://docs.justifi.tech/api-spec#tag/Checkout-via-API A checkout is used to initiate the collection of a credit card payment, ACH payment, insurance quote payment, BNPL payment, or card reader payment in a single flow. This walk through will take you through collecting a payment via checkout. We assume you have an activated sub account for payment processing. If you want to offer BNPL or insurance as part of the checkout process you will need to implement the [Unified Fintech Checkout™](https://docs.justifi.tech/api-spec#tag/Checkout-via-Component). 1. Get an access token 2. Create a checkout 3. Tokenize or select a payment method 4. Complete a checkout ### Get an access token On your backend, using your client id and client secret from the Developer > API keys section of the JustiFi dashboard, generate an [access token](https://docs.justifi.tech/api-spec#tag/API-Credentials/operation/CreateAccessToken). ``` function getToken() { return fetch('https://api.justifi.ai/oauth/token', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ "client_id": "YOUR CLIENT ID", "client_secret": "YOUR CLIENT SECRET" }) }) .then(response => response.json()) .then(data => data.access_token); } const token = await getToken(); ``` ### Create a checkout From your backend create a checkout using the [Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout). A checkout requires a payment `amount` and `descripton`. You can also pass a [Payment Method Group](https://docs.justifi.tech/api-spec#tag/Payment-Method-Groups), if you want a customer's pre-entered card information to be shown on the checkout. ``` async function makeCheckout(token, subAccountId) { const response = await fetch('https://api.justifi.ai/v1/checkouts', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`, 'Sub-Account': `${subAccount}`, }, body: JSON.stringify({ "amount": 1799, "description": "One Chocolate Donut", "payment_method_group_id": "(optional)" }) }); const data = await response.json(); return data; } const subAccountId = "acc_5Et9iXrSSAZR2KSouQGAWi const checkout = await makeCheckout(token, subAccountId); ``` ### Tokenize or select a payment method In order to complete a checkout, you must provide a payment method token. To avoid entering PCI scope, we recommend using our [Payment Form](/web-components/payment-facilitation/tokenize-payment-method) web component. You can also collect the payment method information directly and use our Payment Method APIs, but you will likely be entering PCI scope. Once you have tokenized a payment method you can complete a checkout using the ID of the payment method as payment method token. ### Complete a checkout To complete a checkout, using the [Complete Checkout API](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CompleteCheckout) pass the payment method token collected above as well as an `Idempotency-Key`. A checkout completion will be recorded upon success or failure. If the `payment_status` attribute in the response is `succeeded` the payment has been collected. If insurance quotes have been attached, the outcome of those payments will be in the `additional_transactions` attribute. --- # Bind Insurance Reference: https://docs.justifi.tech/api-spec#tag/Bind-Insurance ## Bind an Insurance Policy `POST https://api.justifi.ai/v1/insurance/bind` Reference: https://docs.justifi.tech/api-spec#tag/Bind-Insurance/operation/BindInsurance Used to bind an insurance policy with a JustiFi insurance partner ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `payment_method_id` (string (uuid), required): Payment method to charge for insurance policy Example: `"pm_123"`. - `amount` (number, required): amount to charge in cents Example: `10000`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `partner_quote_id` (string, required): quote id provided by partner provider Example: `"ins-test-123"`. - `partner_name` (string, required): partner insurance provider One of: `vertical_insure`. Example: `"vertical_insure"`. - `metadata` (object (json)): any useful information you'd like to store alongside this record ### Responses #### 201: Insurance Policy was bound successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"ins_xyz"`. - `type` (string): the object type, or array of objects Example: `"insurance_policy"`. - `data` (object): the attributes for the object - `id` (string): unique record id Example: `"ins_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): the amount charged in cents Example: `10000`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `partner_name` (string): partner insurance provider name Example: `"vertical_insure"`. - `partner_quote_id` (string): quote id provided by partner provider Example: `"test-123"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment intent - `status` (string): status of the payment intent One of: `created`, `bound`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records --- # Business Reference: https://docs.justifi.tech/api-spec#tag/Business Creating a business entity is an essential step in integrating your business operations with JustiFi. It is also necessary to comply with local laws and regulations governing your operations. To create a new business entity, you will need to provide basic information such as the business name, website, business type, business structure, and your industry. You may also add details like the legal address, tax ID, and ownership structure. Providing detailed and accurate information about the business entity is essential for ensuring legal compliance, financial accuracy, and it can also help avoid potential legal and financial issues. Business classification encompasses both the type of business and its operational structure. Use the following table to map your current business type and structure to the correct business classification: | Business Type | Business Structure | Business Classification | | ------------- | ------------------ | ----------------------- | | individual | * | sole_proprietor | | for_profit | unincorporated_association | sole_proprietor | | for_profit | sole_proprietorship | sole_proprietor | | for_profit | public_partnership | partnership | | for_profit | private_partnership | partnership | | for_profit | private_corporation | corporation | | for_profit | public_corporation | public_company | | for_profit | multi_llc | limited | | for_profit | single_llc | limited | | non_profit | incorporated | non_profit | | non_profit | unincorporated | non_profit | | government_entity | government_unit | government | | government_entity | government_instrumentality | government | | government_entity | tax_exempt_government_instrumentality | government | Please, choose whether you want to use the business classification (preferred) or the business type and structure (deprecated), but not both. Business classification is a simplification of business type and structure with the same goals. _Note: If you use the classification, it will not have the exact same correspondence with the business type and structure from the previous table because there are fewer classifications than types/structures._ ## List Businesses `GET https://api.justifi.ai/v1/entities/business` Reference: https://docs.justifi.tech/api-spec#tag/Business/operation/ListBusinesses List businesses for your platform. Archived businesses are not returned. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `business_name` | query | string | no | filter businesses by name | ### Responses #### 200: Successfully list businesses Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `BusinessResponse`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Business `POST https://api.justifi.ai/v1/entities/business` Reference: https://docs.justifi.tech/api-spec#tag/Business/operation/CreateBusiness Create a Business ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `legal_name` (string): legal business entity name; must be unique among the active businesses on your platform. Archived businesses do not reserve their name, so an archived business's legal_name can be reused Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): (deprecated) use classification instead - see [classification mapping table](https://docs.justifi.tech/api-spec#tag/Business) One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): (deprecated) use classification instead - see [classification mapping table](https://docs.justifi.tech/api-spec#tag/Business) One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `classification` (string): simplified classification, use instead of business_type and business_structure - see [classification mapping table](https://docs.justifi.tech/api-spec#tag/Business) One of: `government`, `limited`, `non_profit`, `partnership`, `corporation`, `public_company`, `sole_proprietor`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is saved but not returned in any API response - `date_of_incorporation` (string): the specific day when this business was officially registered with a relevant government authority and was then permitted to carry out its activities Example: `"2015-02-20"`. - `country_of_establishment` (string): country where the business was established. Defaults to "USA" if not provided (_cannot be changed after creation_) One of: `USA`, `CAN`. Example: `"USA"`. - `metadata` (object): any useful information you'd like to store alongside this business - `additional_questions` (`AdditionalQuestions`) - `legal_address` (one of `Address` | object) - Option 2: - `id` (string): Example: `"addr_xyz"`. - `representative` (one of `Identity` | object) - Option 2: - `id` (string): Example: `"idty_xyz"`. - `owners` (array of one of `Identity` | object): up to four business owners total - Option 2: - `id` (string): Example: `"idty_xyz"`. ### Responses #### 201: Business entity was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"business"`. - `data` (object): the attributes for the object - `id` (string): unique business id Example: `"biz_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `mode` (string): whether this business is a test or live business, set from the credentials used to create it and fixed for the life of the business One of: `test`, `live`. Example: `"test"`. - `archived` (boolean): indicates whether this business has been archived. Test mode businesses can always be archived; a live mode business can only be archived while it has not been provisioned. Archived businesses are excluded from the list businesses endpoint Example: `false`. - `legal_name` (string): legal business entity name Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `classification` (string): One of: `government`, `limited`, `non_profit`, `partnership`, `corporation`, `public_company`, `sole_proprietor`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is not returned in any API response - `tax_id_last4` (string): last 4 digits of the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be the last 4 digits of their SSN) - `date_of_incorporation` (string): Example: `"2015-02-20"`. - `country_of_establishment` (string): country where the business was established One of: `USA`, `CAN`. Example: `"USA"`. - `terms_conditions_accepted` (boolean): returns true if terms and conditions were accepted Example: `false`. - `metadata` (object (json)): any useful information you'd like to store alongside this business - `associated_accounts` (array of object): the sub account associated with this business, populated once the business has been provisioned - `id` (string): Example: `"acc_123xyz"`. - `provisioned` (array of string): products successfully provisioned for this business, empty until a provisioning request succeeds. This list reflects completed provisioning only. A business whose provisioning is still in flight, or that already has a sub account associated, reports an empty list but can no longer be archived - `legal_address` (`AddressResponse`) - `representative` (`IdentityResponse`) - `owners` (array of `IdentityResponse`) - `documents` (array of `Document`) - `bank_accounts` (array of `EntityBankAccount`) - `additional_questions` (`AdditionalQuestions`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Business `GET https://api.justifi.ai/v1/entities/business/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Business/operation/GetBusiness Get information about a Business ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a business Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"business"`. - `data` (object): the attributes for the object - `id` (string): unique business id Example: `"biz_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `mode` (string): whether this business is a test or live business, set from the credentials used to create it and fixed for the life of the business One of: `test`, `live`. Example: `"test"`. - `archived` (boolean): indicates whether this business has been archived. Test mode businesses can always be archived; a live mode business can only be archived while it has not been provisioned. Archived businesses are excluded from the list businesses endpoint Example: `false`. - `legal_name` (string): legal business entity name Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `classification` (string): One of: `government`, `limited`, `non_profit`, `partnership`, `corporation`, `public_company`, `sole_proprietor`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is not returned in any API response - `tax_id_last4` (string): last 4 digits of the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be the last 4 digits of their SSN) - `date_of_incorporation` (string): Example: `"2015-02-20"`. - `country_of_establishment` (string): country where the business was established One of: `USA`, `CAN`. Example: `"USA"`. - `terms_conditions_accepted` (boolean): returns true if terms and conditions were accepted Example: `false`. - `metadata` (object (json)): any useful information you'd like to store alongside this business - `associated_accounts` (array of object): the sub account associated with this business, populated once the business has been provisioned - `id` (string): Example: `"acc_123xyz"`. - `provisioned` (array of string): products successfully provisioned for this business, empty until a provisioning request succeeds. This list reflects completed provisioning only. A business whose provisioning is still in flight, or that already has a sub account associated, reports an empty list but can no longer be archived - `legal_address` (`AddressResponse`) - `representative` (`IdentityResponse`) - `owners` (array of `IdentityResponse`) - `documents` (array of `Document`) - `bank_accounts` (array of `EntityBankAccount`) - `additional_questions` (`AdditionalQuestions`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Business `PATCH https://api.justifi.ai/v1/entities/business/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Business/operation/UpdateBusiness Update information about a Business ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `archived` (boolean): set to true to archive this business. Test mode businesses can always be archived. A live mode business can only be archived while it has not been provisioned; once a product has been provisioned for it, or a sub account is associated with it, archiving returns an error. Archiving frees the business's legal_name for reuse, so setting this back to false returns an error if another active business on your platform has taken that name in the meantime Example: `true`. - `legal_name` (string): legal business entity name Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is saved but not returned in any API response - `date_of_incorporation` (string): the specific day when this business was officially registered with a relevant government authority and was then permitted to carry out its activities Example: `"2015-02-20"`. - `metadata` (object): any useful information you'd like to store alongside this business - `additional_questions` (`AdditionalQuestions`) - `legal_address` (one of `Address` | object) - Option 2: - `id` (string): Example: `"addr_xyz"`. - `representative` (one of `Identity` | object) - Option 2: - `id` (string): Example: `"idty_xyz"`. ### Responses #### 200: Successfully update a business Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"business"`. - `data` (object): the attributes for the object - `id` (string): unique business id Example: `"biz_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `mode` (string): whether this business is a test or live business, set from the credentials used to create it and fixed for the life of the business One of: `test`, `live`. Example: `"test"`. - `archived` (boolean): indicates whether this business has been archived. Test mode businesses can always be archived; a live mode business can only be archived while it has not been provisioned. Archived businesses are excluded from the list businesses endpoint Example: `false`. - `legal_name` (string): legal business entity name Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `classification` (string): One of: `government`, `limited`, `non_profit`, `partnership`, `corporation`, `public_company`, `sole_proprietor`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is not returned in any API response - `tax_id_last4` (string): last 4 digits of the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be the last 4 digits of their SSN) - `date_of_incorporation` (string): Example: `"2015-02-20"`. - `country_of_establishment` (string): country where the business was established One of: `USA`, `CAN`. Example: `"USA"`. - `terms_conditions_accepted` (boolean): returns true if terms and conditions were accepted Example: `false`. - `metadata` (object (json)): any useful information you'd like to store alongside this business - `associated_accounts` (array of object): the sub account associated with this business, populated once the business has been provisioned - `id` (string): Example: `"acc_123xyz"`. - `provisioned` (array of string): products successfully provisioned for this business, empty until a provisioning request succeeds. This list reflects completed provisioning only. A business whose provisioning is still in flight, or that already has a sub account associated, reports an empty list but can no longer be archived - `legal_address` (`AddressResponse`) - `representative` (`IdentityResponse`) - `owners` (array of `IdentityResponse`) - `documents` (array of `Document`) - `bank_accounts` (array of `EntityBankAccount`) - `additional_questions` (`AdditionalQuestions`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### BusinessResponse - `id` (string): unique business id Example: `"biz_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `mode` (string): whether this business is a test or live business, set from the credentials used to create it and fixed for the life of the business One of: `test`, `live`. Example: `"test"`. - `archived` (boolean): indicates whether this business has been archived. Test mode businesses can always be archived; a live mode business can only be archived while it has not been provisioned. Archived businesses are excluded from the list businesses endpoint Example: `false`. - `legal_name` (string): legal business entity name Example: `"Business Name"`. - `website_url` (string): website for this business (if they don't have a website, can send their social media business page, app store link, or a product description instead) Example: `"https://justifi.ai"`. - `email` (string): email address of business entity or representative Example: `"business@justifi.ai"`. - `phone` (string): business phone number Example: `"6124011111"`. - `doing_business_as` (string): only needed if registered with DBA/Trade Name on SS-4 tax document Example: `"Best Business"`. - `business_type` (string): One of: `for_profit`, `non_profit`, `government_entity`, `individual`. - `business_structure` (string): One of: `sole_proprietorship`, `single_llc`, `multi_llc`, `private_partnership`, `private_corporation`, `unincorporated_association`, `public_partnership`, `public_corporation`, `incorporated`, `unincorporated`, `government_unit`, `government_instrumentality`, `tax_exempt_government_instrumentality`. - `classification` (string): One of: `government`, `limited`, `non_profit`, `partnership`, `corporation`, `public_company`, `sole_proprietor`. - `industry` (string): to help us identify this business entity's category code (MCC), please provide a concise description of what service they offer Example: `"Big Business"`. - `mcc` (string): merchant category code for this business, if known. Please note, the JustiFi underwriting team may modify this. If you are unsure, just submit a description in the industry field instead of an MCC Example: `"8021"`. - `tax_id` (string): the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be their full SSN), the value is not returned in any API response - `tax_id_last4` (string): last 4 digits of the federal tax identification number/EIN issued to this sub account by the IRS (for Individual type, this will be the last 4 digits of their SSN) - `date_of_incorporation` (string): Example: `"2015-02-20"`. - `country_of_establishment` (string): country where the business was established One of: `USA`, `CAN`. Example: `"USA"`. - `terms_conditions_accepted` (boolean): returns true if terms and conditions were accepted Example: `false`. - `metadata` (object (json)): any useful information you'd like to store alongside this business - `associated_accounts` (array of object): the sub account associated with this business, populated once the business has been provisioned - `id` (string): Example: `"acc_123xyz"`. - `provisioned` (array of string): products successfully provisioned for this business, empty until a provisioning request succeeds. This list reflects completed provisioning only. A business whose provisioning is still in flight, or that already has a sub account associated, reports an empty list but can no longer be archived - `legal_address` (`AddressResponse`) - `representative` (`IdentityResponse`) - `owners` (array of `IdentityResponse`) - `documents` (array of `Document`) - `bank_accounts` (array of `EntityBankAccount`) - `additional_questions` (`AdditionalQuestions`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### AdditionalQuestions - `business_revenue` (string): amount of money the company receives from its primary business activities Example: `"84220"`. - `business_payment_volume` (string): annual credit card & ACH volume anticipated to process with Justifi Example: `"1000000"`. - `business_when_service_received` (string): how long after paying will your customers typically receive their goods or services Example: `"Within 7 days"`. - `business_recurring_payments` (string): business offer recurring payments Example: `"true"`. - `business_recurring_payments_percentage` (string): percentage of revenue is generated from each recurring payment type offered Example: `"50% monthly, 50% annual"`. - `business_seasonal` (string): is the business seasonal Example: `"No. The business revenue is generated evenly throughout the year"`. - `business_other_payment_details` (string): anything else you would like us to know about how your customers pay the business Example: `"50% of revenue is taken 90 days in advance of service and 50% of revenue is taken 30 days in advance of service"`. - `business_purchase_order_volume` (string): total number of purchase orders made by a business Example: `"150"`. - `business_invoice_volume` (string): total number of invoices generated by a business Example: `"500"`. - `business_fund_use_intent` (string): planned purpose for which a business intends to use funds Example: `"expanding marketing efforts"`. - `equipment_invoice` (string): document specifying the cost and details of equipment purchased Example: `"$10,000 invoice for computer equipment"`. - `business_invoice_number` (string): unique identifier assigned to a specific invoice issued by a business Example: `"202105-001"`. - `business_invoice_amount` (string): total monetary value stated on an invoice issued by a business Example: `"$4500"`. - `business_purchase_order_number` (string): number of unique purchase orders made by a business Example: `"120"`. - `industry_code` (string): numerical or alphanumeric code that classifies businesses according to their industry Example: `"541512"`. - `duns_number` (string): unique nine-digit identification number assigned to a business entity Example: `"123456789"`. - `business_payment_decline_volume` (string): total number of payment declines experienced by a business Example: `"500"`. - `business_refund_volume` (string): total number of refunds issued by a business Example: `"100"`. - `business_dispute_volume` (string): total number of disputes raised by customers against a business Example: `"50"`. - `business_receivable_volume` (string): total value of outstanding payments owed to a business Example: `"US $100,000"`. - `business_future_scheduled_payment_volume` (string): total number of future scheduled payments for a business Example: `"200"`. - `business_dispute_win_rate` (string): percentage of business disputes won out of the total number of disputes Example: `"75%"`. - `length_of_business_relationship` (string): duration of a business relationship between two parties Example: `"5 years"`. ### Address - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. ### Identity - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `identification_number` (string): full social security number Example: `"123456789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when the identity owns a business (proprietor_id set), not based on the is_owner column. Only owners with at least 25% ownership should be included. Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (one of `Address` | object) - Option 2: - `id` (string) ### AddressResponse - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### IdentityResponse - `id` (string): unique identity id Example: `"idty_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `business_id` (string (uuid)): associated business Example: `"biz_xyz"`. - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `ssn_last4` (string): last four digits of social security number (computed from identification_number) Example: `"6789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when is_owner is true Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (`AddressResponse`) - `documents` (array of `Document`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### Document - `id` (string (uuid)): Example: `"doc_abc123"`. - `description` (string): description of the document, used for your reference Example: `"My Document"`. - `file_name` (string): file name of the document Example: `"my_document"`. - `file_type` (string): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"pdf"`. - `document_type` (string): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `presigned_url` (string (url)): url used to PUT or GET the document to our cloud provider. This is not returned via the list API Example: `"https://test.test/doc_abc123/file_name.pdf"`. - `metadata` (object (json)): any useful information you'd like to store alongside this document - `status` (string): One of: `pending uploaded canceled`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### EntityBankAccount - `id` (string (uuid)): unique bank account id Example: `"ba_123xyz"`. - `account_owner_name` (string): name of the account owner Example: `"Napheesa Collier"`. - `account_type` (string): type of the account One of: `checking`, `savings`. Example: `"checking"`. - `acct_last_four` (string): last 4 digits of the account number Example: `"6789"`. - `routing_number` (string): routing number for account Example: `"110000000"`. - `bank_name` (string): name of the bank Example: `"Wells Fargo"`. - `country` (string): country for the bank account One of: `US`, `CA`. - `currency` (string): currency for the bank account One of: `usd`, `cad`. - `nickname` (string): nickname for the bank account Example: `"Phee's money"`. - `metadata` (object (json)): any useful information you'd like to store alongside this bank account - `business_id` (string (uuid)): Example: `"biz_123abc"`. - `platform_account_id` (string (uuid)): Example: `"acc_123abc"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. --- # Identity Reference: https://docs.justifi.tech/api-spec#tag/Identity Creating an identity establishes a unique identification for people associated with your business. Accurately providing your information is crucial in ensuring that your identity is properly verified and maintained, and can have important consequences for a variety of financial and legal transactions. Our platform has a secure database for storing identity information, encryption and other security measures to protect your sensitive data. ## List Identities `GET https://api.justifi.ai/v1/entities/identity` Reference: https://docs.justifi.tech/api-spec#tag/Identity/operation/ListIdentities List identities for your platform. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully list identities Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `IdentityResponse`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create an Identity `POST https://api.justifi.ai/v1/entities/identity` Reference: https://docs.justifi.tech/api-spec#tag/Identity/operation/CreateIdentity Create an Identity ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `identification_number` (string): full social security number Example: `"123456789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); applies when is_owner is true Example: `25`. - `metadata` (object): any useful information you'd like to store alongside this identity - `address` (one of `Address` | object) - Option 2: - `id` (string): Example: `"addr_xyz"`. ### Responses #### 201: Identity was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"identity"`. - `data` (object): the attributes for the object - `id` (string): unique identity id Example: `"idty_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `business_id` (string (uuid)): associated business Example: `"biz_xyz"`. - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `ssn_last4` (string): last four digits of social security number (computed from identification_number) Example: `"6789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when is_owner is true Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (`AddressResponse`) - `documents` (array of `Document`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get an Identity `GET https://api.justifi.ai/v1/entities/identity/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Identity/operation/GetIdentity Get information about an Identity ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Get Identity Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"identity"`. - `data` (object): the attributes for the object - `id` (string): unique identity id Example: `"idty_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `business_id` (string (uuid)): associated business Example: `"biz_xyz"`. - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `ssn_last4` (string): last four digits of social security number (computed from identification_number) Example: `"6789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when is_owner is true Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (`AddressResponse`) - `documents` (array of `Document`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update an Identity `PATCH https://api.justifi.ai/v1/entities/identity/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Identity/operation/UpdateIdentity Update information about an Identity ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `identification_number` (string): full social security number Example: `"123456789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); applies when is_owner is true Example: `25`. - `metadata` (object): any useful information you'd like to store alongside this identity ### Responses #### 200: Identity updated Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"identity"`. - `data` (object): the attributes for the object - `id` (string): unique identity id Example: `"idty_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `business_id` (string (uuid)): associated business Example: `"biz_xyz"`. - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `ssn_last4` (string): last four digits of social security number (computed from identification_number) Example: `"6789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when is_owner is true Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (`AddressResponse`) - `documents` (array of `Document`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### IdentityResponse - `id` (string): unique identity id Example: `"idty_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_xyz"`. - `business_id` (string (uuid)): associated business Example: `"biz_xyz"`. - `name` (string): legal name Example: `"Person Name"`. - `title` (string): job title Example: `"President"`. - `email` (string): email address Example: `"person.name@justifi.ai"`. - `phone` (string): phone number Example: `"6124011111"`. - `dob_day` (string): two-digit birth day Example: `"01"`. - `dob_month` (string): two-digit birth month Example: `"01"`. - `dob_year` (string): four-digit birth year (must be at least 18 years old) Example: `"1980"`. - `ssn_last4` (string): last four digits of social security number (computed from identification_number) Example: `"6789"`. - `is_owner` (boolean): if an identity owns 25% or more of the business, they are considered an owner Example: `true`. - `ownership_percentage` (integer): percentage of the business owned by this identity (0–100); only returned when is_owner is true Example: `25`. - `metadata` (object (json)): any useful information you'd like to store alongside this identity - `address` (`AddressResponse`) - `documents` (array of `Document`) - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. ### Address - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. ### AddressResponse - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### Document - `id` (string (uuid)): Example: `"doc_abc123"`. - `description` (string): description of the document, used for your reference Example: `"My Document"`. - `file_name` (string): file name of the document Example: `"my_document"`. - `file_type` (string): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"pdf"`. - `document_type` (string): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `presigned_url` (string (url)): url used to PUT or GET the document to our cloud provider. This is not returned via the list API Example: `"https://test.test/doc_abc123/file_name.pdf"`. - `metadata` (object (json)): any useful information you'd like to store alongside this document - `status` (string): One of: `pending uploaded canceled`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. --- # Address Reference: https://docs.justifi.tech/api-spec#tag/Address Creating an Address entity provides the necessary information to identify and locate a physical address. It may be associated with an Identity entity or Business entity to provide a more complete picture of the parties involved. ## List Addresses `GET https://api.justifi.ai/v1/entities/address` Reference: https://docs.justifi.tech/api-spec#tag/Address/operation/ListAddresses List addresses for your platform. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully list addresses Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `AddressResponse`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create an Address `POST https://api.justifi.ai/v1/entities/address` Reference: https://docs.justifi.tech/api-spec#tag/Address/operation/CreateAddress Create an Address ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"# 61157"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. ### Responses #### 201: Address was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"address"`. - `data` (object): the attributes for the object - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get an Address `GET https://api.justifi.ai/v1/entities/address/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Address/operation/GetAddress Get information about an Address ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Get Address Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"address"`. - `data` (object): the attributes for the object - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update an Address `PATCH https://api.justifi.ai/v1/entities/address/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Address/operation/UpdateAddress Update information about an Address ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"# 61157"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. ### Responses #### 200: Address updated Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"address"`. - `data` (object): the attributes for the object - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### AddressResponse - `id` (string): unique address id Example: `"addr_123xyz"`. - `line1` (string): Example: `"123 Example St"`. - `line2` (string): Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `"55555"`. - `country` (string): Example: `"USA"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Document Reference: https://docs.justifi.tech/api-spec#tag/Document Create/manage documents attached to your businesses and identities. When a document record is created using this API the response object returns a presigned url used to upload this document to an encrypted bucket. The presigned url can then be used to upload directly to an AWS s3 bucket, with a command like `curl -X PUT -T /path/to/file.pdf "insert presigned url"`. You must use the PUT method. This can also be accomplished from a backend or mobile app, from the browser or using our web components. After upload is complete the status changes from `pending` to `uploaded`. ## List Documents `GET https://api.justifi.ai/v1/entities/document` Reference: https://docs.justifi.tech/api-spec#tag/Document/operation/ListDocuments List the documents you have uploaded. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully list documents Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Document`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Document `POST https://api.justifi.ai/v1/entities/document` Reference: https://docs.justifi.tech/api-spec#tag/Document/operation/CreateDocument Create a reference to a document, and receive a presigned URL for uploading the document ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `description` (string): Example: `"My Document"`. - `file_name` (string, required): Example: `"the_file_name"`. - `file_type` (string, required): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"application/pdf"`. - `document_type` (string, required): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `metadata` (object): any useful information you'd like to store alongside this document ### Responses #### 201: Document was created and presigned successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"document"`. - `data` (object): the attributes for the object - `id` (string (uuid)): Example: `"doc_abc123"`. - `description` (string): description of the document, used for your reference Example: `"My Document"`. - `file_name` (string): file name of the document Example: `"my_document"`. - `file_type` (string): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"pdf"`. - `document_type` (string): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `presigned_url` (string (url)): url used to PUT or GET the document to our cloud provider. This is not returned via the list API Example: `"https://test.test/doc_abc123/file_name.pdf"`. - `metadata` (object (json)): any useful information you'd like to store alongside this document - `status` (string): One of: `pending uploaded canceled`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Document `GET https://api.justifi.ai/v1/entities/document/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Document/operation/GetDocument Get details about a document, and a presigned download URL ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Get Document Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"document"`. - `data` (object): the attributes for the object - `id` (string (uuid)): Example: `"doc_abc123"`. - `description` (string): description of the document, used for your reference Example: `"My Document"`. - `file_name` (string): file name of the document Example: `"my_document"`. - `file_type` (string): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"pdf"`. - `document_type` (string): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `presigned_url` (string (url)): url used to PUT or GET the document to our cloud provider. This is not returned via the list API Example: `"https://test.test/doc_abc123/file_name.pdf"`. - `metadata` (object (json)): any useful information you'd like to store alongside this document - `status` (string): One of: `pending uploaded canceled`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### Document - `id` (string (uuid)): Example: `"doc_abc123"`. - `description` (string): description of the document, used for your reference Example: `"My Document"`. - `file_name` (string): file name of the document Example: `"my_document"`. - `file_type` (string): the file media type/extension of the file you are uploading. For example, text/plain, application/pdf, image/png Example: `"pdf"`. - `document_type` (string): One of: `articles_of_incorporation`, `balance_sheet`, `bank_statement`, `birth_certificate`, `business_registration`, `citizenship_card`, `driver_license`, `foreign_passport`, `government_id`, `nexus_card`, `passport`, `profit_and_loss_statement`, `resident_card`, `sin_card`, `ssn_card`, `status_card`, `tax_return`, `voided_check`, `other`. Example: `"balance_sheet"`. - `business_id` (string (uuid)): the business id to associate with this document (one of business id or identity id is required) Example: `"biz_abc123"`. - `identity_id` (string (uuid)): the identity id to associate with this document (one of business id or identity id is required) Example: `"idty_abc123"`. - `presigned_url` (string (url)): url used to PUT or GET the document to our cloud provider. This is not returned via the list API Example: `"https://test.test/doc_abc123/file_name.pdf"`. - `metadata` (object (json)): any useful information you'd like to store alongside this document - `status` (string): One of: `pending uploaded canceled`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Bank Account Reference: https://docs.justifi.tech/api-spec#tag/Bank-Account Create/manage bank accounts for your businesses. These accounts are used for paying out earnings for usage of various products, for example card processing. ## List Bank Accounts `GET https://api.justifi.ai/v1/entities/bank_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Bank-Account/operation/ListBankAccounts List the bank accounts you have created for a business. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `business_id` | query | string | no | filter bank accounts which are associated with a business | ### Responses #### 200: Successfully list bank accounts Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `EntityBankAccount`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Create a Bank Account `POST https://api.justifi.ai/v1/entities/bank_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Bank-Account/operation/CreateBankAccount Create a bank account ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `account_owner_name` (string, required): name of the account owner Example: `"Napheesa Collier"`. - `account_type` (string, required): type of account One of: `checking`, `savings`. Example: `"checking"`. - `account_number` (string, required): the account number Example: `"000123456789"`. - `routing_number` (string, required): routing number Example: `"110000000"`. - `business_id` (string (uuid), required): business id which owns the account Example: `"biz_abc123"`. - `bank_name` (string, required): bank name Example: `"Wells Fargo"`. - `nickname` (string): nickname for the bank account Example: `"Phee's Money"`. - `metadata` (object): any useful information you'd like to store alongside this bank account ### Responses #### 201: Bank Account was created successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"bank_account"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique bank account id Example: `"ba_123xyz"`. - `account_owner_name` (string): name of the account owner Example: `"Napheesa Collier"`. - `account_type` (string): type of the account One of: `checking`, `savings`. Example: `"checking"`. - `acct_last_four` (string): last 4 digits of the account number Example: `"6789"`. - `routing_number` (string): routing number for account Example: `"110000000"`. - `bank_name` (string): name of the bank Example: `"Wells Fargo"`. - `country` (string): country for the bank account One of: `US`, `CA`. - `currency` (string): currency for the bank account One of: `usd`, `cad`. - `nickname` (string): nickname for the bank account Example: `"Phee's money"`. - `metadata` (object (json)): any useful information you'd like to store alongside this bank account - `business_id` (string (uuid)): Example: `"biz_123abc"`. - `platform_account_id` (string (uuid)): Example: `"acc_123abc"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get a Bank Account `GET https://api.justifi.ai/v1/entities/bank_accounts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Bank-Account/operation/GetBankAccount Get details about a bank account ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Get Bank Account Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"bank_account"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique bank account id Example: `"ba_123xyz"`. - `account_owner_name` (string): name of the account owner Example: `"Napheesa Collier"`. - `account_type` (string): type of the account One of: `checking`, `savings`. Example: `"checking"`. - `acct_last_four` (string): last 4 digits of the account number Example: `"6789"`. - `routing_number` (string): routing number for account Example: `"110000000"`. - `bank_name` (string): name of the bank Example: `"Wells Fargo"`. - `country` (string): country for the bank account One of: `US`, `CA`. - `currency` (string): currency for the bank account One of: `usd`, `cad`. - `nickname` (string): nickname for the bank account Example: `"Phee's money"`. - `metadata` (object (json)): any useful information you'd like to store alongside this bank account - `business_id` (string (uuid)): Example: `"biz_123abc"`. - `platform_account_id` (string (uuid)): Example: `"acc_123abc"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### EntityBankAccount - `id` (string (uuid)): unique bank account id Example: `"ba_123xyz"`. - `account_owner_name` (string): name of the account owner Example: `"Napheesa Collier"`. - `account_type` (string): type of the account One of: `checking`, `savings`. Example: `"checking"`. - `acct_last_four` (string): last 4 digits of the account number Example: `"6789"`. - `routing_number` (string): routing number for account Example: `"110000000"`. - `bank_name` (string): name of the bank Example: `"Wells Fargo"`. - `country` (string): country for the bank account One of: `US`, `CA`. - `currency` (string): currency for the bank account One of: `usd`, `cad`. - `nickname` (string): nickname for the bank account Example: `"Phee's money"`. - `metadata` (object (json)): any useful information you'd like to store alongside this bank account - `business_id` (string (uuid)): Example: `"biz_123abc"`. - `platform_account_id` (string (uuid)): Example: `"acc_123abc"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Terms and Conditions Reference: https://docs.justifi.tech/api-spec#tag/Terms-and-Conditions Legally binding rules and agreements that outline the rights, responsibilities, and limitations governing the use of the platform. ## Terms and Conditions `POST https://api.justifi.ai/v1/entities/terms_and_conditions` Reference: https://docs.justifi.tech/api-spec#tag/Terms-and-Conditions/operation/TermsAndConditions Accept current Terms and Conditions ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `business_id` (string, required): business id Example: `"biz_xyz"`. - `accepted` (boolean, required): accepts terms and conditions Example: `true`. - `ip` (string, required): client ip address Example: `"142.250.219.46"`. - `user_agent` (string): client identification information Example: `"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15"`. ### Responses #### 201: Terms and Conditions successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"onboarding"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique terms and conditions id Example: `"tac_xyz"`. - `business_id` (string): Example: `"biz_xyz"`. - `accepted` (boolean): Example: `true`. - `ip` (string): Example: `"142.250.219.46"`. - `user_agent` (string): Example: `"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records --- # Provisioning Reference: https://docs.justifi.tech/api-spec#tag/Provisioning Provisioning API for Products serves as an automated interface to configure resources based on your current entities informations, for example creating an account for card processing. ## Product Provisioning `POST https://api.justifi.ai/v1/entities/provisioning` Reference: https://docs.justifi.tech/api-spec#tag/Provisioning/operation/ProductProvisioning Product Provisioning An archived business cannot be provisioned. Un-archive it first by sending `archived: false` to the update business endpoint. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `business_id` (string, required): business associated with the account Example: `"biz_123"`. - `product_category` (string, required): type of product to be provisioned Example: `"payment"`. ### Responses #### 201: Provisioning successfully Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"onboarding"`. - `data` (object): the attributes for the object - `account_type` (string): account type (live or test) Example: `"test"`. - `sub_account_id` (string (uuid)): Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): Example: `"acc_123"`. - `payload` (object): business information - `page_info` (any, nullable): information for cursor style pagination, is null for single records --- # Terminals Reference: https://docs.justifi.tech/api-spec#tag/Terminals JustiFi provides a card present solution which allows you to collect a payment via a terminal provider via one of our technology partners. To collect a payment via terminal, you must first ensure you ask the JustiFi team to enable the card present feature for your platform. Next, we will work to provision and configure terminals for your sub accounts. Once you have configured a terminal, you must complete the following steps to complete a payment: 1. Create a Checkout 2. Send a checkout to a terminal 3. Terminal processes payment async 4. Handle checkout.completed event (recommended) 5. OR poll checkouts API for status change (optional) ### Create a checkout [Create a Checkout](https://docs.justifi.tech/api-spec#tag/Checkouts/operation/CreateCheckout) with the amount you'd like to capture, and a description of the payment. ### Send a checkout to a terminal [POST to the terminal pay endpoint](https://docs.justifi.tech/api-spec#tag/Terminals/operation/payTerminal) which will be used to send your checkout to a terminal for processing. This process can take some time as it requires customer interaction. For this reason, the API will return immediately but the process is asynchronusly happening on a terminal. ### Terminal processes payment async At this point, the process is handed over to the terminal to complete. Once the payment transaction is completed, we will publish an event for you to continue the process and take further action, as noted in the next step. ### Handle checkout.completed event Create an [Event Publisher](https://docs.justifi.tech/api-spec#tag/Events) which publishes [`checkout.completed` events](https://docs.justifi.tech/api-spec#tag/Events/operation/checkoutEvent). This will provide a means to ensure the payment was successful. You can also listen to checkout completion events, for example a checkout.completion.failed event will be published each time a card is attempted to be processed but the transaction fails for some reason. ### Poll checkouts API for status change If you do not have the ability to handle event publishing, you could poll our checkout API with the id of the checkout you are processing. Contine to poll until the checkout status attribute changes. We recommend you use the checkout events instead of this approach. ## Pay via Terminal `POST https://api.justifi.ai/v1/terminals/pay` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/payTerminal Send a checkout to be processed via terminal, listen for checkout events (recommended) or poll checkout API for payment outcome ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `payment_intent_id` (string (uuid)): (deprecated, use checkout id) id for the payment intent which you want to process via terminal Example: `"pi_abc123"`. - `checkout_id` (string (uuid), required): id of the checkout which you want to process via terminal Example: `"cho_abc123"`. - `terminal_id` (string (uuid), required): id of the terminal on which you want to process a transaction Example: `"trm_abc123"`. ### Responses #### 201: Checkout sent to terminal for processing Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"tses_FQz6I0hMTrcU9Ur7TpOPZ"`. - `type` (string): the object type, or array of objects Example: `"terminal_sessions"`. - `data` (object): the attributes for the object - `id` (string (uuid)): Example: `"tses_FQz6I0hMTrcU9Ur7TpOPZ"`. - `session_type` (string): Example: `"payment"`. - `status` (string): Example: `"created"`. - `payment_id` (string (uuid)): Example: `"py_abc123"`. - `payment_intent_id` (string (uuid)) - `terminal_id` (string (uuid)): Example: `"trm_abc123"`. - `account_id` (string (uuid)): Example: `"acc_abc123"`. - `platform_account_id` (string (uuid)): Example: `"acc_abc123"`. - `checkout_id` (string (uuid)): Example: `"cho_abc123"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## List Terminals `GET https://api.justifi.ai/v1/terminals` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/listTerminals ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `Sub-Account` | header | string | no | the id of the [sub account](https://docs.justifi.tech/api-spec#tag/Sub-Accounts) that this request applies to | | `status` | query | string | no | filter records by the terminal status. Accepts multiple comma separated status values. One of: `connected`, `disconnected`, `unknown`, `pending_configuration`, `archived`. | | `terminal_id` | query | string | no | filter records by terminal id | | `provider_id` | query | string | no | filter records by provider id, also called device id (DID). Accepts multiple comma separated provider ids. | | `terminal_order_id` | query | string | no | filter records by terminal order id | | `verified_after` | query | string (date-time) | no | filter records which were verified after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `verified_before` | query | string (date-time) | no | filter records which were verified before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `verified_on` | query | string (date) | no | filter records which were verified on the date specified between 00:00:00 and 23:59:59 (UTC) | ### Responses #### 200: Successfully list terminals Content type: `application/json` - `id` (number): the object id Example: `1`. - `type` (string): the object type, or array of objects Example: `"array"`. - `data` (array of `Terminal`): the list of objects - `page_info` (`PageInfo`): information for cursor style pagination ## Get a Terminal `GET https://api.justifi.ai/v1/terminals/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/getTerminal ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a terminal Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminal"`. - `data` (object): the attributes for the object - `id` (string): unique terminal id Example: `"trm_abc123"`. - `account_id` (string (uuid)): id of the account associated with the terminal Example: `"acc_123xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the terminal Example: `"acct_789abc"`. - `provider` (enum[verifone verifone_simulator]): terminal provider Example: `"verifone"`. - `status` (enum[connected, disconnected, unknown, pending_configuration, archived]): last known terminal status. For performance reasons, this field is only updated when you check the terminal status via API. Example: `"disconnected"`. - `provider_id` (string): terminal identification from provider, also called device id (DID) Example: `"23456789"`. - `provider_serial_number` (string): serial number of the terminal device. Present after device was configured by entering the provider id (also called device id) into device. Example: `"888-222-444"`. - `nickname` (string): terminal custom identification, can be added and modified via update terminal API Example: `"My Favorite Terminal"`. - `verified_at` (string (date-time)): Example: `"2024-01-01T15:00:00Z"`. - `model_name` (string): name of terminal device model Example: `"e285"`. - `terminal_order_created_at` (string (date-time)): timestamp of when the terminal order was placed Example: `"2024-01-01T15:00:00Z"`. - `status_last_requested_at` (string (date-time)): timestamp of last terminal status request Example: `"2024-01-01T15:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Update a Terminal `PATCH https://api.justifi.ai/v1/terminals/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/updateTerminal ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `nickname` (string): terminal nickname Example: `"My Favorite Terminal"`. ### Responses #### 200: Successfully update a terminal Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminal"`. - `data` (object): the attributes for the object - `id` (string): unique terminal id Example: `"trm_abc123"`. - `account_id` (string (uuid)): id of the account associated with the terminal Example: `"acc_123xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the terminal Example: `"acct_789abc"`. - `provider` (enum[verifone verifone_simulator]): terminal provider Example: `"verifone"`. - `status` (enum[connected, disconnected, unknown, pending_configuration, archived]): last known terminal status. For performance reasons, this field is only updated when you check the terminal status via API. Example: `"disconnected"`. - `provider_id` (string): terminal identification from provider, also called device id (DID) Example: `"23456789"`. - `provider_serial_number` (string): serial number of the terminal device. Present after device was configured by entering the provider id (also called device id) into device. Example: `"888-222-444"`. - `nickname` (string): terminal custom identification, can be added and modified via update terminal API Example: `"My Favorite Terminal"`. - `verified_at` (string (date-time)): Example: `"2024-01-01T15:00:00Z"`. - `model_name` (string): name of terminal device model Example: `"e285"`. - `terminal_order_created_at` (string (date-time)): timestamp of when the terminal order was placed Example: `"2024-01-01T15:00:00Z"`. - `status_last_requested_at` (string (date-time)): timestamp of last terminal status request Example: `"2024-01-01T15:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Get Terminal Status `GET https://api.justifi.ai/v1/terminals/{id}/status` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/getTerminalStatus ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get terminal status Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminal"`. - `data` (object): the attributes for the object - `id` (string): unique terminal id Example: `"trm_abc123"`. - `status` (string): current terminal status Example: `"CONNECTED"`. - `last_date_time_connected` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `last_date_time_active` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Identify Terminal `POST https://api.justifi.ai/v1/terminals/{id}/identify` Reference: https://docs.justifi.tech/api-spec#tag/Terminals/operation/postIdentifyTerminal This API will attempt to display the nickname or serial number on the screen of the given terminal for 20 seconds. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 204: The request was sent to the terminal ## Schemas ### Terminal - `id` (string): unique terminal id Example: `"trm_abc123"`. - `account_id` (string (uuid)): id of the account associated with the terminal Example: `"acc_123xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the terminal Example: `"acct_789abc"`. - `provider` (enum[verifone verifone_simulator]): terminal provider Example: `"verifone"`. - `status` (enum[connected, disconnected, unknown, pending_configuration, archived]): last known terminal status. For performance reasons, this field is only updated when you check the terminal status via API. Example: `"disconnected"`. - `provider_id` (string): terminal identification from provider, also called device id (DID) Example: `"23456789"`. - `provider_serial_number` (string): serial number of the terminal device. Present after device was configured by entering the provider id (also called device id) into device. Example: `"888-222-444"`. - `nickname` (string): terminal custom identification, can be added and modified via update terminal API Example: `"My Favorite Terminal"`. - `verified_at` (string (date-time)): Example: `"2024-01-01T15:00:00Z"`. - `model_name` (string): name of terminal device model Example: `"e285"`. - `terminal_order_created_at` (string (date-time)): timestamp of when the terminal order was placed Example: `"2024-01-01T15:00:00Z"`. - `status_last_requested_at` (string (date-time)): timestamp of last terminal status request Example: `"2024-01-01T15:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### PageInfo - `end_cursor` (string): the encoded id of the last record in the current list Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if the collection contains records following the current list Default: `false`. - `has_previous` (boolean): true if the collection contains records ahead of the current list Default: `false`. - `start_cursor` (string): the encoded id of the first record in the current list Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. --- # Terminals Orders Reference: https://docs.justifi.tech/api-spec#tag/Terminals-Orders Terminals Orders API for order management ## Get Terminals Order `GET https://api.justifi.ai/v1/terminals/orders/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/GetTerminalsOrder Get information about terminals order ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `id` | path | string (uuid) | yes | | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Responses #### 200: Successfully get a terminal order Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminals_order"`. - `data` (object): the attributes for the object - `id` (string): unique terminal order id Example: `"tord_xyz"`. - `business_id` (string (uuid)): Example: `"biz_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `order_type` (string): One of: `boarding_only`, `boarding_shipping`. Example: `"boarding_only"`. - `order_status` (string): status of the order One of: `created`, `submitted`, `in_progress`, `completed`, `on_hold`, `canceled`. - `company_name` (string): business legal name when the terminal order was created Example: `"Business Name"`. - `mcc` (string): Merchant Category Code Example: `7998`. - `receiver_name` (string): name of the person receiving the terminal Example: `"John Doe"`. - `contact_first_name` (string): company's representative first name Example: `"John"`. - `contact_last_name` (string): company's representative last name Example: `"Doe"`. - `contact_email` (string): company's contact email Example: `"john.doe@example.com"`. - `contact_phone_number` (string): company's contact phone number Example: `2125554567`. - `line1` (string): Example: `"123 Main St"`. - `line2` (string): Example: `"Apt 4B"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `55401`. - `time_zone` (string): determined by postal code Example: `"US/Central"`. - `country` (string): Example: `"USA"`. - `shipping_tracking_reference` (string): FedEx tracking number associated with the terminal order shipment. This field is populated only when the terminal order status is completed and the order includes a physical shipment. Always null for boarding_only terminal orders, as no shipment occurs. Example: `12345678`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `terminals` (array of object): list of ordered terminals - `terminal_id` (string (uuid)): unique terminal id Example: `"tmn_abc"`. - `terminal_did` (string): terminal device identification Example: `"12345678"`. - `model_name` (string): One of: `V400m`, `P400`, `E285`. Example: `"V400m"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## List Terminal Orders `GET https://api.justifi.ai/v1/terminals/orders` Reference: https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/ListTerminalsOrders Retrieve a list of terminal orders for your account. This endpoint supports [pagination](https://docs.justifi.tech/api-spec#section/Pagination). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `created_before` | query | string (date-time) | no | filter records which were created before the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `created_after` | query | string (date-time) | no | filter records which were created after the date and time (UTC) specified. Dates without time specified will default to 00:00:00 | | `order_type` | query | string | no | filter terminal orders of a specific type One of: `boarding_only`, `boarding_shipping`. | | `order_status` | query | string | no | filter terminal orders of a specific status One of: `created`, `submitted`, `completed`. | | `sub_account_id` | query | string | no | filter terminal orders of a specific sub account | ### Responses #### 200: Successful response Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminals_orders"`. - `data` (array of `TerminalsOrder`): the attributes for the object - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Order Terminals `POST https://api.justifi.ai/v1/terminals/orders` Reference: https://docs.justifi.tech/api-spec#tag/Terminals-Orders/operation/terminalsOrder Order (one or multiple) terminals from one of our technology partners ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | ### Request body Content type: `application/json` - `business_id` (string (uuid), required): id of the business entity ordering a terminal Example: `"biz_abc123"`. - `sub_account_id` (string (uuid), required): id of the account all terminals from this order will be associated Example: `"acc_abc123"`. - `order_type` (string, required): One of: `boarding_only`, `boarding_shipping`. Example: `"boarding_only"`. - `order_items` (array of object, required): list of terminals being ordered - `model_name` (string): One of: `V400m`, `P400`, `E285`. Example: `"V400m"`. - `quantity` (integer): Example: `1`. ### Responses #### 201: Successful place a Terminal Order Content type: `application/json` - `id` (string (uuid)): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string): the object type, or array of objects Example: `"terminals_order"`. - `data` (object): the attributes for the object - `id` (string): unique terminal order id Example: `"tord_xyz"`. - `business_id` (string (uuid)): Example: `"biz_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `order_type` (string): One of: `boarding_only`, `boarding_shipping`. Example: `"boarding_only"`. - `order_status` (string): status of the order One of: `created`, `submitted`, `in_progress`, `completed`, `on_hold`, `canceled`. - `company_name` (string): business legal name when the terminal order was created Example: `"Business Name"`. - `mcc` (string): Merchant Category Code Example: `7998`. - `receiver_name` (string): name of the person receiving the terminal Example: `"John Doe"`. - `contact_first_name` (string): company's representative first name Example: `"John"`. - `contact_last_name` (string): company's representative last name Example: `"Doe"`. - `contact_email` (string): company's contact email Example: `"john.doe@example.com"`. - `contact_phone_number` (string): company's contact phone number Example: `2125554567`. - `line1` (string): Example: `"123 Main St"`. - `line2` (string): Example: `"Apt 4B"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `55401`. - `time_zone` (string): determined by postal code Example: `"US/Central"`. - `country` (string): Example: `"USA"`. - `shipping_tracking_reference` (string): FedEx tracking number associated with the terminal order shipment. This field is populated only when the terminal order status is completed and the order includes a physical shipment. Always null for boarding_only terminal orders, as no shipment occurs. Example: `12345678`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `terminals` (array of object): list of ordered terminals - `terminal_id` (string (uuid)): unique terminal id Example: `"tmn_abc"`. - `terminal_did` (string): terminal device identification Example: `"12345678"`. - `model_name` (string): One of: `V400m`, `P400`, `E285`. Example: `"V400m"`. - `page_info` (any, nullable): information for cursor style pagination, is null for single records ## Schemas ### TerminalsOrder - `id` (string): unique terminal order id Example: `"tord_xyz"`. - `business_id` (string (uuid)): Example: `"biz_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `order_type` (string): One of: `boarding_only`, `boarding_shipping`. Example: `"boarding_only"`. - `order_status` (string): status of the order One of: `created`, `submitted`, `in_progress`, `completed`, `on_hold`, `canceled`. - `company_name` (string): business legal name when the terminal order was created Example: `"Business Name"`. - `mcc` (string): Merchant Category Code Example: `7998`. - `receiver_name` (string): name of the person receiving the terminal Example: `"John Doe"`. - `contact_first_name` (string): company's representative first name Example: `"John"`. - `contact_last_name` (string): company's representative last name Example: `"Doe"`. - `contact_email` (string): company's contact email Example: `"john.doe@example.com"`. - `contact_phone_number` (string): company's contact phone number Example: `2125554567`. - `line1` (string): Example: `"123 Main St"`. - `line2` (string): Example: `"Apt 4B"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `55401`. - `time_zone` (string): determined by postal code Example: `"US/Central"`. - `country` (string): Example: `"USA"`. - `shipping_tracking_reference` (string): FedEx tracking number associated with the terminal order shipment. This field is populated only when the terminal order status is completed and the order includes a physical shipment. Always null for boarding_only terminal orders, as no shipment occurs. Example: `12345678`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `terminals` (array of object): list of ordered terminals - `terminal_id` (string (uuid)): unique terminal id Example: `"tmn_abc"`. - `terminal_did` (string): terminal device identification Example: `"12345678"`. - `model_name` (string): One of: `V400m`, `P400`, `E285`. Example: `"V400m"`. --- # Payer Account Scope Reference: https://docs.justifi.tech/api-spec#tag/Payer-Account-Scope A request is scoped to a payer account by its path (`/v1/payables/payer_accounts/{payer_id}/…`); your token's permissions determine which payer accounts you can reach. Obtaining a token is unchanged — see [API Credentials](#tag/API-Credentials). --- # Payer Account Provisioning Reference: https://docs.justifi.tech/api-spec#tag/Payer-Account-Provisioning A **payer account** is created automatically when a platform begins provisioning Payables for one of its businesses — you don't create it through this API. It starts `pending` and becomes `active` once JustiFi's risk platform reports the business has met Payables's onboarding requirements. That bar is lighter than card/ACH payments, so a business can be Payables-ready before it is enabled for payments. **Bank account validation is asymmetric.** A payer (funding) account must be `verified` before it can fund a payment (payer accounts are validated in-app). A payee (receiving) account is not verified — it is created `not_required` and paid without upfront validation. Subscribe to `payables.payer_account.*` and `payables.bank_account.*` webhooks to follow provisioning and validation. --- # Payee Payment lifecycle Reference: https://docs.justifi.tech/api-spec#tag/Payee-Payment-lifecycle A payment progresses `initiated → inbound_submitted → holding → outbound_submitted → succeeded`. There is **no automatic retry**, and where a return leaves the payment depends on whose money had already moved: a returned debit-pull means nothing settled, so the payment is `failed` and nobody is owed anything; a returned credit to the payee means the payer was already debited, so the payment goes to `refunding_payer` and then `refunded`. Subscribe to `payables.payee_payment.*` webhooks to track progress. All Payables events are namespaced under `payables.` so they never collide with JustiFi's core `payment.*` events. ### A return that arrives after a payment succeeded ACH lets a return arrive days after an entry has settled, so one can land after we have already told you a payment succeeded. **The payment moves to `failed_late_return`**, which is terminal, and a `payables.payee_payment.failed_late_return` event is delivered — so a payment you were told had succeeded can still change. Handle that in your reconciliation. **It does not mean your payee holds nothing**, and the difference matters before you act. A returned **outbound** credit means the payee never kept the money. A returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — the payee still has it, and JustiFi is the one out of pocket. **Re-sending a payment on this status can pay a payee twice.** Read `transfers` to see which leg returned. What changes is the leg. Its `status` becomes `returned` and it carries the network's `network_error_code`. JustiFi works the break by hand and records the corrective movement as a **further leg on the same payment** — `purpose: recovery`, with `transfer_type: manual` where the money moved off the ACH network. The payment's `transfers` array is where you will see it, and the payment's `amount` is unchanged throughout, because the amount is what was instructed rather than a running balance. One limit to plan around: a corrective leg does not name the leg it cleared. _Payments are read and create only: a payment cannot be cancelled once initiated._ --- # Testing payment outcomes Reference: https://docs.justifi.tech/api-spec#tag/Testing-payment-outcomes A `test` payer account runs against a simulated ACH network: no money moves, and a whole lifecycle takes about a minute instead of several banking days. By default a test payment settles and succeeds. To exercise anything else, name a scenario when you create the payment: ```json { "amount": 91000, "currency": "usd", "payee_id": "pe_...", "fees": [{ "type": "processing_fee", "amount": 1000 }], "metadata": { "simulator": { "scenario": "inbound_returned" } } } ``` `metadata` is otherwise yours to use as you like — `simulator` is the one reserved key, and it is read only for test payer accounts. A live payer account ignores it entirely. | Scenario | What the network does | Payment ends | Also | | --- | --- | --- | --- | | `settles` | both legs settle on schedule | `succeeded` | the default; omit `metadata` for the same result | | `inbound_returned` | the payer's debit-pull is returned, `R01` | `failed` | nothing settled and the payee is never paid | | `outbound_returned` | the payee's credit is returned, `R03` | `refunded` | the payer is refunded automatically. **`R03` says the account does not exist, so the payee is disabled** | | `inbound_returned_late` | the payer's funding is clawed back after the payee was paid, `R10` | `failed_late_return` | the payee keeps the money; see *A return that arrives after a payment succeeded* | | `correction_received` | the payee's bank corrects the account number, `C01` | `succeeded` | the payee is repointed at the corrected account and a `payables.bank_account.corrected` event is delivered | | `correction_received_without_data` | the payee's bank says the account is wrong and does not say what to | `succeeded` | **the payee is disabled** — we cannot correct an account the bank did not describe | | `canceled_by_provider` | the bank ends the payee's credit without a return code | `refunded` | the leg is `failed` and carries no `network_error_code` | | `submission_rejected` | the bank refuses the payer's debit outright, `R13` | `failed` | refused at submission, so no entry was ever sent | | `outbound_submission_rejected` | the bank refuses the payee's credit after the payer was debited, `R13` | `refunded` | the refund returns `amount` less `fees` | **Three of these disable the payee**, which is the same behaviour a live account would produce: a bank that refuses an account, or corrects it without saying what to, means the next payment would go to an account already refused. A disabled payee returns `400` on payment create. **Register a new receiving bank account for it to make it payable again** — that is the way back in test and in production alike, and any payment still held for the payee pays out once it is active. So a scenario that disables the payee ends your run against that payee unless you register a corrected account first. Creating one payee per scenario is the simplest way to walk several in a row. --- # Payer Accounts Reference: https://docs.justifi.tech/api-spec#tag/Payer-Accounts A payer account is the payer in Payables — a first-class entity, with its own `payer_…` id, that funding bank accounts, payees, and payments attach to. It belongs to a JustiFi business (`business_id`) under a platform (`platform_account_id`); a business holds exactly one payer account. Operate routes are scoped to a payer account in the path (`/v1/payables/payer_accounts/{payer_id}/…`); this collection and `/v1/payables/payer_accounts/{id}` are the platform-level reads. A payer account is created when a platform begins provisioning Payables and becomes `active` once JustiFi's risk platform reports the business Payables-ready (a lighter bar than payments). This API exposes payer accounts read-only. Every payer account is `test` or `live`, inherited from the JustiFi account it is provisioned under and fixed for its life. A `test` payer account runs against a simulated ACH network: payments complete in seconds rather than banking days, returns and corrections can be produced on demand, and no money moves. ## List Payer Accounts `GET https://api.justifi.ai/v1/payables/payer_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Payer-Accounts/operation/PayablesListPayerAccounts List the payer accounts your credentials can access — the platform-level (Tier 2) read backing the cross-account view and account switcher; scoped credentials return only the ones they cover. Payer accounts are provisioned when a platform onboards a business — there is no customer-facing create endpoint. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `status` | query | string | no | filter payer accounts by status One of: `pending`, `active`, `disabled`, `archived`. | | `business` | query | string | no | filter to the payer accounts belonging to a single business. Use this to resolve a business's payer account(s) from the `biz_…` id you already hold — a business holds one payer account, so it returns a single record. Example: `"biz_123xyz"`. | | `name` | query | string | no | filter payer accounts to those whose `name` contains this value, case-insensitively. Partial matches count, so `northside` matches "Northside Physical Therapy" — this backs the type-ahead in the account switcher rather than an exact-name lookup. Example: `"northside"`. | | `payer_id` | query | string | no | filter to a single payer account by its `payer_…` id. Matches exactly; an id that is not a `payer_…` id is rejected with `400`. Example: `"payer_123xyz"`. | ### Responses #### 200: Successfully listed payer accounts Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): unique payer account id Example: `"payer_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payer_account"`. - `business_id` (string): the JustiFi business this payer account belongs to. Requests operate *within* a payer account (see the `/v1/payables/payer_accounts/{payer_id}/…` routes); `business_id` records the owning business for reporting and cross-account grouping, it is not the request scope. Discover a business's payer accounts with `GET /v1/payables/payer_accounts?business=biz_…`. Example: `"biz_123xyz"`. - `name` (string): display name for the payer account Example: `"Northside Physical Therapy"`. - `mode` (string): whether this payer account operates against real money. Inherited from the JustiFi account it belongs to — a test account and a live account are different accounts with different ids, so a payer account is one or the other for its life and cannot be switched. In `test`, payments run against a simulated ACH network: they complete in seconds rather than banking days, and no money moves. One of: `test`, `live`. Example: `"live"`. - `status` (string): the payer account's Payables lifecycle state, and what each state prevents. `pending` — provisioning has begun but the risk platform has not yet reported the business Payables-ready; `active` — Payables-ready, and the only state under which anything can be created; `disabled` — was active previously, and can no longer schedule payments, create payees or register bank accounts; `archived` — the same, and permanent: an archived payer account cannot be reactivated. A payment whose payee credit is already held is not paid out while the account is not `active`. It stays held until the account is active again, rather than failing. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `provisioned_at` (string (date-time), nullable): when the payer account was provisioned to use Payables; null until provisioning completes Example: `"2026-01-01T12:00:00Z"`. - `funding_bank_account_id` (string, nullable): pointer to the payer account's active funding bank account. In this version a payer account has a single active funding account. Null until one is registered and verified. Example: `"ba_fund456"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Get a Payer Account `GET https://api.justifi.ai/v1/payables/payer_accounts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payer-Accounts/operation/PayablesGetPayerAccount Retrieve a single payer account by its `payer_…` id. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Successfully retrieved the payer account Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payer_account"`. - `data` (object, required): A payer account is the payer in Payables — a first-class Payables entity with its own `payer_…` id. Every payee, bank account, and payment is scoped to one payer account. Each payer account belongs to a JustiFi business (`business_id`). The record is created (`pending`) when a platform begins provisioning Payables, and becomes `active` once JustiFi's risk platform reports the business has met Payables's onboarding requirements — a lighter bar than our payments-processing product, so a business can be Payables-ready before it is enabled for payments. The customer-facing API exposes payer accounts read-only. - `id` (string): unique payer account id Example: `"payer_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payer_account"`. - `business_id` (string): the JustiFi business this payer account belongs to. Requests operate *within* a payer account (see the `/v1/payables/payer_accounts/{payer_id}/…` routes); `business_id` records the owning business for reporting and cross-account grouping, it is not the request scope. Discover a business's payer accounts with `GET /v1/payables/payer_accounts?business=biz_…`. Example: `"biz_123xyz"`. - `name` (string): display name for the payer account Example: `"Northside Physical Therapy"`. - `mode` (string): whether this payer account operates against real money. Inherited from the JustiFi account it belongs to — a test account and a live account are different accounts with different ids, so a payer account is one or the other for its life and cannot be switched. In `test`, payments run against a simulated ACH network: they complete in seconds rather than banking days, and no money moves. One of: `test`, `live`. Example: `"live"`. - `status` (string): the payer account's Payables lifecycle state, and what each state prevents. `pending` — provisioning has begun but the risk platform has not yet reported the business Payables-ready; `active` — Payables-ready, and the only state under which anything can be created; `disabled` — was active previously, and can no longer schedule payments, create payees or register bank accounts; `archived` — the same, and permanent: an archived payer account cannot be reactivated. A payment whose payee credit is already held is not paid out while the account is not `active`. It stays held until the account is active again, rather than failing. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `provisioned_at` (string (date-time), nullable): when the payer account was provisioned to use Payables; null until provisioning completes Example: `"2026-01-01T12:00:00Z"`. - `funding_bank_account_id` (string, nullable): pointer to the payer account's active funding bank account. In this version a payer account has a single active funding account. Null until one is registered and verified. Example: `"ba_fund456"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # Payees Reference: https://docs.justifi.tech/api-spec#tag/Payees Payees are the parties you send Payables payments to. A payee is standalone — it can be created and paid without being tied to a business — and carries the identity it is paid and filed against: a legal name, an IRS `entity_type`, a taxpayer identification number (an EIN, or an SSN for a sole proprietor) and an address. All four are required. The tax id is write-only; responses return `tax_id_last4`. Name, address and email are updatable; `entity_type` and `tax_id` are the taxpayer and are fixed at create. ## List Payees `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payees` Reference: https://docs.justifi.tech/api-spec#tag/Payees/operation/PayablesListPayees List the payees under this payer account. Supports cursor pagination. Archived payees are excluded unless you ask for them with `?status=archived`. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `created_after` | query | string (date-time) | no | filter records created after the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `created_before` | query | string (date-time) | no | filter records created before the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `status` | query | string | no | filter payees by status. Omit it and every payee except `archived` is returned; archiving is a soft delete, so archived payees are visible only when asked for by name. One of: `pending`, `active`, `disabled`, `archived`. | ### Responses #### 200: Successfully listed payees Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Create a Payee `POST https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payees` Reference: https://docs.justifi.tech/api-spec#tag/Payees/operation/PayablesCreatePayee Create a payee under this payer account. `name`, `entity_type`, `tax_id` and `address` are all required — together they are the identity a payee is paid and filed against, and none of them has a sensible default. A payee is still created without a bank account and has one registered later, through `CreateBankAccount`. `entity_type` and `tax_id` are fixed here — they are the taxpayer the payee is filed against, and `UpdatePayee` does not accept them. **The payer account must be `active`.** A payer account that is `pending`, `disabled` or `archived` creates nothing, and a payee create under one is refused with a `400`. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | ### Request body Content type: `application/json` - `name` (string, required): the payee's legal name Example: `"Acme Plumbing LLC"`. - `entity_type` (string, required): the payee's IRS entity classification; no default, and not changeable later One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `tax_id` (string, required): the payee's taxpayer identification number — **an EIN or an SSN**, nine digits with or without separators. Which one it is follows `entity_type`: a `sole_proprietorship` files under the proprietor's SSN, or under an EIN where it has one; every other entity type files under an EIN. Write-only — it is stored encrypted and never returned; responses carry `tax_id_last4`. Payables does not validate it against the IRS, and does not check it against the entity type. Example: `"12-3454021"`. - `address` (object, required): A postal address, in the shape JustiFi's other APIs use. The shape is enforced; the address itself is not — Payables does not verify that it exists, and stores it as given without normalizing case or spacing. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `email` (string (email)): Example: `"billing@acmeplumbing.com"`. - `metadata` (object) ### Responses #### 201: Payee was created successfully Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee"`. - `data` (object, required): A payee is a party that receives Payables payments. Payees are standalone: they can exist and be paid without being tied to a business. `business_id` reports a link to a JustiFi business where there is one, and is null by default. - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 422: The request was well-formed and passed field validation, but a business rule rejected it — for example a payer funding account that is not `verified`, or a payee with no receiving bank account to credit. Field-level validation failures return `400`, not this. `error.details` carries per-attribute messages where the rule is attributable to one. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "unprocessable_entity", "message": "The request could not be processed", "details": { "amount": [ "must be greater than 0" ], "payee_id": [ "is required" ] } } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Get a Payee `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payees/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payees/operation/PayablesGetPayee ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Successfully retrieved the payee Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee"`. - `data` (object, required): A payee is a party that receives Payables payments. Payees are standalone: they can exist and be paid without being tied to a business. `business_id` reports a link to a JustiFi business where there is one, and is null by default. - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Update a Payee `PATCH https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payees/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payees/operation/PayablesUpdatePayee Update mutable fields on a payee. Only the fields you send are changed, except `address`, which is replaced whole rather than merged field by field. `entity_type` and `tax_id` are not updatable. They are the taxpayer the payee is filed against and are fixed at create; a name or address change does not make a payee a different taxpayer, and a change to either of those two does. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `id` | path | string | yes | the id of the resource | ### Request body Content type: `application/json` - `name` (string): the payee's legal name Example: `"Acme Plumbing LLC"`. - `address` (object): replaces the whole address. Partial addresses are not merged. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `email` (string (email)): Example: `"ap@acmeplumbing.com"`. - `metadata` (object) ### Responses #### 200: Payee was updated successfully Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee"`. - `data` (object, required): A payee is a party that receives Payables payments. Payees are standalone: they can exist and be paid without being tied to a business. `business_id` reports a link to a JustiFi business where there is one, and is null by default. - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 422: The request was well-formed and passed field validation, but a business rule rejected it — for example a payer funding account that is not `verified`, or a payee with no receiving bank account to credit. Field-level validation failures return `400`, not this. `error.details` carries per-attribute messages where the rule is attributable to one. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "unprocessable_entity", "message": "The request could not be processed", "details": { "amount": [ "must be greater than 0" ], "payee_id": [ "is required" ] } } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Archive a Payee `DELETE https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payees/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payees/operation/PayablesArchivePayee Archive a payee. Archiving is a soft delete: the payee's record and payment history are retained, but the payee can no longer be paid. Returns the archived payee. **Archiving reaches the payments already in flight, up to a point.** A credit already submitted to the network completes — nothing recalls an ACH entry. A payment still holding the payer's funds is not paid out: it stays held rather than failing, and would resume only if the payee were active again, which archiving rules out. Archiving is also always allowed, whatever the payer account's status. Archiving is one-way — there is no unarchive operation, and `status` is not writable through `UpdatePayee`. To pay a party again after archiving it, create a new payee. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Payee was archived successfully Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee"`. - `data` (object, required): A payee is a party that receives Payables payments. Payees are standalone: they can exist and be paid without being tied to a business. `business_id` reports a link to a JustiFi business where there is one, and is null by default. - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # Payee Bank Accounts Reference: https://docs.justifi.tech/api-spec#tag/Payee-Bank-Accounts Bank accounts fund payments (the payer account's funding account) or receive them (a payee's account). Account numbers are write-only and never returned. Records are immutable — correcting an account creates a new record and supersedes the old one rather than editing it. Both kinds are readable here, but only payee receiving accounts can be **created** here. The payer account's funding account decides where money is pulled from, so it is set during provisioning and replaced by JustiFi rather than through this API. ## List Bank Accounts `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/bank_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Bank-Accounts/operation/PayablesListBankAccounts List bank accounts under this payer account, optionally filtered by owner. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `payee_id` | query | string | no | filter to a specific payee's receiving accounts. Ordered by `created_at`, this gives that payee's full bank account history — the current one is whichever `payee.receiving_bank_account_id` names. | | `funding` | query | boolean | no | `true` returns only the payer account's funding accounts (those with `payer_account_id` set); `false` returns only payee receiving accounts | ### Responses #### 200: Successfully listed bank accounts Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): unique bank account id Example: `"ba_recv123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"bank_account"`. - `payer_account_id` (string, nullable): the payer account that owns this bank account, when it is a **funding** account. Null on a payee's receiving account. Exactly one of `payer_account_id` and `payee_id` is non-null. - `account_holder_name` (string): the name on the bank account Example: `"Acme Plumbing LLC"`. - `routing_number` (string): the 9-digit ABA routing number Example: `"021000021"`. - `account_number_last4` (string): the last four digits of the account number (the full number is never returned) Example: `"6789"`. - `account_type` (string): the type of bank account One of: `checking`, `savings`. Example: `"checking"`. - `payee_id` (string, nullable): the payee that owns this bank account, when it is a **receiving** account. Null on a payer's funding account. Exactly one of `payer_account_id` and `payee_id` is non-null. Example: `"pe_abc123"`. - `verification_status` (string): the state of bank account verification. Read together with which owner field is set, this is the model's signal for how the account is handled: - `not_required` — a payee (receiving) account. Payables does not verify payee accounts; payments are sent without upfront validation, and a bad account surfaces as a returned credit. This is a settled state rather than a "not yet verified" one. - `pending` — a payer (funding) account whose validation is in progress. Payer funding accounts are validated in-app (e.g. during portal funding setup). - `verified` — a payer funding account that has been validated; only a `verified` funding account may fund a payment. - `failed` — validation of a payer funding account failed; it cannot fund payments. One of: `not_required`, `pending`, `verified`, `failed`. Example: `"verified"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Create a Payee Bank Account `POST https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/bank_accounts` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Bank-Accounts/operation/PayablesCreateBankAccount Register a **receiving** bank account for a payee under this payer account (the account a payment is paid to). The `account_number` is write-only — it is accepted here but never returned; responses expose only `account_number_last4`. **Funding accounts cannot be created here.** The payer account's own funding account — the one payments are pulled from — is set during provisioning and replaced by JustiFi rather than through this API, because it decides where money is taken from. This endpoint creates payee receiving accounts only, and they are created `not_required`: Payables does not validate payee accounts. You can still *read* funding accounts through `ListBankAccounts` and `GetBankAccount`. In this version an owner has a single active bank account — creating one for a payee that already has an active account supersedes the previous one. **The payer account must be `active` and the payee must not be archived.** Either one is a `400`: a payer account that is not active registers nothing, and an archived payee can never be paid, so it has nothing to be paid to. **A `disabled` payee may still register an account, and doing so returns it to `active`.** That is the way back for a payee Payables disabled because its bank refused the credit or corrected the account without saying what to: register the corrected numbers and the payee is payable again, along with any payment still held for it. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | ### Request body Content type: `application/json` - `account_holder_name` (string, required): Example: `"Acme Plumbing LLC"`. - `routing_number` (string, required): Example: `"021000021"`. - `account_number` (string, required): the full account number; write-only, never returned Example: `"123456789"`. - `account_type` (string, required): One of: `checking`, `savings`. Example: `"checking"`. - `payee_id` (string, required): the payee this receiving account belongs to. The payee must be scoped to the payer account in the path. Example: `"pe_abc123"`. ### Responses #### 201: Bank account was created successfully Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"bank_account"`. - `data` (object, required): A bank account used for Payables money movement. Exactly one of `payer_account_id` or `payee_id` is set: the former for a funding account (the principal is pulled from it), the latter for a payee's receiving account (the principal is paid to it). Account numbers are write-only — accepted on create, never returned; responses expose only the last four digits. Bank accounts are immutable: to correct details (e.g. after a NOC), a new record is created rather than edited in place. **Which record is active is determined by the owner**, via `payer_account.funding_bank_account_id` or `payee.receiving_bank_account_id` — so registering a new account and pointing the owner at it supersedes the previous one. Listing an owner's bank accounts by `created_at` therefore gives its full account history. - `id` (string): unique bank account id Example: `"ba_recv123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"bank_account"`. - `payer_account_id` (string, nullable): the payer account that owns this bank account, when it is a **funding** account. Null on a payee's receiving account. Exactly one of `payer_account_id` and `payee_id` is non-null. - `account_holder_name` (string): the name on the bank account Example: `"Acme Plumbing LLC"`. - `routing_number` (string): the 9-digit ABA routing number Example: `"021000021"`. - `account_number_last4` (string): the last four digits of the account number (the full number is never returned) Example: `"6789"`. - `account_type` (string): the type of bank account One of: `checking`, `savings`. Example: `"checking"`. - `payee_id` (string, nullable): the payee that owns this bank account, when it is a **receiving** account. Null on a payer's funding account. Exactly one of `payer_account_id` and `payee_id` is non-null. Example: `"pe_abc123"`. - `verification_status` (string): the state of bank account verification. Read together with which owner field is set, this is the model's signal for how the account is handled: - `not_required` — a payee (receiving) account. Payables does not verify payee accounts; payments are sent without upfront validation, and a bad account surfaces as a returned credit. This is a settled state rather than a "not yet verified" one. - `pending` — a payer (funding) account whose validation is in progress. Payer funding accounts are validated in-app (e.g. during portal funding setup). - `verified` — a payer funding account that has been validated; only a `verified` funding account may fund a payment. - `failed` — validation of a payer funding account failed; it cannot fund payments. One of: `not_required`, `pending`, `verified`, `failed`. Example: `"verified"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 422: The request was well-formed and passed field validation, but a business rule rejected it — for example a payer funding account that is not `verified`, or a payee with no receiving bank account to credit. Field-level validation failures return `400`, not this. `error.details` carries per-attribute messages where the rule is attributable to one. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "unprocessable_entity", "message": "The request could not be processed", "details": { "amount": [ "must be greater than 0" ], "payee_id": [ "is required" ] } } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Get a Bank Account `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/bank_accounts/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Bank-Accounts/operation/PayablesGetBankAccount ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Successfully retrieved the bank account Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"bank_account"`. - `data` (object, required): A bank account used for Payables money movement. Exactly one of `payer_account_id` or `payee_id` is set: the former for a funding account (the principal is pulled from it), the latter for a payee's receiving account (the principal is paid to it). Account numbers are write-only — accepted on create, never returned; responses expose only the last four digits. Bank accounts are immutable: to correct details (e.g. after a NOC), a new record is created rather than edited in place. **Which record is active is determined by the owner**, via `payer_account.funding_bank_account_id` or `payee.receiving_bank_account_id` — so registering a new account and pointing the owner at it supersedes the previous one. Listing an owner's bank accounts by `created_at` therefore gives its full account history. - `id` (string): unique bank account id Example: `"ba_recv123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"bank_account"`. - `payer_account_id` (string, nullable): the payer account that owns this bank account, when it is a **funding** account. Null on a payee's receiving account. Exactly one of `payer_account_id` and `payee_id` is non-null. - `account_holder_name` (string): the name on the bank account Example: `"Acme Plumbing LLC"`. - `routing_number` (string): the 9-digit ABA routing number Example: `"021000021"`. - `account_number_last4` (string): the last four digits of the account number (the full number is never returned) Example: `"6789"`. - `account_type` (string): the type of bank account One of: `checking`, `savings`. Example: `"checking"`. - `payee_id` (string, nullable): the payee that owns this bank account, when it is a **receiving** account. Null on a payer's funding account. Exactly one of `payer_account_id` and `payee_id` is non-null. Example: `"pe_abc123"`. - `verification_status` (string): the state of bank account verification. Read together with which owner field is set, this is the model's signal for how the account is handled: - `not_required` — a payee (receiving) account. Payables does not verify payee accounts; payments are sent without upfront validation, and a bad account surfaces as a returned credit. This is a settled state rather than a "not yet verified" one. - `pending` — a payer (funding) account whose validation is in progress. Payer funding accounts are validated in-app (e.g. during portal funding setup). - `verified` — a payer funding account that has been validated; only a `verified` funding account may fund a payment. - `failed` — validation of a payer funding account failed; it cannot fund payments. One of: `not_required`, `pending`, `verified`, `failed`. Example: `"verified"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # Payee Payments Reference: https://docs.justifi.tech/api-spec#tag/Payee-Payments A payee payment debit-pulls the principal from the payer account's funding bank account, holds it, then credits the payee. There is no automatic retry: a returned debit-pull fails the payment, and a returned credit refunds the payer. Payments cannot be cancelled once initiated. ## List Payee Payments `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payee_payments` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Payments/operation/PayablesListPayeePayments List payee payments under this payer account. Supports cursor pagination and filtering. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `created_after` | query | string (date-time) | no | filter records created after the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `created_before` | query | string (date-time) | no | filter records created before the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `status` | query | string | no | filter payments by lifecycle status One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`. | | `payee_id` | query | string | no | filter payments to a single payee | ### Responses #### 200: Successfully listed payee payments Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): unique payee payment id Example: `"pp_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee_payment"`. - `payer_account_id` (string): the id of the payer account this payment is scoped to Example: `"payer_123xyz"`. - `amount` (integer): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (e.g. `amount` 91000 with a 1000 fee pays the payee 90000). Example: `91000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `status` (string): the payment's position in its lifecycle. `initiated` → `inbound_submitted` → `holding` → `outbound_submitted` → `succeeded` is the happy path. **`holding` is a real wait.** Once the payer's funding has settled, the payee's credit is held until the next banking day before it is submitted, so a payment rests in `holding` rather than passing through it. Read `deposits_at` for when the payee is expected to be deposited; the hold is already in that estimate. **The hold only lifts for an active payer account and an active payee.** When the wait is up, the payee's credit is sent if both are `active`; if either is not, the payment stays in `holding` and is reconsidered periodically, so it pays out once both are active again. A hold that persists pushes the deposit past the `deposits_at` estimate, which is why that field is an estimate. Which return path a payment takes depends on whose money was already moved. A returned **inbound** debit-pull means nothing settled, so the payment is `failed` and no one is owed anything. A returned **outbound** credit means the payer was already debited, so the payment moves to `refunding_payer` and then `refunded` once the payer has their money back. Both `failed` and `refunded` are terminal. **`succeeded` is not the end.** ACH lets a return arrive days after an entry settled, so one can land after a payment has succeeded. That moves the payment to `failed_late_return`, which is terminal — JustiFi works the break by hand and records the corrective movement as a further leg on the same payment. See "A return that arrives after a payment succeeded" in the overview. **`failed_late_return` does not mean the payee holds nothing.** It reports that the payment did not stick, and the two ways that happens are opposites: a returned **outbound** credit means the payee never kept the money, while a returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — so the payee still has it. **Re-sending on this status can pay a payee twice.** Read the payment's `transfers` to see which leg returned before acting. One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`, `failed_late_return`. Example: `"succeeded"`. - `payment_type` (string): how the funds move. ACH is the only option. Named `payment_type` rather than `payment_method`, which in the JustiFi API denotes a stored instrument object, not a rail. One of: `ach`. Example: `"ach"`. - `payee_id` (string): the payee being paid Example: `"pe_abc123"`. - `funding_bank_account_id` (string): the account's funding bank account the principal is debit-pulled from Example: `"ba_fund456"`. - `receiving_bank_account_id` (string): the payee's receiving account the principal is credited to Example: `"ba_recv123"`. - `debits_at` (string (date-time), nullable): in UTC, the estimated date and time the payer's funding account is debited (from the inbound leg); null until scheduled. Normally three banking days after the payment is submitted. Example: `"2026-01-01T12:00:00Z"`. - `deposits_at` (string (date-time), nullable): in UTC, the estimated date and time the payee is deposited (from the outbound leg); null until scheduled. Each ACH leg takes three banking days and the payee's credit is held for one banking day after the payer's funding settles, so this is normally four banking days after `debits_at`. Estimated, and may shift if the provider revises an effective entry date. Example: `"2026-01-04T12:00:00Z"`. - `description` (string, nullable): Example: `"Invoice 4021"`. - `fees` (array of object): the fees charged on this payment (v2 fee convention), carved out of `amount`. Supplied in the create request (required, no default) and echoed here. Fees incurred later by NOCs or returns are not shown here — they are billed to the platform monthly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `transfers` (array of object): the ACH legs that make up this payment - `id` (string): unique transfer leg id Example: `"ptr_123"`. - `direction` (string): the direction of funds for this leg (a refund is an outbound, a recovery an inbound) One of: `inbound`, `outbound`. Example: `"inbound"`. - `purpose` (string): what this leg is — moves the principal, refunds the payer, or recovers owed funds from the payer One of: `principal`, `refund`, `recovery`. Example: `"principal"`. - `transfer_type` (string): how the money moved. `ach` — over the ACH network; `manual` — a movement JustiFi recorded off it. Widens to further rails (e.g. `rtp`) without a breaking change. One of: `ach`, `manual`. Example: `"ach"`. - `amount` (integer): the leg amount in cents Example: `50000`. - `status` (string): the state of this leg One of: `initiated`, `submitted`, `settled`, `returned`, `failed`. Example: `"settled"`. - `error_code` (string, nullable): normalised, rail-agnostic reason the leg failed, in snake_case (e.g. `insufficient_funds`). Stable across rails — **branch on this, not on `network_error_code`**, which is the network's own code and changes meaning between rails. Set when a leg is `failed` or `returned`, and null otherwise. A correction is not a failure: a leg that settled after a notification of change carries `network_error_code` but no `error_code`. A return code with no normalised equivalent reports `unclassified_return`, so this is never null on a leg that failed — the raw code is always there to fall back on. Example: `"insufficient_funds"`. - `error_description` (string, nullable): human-readable text for `error_code`, in English — for support and logs, not for branching. Null whenever `error_code` is. Example: `"Insufficient funds in the account"`. - `network_error_code` (string, nullable): the raw code from the network, verbatim — an ACH return code (`R01`). Preserved for reconciliation. Present whenever the network said anything about this leg, which is not only when it went wrong: a notification of change carries an advisory code (`C01`) on a leg that **settled** normally. Read it together with `status` — the code alone does not mean the money did not move. - `metadata` (object): any useful information you'd like to store alongside this payment - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-05T12:00:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Schedule a Payee Payment `POST https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payee_payments` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Payments/operation/PayablesCreatePayeePayment Schedule a payment to a payee. This debit-pulls the gross `amount` from the payer's funding bank account, holds it, then credits the payee's receiving account with `amount` minus `fees`. The `fees` array is required (no default) and is carved out of `amount`. There is no automatic retry: a returned debit-pull fails the payment, and a returned credit to the payee refunds the payer. **You name the payee; everything else about the routing is resolved for you.** The funding account comes from the payer account in the path and the receiving account from the payee, so neither is a request field — a payment can only ever move money between the two accounts those records already point at. The schedule is set by the system: each leg takes three banking days, and `debits_at` and `deposits_at` are returned once known. `payment_type` and `currency` are optional and default to `ach` and `usd`, the only values either accepts. **The payer account and the payee must both be `active`**, and either one that is not is a `400` rather than a `422` — a status is the state of a record the request refers to, not a problem with the body. A payee that is `pending`, `disabled` or `archived` cannot be paid. Both accounts must be usable, and the bar differs by side. The payer account's funding account must be **verified**. The payee's receiving account does **not** need to be verified — `not_required` is the normal state for one — but it must **exist** and must not have **failed** verification: a payee can be created without a bank account, and naming one that has none leaves the payment with nothing to credit. Either failure is a `422`. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `Idempotency-Key` | header | string | yes | a string to uniquely identify your request (we recommend a generated uuid, but any unique string works). Replaying the same key returns `200` with the payment that key already created — as it stands now, not a cached copy of the first response — instead of performing the operation twice. Reusing a key with a different request body is a `409`. Keys are scoped to the payer account, so two payer accounts may use the same key without colliding. | ### Request body Content type: `application/json` - `amount` (integer, required): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (pass 91000 with a 1000 fee to net the payee 90000). Example: `91000`. - `currency` (string): defaults to `usd`, the only supported currency One of: `usd`. Default: `"usd"`. Example: `"usd"`. - `payee_id` (string, required): Example: `"pe_abc123"`. - `fees` (array of object, required): fees to charge on this payment (v2 fee convention), carved out of `amount`. **Required, no default** — the platform sets the fee explicitly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `payment_type` (string): the rail the payment moves over. **Optional, and defaults to `ach`** — ACH is the only rail Payables moves money over, so there is nothing to select. One of: `ach`. Default: `"ach"`. Example: `"ach"`. - `description` (string): Example: `"Invoice 4021"`. - `metadata` (object) ### Responses #### 200: This `Idempotency-Key` already scheduled a payment for this payer account, and the request body matches. The payment is returned **as it stands now** — not a cached copy of the first response — so it may have advanced past `initiated`. Nothing was scheduled a second time. Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee_payment"`. - `data` (object, required): A payee payment moves money from the account's funding bank account to a payee's receiving account over ACH. It orchestrates an inbound debit-pull, a hold, and an outbound credit, accruing fees along the way. There is no automatic retry, and a payment cannot be cancelled once initiated. A return ends the payment either at `failed` or, when the payer has already been debited, at `refunding_payer` — see `status`. - `id` (string): unique payee payment id Example: `"pp_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee_payment"`. - `payer_account_id` (string): the id of the payer account this payment is scoped to Example: `"payer_123xyz"`. - `amount` (integer): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (e.g. `amount` 91000 with a 1000 fee pays the payee 90000). Example: `91000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `status` (string): the payment's position in its lifecycle. `initiated` → `inbound_submitted` → `holding` → `outbound_submitted` → `succeeded` is the happy path. **`holding` is a real wait.** Once the payer's funding has settled, the payee's credit is held until the next banking day before it is submitted, so a payment rests in `holding` rather than passing through it. Read `deposits_at` for when the payee is expected to be deposited; the hold is already in that estimate. **The hold only lifts for an active payer account and an active payee.** When the wait is up, the payee's credit is sent if both are `active`; if either is not, the payment stays in `holding` and is reconsidered periodically, so it pays out once both are active again. A hold that persists pushes the deposit past the `deposits_at` estimate, which is why that field is an estimate. Which return path a payment takes depends on whose money was already moved. A returned **inbound** debit-pull means nothing settled, so the payment is `failed` and no one is owed anything. A returned **outbound** credit means the payer was already debited, so the payment moves to `refunding_payer` and then `refunded` once the payer has their money back. Both `failed` and `refunded` are terminal. **`succeeded` is not the end.** ACH lets a return arrive days after an entry settled, so one can land after a payment has succeeded. That moves the payment to `failed_late_return`, which is terminal — JustiFi works the break by hand and records the corrective movement as a further leg on the same payment. See "A return that arrives after a payment succeeded" in the overview. **`failed_late_return` does not mean the payee holds nothing.** It reports that the payment did not stick, and the two ways that happens are opposites: a returned **outbound** credit means the payee never kept the money, while a returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — so the payee still has it. **Re-sending on this status can pay a payee twice.** Read the payment's `transfers` to see which leg returned before acting. One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`, `failed_late_return`. Example: `"succeeded"`. - `payment_type` (string): how the funds move. ACH is the only option. Named `payment_type` rather than `payment_method`, which in the JustiFi API denotes a stored instrument object, not a rail. One of: `ach`. Example: `"ach"`. - `payee_id` (string): the payee being paid Example: `"pe_abc123"`. - `funding_bank_account_id` (string): the account's funding bank account the principal is debit-pulled from Example: `"ba_fund456"`. - `receiving_bank_account_id` (string): the payee's receiving account the principal is credited to Example: `"ba_recv123"`. - `debits_at` (string (date-time), nullable): in UTC, the estimated date and time the payer's funding account is debited (from the inbound leg); null until scheduled. Normally three banking days after the payment is submitted. Example: `"2026-01-01T12:00:00Z"`. - `deposits_at` (string (date-time), nullable): in UTC, the estimated date and time the payee is deposited (from the outbound leg); null until scheduled. Each ACH leg takes three banking days and the payee's credit is held for one banking day after the payer's funding settles, so this is normally four banking days after `debits_at`. Estimated, and may shift if the provider revises an effective entry date. Example: `"2026-01-04T12:00:00Z"`. - `description` (string, nullable): Example: `"Invoice 4021"`. - `fees` (array of object): the fees charged on this payment (v2 fee convention), carved out of `amount`. Supplied in the create request (required, no default) and echoed here. Fees incurred later by NOCs or returns are not shown here — they are billed to the platform monthly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `transfers` (array of object): the ACH legs that make up this payment - `id` (string): unique transfer leg id Example: `"ptr_123"`. - `direction` (string): the direction of funds for this leg (a refund is an outbound, a recovery an inbound) One of: `inbound`, `outbound`. Example: `"inbound"`. - `purpose` (string): what this leg is — moves the principal, refunds the payer, or recovers owed funds from the payer One of: `principal`, `refund`, `recovery`. Example: `"principal"`. - `transfer_type` (string): how the money moved. `ach` — over the ACH network; `manual` — a movement JustiFi recorded off it. Widens to further rails (e.g. `rtp`) without a breaking change. One of: `ach`, `manual`. Example: `"ach"`. - `amount` (integer): the leg amount in cents Example: `50000`. - `status` (string): the state of this leg One of: `initiated`, `submitted`, `settled`, `returned`, `failed`. Example: `"settled"`. - `error_code` (string, nullable): normalised, rail-agnostic reason the leg failed, in snake_case (e.g. `insufficient_funds`). Stable across rails — **branch on this, not on `network_error_code`**, which is the network's own code and changes meaning between rails. Set when a leg is `failed` or `returned`, and null otherwise. A correction is not a failure: a leg that settled after a notification of change carries `network_error_code` but no `error_code`. A return code with no normalised equivalent reports `unclassified_return`, so this is never null on a leg that failed — the raw code is always there to fall back on. Example: `"insufficient_funds"`. - `error_description` (string, nullable): human-readable text for `error_code`, in English — for support and logs, not for branching. Null whenever `error_code` is. Example: `"Insufficient funds in the account"`. - `network_error_code` (string, nullable): the raw code from the network, verbatim — an ACH return code (`R01`). Preserved for reconciliation. Present whenever the network said anything about this leg, which is not only when it went wrong: a notification of change carries an advisory code (`C01`) on a leg that **settled** normally. Read it together with `status` — the code alone does not mean the money did not move. - `metadata` (object): any useful information you'd like to store alongside this payment - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-05T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 201: Payee payment was scheduled successfully Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee_payment"`. - `data` (object, required): A payee payment moves money from the account's funding bank account to a payee's receiving account over ACH. It orchestrates an inbound debit-pull, a hold, and an outbound credit, accruing fees along the way. There is no automatic retry, and a payment cannot be cancelled once initiated. A return ends the payment either at `failed` or, when the payer has already been debited, at `refunding_payer` — see `status`. - `id` (string): unique payee payment id Example: `"pp_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee_payment"`. - `payer_account_id` (string): the id of the payer account this payment is scoped to Example: `"payer_123xyz"`. - `amount` (integer): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (e.g. `amount` 91000 with a 1000 fee pays the payee 90000). Example: `91000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `status` (string): the payment's position in its lifecycle. `initiated` → `inbound_submitted` → `holding` → `outbound_submitted` → `succeeded` is the happy path. **`holding` is a real wait.** Once the payer's funding has settled, the payee's credit is held until the next banking day before it is submitted, so a payment rests in `holding` rather than passing through it. Read `deposits_at` for when the payee is expected to be deposited; the hold is already in that estimate. **The hold only lifts for an active payer account and an active payee.** When the wait is up, the payee's credit is sent if both are `active`; if either is not, the payment stays in `holding` and is reconsidered periodically, so it pays out once both are active again. A hold that persists pushes the deposit past the `deposits_at` estimate, which is why that field is an estimate. Which return path a payment takes depends on whose money was already moved. A returned **inbound** debit-pull means nothing settled, so the payment is `failed` and no one is owed anything. A returned **outbound** credit means the payer was already debited, so the payment moves to `refunding_payer` and then `refunded` once the payer has their money back. Both `failed` and `refunded` are terminal. **`succeeded` is not the end.** ACH lets a return arrive days after an entry settled, so one can land after a payment has succeeded. That moves the payment to `failed_late_return`, which is terminal — JustiFi works the break by hand and records the corrective movement as a further leg on the same payment. See "A return that arrives after a payment succeeded" in the overview. **`failed_late_return` does not mean the payee holds nothing.** It reports that the payment did not stick, and the two ways that happens are opposites: a returned **outbound** credit means the payee never kept the money, while a returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — so the payee still has it. **Re-sending on this status can pay a payee twice.** Read the payment's `transfers` to see which leg returned before acting. One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`, `failed_late_return`. Example: `"succeeded"`. - `payment_type` (string): how the funds move. ACH is the only option. Named `payment_type` rather than `payment_method`, which in the JustiFi API denotes a stored instrument object, not a rail. One of: `ach`. Example: `"ach"`. - `payee_id` (string): the payee being paid Example: `"pe_abc123"`. - `funding_bank_account_id` (string): the account's funding bank account the principal is debit-pulled from Example: `"ba_fund456"`. - `receiving_bank_account_id` (string): the payee's receiving account the principal is credited to Example: `"ba_recv123"`. - `debits_at` (string (date-time), nullable): in UTC, the estimated date and time the payer's funding account is debited (from the inbound leg); null until scheduled. Normally three banking days after the payment is submitted. Example: `"2026-01-01T12:00:00Z"`. - `deposits_at` (string (date-time), nullable): in UTC, the estimated date and time the payee is deposited (from the outbound leg); null until scheduled. Each ACH leg takes three banking days and the payee's credit is held for one banking day after the payer's funding settles, so this is normally four banking days after `debits_at`. Estimated, and may shift if the provider revises an effective entry date. Example: `"2026-01-04T12:00:00Z"`. - `description` (string, nullable): Example: `"Invoice 4021"`. - `fees` (array of object): the fees charged on this payment (v2 fee convention), carved out of `amount`. Supplied in the create request (required, no default) and echoed here. Fees incurred later by NOCs or returns are not shown here — they are billed to the platform monthly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `transfers` (array of object): the ACH legs that make up this payment - `id` (string): unique transfer leg id Example: `"ptr_123"`. - `direction` (string): the direction of funds for this leg (a refund is an outbound, a recovery an inbound) One of: `inbound`, `outbound`. Example: `"inbound"`. - `purpose` (string): what this leg is — moves the principal, refunds the payer, or recovers owed funds from the payer One of: `principal`, `refund`, `recovery`. Example: `"principal"`. - `transfer_type` (string): how the money moved. `ach` — over the ACH network; `manual` — a movement JustiFi recorded off it. Widens to further rails (e.g. `rtp`) without a breaking change. One of: `ach`, `manual`. Example: `"ach"`. - `amount` (integer): the leg amount in cents Example: `50000`. - `status` (string): the state of this leg One of: `initiated`, `submitted`, `settled`, `returned`, `failed`. Example: `"settled"`. - `error_code` (string, nullable): normalised, rail-agnostic reason the leg failed, in snake_case (e.g. `insufficient_funds`). Stable across rails — **branch on this, not on `network_error_code`**, which is the network's own code and changes meaning between rails. Set when a leg is `failed` or `returned`, and null otherwise. A correction is not a failure: a leg that settled after a notification of change carries `network_error_code` but no `error_code`. A return code with no normalised equivalent reports `unclassified_return`, so this is never null on a leg that failed — the raw code is always there to fall back on. Example: `"insufficient_funds"`. - `error_description` (string, nullable): human-readable text for `error_code`, in English — for support and logs, not for branching. Null whenever `error_code` is. Example: `"Insufficient funds in the account"`. - `network_error_code` (string, nullable): the raw code from the network, verbatim — an ACH return code (`R01`). Preserved for reconciliation. Present whenever the network said anything about this leg, which is not only when it went wrong: a notification of change carries an advisory code (`C01`) on a leg that **settled** normally. Read it together with `status` — the code alone does not mean the money did not move. - `metadata` (object): any useful information you'd like to store alongside this payment - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-05T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 409: An `Idempotency-Key` was reused with a different request body. Retry with a fresh key, or resend the original body to get the payment that key already created. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "conflict", "message": "This Idempotency-Key was used with a different request body" } } ``` #### 422: The request was well-formed and passed field validation, but a business rule rejected it — for example a payer funding account that is not `verified`, or a payee with no receiving bank account to credit. Field-level validation failures return `400`, not this. `error.details` carries per-attribute messages where the rule is attributable to one. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "unprocessable_entity", "message": "The request could not be processed", "details": { "amount": [ "must be greater than 0" ], "payee_id": [ "is required" ] } } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Get a Payee Payment `GET https://api.justifi.ai/v1/payables/payer_accounts/{payer_id}/payee_payments/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Payee-Payments/operation/PayablesGetPayeePayment Retrieve a payee payment, including its fees and ACH legs. ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `payer_id` | path | string | yes | the payer account this request is scoped to. Every payee, bank account, and payment lives under one payer account, so it is part of the path on all operate (Tier 1) routes. | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Successfully retrieved the payee payment Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"payee_payment"`. - `data` (object, required): A payee payment moves money from the account's funding bank account to a payee's receiving account over ACH. It orchestrates an inbound debit-pull, a hold, and an outbound credit, accruing fees along the way. There is no automatic retry, and a payment cannot be cancelled once initiated. A return ends the payment either at `failed` or, when the payer has already been debited, at `refunding_payer` — see `status`. - `id` (string): unique payee payment id Example: `"pp_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee_payment"`. - `payer_account_id` (string): the id of the payer account this payment is scoped to Example: `"payer_123xyz"`. - `amount` (integer): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (e.g. `amount` 91000 with a 1000 fee pays the payee 90000). Example: `91000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `status` (string): the payment's position in its lifecycle. `initiated` → `inbound_submitted` → `holding` → `outbound_submitted` → `succeeded` is the happy path. **`holding` is a real wait.** Once the payer's funding has settled, the payee's credit is held until the next banking day before it is submitted, so a payment rests in `holding` rather than passing through it. Read `deposits_at` for when the payee is expected to be deposited; the hold is already in that estimate. **The hold only lifts for an active payer account and an active payee.** When the wait is up, the payee's credit is sent if both are `active`; if either is not, the payment stays in `holding` and is reconsidered periodically, so it pays out once both are active again. A hold that persists pushes the deposit past the `deposits_at` estimate, which is why that field is an estimate. Which return path a payment takes depends on whose money was already moved. A returned **inbound** debit-pull means nothing settled, so the payment is `failed` and no one is owed anything. A returned **outbound** credit means the payer was already debited, so the payment moves to `refunding_payer` and then `refunded` once the payer has their money back. Both `failed` and `refunded` are terminal. **`succeeded` is not the end.** ACH lets a return arrive days after an entry settled, so one can land after a payment has succeeded. That moves the payment to `failed_late_return`, which is terminal — JustiFi works the break by hand and records the corrective movement as a further leg on the same payment. See "A return that arrives after a payment succeeded" in the overview. **`failed_late_return` does not mean the payee holds nothing.** It reports that the payment did not stick, and the two ways that happens are opposites: a returned **outbound** credit means the payee never kept the money, while a returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — so the payee still has it. **Re-sending on this status can pay a payee twice.** Read the payment's `transfers` to see which leg returned before acting. One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`, `failed_late_return`. Example: `"succeeded"`. - `payment_type` (string): how the funds move. ACH is the only option. Named `payment_type` rather than `payment_method`, which in the JustiFi API denotes a stored instrument object, not a rail. One of: `ach`. Example: `"ach"`. - `payee_id` (string): the payee being paid Example: `"pe_abc123"`. - `funding_bank_account_id` (string): the account's funding bank account the principal is debit-pulled from Example: `"ba_fund456"`. - `receiving_bank_account_id` (string): the payee's receiving account the principal is credited to Example: `"ba_recv123"`. - `debits_at` (string (date-time), nullable): in UTC, the estimated date and time the payer's funding account is debited (from the inbound leg); null until scheduled. Normally three banking days after the payment is submitted. Example: `"2026-01-01T12:00:00Z"`. - `deposits_at` (string (date-time), nullable): in UTC, the estimated date and time the payee is deposited (from the outbound leg); null until scheduled. Each ACH leg takes three banking days and the payee's credit is held for one banking day after the payer's funding settles, so this is normally four banking days after `debits_at`. Estimated, and may shift if the provider revises an effective entry date. Example: `"2026-01-04T12:00:00Z"`. - `description` (string, nullable): Example: `"Invoice 4021"`. - `fees` (array of object): the fees charged on this payment (v2 fee convention), carved out of `amount`. Supplied in the create request (required, no default) and echoed here. Fees incurred later by NOCs or returns are not shown here — they are billed to the platform monthly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `transfers` (array of object): the ACH legs that make up this payment - `id` (string): unique transfer leg id Example: `"ptr_123"`. - `direction` (string): the direction of funds for this leg (a refund is an outbound, a recovery an inbound) One of: `inbound`, `outbound`. Example: `"inbound"`. - `purpose` (string): what this leg is — moves the principal, refunds the payer, or recovers owed funds from the payer One of: `principal`, `refund`, `recovery`. Example: `"principal"`. - `transfer_type` (string): how the money moved. `ach` — over the ACH network; `manual` — a movement JustiFi recorded off it. Widens to further rails (e.g. `rtp`) without a breaking change. One of: `ach`, `manual`. Example: `"ach"`. - `amount` (integer): the leg amount in cents Example: `50000`. - `status` (string): the state of this leg One of: `initiated`, `submitted`, `settled`, `returned`, `failed`. Example: `"settled"`. - `error_code` (string, nullable): normalised, rail-agnostic reason the leg failed, in snake_case (e.g. `insufficient_funds`). Stable across rails — **branch on this, not on `network_error_code`**, which is the network's own code and changes meaning between rails. Set when a leg is `failed` or `returned`, and null otherwise. A correction is not a failure: a leg that settled after a notification of change carries `network_error_code` but no `error_code`. A return code with no normalised equivalent reports `unclassified_return`, so this is never null on a leg that failed — the raw code is always there to fall back on. Example: `"insufficient_funds"`. - `error_description` (string, nullable): human-readable text for `error_code`, in English — for support and logs, not for branching. Null whenever `error_code` is. Example: `"Insufficient funds in the account"`. - `network_error_code` (string, nullable): the raw code from the network, verbatim — an ACH return code (`R01`). Preserved for reconciliation. Present whenever the network said anything about this leg, which is not only when it went wrong: a notification of change carries an advisory code (`C01`) on a leg that **settled** normally. Read it together with `status` — the code alone does not mean the money did not move. - `metadata` (object): any useful information you'd like to store alongside this payment - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-05T12:00:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # Platform Ledger Reference: https://docs.justifi.tech/api-spec#tag/Platform-Ledger The platform's single-entry ledger — one entry per fee the platform earned, per JustiFi fee (payment, return handling, NOC handling), or per `settlement` paying the platform its balance, each referencing its source. Read-only and append-only; the platform's balance is the **sum** of its entries, and a `settlement` nets it toward zero. ## List Platform Ledger Entries `GET https://api.justifi.ai/v1/payables/platform_ledger` Reference: https://docs.justifi.tech/api-spec#tag/Platform-Ledger/operation/PayablesListPlatformLedger List the platform's ledger entries — one per fee the platform earned, per JustiFi fee (payment, return handling, NOC handling), or per `settlement` paying the platform its balance, each referencing its source. Read-only and append-only; scoped to the platform your credentials belong to. The platform's outstanding balance is the **sum** of these entries; a `settlement` nets it toward zero. Optionally narrow to a window (`created_after`/`created_before`), a `txn_type`, or whether the entry has been settled (`settled`). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `created_after` | query | string (date-time) | no | filter records created after the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `created_before` | query | string (date-time) | no | filter records created before the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `txn_type` | query | string | no | filter entries by transaction type One of: `processing_fee`, `justifi_fee`, `return_fee`, `noc_fee`, `settlement`, `adjustment`. | | `settled` | query | boolean | no | `false` returns the outstanding entries — those no `settlement` has covered yet, which together sum to the platform's current balance. | ### Responses #### 200: Successfully listed platform ledger entries Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): Example: `"ple_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"ledger_entry"`. - `platform_account_id` (string): the platform ledger this entry posts to Example: `"acc_123xyz"`. - `txn_type` (string): the kind of entry. `settlement` is JustiFi squaring up with the platform — it closes the balance the other entries accrued, and its `settlement_id` names the entries it covers. `adjustment` is a correction: entries are never edited, so a correction to an already-settled entry posts as a new `adjustment` and is swept by the next settlement. Not to be confused with an ACH leg reaching `settled` — that is money clearing the network, and it is reported on the payment's legs rather than here. One of: `processing_fee`, `justifi_fee`, `return_fee`, `noc_fee`, `settlement`, `adjustment`. Example: `"justifi_fee"`. - `amount_cents` (integer): signed amount, in cents. Positive = owed to the platform; negative = charged to, or paid out to, the platform. On a `settlement`, whichever of those closes the set it covers. Example: `1000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `payer_account_id` (string, nullable): the payer account whose payment this entry derives from; set on fee entries, null on a `settlement` Example: `"payer_123xyz"`. - `payee_payment_id` (string, nullable): the payee payment this entry derives from, if any (payment / JustiFi fees) Example: `"pp_9"`. - `payee_payment_fee_id` (string, nullable): on a `processing_fee` entry — the submitted fee this entry was posted from. Links the platform's declared intent to the frozen ledger entry. - `source_type` (string, nullable): the kind of object that caused this entry, mirroring how balance transactions identify their source elsewhere in the JustiFi API. A return or NOC fee names the `transfer` it arose from. One of: `payee_payment`, `transfer`, `settlement`, `null`. Example: `"transfer"`. - `source_id` (string, nullable): the id of the object named by `source_type`. On a `settlement` this is the **platform settlement** (`pst_`) the entry was written for. Example: `"ptr_123"`. - `external_reference` (string, nullable): on a `settlement` — the external ACH/wire/manual reference for the money that moved. An identifier from outside Payables rather than a Payables id, which is why it is not folded into `source_id`. - `settlement_id` (string, nullable): the **platform settlement** (`pst_`) that covered this entry, if any — **null means the entry is still outstanding**. Every entry sharing a `settlement_id` sums to zero, so the ledger balance is exactly the sum of the entries where this is null. The `settlement` entry that balances a set carries the same value as the entries it closes, because it is one of them. Its `source_id` is that id too: a balancing entry both belongs to a settlement and is the entry written for it. Example: `"pst_987abc"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # Platform Settlements Reference: https://docs.justifi.tech/api-spec#tag/Platform-Settlements The disbursements between JustiFi and your platform — when each happens, how much, and which way the money goes. Read-only. A settlement is declared before it is paid, so one appears here while still `scheduled`, which is what the ledger by construction cannot show you. ## List Platform Settlements `GET https://api.justifi.ai/v1/payables/platform_settlements` Reference: https://docs.justifi.tech/api-spec#tag/Platform-Settlements/operation/PayablesListPlatformSettlements List the disbursements between JustiFi and your platform — when each happens, how much, which way the money goes, and the reference to reconcile it against your bank statement. Read-only and scoped to the platform your credentials belong to. This answers "when were we paid" directly. The same facts are derivable from `/v1/payables/platform_ledger` by filtering to `txn_type=settlement`, but a ledger entry is one line: it carries neither the reference nor what the disbursement covered, and it does not exist until after the money has moved. A settlement appears here while it is still `scheduled`. Optionally narrow to a `status` or a window (`created_after`/`created_before`). ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `after_cursor` | query | string | no | token to fetch the next page of a list (the `end_cursor` from a previous response's `page_info`) | | `before_cursor` | query | string | no | token to fetch the previous page of a list (the `start_cursor` from a previous response's `page_info`) | | `limit` | query | integer | no | the number of resources to retrieve per page (default 25, max 100) Default: `25`. | | `created_after` | query | string (date-time) | no | filter records created after the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `created_before` | query | string (date-time) | no | filter records created before the date and time (UTC) specified. Dates without a time default to 00:00:00 | | `status` | query | string | no | filter settlements by status One of: `scheduled`, `in_transit`, `paid`, `failed`, `canceled`, `forwarded`. | ### Responses #### 200: Successfully listed platform settlements Content type: `application/json` - `id` (null, required): always null for list responses — a list has no id of its own; the ids are on `data` - `type` (string, required): the object type Example: `"array"`. - `data` (array of object, required): the list of objects - `id` (string): unique settlement id Example: `"pst_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"platform_settlement"`. - `platform_account_id` (string): the platform this settlement is between JustiFi and Example: `"acc_123xyz"`. - `status` (string): where the disbursement is in its lifecycle. `scheduled` — the amount is frozen and the disbursement is queued to be paid; `in_transit` — instructed, with a reference attached, not yet confirmed; `paid` — the money moved; `failed` — it did not, and the balance it covered is owed again; `canceled` — withdrawn before it moved, same effect; `forwarded` — a later settlement took over what this one failed to pay. One of: `scheduled`, `in_transit`, `paid`, `failed`, `canceled`, `forwarded`. Example: `"paid"`. - `direction` (string): which way the money goes. `paid_out` — JustiFi pays your platform its accrued balance; `charged` — JustiFi collects, because the fees it levied over the period exceeded the ones your platform earned. Read this rather than a sign: `amount_cents` is always positive. One of: `paid_out`, `charged`. Example: `"paid_out"`. - `amount_cents` (integer): the amount of the disbursement, always positive — `direction` says which way it goes Example: `124500`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `entries_count` (integer): how many platform ledger entries this settlement covers, its own balancing entry included. To read the entries themselves, list `/v1/payables/platform_ledger` and match on `settlement_id`. Example: `42`. - `ledger_entry_id` (string): the `settlement` entry on your platform ledger that balances what this covers Example: `"ple_123xyz"`. - `external_reference` (string, nullable): the ACH, wire or manual reference for the money movement — what to match against your bank statement. Null until the disbursement is instructed. Example: `"WIRE-20260819-0042"`. - `scheduled_at` (string (date-time)): when the amount was frozen and the disbursement was queued Example: `"2026-08-19T12:00:00Z"`. - `recorded_at` (string (date-time), nullable): when the money moved; null until it has Example: `"2026-08-21T09:30:00Z"`. - `created_at` (string (date-time)): Example: `"2026-08-19T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-08-21T09:30:00Z"`. - `page_info` (object, required): cursor pagination info - `start_cursor` (string): the encoded id of the first record in the current page Example: `"WyIyMDIyLTAyLTA4IDIwOjAxOjU4LjEyMDIzMjAwMCIsIjU5ZTFjNGI1LWFlOWQtNDIyZC04MTVkLWNjNzQ5NzdlYmFjYSJd"`. - `end_cursor` (string): the encoded id of the last record in the current page Example: `"WyIyMDIyLTAyLTA4IDE5OjUyOjM3LjEwNDE3MzAwMCIsIjY4MDliYTU5LTYxYjctNDg3MS05YWFiLWE2Y2MyNmY3M2M1ZCJd"`. - `has_next` (boolean): true if there are records following the current page Default: `false`. - `has_previous` (boolean): true if there are records ahead of the current page Default: `false`. #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` ## Get a Platform Settlement `GET https://api.justifi.ai/v1/payables/platform_settlements/{id}` Reference: https://docs.justifi.tech/api-spec#tag/Platform-Settlements/operation/PayablesGetPlatformSettlement ### Parameters | Name | In | Type | Required | Description | | --- | --- | --- | --- | --- | | `Authorization` | header | string | yes | the `access_token` value returned from the JustiFi `oauth/token` endpoint (be sure to append `Bearer` before the token) | | `id` | path | string | yes | the id of the resource | ### Responses #### 200: Successfully retrieved the settlement Content type: `application/json` - `id` (string, required): the object id, also found in the data object Example: `"prefix_xyz (same as id of data object)"`. - `type` (string, required): the object type Example: `"platform_settlement"`. - `data` (object, required): One disbursement between JustiFi and your platform: when it happens, how much, which way the money goes, and the reference to reconcile it against your bank statement. A settlement is **declared and then recorded**. It is `scheduled` with a frozen amount before any money moves, and only reaches `paid` once it has. A scheduled settlement is a statement of intent, not a promise — `failed` and `canceled` can still take it away. - `id` (string): unique settlement id Example: `"pst_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"platform_settlement"`. - `platform_account_id` (string): the platform this settlement is between JustiFi and Example: `"acc_123xyz"`. - `status` (string): where the disbursement is in its lifecycle. `scheduled` — the amount is frozen and the disbursement is queued to be paid; `in_transit` — instructed, with a reference attached, not yet confirmed; `paid` — the money moved; `failed` — it did not, and the balance it covered is owed again; `canceled` — withdrawn before it moved, same effect; `forwarded` — a later settlement took over what this one failed to pay. One of: `scheduled`, `in_transit`, `paid`, `failed`, `canceled`, `forwarded`. Example: `"paid"`. - `direction` (string): which way the money goes. `paid_out` — JustiFi pays your platform its accrued balance; `charged` — JustiFi collects, because the fees it levied over the period exceeded the ones your platform earned. Read this rather than a sign: `amount_cents` is always positive. One of: `paid_out`, `charged`. Example: `"paid_out"`. - `amount_cents` (integer): the amount of the disbursement, always positive — `direction` says which way it goes Example: `124500`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `entries_count` (integer): how many platform ledger entries this settlement covers, its own balancing entry included. To read the entries themselves, list `/v1/payables/platform_ledger` and match on `settlement_id`. Example: `42`. - `ledger_entry_id` (string): the `settlement` entry on your platform ledger that balances what this covers Example: `"ple_123xyz"`. - `external_reference` (string, nullable): the ACH, wire or manual reference for the money movement — what to match against your bank statement. Null until the disbursement is instructed. Example: `"WIRE-20260819-0042"`. - `scheduled_at` (string (date-time)): when the amount was frozen and the disbursement was queued Example: `"2026-08-19T12:00:00Z"`. - `recorded_at` (string (date-time), nullable): when the money moved; null until it has Example: `"2026-08-21T09:30:00Z"`. - `created_at` (string (date-time)): Example: `"2026-08-19T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-08-21T09:30:00Z"`. - `page_info` (null, required): cursor pagination info; always null for single records #### 400: The request was malformed, failed validation, or referenced a resource that cannot be used in its current state — for example scheduling a payment to a payee that is not active, or creating anything under a payer account that is not active. When the failure is field-level, `error.details` carries one array of messages per rejected attribute. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "bad_request", "message": "payee pe_abc123 is archived and cannot be paid" } } ``` #### 401: The access token is missing, expired, or invalid. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authenticated", "message": "The access token provided is invalid or has expired" } } ``` #### 403: The credentials are valid but not permitted to access this resource. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "not_authorized", "message": "Your credentials do not have access to the requested payer account" } } ``` #### 404: No resource exists for the given id (within the scoped payer account). Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "resource_not_found", "message": "No payee_payment found with id pp_123xyz" } } ``` #### 429: The rate limit has been exceeded. Back off and retry after the interval indicated by the `Retry-After` header. Content type: `application/json` - `error` (object, required) - `code` (string, required): a stable, machine-readable error code Example: `"unprocessable_entity"`. - `message` (string, required): a human-readable description of what went wrong Example: `"payee_id is required"`. - `details` (object): optional field-level detail, keyed by request attribute ```json { "error": { "code": "too_many_requests", "message": "Rate limit exceeded" } } ``` --- # JustiFi Web Components Reference: https://docs.justifi.tech/api-spec#tag/JustiFi-Web-Components JustiFi Web Components offer an expanding collection of components that can be used in virtually any application, no matter the tech stack. They can be installed using NPM, or included via CDN using a script tag. To learn more, see the documentation in [our public GitHub repositiory](https://github.com/justifi-tech/web-component-library#documentation). --- # JustiFi SDK Reference: https://docs.justifi.tech/api-spec#tag/JustiFi-SDK We offer support for using our API via a Ruby SDK and a Node SDK. The projects are open source and available on Github. You can view full documentation on usage there. As more languages are supported, they will be added to this list: - [JustiFi Ruby SDK](https://github.com/justifi-tech/justifi-ruby) - [JustiFi Node SDK](https://github.com/justifi-tech/justifi-node) - [JustiFi Mobile SDK](https://github.com/justifi-tech/justifi-react-native-sdk) --- # Events Reference: https://docs.justifi.tech/api-spec#tag/Events Our event publishing system allows you to subscribe to certain events on the JustiFi platform. Once subscribed, your application will be notified anytime those events occur, so you can react accordingly in real time. You can receive events via webhooks. See the [Webhook Delivery section](https://docs.justifi.tech/api-spec#tag/Webhook-Delivery) for more details. We will publish the following events: - payment.created - payment.succeeded - payment.failed - payment.pending - payment.authorized - payment.captured - payment.canceled - payment.refunded - payment.refund.updated - payment.dispute.created - payment.dispute.closed - payment_method.created - payment_method.updated - payment_method.bin_mapped - payment_method.card_present_payment_method_imported - payment_intent.attached - payment_intent.created - payment_intent.requires_capture - payment_intent.succeeded - payout.bank_account.activated - payout.created - payout.paid - payout.failed - proceeds.payout.created - sub_account.updated - application_fee_rate.created - application_fee_rate.updated - entity.business.created - entity.business.updated - entity.identity.created - entity.identity.updated - entity.address.created - entity.address.updated - entity.document.created - entity.document.uploaded - entity.bank_account.created - checkout.created - checkout.completed - checkout.completion.succeeded - checkout.completion.failed - account.payment_setting.updated - account.payout_setting.updated - terminal_order.created - terminal_order.updated ## Payments Webhook event `payments`: JustiFi sends `POST` to your webhook URL. Received for the following events: payment.created, payment.succeeded, payment.failed, payment.pending, payment.authorized, payment.captured, payment.canceled ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (one of `CardPayment` | `BankAccountPayment`): the attributes for the object - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ```json { "id": "evt_123xyz", "account_id": "acc_123xyz", "account_type": "test", "platform_account_id": "acc_987zyx", "idempotency_key": "string", "request_id": "req_123", "version": "v1", "data": { "id": "py_xyz", "account_id": "acc_123xyz", "amount_disputed": 0, "amount_refunded": 0, "amount_returned": 0, "amount": 10000, "amount_refundable": 10000, "application_fee_rate_id": "afr_123xyz", "balance": 99850, "capture_strategy": "automatic", "captured": true, "created_at": "2021-01-01T12:00:00Z", "currency": "usd", "description": "my order xyz", "disputed": false, "error_code": null, "error_description": null, "fee_amount": 150, "financial_transaction_id": "ft_123xyz", "is_test": true, "metadata": {}, "payment_intent_id": "pi_xyz", "refunded": false, "returned": false, "status": "succeeded", "terminal_id": "trm_123_xyz", "updated_at": "2021-01-01T12:00:00Z", "payment_method": { "card": { "id": "pm_123xyz", "acct_last_four": "4242", "brand": "visa", "name": "Sylvia Fowles", "token": "pm_123xyz", "metadata": {}, "bin_details": { "type": "Debit", "card_brand": "Visa", "card_class": "Consumer", "country": "United States of America", "issuer": "WELLS FARGO BANK", "funding_source": "Debit" }, "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "customer_id": null, "signature": "123abc" }, "application_fee": { "id": "fee_123xyz", "amount": 150, "currency": "usd", "created_at": "2021-01-01T12:00:00Z", "updated_at": "2021-01-01T12:00:00Z" }, "transaction_hold": { "id": "th_123xyz", "financial_transaction_id": "ft_123xyz" }, "refunds": [], "disputes": [] }, "event_name": "payment.created" } ``` ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Payment Methods Webhook event `payment_methods`: JustiFi sends `POST` to your webhook URL. Received for the following events: payment_method.created, payment_method.updated, payment_method.bin_mapped ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique id of the payment method Example: `"pm_123xyz"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ```json { "id": "evt_123xyz", "account_id": "acc_123xyz", "account_type": "test", "platform_account_id": "acc_456abc", "idempotency_key": "30abie390hjag49h", "request_id": "req_100abc", "version": "v1", "data": { "id": "pm_123xyz", "signature": "9fxy123", "customer_id": "cust_987zyx", "status": "valid", "invalid_reason": "nil", "card": { "id": "pm_123xyz", "name": "Sylvia Fowles", "acct_last_four": "4242", "brand": "visa", "token": "pm_123xyz", "month": "5", "year": "2042", "metadata": {}, "address_line1_check": "pass", "address_postal_code_check": "pass" } }, "event_name": "payment_method.created" } ``` ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Refunds Webhook event `refunds`: JustiFi sends `POST` to your webhook URL. Received for the following events: payment.refunded, payment.refund.updated ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): refund unique id Example: `"re_xyz"`. - `payment_id` (string (uuid)): the payment for which this refund is being issued Example: `"py_xyz"`. - `amount` (number): the amount of this refund in cents Example: `100`. - `description` (string): an optional note about this refund Example: `"customer canceled their order"`. - `reason` (string): the reason this refund is being issued One of: `duplicate`, `fraudulent`, `customer_request`. Example: `"duplicate"`. - `status` (string): the status of this refund One of: `pending`, `succeeded`, `failed`. Example: `"succeeded"`. - `metadata` (object (json)): any useful information you'd like to store alongside this refund - `returned_fees` (array of `ReturnedFeeResponse`): Array of returned fee objects showing the fees returned to the merchant with this refund. Present when fees were specified in the refund request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Disputes Webhook event `disputes`: JustiFi sends `POST` to your webhook URL. Received for the following events: payment.dispute.created, payment.dispute.closed, payment.dispute.forfeited, payment.dispute.submitted ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique dispute id Example: `"dp_xyz"`. - `payment_id` (string (uuid)): the disputed payment Example: `"py_xyz"`. - `account_id` (string (uuid)): id of the account associated with the dispute Example: `"acc_xyz"`. - `amount` (number): amount disputed in cents Example: `100`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `reason` (string): the reason this payment was disputed Example: `"fraudulent"`. - `due_date` (string (date)): due date for evidence submission to counter the dispute Example: `"2025-02-23"`. - `status` (string): status of the dispute One of: `needs_response`, `under_review`, `won`, `lost`. Example: `"won"`. - `metadata` (object (json)): any useful information you'd like to store alongside this dispute - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `dispute_response` (object) - `additional_statement` (string): any additional evidence or statements - `cancellation_policy_disclosure` (string): an explanation of how and when the customer was shown your cancellation policy prior to purchase - `cancellation_rebuttal` (string): a justification for why the customer’s subscription was not canceled - `customer_billing_address` (string): the billing address provided by the customer - `customer_email_address` (string): the email address of the customer - `customer_name` (string): the name of the customer - `customer_purchase_ip_address` (string): the IP address that the customer used when making the purchase - `duplicate_charge_explanation` (string): an explanation of the difference between the disputed charge versus the prior charge that appears to be a duplicate - `product_description` (string): a description of the product or service that was sold - `refund_policy_disclosure` (string): documentation demonstrating that the customer was shown your refund policy prior to purchase - `refund_refusal_explanation` (string): justification for why the customer is not entitled to a refund - `service_date` (string): the date on which the customer received or began receiving the purchased service Example: `"2024-10-31"`. - `shipping_address` (string): the address to which a physical product was shipped - `shipping_carrier` (string): the delivery service that shipped a physical product, such as Fedex, UPS, USPS, etc. If multiple carriers were used for this purchase, please separate them with commas - `shipping_date` (string): the date on which a physical product began its route to the shipping address Example: `"2024-10-31"`. - `shipping_tracking_number` (string): the tracking number for a physical product. If multiple tracking numbers were generated for this purchase, please separate them with commas - `duplicate_charge_original_payment_id` (string): the payment id for the prior charge which appears to be a duplicate of the disputed charge - `dispute_reversal` (object, nullable): present when dispute gets reversed from lost to won - `description` (string): Example: `"Dispute was reversed"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Dispute Evidence Webhook event `dispute_evidence`: JustiFi sends `POST` to your webhook URL. Received for the following events: payment.dispute_evidence.created, payment.dispute_evidence.uploaded ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique dispute evidence id Example: `"dpe_xyz"`. - `file_name` (string): dispute evidence file name Example: `"receipt.pdf"`. - `file_type` (string): dispute evidence file type One of: `image/jpeg`, `image/png`, `application/pdf`, `application/zip`, `application/x-zip-compressed`. Example: `"application/pdf"`. - `dispute_evidence_type` (string): dispute evidence type matching the file that will be uploaded One of: `cancellation_policy`, `customer_communication`, `customer_signature`, `duplicate_charge_documentation`, `receipt`, `refund_policy`, `service_documentation`, `shipping_documentation`, `uncategorized_file`. Example: `"receipt"`. - `status` (string): dispute evidence status One of: `pending`, `uploaded`. - `description` (string): description of the dispute evidence file that will be uploaded - `presigned_url` (string): url that should be used to submit a put request to upload the evidence file - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Payouts Webhook event `payouts`: JustiFi sends `POST` to your webhook URL. Received for the following events: payout.created, payout.paid, payout.failed, proceeds.payout.created ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique payout id Example: `"po_xyz"`. - `account_id` (string (uuid)): id of the account associated with the payout - `amount` (number): payout amount in cents Example: `100000`. - `bank_account` (`PayoutBankAccount`) - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `delivery_method` (string): how the payout is delivered One of: `standard`. - `description` (string, nullable) - `deposits_at` (string (date-time)): in UTC, the estimated date and time of the payout deposit (or in rare cases, withdrawal) Example: `"2021-01-01T12:00:00Z"`. - `fees_total` (number): sum of fees in the payout, in cents Example: `5000`. - `refunds_count` (number): number of refunds in the payout Example: `5`. - `refunds_total` (number): sum of refunds in the payout, in cents Example: `10000`. - `payments_count` (number): number of payments in the payout Example: `50`. - `payments_total` (number): sum of payments in the payout, in cents Example: `110000`. - `payout_type` (string): type of payment method used for the payments in the payout (funds from different types of payment methods settle at different intervals; in order to pay out your funds ASAP, we batch separate payouts for each payment method type) One of: `ach cc`. - `other_total` (number): sum of other less common transactions in the payout, in cents Example: `100`. - `platform_fees_total` (number, nullable): gross fees your platform charged its sub accounts in a proceeds payout, in cents, null for sub account payouts - `justifi_fees_total` (number, nullable): processing fees JustiFi charged your platform in a proceeds payout, in cents, always positive, null for sub account payouts - `interchange_network_fees` (number, nullable): interchange and card network fees passed through to your platform in a proceeds payout, in cents, usually negative, null for sub account payouts - `status` (string): status of the payout One of: `paid failed forwarded scheduled in_transit canceled`. Example: `"paid"`. - `settlement_priority` (string): settlement priority of the payout, either standard or expedited. One of: `standard expedited`. Example: `"standard"`. - `metadata` (object (json)): any useful information you'd like to store alongside this payout - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Sub Accounts Webhook event `sub_accounts`: JustiFi sends `POST` to your webhook URL. Received for the following events: sub_account.updated. This is published when an account's status changes. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string (uuid)): sub account id Example: `"acc_xyz"`. - `name` (string): sub account name Example: `"The Shire Haberdashery"`. - `account_type` (string): sub account type (live or test) Example: `"live"`. - `status` (string): sub account status One of: `created`, `submitted`, `information_needed`, `rejected`, `enabled`, `disabled`, `archived`. Example: `"enabled"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `platform_account_id` (string (uuid)): id of associated platform account Example: `"acc_xyz"`. - `payout_account_id` (string (uuid)): id of active payout bank account Example: `"ba_xyz"`. - `business_id` (string (uuid)): id of associated business Example: `"biz_xyz"`. - `application_fee_rates` (array): list of associated application fee rates - `processing_ready` (boolean): sub account ready for processing Example: `false`. - `payout_ready` (boolean): sub account ready for payouts Example: `false`. - `related_accounts` (object): when a live sub account is created, a related test account is automatically created; this provides both ids - `live_account_id` (string (uuid)): live sub account id (this will be nil if a sub account was created with test credentials) Example: `"acc_xyz"`. - `test_account_id` (string (uuid)): test sub account id Example: `"acc_xyz"`. - `payments_activated_on` (string (date-time), nullable): date and time when the first successful payment was processed on this sub account Example: `"2021-01-15T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Application Fee Rates Webhook event `application_fee_rates`: JustiFi sends `POST` to your webhook URL. Received for the following events: application_fee_rate.created, application_fee_rate.updated ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique application fee rate id Example: `"afr_123xyz"`. - `transaction_fee` (number): transaction fee amount, in cents Example: `50`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `basis_point_rate` (number): variable percentage of the payment amount that, combined with transaction fee, will be charged as the application fee. Expressed as the number of basis points Example: `250`. - `rate_type` (string): One of: `cc`, `ach`. Example: `"cc"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `effective_start` (string (date-time)): date and time (UTC) application fee rate went into effect Example: `"2021-01-01T12:00:00Z"`. - `effective_end` (string (date-time)): date and time (UTC) application fee rate is effectively archived. If null, no end date is currently assigned and application fee rate is currently effective Example: `"2021-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Checkouts Webhook event `checkouts`: JustiFi sends `POST` to your webhook URL. Received for the following events: checkout.created, checkout.completed ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Checkout Completions Webhook event `checkout_completions`: JustiFi sends `POST` to your webhook URL. Received for the following events: checkout.completion.succeeded, checkout.completion.failed, and checkout.completion.processing. Note checkout.completion.processing is only sent for terminal payments when a payment amount is sent to a terminal for processing. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique checkout completion id Example: `"chc_xyz"`. - `payment_mode` (string): One of: `ecom`, `bnpl`, `card_present`. Example: `"ecom"`. - `payment_token` (string): the payment method token used to process the payment, only for ecom payments Example: `"pm_xyz123"`. - `status` (string): the status of the completion, only succeeded or failed One of: `succeeded`, `failed`, `processing`. Example: `"succeeded"`. - `payment_status` (string): depending upon payment mode, the status of the payment API call, bnpl transaction, or card reader transaction. One of: `succeeded`, `failed`, `pending`, `canceled`, `skipped`. Example: `"succeeded"`. - `payment_error_code` (string): when payment fails, related error code Example: `"card_declined"`. - `payment_error_description` (string): when payment fails, related error description Example: `"Your card was declined"`. - `payment_response` (object) - `id` (string): unique payment id, same as id in data object Example: `"py_xyz"`. - `type` (string): the object type Example: `"payment"`. - `data` (`CardPayment`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records - `checkout_id` (string (uuid)): id of the checkout for this completion Example: `"cho_xyz123"`. - `additional_transactions` (array of objects): legacy attribute, other transactions processed during checkout completion. For example, insurance payments - `checkout` (`Checkout`) - `payment_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"py_xyz123"`. - `payment_method_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"pm_xyz123"`. - `terminal_id` (string (uuid)): id of the terminal used for this checkout, when mode is card present Example: `"trm_xyz123"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Account Payment Setting Updated Webhook event `payment_setting_updated`: JustiFi sends `POST` to your webhook URL. Received for the following event: account.payment_setting.updated ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique payment setting id Example: `"stpy_123abc"`. - `account_id` (string): unique id of the associated account Example: `"acc_123abc"`. - `mcc_code` (string): merchant category code configured Example: `"5045"`. - `credit_card_payments` (boolean): credit card payments enabled for processing Example: `true`. - `ach_payments` (boolean): ach payments enabled for processing Example: `true`. - `card_present` (boolean): card present feature enabled for processing Example: `false`. - `bnpl_payments` (boolean): buy now pay later feature enabled Example: `false`. - `insurance_payments` (boolean): insurance feature enabled Example: `false`. - `platform_wallet_account` (boolean): wether this account is configured as platform_wallet_account Example: `false`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Account Payout Setting Updated Webhook event `payout_setting_updated`: JustiFi sends `POST` to your webhook URL. Received for the following event: account.payout_setting.updated ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `public_id` (string): unique payout setting id Example: `"stpo_213abc"`. - `account_id` (string): unique id of the associated account Example: `"acc_123abc"`. - `enabled` (boolean): whether the payout setting is currently enabled Example: `true`. - `interval` (string): payout frequency Example: `"daily"`. - `statement_descriptor` (string): custom text to appear on bank statements Example: `"Name of Account"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Terminal Orders Webhook event `terminal_orders`: JustiFi sends `POST` to your webhook URL. Received for the following events: terminal_order.created, terminal_order.updated ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique terminal order id Example: `"tord_xyz"`. - `business_id` (string (uuid)): Example: `"biz_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `order_type` (string): One of: `boarding_only`, `boarding_shipping`. Example: `"boarding_only"`. - `order_status` (string): status of the order One of: `created`, `submitted`, `in_progress`, `completed`, `on_hold`, `canceled`. - `company_name` (string): business legal name when the terminal order was created Example: `"Business Name"`. - `mcc` (string): Merchant Category Code Example: `7998`. - `receiver_name` (string): name of the person receiving the terminal Example: `"John Doe"`. - `contact_first_name` (string): company's representative first name Example: `"John"`. - `contact_last_name` (string): company's representative last name Example: `"Doe"`. - `contact_email` (string): company's contact email Example: `"john.doe@example.com"`. - `contact_phone_number` (string): company's contact phone number Example: `2125554567`. - `line1` (string): Example: `"123 Main St"`. - `line2` (string): Example: `"Apt 4B"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): Example: `"MN"`. - `postal_code` (string): Example: `55401`. - `time_zone` (string): determined by postal code Example: `"US/Central"`. - `country` (string): Example: `"USA"`. - `shipping_tracking_reference` (string): FedEx tracking number associated with the terminal order shipment. This field is populated only when the terminal order status is completed and the order includes a physical shipment. Always null for boarding_only terminal orders, as no shipment occurs. Example: `12345678`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `terminals` (array of object): list of ordered terminals - `terminal_id` (string (uuid)): unique terminal id Example: `"tmn_abc"`. - `terminal_did` (string): terminal device identification Example: `"12345678"`. - `model_name` (string): One of: `V400m`, `P400`, `E285`. Example: `"V400m"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Reports Webhook event `reports`: JustiFi sends `POST` to your webhook URL. Received for the following events: report.scheduled, report.processing, report.completed, report.failed, report.canceled ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): report unique id Example: `"rpt_xyz"`. - `report_type` (`ReportType`): which report was generated One of: `proceeds`, `payout`, `interchange_fee`, `sub_account_summary`, `payment_list`. Example: `"proceeds"`. - `nickname` (string, nullable): the report nickname Example: `"My Report"`. - `status` (string): the report status One of: `scheduled`, `processing`, `completed`, `failed`, `canceled`, `expired`. Example: `"scheduled"`. - `scheduled_at` (string (date)): when the report was scheduled Example: `"2025-12-25T14:44:45.026Z"`. - `run_at` (string (date)): when the report started processing Example: `"2025-12-30T14:44:45.026Z"`. - `created_at` (string (date)): when the report was created Example: `"2025-12-31T14:44:45.026Z"`. - `error_description` (string): error description in case of errors - `account_id` (string): the account id the report was created for Example: `"acc_xyz"`. - `presigned_url` (string (url)): the url to download the report when completed - `platform_account_id` (string): the platform account id the report was created for Example: `"acc_xyz"`. - `parameters` (`ReportParameters`) - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Forwarding Requests (Beta) Webhook event `forwarding_requests`: JustiFi sends `POST` to your webhook URL. Received for the following events: forwarding_request.completed, forwarding_request.failed `forwarding_request.completed` means the destination answered. Check `data.response.status_code` to see whether the request was accepted. `forwarding_request.failed` means the destination could not be reached, and `data.failure_reason` explains why. Forwarding requests are attempted once and are not retried, so exactly one of these two events is published per forwarding request. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `idempotency_key` (string, nullable): idempotency key for request, when available - `request_id` (string, nullable): id for request, when available - `account_id` (string): sub account id for event Example: `"acc_123xyz"`. - `account_type` (string): live or test account Example: `"test"`. - `platform_account_id` (string, nullable): platform account id for event, when available Example: `"acc_123xyz"`. - `data` (object): the attributes for the object - `id` (string): unique id of the forwarding request Example: `"fwd_123xyz"`. - `account_id` (string, nullable): the sub account that owns the payment method the request was created from Example: `"acc_123xyz"`. - `payment_method_id` (string, nullable): the payment method whose card details are substituted into the request body Example: `"pm_123xyz"`. - `url` (string): the allow-listed destination the request is sent to Example: `"https://api.stripe.com/v1/payment_methods"`. - `http_method` (string): the HTTP method used to reach the destination, determined by the destination itself One of: `POST`. Example: `"POST"`. - `provider` (string): the destination provider, determined by the destination itself One of: `stripe`. Example: `"stripe"`. - `status` (string): `pending` — accepted and queued, nothing has been sent yet; `processing` — the request is being sent and the outcome is not known yet; `completed` — the destination answered, see `data.response.status_code` for the outcome; `failed` — the destination could not be reached, see `failure_reason`. One of: `pending`, `processing`, `completed`, `failed`. Example: `"completed"`. - `failure_reason` (string, nullable): why the destination could not be reached, `null` unless `status` is `failed`. `timeout` — the destination did not answer in time; `connection_error` — the connection or TLS handshake failed; `internal_error` — JustiFi failed to send the request. One of: `timeout`, `connection_error`, `internal_error`. Example: `"timeout"`. - `replacements` (array of string): the card tags JustiFi found in the request body and substituted before sending - `request` (object): what was sent to the destination, masked - `body` (object, nullable): the request body as it was sent, with card details masked. The card number renders as its last four digits; the expiration date and cardholder name render in the clear. - `headers` (object): the headers as they were sent, with every value replaced by `[FILTERED]`. Header names are kept so you can confirm what was relayed; values are never stored in readable form. - `response` (object, nullable): the destination's response, `null` until the destination has answered - `id` (string): unique id of the forwarding response Example: `"fwdr_123xyz"`. - `status_code` (integer): the HTTP status code the destination answered with Example: `200`. - `body` (any, nullable): the response body, scrubbed of anything that looks like a card number - `headers` (any, nullable): the response headers, scrubbed of anything that looks like a card number - `response_time_ms` (integer, nullable): how long the destination took to answer, in milliseconds Example: `512`. - `attempted_at` (string (date-time), nullable): when JustiFi started sending the request (in UTC), `null` while the request is still queued Example: `"2024-01-01T12:00:01Z"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:02Z"`. - `version` (string): version of the event payload Example: `"v1"`. - `event_name` (string): name of the event (payment.succeeded, sub_account.updated, etc.) Example: `"payment.succeeded"`. ```json { "id": "evt_123xyz", "account_id": "acc_123xyz", "account_type": "test", "platform_account_id": "acc_456abc", "idempotency_key": "30abie390hjag49h", "request_id": "req_100abc", "version": "v1", "data": { "id": "fwd_123xyz", "account_id": "acc_123xyz", "payment_method_id": "pm_123xyz", "url": "https://api.stripe.com/v1/payment_methods", "http_method": "POST", "provider": "stripe", "status": "completed", "failure_reason": null, "replacements": [ "card_number", "card_expiry_month", "card_expiry_year", "cardholder_name" ], "request": { "body": { "type": "card", "card": { "number": "4242", "exp_month": 5, "exp_year": 2042 }, "billing_details": { "name": "Lindsay Whalen" } }, "headers": { "Authorization": "[FILTERED]" } }, "response": { "id": "fwdr_123xyz", "status_code": 200, "body": { "id": "pm_1QabcStripeExample", "object": "payment_method", "card": { "last4": "4242" } }, "headers": { "content-type": "application/json" }, "response_time_ms": 512 }, "attempted_at": "2024-01-01T12:00:01Z", "created_at": "2024-01-01T12:00:00Z", "updated_at": "2024-01-01T12:00:02Z" }, "event_name": "forwarding_request.completed" } ``` ### Responses #### 200: Return a 200 status to indicate that the data was received successfully. You must respond within 5 seconds. ## Schemas ### CardPayment - `id` (string): unique payment id Example: `"py_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): payment amount in cents Example: `10000`. - `amount_disputed` (number): sum of open or lost disputes for this payment, in cents Example: `0`. - `amount_refunded` (number): sum of refunds for this payment, in cents Example: `0`. - `amount_refundable` (number): amount of this payment currently able to be refunded, in cents Example: `10000`. - `balance` (number): sum of debits and credits for this payment, in cents (reflects the amount this account has earned from this payment). Compiled and calculated value, eventually consistent. To see all changes affecting the payment's balance call [Get Balance Transactions](#operation/GetPaymentBalanceTransactions) Example: `99850`. - `fee_amount` (number): sum of fees for this payment Example: `150`. - `financial_transaction_id` (string): associated financial transaction id Example: `"ft_123xyz"`. - `captured` (boolean): whether or not this payment is captured Example: `true`. - `capture_strategy` (string): One of: `automatic`, `manual`. Example: `"automatic"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my_order_xyz"`. - `disputed` (boolean): whether or not this payment has any open or lost disputes Example: `false`. - `disputes` (array): list of associated disputes - `error_code` (string): error code if the payment fails Example: `"credit_card_number_invalid"`. - `error_description` (string): text description of the error code Example: `"Credit Card Number Invalid (Failed LUHN checksum)"`. - `is_test` (boolean): whether or not this payment was made using the test account Example: `true`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment - `payment_intent_id` (string): unique id of associated payment intent Example: `"pi_123xyz"`. - `checkout_id` (string): unique id of associated checkout Example: `"cho_123xyz"`. - `payment_method` (`CardPaymentMethod`) - `application_fee` (`ApplicationFee`) - `application_fee_rate_id` (string): unique id of application fee rate applied to this payment, if any Example: `"afr_123xyz"`. - `fees` (array of `FeeResponse`): Array of fee objects showing the fees charged on this payment with their remaining refundable amounts. Populated whether the fees were provided via the `fees` array in the payment request or calculated automatically (for example, from a Standard Fee Configuration, or the `processing_fee` on a CAD payment). **Note:** This array is empty in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects (with `id`, `remaining_amount`, and `currency`), or poll with a subsequent Get Payment request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `refunded` (boolean): whether or not this payment has any refunds Example: `false`. - `status` (string): status of the payment One of: `pending`, `authorized`, `canceled`, `succeeded`, `failed`, `partially_refunded`, `fully_refunded`, `disputed`. - `payment_mode` (string): One of: `ecom`, `ach`, `card_present`. Example: `"ecom"`. - `terminal_id` (string): id of terminal used to process the card payment, if any Example: `"trm_123xyz"`. - `transaction_hold` (object) - `id` (string): unique transaction hold id Example: `"th_123xyz"`. - `financial_transaction_id` (string (uuid)): financial transaction id the transaction hold is associated to Example: `"ft_123xyz"`. - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### BankAccountPayment - `id` (string): unique payment id Example: `"py_xyz"`. - `account_id` (string (uuid)): Example: `"acc_xyz"`. - `amount` (number): payment amount in cents Example: `10000`. - `amount_disputed` (number): sum of open or lost disputes for this payment, in cents Example: `0`. - `amount_refunded` (number): sum of refunds for this payment, in cents Example: `0`. - `amount_refundable` (number): amount of this payment currently able to be refunded, in cents Example: `10000`. - `amount_returned` (number): amount of this payment reversed by an ACH return, in cents. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns) Example: `0`. - `balance` (number): Sum of debits and credits for this payment, in cents (reflects the amount this account has earned from this payment). Compiled and calculated value, eventually consistent. To see all changes affecting the payment's balance see [Get Payment Balance Transactions](#operation/GetPaymentBalanceTransactions). When an ACH payment is returned, the payment amount and its original fees are both reversed, so any remaining negative `balance` is the ACH return fee. Example: `99850`. - `fee_amount` (number): Sum of fees for this payment. Payments using an application fee include the ACH return fee here once the payment is returned; payments using [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) do not. Either way the return fee is recorded as a balance transaction. See [ACH Returns](https://docs.justifi.tech/paymentMethods/achReturns). Example: `150`. - `financial_transaction_id` (string): associated financial transaction id Example: `"ft_123xyz"`. - `captured` (boolean): whether or not this payment is captured Example: `true`. - `capture_strategy` (string): One of: `automatic`, `manual`. Example: `"automatic"`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my_order_xyz"`. - `disputed` (boolean): whether or not this payment has any open or lost disputes Example: `false`. - `disputes` (array): list of associated disputes - `error_code` (string): error code if the payment fails Example: `"credit_card_number_invalid"`. - `error_description` (string): text description of the error code Example: `"Credit Card Number Invalid (Failed LUHN checksum)"`. - `is_test` (boolean): whether or not this payment was made using the test account Example: `true`. - `metadata` (object (json)): any useful information you'd like to store alongside this payment - `payment_intent_id` (string): unique id of associated payment intent Example: `"pi_123xyz"`. - `checkout_id` (string): unique id of associated checkout Example: `"cho_123"`. - `payment_method` (`BankAccountPaymentMethod`) - `application_fee` (`ApplicationFee`) - `application_fee_rate_id` (string): unique id of application fee rate applied to this payment, if any Example: `"afr_123xyz"`. - `fees` (array of `FeeResponse`): Array of fee objects showing the fees charged on this payment with their remaining refundable amounts. Populated whether the fees were provided via the `fees` array in the payment request or calculated automatically (for example, from a Standard Fee Configuration). **Note:** This array is empty in the Create Payment response. Fees are processed asynchronously — subscribe to payment webhook events (recommended) to receive the full fee objects (with `id`, `remaining_amount`, and `currency`), or poll with a subsequent Get Payment request. See [Enhanced Fee Management](https://docs.justifi.tech/api-spec#section/Enhanced-Fee-Management) for full documentation. - `refunded` (boolean): whether or not this payment has any refunds Example: `false`. - `returned` (boolean): whether or not this payment was reversed by an ACH return Example: `false`. - `status` (string): status of the payment One of: `pending`, `authorized`, `canceled`, `succeeded`, `failed`, `partially_refunded`, `fully_refunded`, `disputed`. - `payment_mode` (string): One of: `ecom`, `ach`, `card_present`. Example: `"ecom"`. - `terminal_id` (string): id of terminal used to process a card payment, null for bank account payments Example: `"trm_123xyz"`. - `transaction_hold` (object) - `id` (string): unique transaction hold id Example: `"th_123xyz"`. - `financial_transaction_id` (string (uuid)): financial transaction id the transaction hold is associated to Example: `"ft_123xyz"`. - `expedited` (boolean, nullable): settlement priority of the payment, only applies to ACH payments Example: `true`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### ReturnedFeeResponse A returned fee object showing fee details returned to the merchant with a refund - `id` (string, required): Unique identifier for this returned fee Example: `"rtfee_xyz"`. - `payment_fee_id` (string, required): Unique identifier for the original payment fee that was partially or fully returned Example: `"pyfee_abc"`. - `type` (string, required): The type of fee that was returned: - `processing_fee`: Processing fee returned to merchant - `platform_fee`: Platform fee returned to merchant One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `returned_amount` (integer, required): Amount returned to the merchant in cents Example: `175`. - `original_amount` (integer, required): Original fee amount in cents from the payment Example: `350`. - `currency` (string, required): Currency of the fee amounts Example: `"usd"`. - `remaining_amount` (integer, required): Amount still available for refund on the original payment fee in cents Example: `175`. ### PayoutBankAccount - `id` (string (uuid)): unique bank account id - `full_name` (string): account holder's full name - `bank_name` (string): name of bank - `account_number_last4` (string): last 4 digits of the account number Example: `1111`. - `routing_number` (string) - `country` (string): One of: `US`, `CA`. Example: `"US"`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `nickname` (string) - `account_type` (string): One of: `checking`. ### Fee A fee object specifying type and amount - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services One of: `processing_fee`, `platform_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. ### CheckoutCompletionAttempt - `id` (string): unique checkout completion id Example: `"chc_xyz123"`. - `payment_mode` (string): One of: `ecom`, `bnpl`, `card_present`. Example: `"ecom"`. - `payment_token` (string): the payment method token used to process the payment, only for ecom payments Example: `"pm_xyz123"`. - `status` (string): the status of the completion, only succeeded or failed One of: `succeeded`, `failed`, `processing`. Example: `"succeeded"`. - `payment_status` (string): depending upon payment mode, the status of the payment API call, bnpl transaction, or card reader transaction. One of: `succeeded`, `failed`, `pending`, `canceled`, `skipped`. Example: `"succeeded"`. - `payment_error_code` (string): when payment fails, related error code Example: `"card_declined"`. - `payment_error_description` (string): when payment fails, related error description Example: `"Your card was declined"`. - `payment_response` (object) - `id` (string): unique payment id, same as id in data object Example: `"py_xyz"`. - `type` (string): the object type Example: `"payment"`. - `data` (`CardPayment`) - `page_info` (any, nullable): information for cursor style pagination, is null for single records - `checkout_id` (string (uuid)): id of the checkout for this completion Example: `"cho_xyz123"`. - `additional_transactions` (array of objects): legacy attribute, any other transactions processed during checkout completion. For example, insurance payments - `payment_id` (string (uuid)): id of the payment associated with this checkout, when successful Example: `"py_xyz123"`. - `payment_method_id` (string (uuid)): id of the payment method associated with this checkout, when successful Example: `"pm_xyz123"`. - `terminal_id` (string (uuid)): id of the terminal used for this checkout, when mode is card present Example: `"trm_xyz123"`. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. ### Checkout - `id` (string (uuid)): unique checkout id Example: `"cho_xyz"`. - `account_id` (string (uuid)): id of the account associated with the checkout Example: `"acc_xyz"`. - `platform_account_id` (string (uuid)): id of the platform account associated with the checkout Example: `"acc_xyz"`. - `payment_intent_id` (string (uuid)): id of the payment intent associated with the checkout Example: `"pi_xyz"`. - `payment_amount` (number): the amount charged in cents Example: `10000`. - `payment_currency` (string): One of: `USD`, `CAD`. Example: `"USD"`. - `payment_description` (string): your custom description of the payment if passed in the `payment` property during checkout creation, otherwise "Checkout [checkout id]" Example: `"my order xyz"`. - `payment_methods` (array): if `payment_method_group_id` was provided, list of payment methods contained in that payment method group - `payment_method_group_id` (string (uuid)): id of payment method group used for checkout, if provided Example: `"pmg_xyz"`. - `status` (string): status of the checkout One of: `created`, `completed`, `attempted`, `expired`. - `mode` (string): mode of the checkout One of: `test`, `live`. Example: `"test"`. - `successful_payment_id` (string (uuid)): payment id, if this checkout was paid for successfully Example: `"py_123xyz"`. - `statement_descriptor` (string): description of the payment that will be available on the account's bank statement Example: `"Big Business"`. - `metadata` (object) - `application_fees` (object, deprecated): **Deprecated**: Use the `fees` object instead for granular control over fee types and selective refunds. **New integrations** should use `payment.fees` instead for selective refund support. See [Enhanced Fee Management](#section/Enhanced-Fee-Management). - `card` (object) - `amount` (any): custom application fee amount that applies to card payment method Example: `300`. - `bank_account` (object) - `amount` (any): custom application fee amount that applies to bank account payment method Example: `150`. - `payment_settings` (object): payment configuration information for the checkout - `payment` (object): data passed to the `payment` property during checkout creation, or null - `description` (string): your meaningful description of the payment (e.g. an order number or other value from your system) Example: `"my order xyz"`. - `metadata` (object (json)): any useful custom information stored alongside this payment - `expedited` (boolean): settlement priority of the payment, defaults to false Example: `true`. - `fees` (array of `Fee`): Array of fee objects specifying the fees to be applied when the checkout is completed. See [Enhanced Fee Management](#section/Enhanced-Fee-Management) for full documentation. - `created_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2024-01-01T12:00:00Z"`. - `completions` (array of `CheckoutCompletionAttempt`): list of checkout completion attempts, if any ### ReportType which report was generated Type: string ### ReportParameters - Option 1: - `report_type` (string, required): One of: `proceeds`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 2: - `report_type` (string, required): One of: `payout`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 3: - `report_type` (string, required): One of: `interchange_fee`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 4: - `report_type` (string, required): One of: `sub_account_summary`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. - Option 5: - `report_type` (string, required): One of: `payment_list`. - `payment_status` (string): the payment status to filter by One of: `authorized`, `failed`, `succeeded`, `canceled`. Example: `"succeeded"`. - `payment_method_id` (string): the payment method id to filter by Example: `"pm_xyz"`. - `terminal_id` (string): the terminal_id to filter by Example: `"trm_xyz"`. - `start_date` (string (date)): Start date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-25"`. - `end_date` (string (date)): End date to filter by. Maximum allowed date rage is 1 month Example: `"2025-12-30"`. - `nickname` (string): the report nickname Example: `"My Report"`. - `account_id` (string): Example: `"acc_xyz"`. - `platform_account_id` (string): Example: `"acc_xyz"`. ### CardPaymentMethod - `card` (`Card`) - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### ApplicationFee - `id` (string (uuid)): unique application fee id Example: `"fee_123xyz"`. - `amount` (number): application fee amount, in cents Example: `150`. - `currency` (string): One of: `usd`, `cad`. Example: `"usd"`. - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. ### FeeResponse A fee object in API responses. The `fees` array is empty in the Create Payment response — subscribe to payment webhook events (recommended) to receive the full fee objects, or poll with a subsequent Get Payment request. - `id` (string): Unique identifier for this fee. Present when fetching a payment. Example: `"pyfee_xyz"`. - `type` (string, required): The type of fee: - `processing_fee`: Fees related to payment processing costs - `platform_fee`: Fees for your platform's services - `refund_processing_fee`: A processing fee charged when a refund is processed. Currently applies to CAD payments only. One of: `processing_fee`, `platform_fee`, `refund_processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): Fee amount in cents Example: `350`. - `currency` (string): Currency of the fee amount. Present when fetching a payment. One of: `usd`, `cad`. Example: `"usd"`. - `remaining_amount` (integer): Amount still available for refund in cents. Updates after each partial refund. Present when fetching a payment. Example: `350`. - `source_configuration_id` (string, nullable): The public ID of the Standard Fee Configuration used to calculate this fee. Null when the fee was explicitly provided in the payment request rather than auto-calculated. Example: `"sfc_abc123"`. - `source_fee_type` (string, nullable): The fee type from the Standard Fee Configuration that generated this fee (e.g., `processing_ecomm`, `amex_brand_ecomm`, `platform`). Null when the fee was explicitly provided in the payment request. Example: `"amex_brand_ecomm"`. - `refund_id` (string, nullable): The public ID of the refund this fee is associated with. Populated for `refund_processing_fee` fees (currently CAD payments only); null for all other fees. Present when fetching a payment. Example: `"re_xyz"`. ### BankAccountPaymentMethod - `bank_account` (`BankAccount`) - `customer_id` (string, nullable): customer_id is a deprecated field. Please use our payment method groups instead. Example: `"cust_xyz"`. - `signature` (string, nullable): signature that uniquely identifies a credit card or bank account across payment methods Example: `"4guAJNkVA3lRLVlanNVoBK"`. - `account_id` (string, nullable): account id associated with payment method Example: `"acc_123"`. ### Card - `id` (string (uuid)): unique card id Example: `"pm_123xyz"`. - `acct_last_four` (string): last 4 digits of the card number Example: `4242`. - `brand` (any): card brand or bank name Example: `"Visa"`. - `digital_wallet` (string, nullable): which digital wallet provider the card is tied to One of: `apple_pay`, `google_pay`, `null`. Example: `"apple_pay"`. - `name` (string, nullable): card or account holder name Example: `"Amanda Kessel"`. - `token` (any): same value as unique card id; can be saved and used to process multiple payments with the same card Example: `"pm_123xyz"`. - `month` (any): expiration date month Example: `"5"`. - `year` (any): expiration date year Example: `"2042"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this card - `created_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2021-01-01T12:00:00Z"`. - `address_line1_check` (string): Result of the address line 1 verification check. `pass` — matches the cardholder's address on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no address was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. - `address_postal_code_check` (string): Result of the postal code verification check. `pass` — matches the cardholder's postal code on file; `fail` — does not match; `unavailable` — verification could not be performed; `unchecked` — no postal code was provided for verification. One of: `fail`, `pass`, `unavailable`, `unchecked`. Example: `"unchecked"`. ### BankAccount - `id` (string (uuid)): unique bank account payment method id Example: `"pm_123xyz"`. - `account_owner_name` (string): account owner name Example: `"Lindsay Whalen"`. - `account_type` (string): type of account (checking, savings, etc.) Example: `"checking"`. - `bank_name` (string, nullable): bank name Example: `"Wells Fargo"`. - `acct_last_four` (string): last 4 digits of the account number Example: `1111`. - `token` (any): same value as unique bank account id; can be saved and used to process multiple payments with the same bank account Example: `"pm_123xyz"`. - `metadata` (object (json), nullable): any useful information you'd like to store alongside this bank account --- # Webhook Delivery Reference: https://docs.justifi.tech/api-spec#tag/Webhook-Delivery We offer event delivery to your app via webhooks. Webhooks are a reliable method to subscribe to our published events via an API endpoint. Webhooks are secured by signature verification, which you will need to verify by generating a SHA-256 hex using the following information: | Parameter | Header | Value | |------------|-------------------|-----------------------------------------------------------------| | Timestamp | JUSTIFI-TIMESTAMP | ISO string format | | Signature | JUSTIFI-SIGNATURE | String | | Algorithm | ----------------- | SHA-256 | | Secret Key | ----------------- | Found in your event publisher's page | | Message | ----------------- | String in the format `.` | To verify the signature simply compare the generated SHA-256 hex against it; if it is successful the webhook signature is valid. Here is a code example for reference: ```ruby def webhook_signature_valid?(signature, received_event, timestamp, secret_key) timestamp_payload = "#{timestamp}.#{received_event.to_json}" algorithm = OpenSSL::Digest.new("sha256") hex = OpenSSL::HMAC.hexdigest(algorithm, secret_key, timestamp_payload) signature == hex end ``` If you are using any of our SDKs, we provide a convenient method for validating the signature. After validating, you must respond with a `200 OK` with in **5 seconds**. In the event of a non-200 response or a delay of more than 5 seconds, delivery will be attempted again. For live accounts, webhooks are retried 10 times over 24 hours. For test accounts, webhooks are retried 3 times over 1 hour. **When you're ready to get started:** - Create the endpoint on your server that will receive published events - Add an event publisher with webhook delivery method in the **"Developers"** section of the JustiFi dashboard (www.justifi.ai -> Developers -> Event Publishers). You’ll subscribe your endpoint to the event types of your choice. We recommend starting with a test account. - Test the publisher by prompting one of the event types you chose and making sure your subscribed endpoint receives the published event --- # Payables Events Reference: https://docs.justifi.tech/api-spec#tag/Payables-Events Payables delivers events to your configured endpoint as payments and bank accounts change. Return a `200` within 5 seconds; non-2xx responses are retried with backoff. ## Payer account events Webhook event `payer_account`: JustiFi sends `POST` to your webhook URL. Delivered as a payer account is provisioned for Payables and as its state changes. The `data` object is the full `PayerAccount`. | Event | Meaning | | ----- | ------- | | `payables.payer_account.provisioned` | the business was provisioned to use Payables (now `active`) | | `payables.payer_account.updated` | the account's details changed | | `payables.payer_account.disabled` | the account can no longer initiate payments, create payees or register bank accounts | | `payables.payer_account.archived` | the account was archived | Return a `200` within 5 seconds to acknowledge receipt; non-2xx responses are retried with backoff. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `event_name` (string): name of the event, namespaced under `payables.` (e.g. payables.payee_payment.succeeded, payables.bank_account.corrected) One of: `payables.payer_account.provisioned`, `payables.payer_account.updated`, `payables.payer_account.disabled`, `payables.payer_account.archived`. Example: `"payables.payee_payment.succeeded"`. - `idempotency_key` (string, nullable): idempotency key of the request that produced the event, when available - `account_id` (string, nullable): the sub account the event is scoped to, where one applies. **Always null for Payables** — a payer account is a first-class entity with its own `payer_…` id and is not a sub account, so there is nothing of this shape to report. The field is retained because the event envelope is shared across JustiFi services. - `platform_account_id` (string, nullable): the platform account the event is scoped to Example: `"acc_987zyx"`. - `version` (string): version of the event payload Example: `"v1"`. - `data` (object): A payer account is the payer in Payables — a first-class Payables entity with its own `payer_…` id. Every payee, bank account, and payment is scoped to one payer account. Each payer account belongs to a JustiFi business (`business_id`). The record is created (`pending`) when a platform begins provisioning Payables, and becomes `active` once JustiFi's risk platform reports the business has met Payables's onboarding requirements — a lighter bar than our payments-processing product, so a business can be Payables-ready before it is enabled for payments. The customer-facing API exposes payer accounts read-only. - `id` (string): unique payer account id Example: `"payer_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payer_account"`. - `business_id` (string): the JustiFi business this payer account belongs to. Requests operate *within* a payer account (see the `/v1/payables/payer_accounts/{payer_id}/…` routes); `business_id` records the owning business for reporting and cross-account grouping, it is not the request scope. Discover a business's payer accounts with `GET /v1/payables/payer_accounts?business=biz_…`. Example: `"biz_123xyz"`. - `name` (string): display name for the payer account Example: `"Northside Physical Therapy"`. - `mode` (string): whether this payer account operates against real money. Inherited from the JustiFi account it belongs to — a test account and a live account are different accounts with different ids, so a payer account is one or the other for its life and cannot be switched. In `test`, payments run against a simulated ACH network: they complete in seconds rather than banking days, and no money moves. One of: `test`, `live`. Example: `"live"`. - `status` (string): the payer account's Payables lifecycle state, and what each state prevents. `pending` — provisioning has begun but the risk platform has not yet reported the business Payables-ready; `active` — Payables-ready, and the only state under which anything can be created; `disabled` — was active previously, and can no longer schedule payments, create payees or register bank accounts; `archived` — the same, and permanent: an archived payer account cannot be reactivated. A payment whose payee credit is already held is not paid out while the account is not `active`. It stays held until the account is active again, rather than failing. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `provisioned_at` (string (date-time), nullable): when the payer account was provisioned to use Payables; null until provisioning completes Example: `"2026-01-01T12:00:00Z"`. - `funding_bank_account_id` (string, nullable): pointer to the payer account's active funding bank account. In this version a payer account has a single active funding account. Null until one is registered and verified. Example: `"ba_fund456"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. ### Responses #### 200: Return a 200 status to indicate the event was received successfully (within 5 seconds). ## Payee events Webhook event `payee`: JustiFi sends `POST` to your webhook URL. Delivered as payees are created, updated, or archived — useful for keeping your own records in sync. The `data` object is the full `Payee`. | Event | Meaning | | ----- | ------- | | `payables.payee.created` | a payee was created | | `payables.payee.updated` | a payee's details changed (name, address, email, default account) | | `payables.payee.disabled` | a payee was disabled and can no longer be paid — including when its bank refuses the credit or corrects the account without saying what to. Register a corrected receiving account to make it payable again | | `payables.payee.archived` | a payee was archived and can no longer be paid | `entity_type` and `tax_id` never move, so no event reports them changing. Return a `200` within 5 seconds to acknowledge receipt; non-2xx responses are retried with backoff. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `event_name` (string): name of the event, namespaced under `payables.` (e.g. payables.payee_payment.succeeded, payables.bank_account.corrected) One of: `payables.payee.created`, `payables.payee.updated`, `payables.payee.disabled`, `payables.payee.archived`. Example: `"payables.payee_payment.succeeded"`. - `idempotency_key` (string, nullable): idempotency key of the request that produced the event, when available - `account_id` (string, nullable): the sub account the event is scoped to, where one applies. **Always null for Payables** — a payer account is a first-class entity with its own `payer_…` id and is not a sub account, so there is nothing of this shape to report. The field is retained because the event envelope is shared across JustiFi services. - `platform_account_id` (string, nullable): the platform account the event is scoped to Example: `"acc_987zyx"`. - `version` (string): version of the event payload Example: `"v1"`. - `data` (object): A payee is a party that receives Payables payments. Payees are standalone: they can exist and be paid without being tied to a business. `business_id` reports a link to a JustiFi business where there is one, and is null by default. - `id` (string): unique payee id Example: `"pe_abc123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee"`. - `payer_account_id` (string): the id of the payer account this payee is scoped to Example: `"payer_123xyz"`. - `name` (string): the payee's legal name. Required on create. Example: `"Acme Plumbing LLC"`. - `entity_type` (string): the payee's IRS entity classification. Required on create, with no default — it decides both the tax form filed for the payee and, for `sole_proprietorship`, how the ACH credit to them is classified. Immutable — with `tax_id` it is the taxpayer this payee is filed against. The set is open and may grow; unknown values should be treated as a business entity. One of: `c_corporation`, `s_corporation`, `partnership`, `limited_liability_company`, `sole_proprietorship`. Example: `"limited_liability_company"`. - `email` (string (email), nullable): contact email for the payee, when provided Example: `"billing@acmeplumbing.com"`. - `tax_id_last4` (string): the last four digits of the payee's taxpayer identification number — an EIN, or an SSN where the payee is a `sole_proprietorship`. The number itself is required on create and never returned — it is stored encrypted, and this is what reads back. Immutable, on the same terms as `entity_type`. Example: `"4021"`. - `address` (object): the payee's address. Required on create. - `line1` (string): street address Example: `"123 Example St"`. - `line2` (string, nullable): suite, unit or floor, when there is one Example: `"Suite 101"`. - `city` (string): Example: `"Minneapolis"`. - `state` (string): two-letter state or territory code, uppercase. Not normalized — `mn` is rejected rather than corrected. Example: `"MN"`. - `postal_code` (string): ZIP or ZIP+4 Example: `"55555"`. - `country` (string): ISO 3166-1 alpha-3 country code, matching the rest of JustiFi. `USA` is the only value Payables accepts — it pays by US domestic ACH and files US tax forms — and it is what a payee gets when the field is omitted. One of: `USA`. Default: `"USA"`. Example: `"USA"`. - `receiving_bank_account_id` (string, nullable): pointer to the payee's active receiving bank account (denormalized for lookup, like capital's `accounts.payout_account_id`). In this version a payee has a single active account. Null until one is registered. Example: `"ba_recv123"`. - `business_id` (string, nullable): the business this payee belongs to, where JustiFi has linked one. Null for standalone payees, and a payee is created and paid without one. - `status` (string): the payee's status. `pending` — created but not cleared for payments; `active` — able to receive payments, and the only state a payment can be scheduled or paid out under; `disabled` — was active previously and can no longer be paid; `archived` — was active previously and can never be paid again. A payment whose payee credit is already held is not paid out while the payee is not `active`. It stays held until the payee is active again, rather than failing. **Payables disables a payee when its bank says the account cannot be paid.** Either the bank returned a credit for a reason a retry will not change — the account is closed, frozen, not a transaction account, or does not exist — or it sent a notification of change we cannot act on, because it named no corrected numbers or corrects something Payables does not hold. Both mean the next payment would go to an account the bank has already refused. A correction about the entry rather than the account — the payee's name, the entry description — changes nothing. **Registering a corrected receiving bank account returns the payee to `active`**, and any payment held for it pays out on the next cycle. Until then those payments wait rather than failing, which is what stops a queue of payments following the first one into a closed account. One of: `pending`, `active`, `disabled`, `archived`. Example: `"active"`. - `metadata` (object): any useful information you'd like to store alongside this payee - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. ### Responses #### 200: Return a 200 status to indicate the event was received successfully (within 5 seconds). ## Payee payment lifecycle events Webhook event `payee_payment`: JustiFi sends `POST` to your webhook URL. Delivered as a payee payment moves through its lifecycle. One webhook fires per transition. All Payables events are namespaced under `payables.` so they never collide with JustiFi's core `payment.*` events. | Event | Meaning | | ----- | ------- | | `payables.payee_payment.initiated` | the payment was accepted and scheduled | | `payables.payee_payment.inbound_submitted` | the debit-pull from the payer has been submitted | | `payables.payee_payment.holding` | the debit-pull settled and the funds are held | | `payables.payee_payment.outbound_submitted` | the credit to the payee has been submitted | | `payables.payee_payment.succeeded` | the outbound credit to the payee has settled | | `payables.payee_payment.failed` | the debit-pull was returned, or a leg failed before the payee was paid (no automatic retry) | | `payables.payee_payment.refunding_payer` | the payee credit failed and the payer is being refunded | | `payables.payee_payment.refunded` | the payer has been refunded (`amount` less any retained fees) | | `payables.payee_payment.failed_late_return` | a return arrived after the payment succeeded, so the payment did not stick — the returned leg is on `transfers` | **Events are named for what happened**, and every payment status has one. Read the payload rather than the name to know where a payment stands. `failed_late_return` is worth reading twice: it does **not** mean the payee holds nothing. A returned outbound credit means the payee never kept the money; a returned inbound debit-pull means the payer's funding was clawed back after the payee was paid. **Re-sending on this event can pay a payee twice.** The `data` object is the full `PayeePayment`. Return a `200` within 5 seconds to acknowledge receipt; non-2xx responses are retried with backoff. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `event_name` (string): name of the event, namespaced under `payables.` (e.g. payables.payee_payment.succeeded, payables.bank_account.corrected) One of: `payables.payee_payment.initiated`, `payables.payee_payment.inbound_submitted`, `payables.payee_payment.holding`, `payables.payee_payment.outbound_submitted`, `payables.payee_payment.succeeded`, `payables.payee_payment.failed`, `payables.payee_payment.refunding_payer`, `payables.payee_payment.refunded`, `payables.payee_payment.failed_late_return`. Example: `"payables.payee_payment.succeeded"`. - `idempotency_key` (string, nullable): idempotency key of the request that produced the event, when available - `account_id` (string, nullable): the sub account the event is scoped to, where one applies. **Always null for Payables** — a payer account is a first-class entity with its own `payer_…` id and is not a sub account, so there is nothing of this shape to report. The field is retained because the event envelope is shared across JustiFi services. - `platform_account_id` (string, nullable): the platform account the event is scoped to Example: `"acc_987zyx"`. - `version` (string): version of the event payload Example: `"v1"`. - `data` (object): A payee payment moves money from the account's funding bank account to a payee's receiving account over ACH. It orchestrates an inbound debit-pull, a hold, and an outbound credit, accruing fees along the way. There is no automatic retry, and a payment cannot be cancelled once initiated. A return ends the payment either at `failed` or, when the payer has already been debited, at `refunding_payer` — see `status`. - `id` (string): unique payee payment id Example: `"pp_123xyz"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"payee_payment"`. - `payer_account_id` (string): the id of the payer account this payment is scoped to Example: `"payer_123xyz"`. - `amount` (integer): the gross amount debited from the payer, in cents. The payee receives `amount` minus the sum of `fees` (e.g. `amount` 91000 with a 1000 fee pays the payee 90000). Example: `91000`. - `currency` (string): One of: `usd`. Example: `"usd"`. - `status` (string): the payment's position in its lifecycle. `initiated` → `inbound_submitted` → `holding` → `outbound_submitted` → `succeeded` is the happy path. **`holding` is a real wait.** Once the payer's funding has settled, the payee's credit is held until the next banking day before it is submitted, so a payment rests in `holding` rather than passing through it. Read `deposits_at` for when the payee is expected to be deposited; the hold is already in that estimate. **The hold only lifts for an active payer account and an active payee.** When the wait is up, the payee's credit is sent if both are `active`; if either is not, the payment stays in `holding` and is reconsidered periodically, so it pays out once both are active again. A hold that persists pushes the deposit past the `deposits_at` estimate, which is why that field is an estimate. Which return path a payment takes depends on whose money was already moved. A returned **inbound** debit-pull means nothing settled, so the payment is `failed` and no one is owed anything. A returned **outbound** credit means the payer was already debited, so the payment moves to `refunding_payer` and then `refunded` once the payer has their money back. Both `failed` and `refunded` are terminal. **`succeeded` is not the end.** ACH lets a return arrive days after an entry settled, so one can land after a payment has succeeded. That moves the payment to `failed_late_return`, which is terminal — JustiFi works the break by hand and records the corrective movement as a further leg on the same payment. See "A return that arrives after a payment succeeded" in the overview. **`failed_late_return` does not mean the payee holds nothing.** It reports that the payment did not stick, and the two ways that happens are opposites: a returned **outbound** credit means the payee never kept the money, while a returned **inbound** debit-pull means the payer's funding was clawed back *after* the payee was paid — so the payee still has it. **Re-sending on this status can pay a payee twice.** Read the payment's `transfers` to see which leg returned before acting. One of: `initiated`, `inbound_submitted`, `holding`, `outbound_submitted`, `succeeded`, `failed`, `refunding_payer`, `refunded`, `failed_late_return`. Example: `"succeeded"`. - `payment_type` (string): how the funds move. ACH is the only option. Named `payment_type` rather than `payment_method`, which in the JustiFi API denotes a stored instrument object, not a rail. One of: `ach`. Example: `"ach"`. - `payee_id` (string): the payee being paid Example: `"pe_abc123"`. - `funding_bank_account_id` (string): the account's funding bank account the principal is debit-pulled from Example: `"ba_fund456"`. - `receiving_bank_account_id` (string): the payee's receiving account the principal is credited to Example: `"ba_recv123"`. - `debits_at` (string (date-time), nullable): in UTC, the estimated date and time the payer's funding account is debited (from the inbound leg); null until scheduled. Normally three banking days after the payment is submitted. Example: `"2026-01-01T12:00:00Z"`. - `deposits_at` (string (date-time), nullable): in UTC, the estimated date and time the payee is deposited (from the outbound leg); null until scheduled. Each ACH leg takes three banking days and the payee's credit is held for one banking day after the payer's funding settles, so this is normally four banking days after `debits_at`. Estimated, and may shift if the provider revises an effective entry date. Example: `"2026-01-04T12:00:00Z"`. - `description` (string, nullable): Example: `"Invoice 4021"`. - `fees` (array of object): the fees charged on this payment (v2 fee convention), carved out of `amount`. Supplied in the create request (required, no default) and echoed here. Fees incurred later by NOCs or returns are not shown here — they are billed to the platform monthly. - `type` (string, required): the fee type (v2 convention): - `processing_fee` — payment-processing cost, passed by platform One of: `processing_fee`. Example: `"processing_fee"`. - `amount` (integer, required): fee amount in cents Example: `1000`. - `transfers` (array of object): the ACH legs that make up this payment - `id` (string): unique transfer leg id Example: `"ptr_123"`. - `direction` (string): the direction of funds for this leg (a refund is an outbound, a recovery an inbound) One of: `inbound`, `outbound`. Example: `"inbound"`. - `purpose` (string): what this leg is — moves the principal, refunds the payer, or recovers owed funds from the payer One of: `principal`, `refund`, `recovery`. Example: `"principal"`. - `transfer_type` (string): how the money moved. `ach` — over the ACH network; `manual` — a movement JustiFi recorded off it. Widens to further rails (e.g. `rtp`) without a breaking change. One of: `ach`, `manual`. Example: `"ach"`. - `amount` (integer): the leg amount in cents Example: `50000`. - `status` (string): the state of this leg One of: `initiated`, `submitted`, `settled`, `returned`, `failed`. Example: `"settled"`. - `error_code` (string, nullable): normalised, rail-agnostic reason the leg failed, in snake_case (e.g. `insufficient_funds`). Stable across rails — **branch on this, not on `network_error_code`**, which is the network's own code and changes meaning between rails. Set when a leg is `failed` or `returned`, and null otherwise. A correction is not a failure: a leg that settled after a notification of change carries `network_error_code` but no `error_code`. A return code with no normalised equivalent reports `unclassified_return`, so this is never null on a leg that failed — the raw code is always there to fall back on. Example: `"insufficient_funds"`. - `error_description` (string, nullable): human-readable text for `error_code`, in English — for support and logs, not for branching. Null whenever `error_code` is. Example: `"Insufficient funds in the account"`. - `network_error_code` (string, nullable): the raw code from the network, verbatim — an ACH return code (`R01`). Preserved for reconciliation. Present whenever the network said anything about this leg, which is not only when it went wrong: a notification of change carries an advisory code (`C01`) on a leg that **settled** normally. Read it together with `status` — the code alone does not mean the money did not move. - `metadata` (object): any useful information you'd like to store alongside this payment - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-05T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. ### Responses #### 200: Return a 200 status to indicate the event was received successfully (within 5 seconds). ## Bank account events Webhook event `bank_account`: JustiFi sends `POST` to your webhook URL. Delivered as a funding account's verification changes, and when any account is corrected. The `data` object is the `BankAccount` record. | Event | Meaning | | ----- | ------- | | `payables.bank_account.verified` | a funding account passed verification and can now fund payments | | `payables.bank_account.failed` | a funding account did not pass verification and cannot fund payments; register a different account | | `payables.bank_account.pending` | a funding account's verification was reopened — it can no longer fund payments until it is verified again | | `payables.bank_account.corrected` | an account was corrected following an ACH Notification of Change (NOC); the new record is the one to use and the previous one is superseded | The verification events are the ones to watch when onboarding. They arrive from underwriting rather than from anything you did, so nothing in your own request flow tells you the answer, and together they are what say whether a payer account can fund. All three are worth handling: waiting on a `verified` that is never coming looks exactly like waiting on one that has not arrived yet, and an account that was verified can go back to `pending` if underwriting reopens it. Only funding accounts are verified — payee receiving accounts are `not_required` and raise none of the three. > An NOC always carries the correction code, but the network does not always supply the corrected > account or routing number. Where it does not, `bank_account.corrected` reports that a correction is > required without carrying the new value. Return a `200` within 5 seconds to acknowledge receipt. ### Request body Content type: `application/json` - `id` (string): event unique id Example: `"evt_123xyz"`. - `event_name` (string): name of the event, namespaced under `payables.` (e.g. payables.payee_payment.succeeded, payables.bank_account.corrected) One of: `payables.bank_account.verified`, `payables.bank_account.failed`, `payables.bank_account.pending`, `payables.bank_account.corrected`. Example: `"payables.payee_payment.succeeded"`. - `idempotency_key` (string, nullable): idempotency key of the request that produced the event, when available - `account_id` (string, nullable): the sub account the event is scoped to, where one applies. **Always null for Payables** — a payer account is a first-class entity with its own `payer_…` id and is not a sub account, so there is nothing of this shape to report. The field is retained because the event envelope is shared across JustiFi services. - `platform_account_id` (string, nullable): the platform account the event is scoped to Example: `"acc_987zyx"`. - `version` (string): version of the event payload Example: `"v1"`. - `data` (object): A bank account used for Payables money movement. Exactly one of `payer_account_id` or `payee_id` is set: the former for a funding account (the principal is pulled from it), the latter for a payee's receiving account (the principal is paid to it). Account numbers are write-only — accepted on create, never returned; responses expose only the last four digits. Bank accounts are immutable: to correct details (e.g. after a NOC), a new record is created rather than edited in place. **Which record is active is determined by the owner**, via `payer_account.funding_bank_account_id` or `payee.receiving_bank_account_id` — so registering a new account and pointing the owner at it supersedes the previous one. Listing an owner's bank accounts by `created_at` therefore gives its full account history. - `id` (string): unique bank account id Example: `"ba_recv123"`. - `type` (string): the object type, matching the enclosing envelope's `type` Example: `"bank_account"`. - `payer_account_id` (string, nullable): the payer account that owns this bank account, when it is a **funding** account. Null on a payee's receiving account. Exactly one of `payer_account_id` and `payee_id` is non-null. - `account_holder_name` (string): the name on the bank account Example: `"Acme Plumbing LLC"`. - `routing_number` (string): the 9-digit ABA routing number Example: `"021000021"`. - `account_number_last4` (string): the last four digits of the account number (the full number is never returned) Example: `"6789"`. - `account_type` (string): the type of bank account One of: `checking`, `savings`. Example: `"checking"`. - `payee_id` (string, nullable): the payee that owns this bank account, when it is a **receiving** account. Null on a payer's funding account. Exactly one of `payer_account_id` and `payee_id` is non-null. Example: `"pe_abc123"`. - `verification_status` (string): the state of bank account verification. Read together with which owner field is set, this is the model's signal for how the account is handled: - `not_required` — a payee (receiving) account. Payables does not verify payee accounts; payments are sent without upfront validation, and a bad account surfaces as a returned credit. This is a settled state rather than a "not yet verified" one. - `pending` — a payer (funding) account whose validation is in progress. Payer funding accounts are validated in-app (e.g. during portal funding setup). - `verified` — a payer funding account that has been validated; only a `verified` funding account may fund a payment. - `failed` — validation of a payer funding account failed; it cannot fund payments. One of: `not_required`, `pending`, `verified`, `failed`. Example: `"verified"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `updated_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. - `created_at` (string (date-time)): Example: `"2026-01-01T12:00:00Z"`. ### Responses #### 200: Return a 200 status to indicate the event was received successfully (within 5 seconds).