Payment Orchestrators
Guide describing how the Orchestrator integrates with inabit’s APIs..
Overview
This guide describes the end-to-end integration with inabit to enable seamless crypto-payment flows and secure treasury operations. The integration provides a compliant, scalable, and self-custodial setup using inabit’s infrastructure.
API Introduction
Our APIs combine GraphQL (core inabit platform) and REST APIs (inabit Terminal), allowing clients to query exactly the data they need with maximum flexibility and efficiency. This hybrid approach enables streamlined integration with both wallet infrastructure and payment flows.
APIs & Auth at a glance
Platform API (GraphQL): wallets, governance, withdrawals, org objects. Auth:
Authorization: Bearer <API_ADMIN_TOKEN>Terminal API (REST): Terminal resources (widgets, purchases, customer addresses, deposits). Auth:
Authorization: Bearer <TERMINAL_ORG_API_KEY>orAuthorization: Bearer <TERMINAL_WIDGET_API_KEY>depending on scope.
Which key do I use, and when?
Create/list UI wallets create withdrawals,view wallets, open new wallet, add coins
API Admin (GraphQL)
Platform-level ops & governance
At account opening — provided by inabit Support
Authorization: Bearer <API_ADMIN_TOKEN>
Org-wide Terminal reads (e.g., get all widgets, get all customers), org-scoped deposit lookups
Terminal Organization API Key (REST)
Organization-level Terminal access across widgets/customers
When Terminal is enabled — provided by inabit Support
Authorization: Bearer <TERMINAL_ORG_API_KEY>
Single-widget reads (e.g., get widget details, purchase and deposit statuses)
Terminal Widget API Key (REST)
Per-widget access; safer for widget-scoped services
During widget setup — shown on the widget implementation instructions page in the platform
Authorization: Bearer <TERMINAL_WIDGET_API_KEY>
Additional Reference
We highly advise taking a look at the following pages as you start developing:
API Login Access / Authentication
Remote & Automatic Approvals (Docker Configuration)
Automate Signing Transactions
Supported Blockchains & Assets
Technical Architecture: Merchant Onboarding
(Architecture diagram)
Merchant Onboarding Flow Explained
When a new merchant is onboarded to inabit, the process begins with registration and device pairing using the inabit mobile app.
Once the merchant is registered and paired:
inabit automatically generates two API users under the merchant’s account:
API Signer (used by the Orchestrator/merchant)
API Admin (used by the Orchestrator)
The merchant owner then receives an approval request on their inabit mobile app and must approve the newly created API users.
After the API users are approved:
inabit securely shares the API credentials with the Orchestrator, enabling the next steps in the onboarding process.
Next, the Orchestrator or the merchant installs the inabit Approver Docker and pairs the API Signer.
Note: The merchant can choose to host the Docker either on their own servers or let the Orchestrator manage it.
To complete the pairing process:
The merchant enters a pairing code into their inabit mobile app that is received from the Orchestrator (via direct communication).
Now that pairing is done:
The Orchestrator opens a Master Wallet with the required blockchains (an inabit wallet used as a central aggregator for the merchant).
The Orchestrator then proceeds to configure the inabit POS widget(s) based on the merchant’s requirements, including:
Supported coins
Sweeping frequency
Expiration time
And more.
After configuration, inabit supplies the implementation guide, and the Orchestrator integrates the widget into the merchant’s platform using the provided code, script or via API.
Now that the flow is clear, let's review the implementation process step by step! ✨
1. Merchant Onboards to inabit
The merchant begins by creating an account on the inabit platform.
Step-by-Step:
As a merchant, visit the onboarding URL: https://use.inabit.com/create_account?channel=[OrchestratorName]
On the Plan Selection screen, select Enterprise. This ensures the merchant is granted access to advanced platform features and API capabilities required for the Wallet-as-a-Service integration.
Complete Device Pairing: As the final onboarding step, the merchant must pair their mobile device with the inabit platform. This process is critical for enabling self-custody-meaning the merchant remains the sole custodian of their customers' funds.
The paired device acts as a cryptographic key manager and approval layer, ensuring secure signing of all transactions and operations on the platform.
(See: How to Perform Device Pairing)
2. inabit Enables API Access
inabit allows access to its API for the Orchestrator by generating 2 API users under the merchant's account:
API Signer Created for the sole purpose of serving as the "Approver" to sign transactions using inabit's Approvals Docker.
API Admin Serves as the API key/access user for inabit's API endpoints.
Learn more about API User Roles in a dedicated guide.
3. inabit Sends Access Tokens to the Orchestrator
After the API users are approved:
inabit shares the API credentials with the Orchestrator, enabling the next steps in the onboarding process.
Sharing the access tokens of both users will occur only on a secured channel of the Orchestrator's preference.
4. Orchestrator Implements inabit Remote Approver App
The Remote Approver App (Approver Docker) enables policy-based, automated approvals for API wallets only (it does not apply to UI wallets).
Deployment options
Self-hosted (recommended default): One-time Docker setup via the inabit CLI on your own infrastructure.
inabit-hosted (managed): inabit can host and operate the Remote Approver App for you
When to choose which?
Choose self-hosted if you require full infrastructure control or have strict internal hosting policies. Setup & configuration guide
Choose inabit-hosted to reduce ops overhead; in this managed mode, API wallets can transfer funds only to internal wallets within your organization, and you still retain self-custody via your approval policies and paired identities.
In order to automate signing transactions on behalf of the merchant, the inabit Remote Approver App needs to be installed and the API Signer user is paired. Please refer to the full guide explaining the Docker setup and configuration in Remote Approver App Setup.
5. Orchestrator/Merchant Sends Pairing Code to the Merchant owner
Once the Docker is up and running, the pairing process will commence as follows:
Docker issues a Pairing Code in the Docker logs (example log output shown in the original guide).
Docker proceeds to send an approval request to the owner to authorize the approver app (just like any other user).
The Orchestrator/merchant sends the Pairing Code to the merchant owner via a secured channel of choice.
The merchant’s owner inserts the code in the mobile app to complete the pairing process.
6. Orchestrator Creates a Master Wallet in the Merchant's inabit Account
Once device pairing is completed, the Orchestrator proceeds to create a Master Wallet for the merchant through inabit's API.
What is a Master Wallet?
The Master Wallet serves as the central aggregator for all crypto transactions and funds flow. It is a secure, self-custody wallet fully accessible by the merchant.
Supported Blockchains
During wallet creation, the Orchestrator selects the required blockchains (e.g., Ethereum, Tron, Polygon) that the merchant will support for their clients. Each blockchain comes with its own address and supports its respective tokens (e.g., USDT on Tron, ETH on Ethereum).
How to Create a Master Wallet?
The CreateWalletWithInabit mutation allows API admins to create a new inabit wallet (that is accessible in the platform's interface, unlike API wallets) with a designated address for a given asset & blockchain.
Remember to authenticate to call our GraphQL API using an access token (bearer) with your API Admin credentials.
Example Mutation:
mutation CreateWalletWithInabit($data: WalletCreateWithInabitInput!) {
createWalletWithInabit(data: $data) {
id
name
}
}Headers
Content-Type: application/json
Authorization: Bearer <token>
Body (WalletCreateWithInabitInput object)
name (string, required) – Name of the wallet
organizationId (string, required) – ID of the organization in inabit
Example body:
{
"data": {
"name": "My Inabit Wallet",
"organization": {
"id": "clu6oj0kg0xxxxxb98guo82u"
}
}
}Response (Success example):
{
"data": {
"createWalletWithInabit": {
"id": "clvw5pxxxxxxx7qhe3atv9d",
"name": "My Inabit Wallet"
}
}
}
In the mutation's response, you will receive the created wallet ID including the associated blockchain address.
You can also try this mutation via Apollo Studio.
For recommended best-practice wallet structures, see here:
7. Orchestrator Enables Terminal Access
To enable inabit Terminal, contact inabit Support. As part of activation:
Provide a generic webhook URL to serve as the organization-level default for events.
inabit will activate Terminal and return an Organization API Key for communicating with the inabit Terminal API at the org scope.
After activation, proceed with widget creation and deployment. You can also schedule an enablement call from the Terminal page in the interface. (Reference)
Note on API keys
Organization API Key (issued during enablement): used to pull organization-level information, e.g., get all widgets, get all customers, etc.
Widget API Key (issued when you create a widget): used to pull widget-level information and interact with that specific widget (e.g., get widget details, purchase status, address-token status).
8. Orchestrator Creates & Configures Widgets
Widget Creation
The Orchestrator will create and edit new widgets via a dedicated endpoint that inabit will provide them upon integration kickoff or from the terminal UI.
Widget Configuration
Choosing the Right Widget Type:
The Orchestrator selects and configures the widget per merchant use case. We support two types: Purchase Address and Customer Address.”
Example use case
Widget type to use
Why
One-time payment per transaction (e.g., single bet, fixed-price checkout, specific game session)
Purchase Address
Creates a time-boxed, amount-bound address per purchase with clear success/expiry states.
Funding a player wallet / account balance with flexible amounts used across sessions
Customer Address
Provides a persistent address per player for ongoing top-ups and balance management.
Dedicated address per player for recurring deposits, reconciliation, and linking on-chain flows to a user profile
Customer Address
Stable, per-customer address simplifies reconciliation and KYC/accounting.
Quick picker
Need exact amount + expiry for a single transaction? → Purchase Address
Need recurring or flexible deposits tied to a player? → Customer Address
Implementation notes
Both types support: confirmations policy, auto-sweep to Master Wallet, and coin/chain allow-lists.
Typically: shorter expiry for Purchase Address; no expiry (or long TTL) for Customer Address.
For a full description of widget types, their behavior, and recommended use cases, see here :
Functionality Settings
Once the widget type is chosen, the Orchestrator customizes the widget based on the merchant’s requirements. inabit offers robust, per-widget configuration options that allow fine-tuning of how each widget behaves. Key parameters include:
Supported Coins – Define which cryptocurrencies the widget will accept.
Deposit Amount – Can be: (relevant Purchase Address only)
Predefined - The widget displays a specific amount to be deposited by the end-customer.
Flexible - The widget does not enforce a specific deposit amount, allowing users to send any amount to the assigned address. In this mode, the deposit address remains the same for that customer/session, and any funds received at that address will be credited accordingly.
Sweeping Frequency – Set how often received funds are automatically moved to the Master Wallet.
Blockchain Confirmations – Configure the required number of confirmations per chain.
These and other advanced options allow for flexible and secure integration into any existing merchant flow.
For the full list of available settings and best practices, refer to:
Customizing the Widget Interface / UX
By default, you can adjust the following UI parameters:
Widget Name– A unique name to identify your widget (e.g., “Basic Plan Payment”).Description(Optional) – Short text explaining what this widget is used for.Merchant Name(Optional) – Merchant name displayed to the end user (if applicable).
If further customization is required (logos, fonts, colors, layout, etc.), you can override the widget’s CSS.
The merchant (or the Orchestrator on their behalf) can also decide whether to let the end user select the asset & blockchain inside the widget. The widget can always be reviewed in preview mode before going live to ensure it looks and behaves as expected.
(Example widget preview details and images remain as in the original guide.)
9. Orchestrator Installs Widgets on the Merchant's Platform
inabit supports multiple, straightforward implementation methods per widget type. Choose the approach that best fits your stack and UX-each method is intuitive and easy to set up.
Customer Address (persistent address per player)
Supported methods:
APIiframeRedirect
1. Using API
This option is best for creating fully custom UI with your own components.
How it works: Use inabit’s APIs to create or fetch the customer’s persistent address, show it in your UI, and track status via webhooks
2. iframe (embedded hosted UI)
Best for: native feel while keeping low frontend effort.
How it works: Generate the Customer Address URL (session/token) server-side → embed in an <iframe> in your account page.
Steps
Step 1: Implement Server-Side Terminal Call
Create or Retrieve a Customer Profile (Backend)To initialize the widget for a user, you must first ensure a customer profile exists in the backend system. This is identified by a unique customerIdentifier (e.g., the user’s email or internal ID). Depending on whether the user is new or already exists, follow the appropriate substep:
a. Create a New Customer (if not yet created)
If the user does not already exist in your backend, send a POST request to create a new customer profile:
curl --location https://api.inabit.biz/v1/customer
--header Content-Type: application/json
--Authorization: Bearer cf4377b581610c77xxxxxxxxxxx9b5375af1ea3be73ab44605be8c30a7ad1d4
data-row-{
customerIdentifier: [email protected]
}
Response: The API will return a JSON object containing the customer's UUID (id)
which will be required in subsequent steps
{
"data": {
"id": "customer-uuid",
}
}b. Retrieve Existing Customer (if already created)
Store this id securely as customerUuid for future requests.
If you’ve already created a customer but did not save their UUID, you can retrieve it using their customerIdentifier:
curl --location https://api.inabit.biz/v1/customer?customerIdentifier=encoded_email
--header Content-Type: application/json
--Authorization: Bearer cf4377b581610xxxxxxxxxxxxx9b5375af1ea3be73ab44605be8c30a7ad1d4
Response:The API will return the customer object containing the UUID:
{
"data": {
"id": "customer-uuid",
}
}c. Once you have the customerUuid, you can proceed to generate the address token in the next step and then add the snippet for the token request
curl --location 'https://api.inabit.biz/v1/customer/address-token'
--header Content-Type: application/json
--Authorization:Bearer cf4377b581610cxxxxxxxxxxxxxx5af1ea3be73ab44605be8c30a7ad1d4
"data":{
"customerUuid": "27b4f808-be6c-xxxx-xxxx-6eeaad8389e9"
}'
Response: The API will return a JSON object containing the token id which will be required in subsequent steps.
{
"data": {
customerUuid": "customer-uuid",
addressGenerationToken: "address-token-id",
}
}Widget API Key:
cf4377b581610c775646c46xxxxxxxxxxxxxxxxxxxxxxc30a7ad1d4Step 2: Add Script Tag to page Header
a. Add the following script tag to your page header:
<script src="https://www.inabit.biz/widget.js" ></script>Step 3: Call open.widget Function Call openwidget function with token id, should open in popup After the customer clicks on the button.
// Open the widget using the token ID returned in the previous step:
window.openWidget(tokenId, {
isToken: true
})
// To open the widget in a popup, you can use:
window.openWidget(tokenId, {
mode: 'popup',
isToken: true
});
1. Add a container where the iframe will be rendered:
<div id="terminal-payment"></div>2. Open the widget using the token ID returned in the previous step:
window.openWidget(tokenId, {
mode: 'iframe',
isToken: true
});
// 3. (Optional) To make the widget take up 100% width, set fullWidth to true:
window.openWidget(tokenId, {
mode: 'iframe',
fullWidth: true,
isToken: true
});The merchant can also retrieve the above information themselves by accessing the terminal through their inabit account by logging into our platform.
3. Redirect (hosted flow)
Best for: fastest integration when you want inabit to fully host the UI.
How it works: Create/obtain the Customer Address session or token → redirect the user to the hosted page tied to that customer.
Deposit Management
How Will the Orchestrator Stay Up-to-Date on Incoming Deposits?
In many industries it's common practice to lock funds once a deposit transaction is detected on-chain, even before it has been fully confirmed. This provides a better user experience by showing a successful deposit immediately-while still protecting the merchant by making the funds non-withdrawable until sufficient blockchain confirmations are received.
inabit's system fully supports this flow: once a transaction is detected, it updates the widget with a pending confirmation status, allowing the platform to reflect the deposit in the UI while ensuring risk mitigation through backend-level enforcement of fund availability only after confirmation.
Best practice for monitoring deposits: use a hybrid of webhooks and API polling for real-time state changes, plus periodic polling as a safety net (e.g., to recover from missed callbacks or network hiccups). See the full guidance here.
To keep the Orchestrator in sync, inabit emits webhook callbacks for each deposit event and any status change, enabling real-time tracking and deterministic, status-based logic within the Orchestrator’s environment.
List of Potential Deposit Statuses:
Confirming– The full amount has been received, and the system is now waiting for the required number of blockchain confirmations to mark the deposit as successful.Unconfirmed– A deposit has been detected on the blockchain but has not yet been included in a block (only relevant for UTXO-based networks such as Bitcoin).Completed– The required number of blockchain confirmations has been received, and the deposit is finalized successfully.PendingFork- Tx confirmed on a forked block; credit on hold until reorg resolves. After settlement, the deposit may complete or fail.Failed- The deposit cannot be credited (e.g., transaction invalid/dropped, double-spent or replaced via RBF to a different address). The payment attempt should be considered unsuccessful.
Get deposit by UUID for merchant:
GET https://www.inabit.biz/v1/merchant/purchase/{{purchaseId}}
(Sample JSON response as in the original guide.)
Merchant Withdrawal Process
How Are Withdrawals Handled?
Withdrawals are processed centrally from the Master Wallet, which acts as the secure treasury account for each merchant. This wallet receives funds via automatic sweeps from all the individual deposit wallets (API wallets) that are generated through inabit’s POS widgets.
Here's How It Works:
Deposit Collection & Sweeping Each time a user deposits via a POS widget, a unique blockchain address (API wallet) is created. Once a deposit is confirmed, inabit automatically sweeps the funds from these individual wallets to the merchant’s Master Wallet at predefined intervals (e.g., hourly, daily). Refer to our documentation to learn more about Gas Fees and Sweeping.
Withdrawal Execution Once the funds are consolidated in the Master Wallet, withdrawals can be initiated. The Orchestrator or the merchant can trigger a withdrawal using inabit’s APIs.
Initiate a mutation to create an asset transfer request to send for approval from the Master Wallet.
mutation CreateWithdrawal($data: WithdrawalCreateInput!) {
createWithdrawal(data: $data) {
id
}
}Headers
Content-Type: application/json
Authorization: Bearer <token>
Body (WithdrawalCreateInput object)
wallet.id(String, required) – Master Wallet IDfinancialAsset.id(String, required) – Asset IDaddress(String, required) – Destination address (To)amount(Integer, required) – Transfer amountblockchain.id(String, required) – Blockchain IDnote(String, optional) – Transaction notepriority(String, optional) – Transaction priority (Slow, Medium, Fast, etc.)
Example body:
{
"data": {
"wallet": {
"id": "clol7o576002oaz011mmtnvru"
},
"financialAsset": {
"id": "clefn78gv011olc6rcwtt0wel"
},
"address": "0x7582f3483116105e0b7845ac1a0df5eb0c8cd062",
"amount": 5,
"blockchain": {
"id": "clefn78em00mslc6r3lzf3h5a"
},
"note": "",
"priority": "Medium"
}
}Response:
id (String) –
Withdrawal ID
Real-Time Visibility
inabit provides real-time status updates on withdrawal requests, including initiation, signing, blockchain confirmation, and completion, allowing the Orchestrator to reflect up-to-date information within its platform and back office.
Security and Policy
All outgoing transactions undergo approval logic (via the Remote Approver Docker and mobile app). Only authorized signers (e.g., the API Signer configured during onboarding) can approve withdrawals.
Last updated
Was this helpful?