The Kima Transaction Back End

This is a web server that works as middleware between the Kima Transaction Widget and Kima Chain. Once it receives a transaction request from the widget, it will submit a transaction to Kima Chain signed by a local wallet.

The server is an Express application and requires minimal setup. Here are the instructions:

Create a wallet for development purposes

We recommend Keplr, which is a widely used wallet for blockchains within the Cosmos ecosystem.

Install it from herearrow-up-right and make sure you back it up by saving the seed phrase.

You will need to record the mnemonic seed phrase rather than the private key, as the seed phrase is used as an environment variable.

⚠️ In order to connect to the Kima chain (both Mainnet and Sardis Testnet), you will need to get your Kima address whitelisted. Please contact us at [email protected]envelope with your public address- it will start with kima1. This is a temporary measure to combat spammers.

You can find your Kima address in the Keplr wallet by

  • Clicking the "Copy Address" button

  • Find "Kima" in the list of chains

  • Click the "Copy Address" button

If you have not yet added the Kima Network to Keplr, you can enter "Kima" in the "Search for a chain" field when copying the address.

Get Kima Address from Keplr wallet

Get some KIMA tokens to use for transaction fees

If you are developing on the KIMA testnet, you can acquire test KIMA tokens from our faucet sitearrow-up-right. For mainnet, there is a list of exchanges where you can buy KIMA tokens herearrow-up-right.

Follow the instructions here if you have not used a faucet before.

Clone the repo at:

https://github.com/kima-finance/kima-transaction-backendarrow-up-right

Set your environment variables

For local development, create a .env file in the project root and copy the relevant values from .env.sample.

This repository does not currently include docker-compose.yml, docker-compose-prod.yml, or separate /env/*.env files. If you containerize the backend in your own environment, pass the same variables from .env.sample through your deployment platform or container runtime.

The .env file will be ignored by git, but .env.sample is not, so do NOT accidentally fill real secrets into the sample file.

A few notes about these environment variables:

KIMA_BACKEND_MNEMONIC is the seed phrase from the wallet you installed. Never share this with anyone. Never commit this to a code repository. Use a secret manager service like Google Secret Managerarrow-up-right or AWS Secrets Managerarrow-up-right to store your seed phrase instead of putting it in the .env file.

KIMA_ENVIRONMENT is separate from the NODE_ENV variable and determines whether information endpoints like /chains will return testnet or mainnet values.

DOMAIN is a comma separated list of urls that the server will accept requests from. All other domains will be blocked (except in the dev environment). Put the url of your frontend here.

COMPLIANCE_URL (OPTIONAL) If your app needs to block non-compliant addresses contact us for more information and the url to use here.

/chains/env returns the environment metadata expected by the widget. A typical response looks like this:

Field meanings:

  • env: active Kima environment used by the widget to configure network behavior

  • kimaExplorer: explorer base URL used for status and transaction links

  • transferLimitMaxUSDT: optional transfer cap used by light mode and validation logic

  • paymentPartnerId: FIAT widget partner identifier used by widget-managed payment flows

Mainnet

Here are the mainnet specific environment variables. See the .env.sample for the most up to date list of ENV variables and default values. The other vars you will need to fill in with your specific values.

Testnet

Install and start

You can run:

npm install

then

npm run dev

If you deploy the backend in a container or cloud runtime, provide the same environment variables shown above through that platform's configuration.

Test the installation

In your terminal, run the following command:

The server should respond with a 200 and a JSON body similar to:

Available routes

See OpenAPI documentation at /docs for more details (only available when NODE_ENV is development). The following is an overview of how the routes are used together.

  • Get various info for the frontend from /chains/* like supported chains, tokens, pool addresses, etc.

    • Token entries in /chains include isPermit2 metadata. Use this to decide whether submit options must include a Permit2 payload.

  • GET /submit/fees: get the service fees and token authorization amounts

    • The response includes feeTotalFiat and feeTotalBigInt for the total fee value.

    • Returns a ready-to-use transactionValues.*.allowanceAmount object with value and decimals, representing the origin token authorization amount. For regular ERC-20 tokens, pass the value using the accompanying decimals context to approve(). For Permit2 tokens, use the same amount data when building the Permit2 authorization flow. Bigints are used to avoid floating point errors.

    • The required authorization step must be completed before submitting the transaction or the transfer will fail.

    • Use the submitAmount when calling /submit/transfer or /submit/swap; it is already properly adjusted based on whether fees are deducted from origin or target.

    • Use the decimals property to convert to a number if needed elsewhere.

  • POST /submit/transfer: initiates a transfer transaction and returns data containing the Kima transaction id

  • POST /submit/swap: initiates a swap transaction and returns data containing the Kima transaction id

  • GET /tx/{txId}/status: use the transaction id returned from submit to get the transaction status

  • BTC route group (/btc/*) for BTC-origin flows:

    • GET /btc/balance?address={address}: fetch BTC balance (sats) for an address

    • POST /btc/htlc/lock-intent: create HTLC lock intent and return lock metadata

    • POST /btc/htlc/record: record a broadcast BTC lock transaction and return submit-ready HTLC fields

    • GET /btc/height: get current BTC chain height from configured mempool backend

    • GET /btc/tip: get current BTC tip height and timestamp

    • GET /btc/outspend?txid={txid}&vout={index}: fetch spend status for a specific transaction output

    • GET /btc/transaction?hash={txid}: fetch BTC transaction details

    • GET /btc/utxo/{address}: fetch UTXO set for an address

Permit2 Tokens

For origin tokens where /chains reports isPermit2: true:

  • submit payload options.signature is still required

  • submit payload options must include permit2

  • permit2 requires r, s, v, deadline

  • mode=light is not supported for Permit2 tokens

What is an HTLC lock?

In BTC-origin flows, funds are first sent to an HTLC address. This creates an on-chain lock with a timeout.

  • Before timeout: funds are handled according to the HTLC conditions.

  • After timeout: the lock can be reclaimed according to HTLC rules.

In Kima, that BTC lock transaction is recorded via /btc/htlc/record, and the returned HTLC metadata is attached to /submit/transfer or /submit/swap.

Expected timing model for BTC-origin flow

Timing is confirmation-based and variable.

  • BTC confirmation threshold is chain-parameter driven (default BTC confirmation blocks: 6).

  • Observer validation waits until the required number of confirmations is reached.

  • Observer hash collection and processing run on a periodic cadence (about every 5 seconds).

Because mempool, block production, and validator consensus timings vary, this flow should be treated as variable-time (no fixed minute SLA).

Optional Features

Custom Transaction Validation

In /src/custom-transaction-validation.ts you can add your own custom validation logic. Kima does not know the requirements of your app, so it is up to you to make sure the transaction makes sense. This is a convenience function, feel free to modify the middleware if you need lower level access.

The customTransValidation function

  • Will be called in middleware after basic param validation and before the /submit/transfer or /submit/swap route handler is called

  • Should return a string with the error message or the empty string if the transaction is valid.

The following are some example of things you may want to check:

  • When accepting cross chain payment for goods and services

    • Ensure the targetAddress is your app's payment address

    • Check the chains are supported by your app

Chain Filtering

Chain filtering is an optional feature that can be enabled by setting the KIMA_CHAIN_FILTER environment variable. This will:

  • Filter the chains returned by the /chains endpoint and therefore the options listed in the React component

  • Restricts the allowed chains for /submit/transfer and /submit/swap, causing a 400 error if the chain is not allowed

It supports two modes:

  • whitelist: Only chains in the whitelist will be returned.

  • blacklist: Only chains not in the blacklist will be returned.

This is a JSON object with the following structure:

  • origin: Filter for the origin chain

    • mode: The mode to use. Can be whitelist or blacklist

    • chains: An array of chain short names to filter

  • target: Filter for the target chain

    • mode: The mode to use. Can be whitelist or blacklist

    • chains: An array of chain short names to filter

FIAT rails note:

  • Request-level origin chain values can be CC and BANK.

  • Backend normalizes CC and BANK to FIAT before submitting to Kima Chain via kima-transaction-api.

  • If you want to block FIAT-origin flows robustly, include CC and BANK in your origin filter.

Example: only ARB and OPT chains are allowed for the origin and all chains except TRX are allowed for the target:

Example filtering out FIAT-origin rails (CC / BANK / normalized FIAT):

The stringified version:

Compliance

If enabled by supplying the COMPLIANCE_URL environment variable, use GET /compliant/enabled to check whether compliance is active, and GET /compliant to check whether an address meets compliance requirements.

Use this in the frontend to check if an address is not compliant BEFORE the authorization step. When compliance is enabled, /submit/transfer and /submit/swap return status 403 (Forbidden) for non-compliant addresses.

If you are interested in using compliance, contact us at [email protected]envelope for more information and the URL to use here.

KYC

If using the KYC in the widget:

  • GET /uuid will return the external identifier you need

  • POST /kyc returns the KYC status for a specific uuid verification session

Again, please contact us for more information on how to implement this feature.

Last updated