# Submitting the Transaction

Once the user has prepared approval (non-BTC origin) or HTLC lock data (BTC origin), it’s time to construct the submit request to the Kima Transaction Backend. Use `transactionValues` returned by the `/submit/fees` endpoint.

Again, like for message signing, select the appropriate submit amount based on whether the user is paying fees from the origin or target chain.

* If the user is paying fees from the origin, use `transactionValues.feeFromOrigin.submitAmount`.
* If the user is paying fees from the target, use `transactionValues.feeFromTarget.submitAmount`.

## Submitting the Transaction

`POST /submit/transfer` (or `POST /submit/swap` for swaps)\
Request Body:

* `originAddress` (Address): sending user address
* `originChain` (string): sending chain
* `originSymbol` (string): sending token symbol
* `targetAddress` (Address): receiving user address
* `targetChain` (string): receiving chain
* `targetSymbol` (string): receiving token symbol
* `amount` (bigint string): amount of token received by the target address
* `fee` (bigint string): amount of token that Kima consumes to pay gas fees for pulling & releasing token transactions
* `decimals` (number): the number of decimals for the bigint amounts. This must match the decimals of the token to be transferred. For details please refer to the [Supported Tokens reference](/kima-network/supported-tokens.md)
* `options` (string- JSON stringified object)
  * `chargeFeeAtTarget` (boolean): true if the user should pay fees on the target chain, false otherwise
  * `feeId` (string): the fee id obtained from `/submit/fees`
  * `signature` (string): for non-BTC origin, the signature from the user's wallet from signing the approval message
  * `permit2` (object): additionally required when selected origin token has `isPermit2=true`
    * `r` (string)
    * `s` (string)
    * `v` (number)
    * `deadline` (number)

> ⚠️ FIAT-origin flows are only supported through the Kima widget. This guide documents direct backend usage for crypto-origin and BTC-origin flows only.

### BTC-origin fields (required when `originChain=BTC`)

For non-BTC origin transactions, omit these fields.

| Field                     | Type   | What it is                                                        | Source                                |
| ------------------------- | ------ | ----------------------------------------------------------------- | ------------------------------------- |
| `htlcCreationHash`        | string | BTC tx hash that created the HTLC output                          | `POST /btc/htlc/record` response      |
| `htlcCreationVout`        | number | output index in the lock transaction                              | `POST /btc/htlc/record` response      |
| `htlcExpirationTimestamp` | string | HTLC timeout value                                                | `POST /btc/htlc/record` response      |
| `htlcVersion`             | string | HTLC script version identifier (currently `p2wsh-sha256-cltv-v1`) | `POST /btc/htlc/record` response      |
| `senderPubKey`            | string | sender public key (hex)                                           | `POST /btc/htlc/record` response      |
| `htlcAddress`             | string | HTLC destination address                                          | `POST /btc/htlc/lock-intent` response |
| `htlcAmountSats`          | string | locked BTC amount in sats                                         | selected lock amount (`amountSats`)   |
| `htlcLockId`              | string | backend lock intent id                                            | `POST /btc/htlc/lock-intent` response |

For BTC-origin swap requests (`POST /submit/swap`), use the same HTLC fields above in addition to swap fields (`amountIn`, `amountOut`, `dex`, `slippage`).

See the list of chain short names in the [Supported Assets](/kima-network/supported-assets.md) section.

### Non-BTC origin example (`/submit/transfer`)

```ts
  const txValues = feeFromOrigin
    ? feeData.transactionValues.feeFromOrigin
    : feeData.transactionValues.feeFromTarget

  const response = await fetch(
    `${backendUrl}/submit/transfer`,
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        originAddress,
        originChain,
        targetAddress,
        targetChain,
        originSymbol,
        targetSymbol,
        amount: txValues.submitAmount.value.toString(),
        fee: feeData.feeTotalBigInt.value.toString(),
        decimals: txValues.submitAmount.decimals,
        options: JSON.stringify({
          // For non-BTC origin flows:
          signature,
          // For Permit2 tokens, also send:
          // permit2: { r, s, v, deadline },
          feeId,
          chargeFeeAtTarget: !feeFromOrigin
        })
      })
  )
```

### BTC-origin example (`/submit/transfer`)

```ts
  const txValues = feeFromOrigin
    ? feeData.transactionValues.feeFromOrigin
    : feeData.transactionValues.feeFromTarget

  // Step 1: lock intent
  const lockIntent = await fetch(`${backendUrl}/btc/htlc/lock-intent`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      senderAddress: originAddress,
      senderPubkey: senderPubkeyHex,
      recipientAddress: targetAddress,
      amountSats: lockAmountSats
    })
  }).then((r) => r.json())

  // Step 2: user wallet sends BTC to lockIntent.htlcAddress and returns txid
  const txid = await sendBitcoin(lockIntent.htlcAddress, lockAmountSats)

  // Step 3: record tx and get submit-ready HTLC values
  const record = await fetch(`${backendUrl}/btc/htlc/record`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ lockId: lockIntent.lockId, txid })
  }).then((r) => r.json())

  // Step 4: submit transfer with HTLC context
  const response = await fetch(`${backendUrl}/submit/transfer`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      originAddress,
      originChain: "BTC",
      targetAddress,
      targetChain,
      originSymbol,
      targetSymbol,
      amount: txValues.submitAmount.value.toString(),
      fee: feeData.feeTotalBigInt.value.toString(),
      decimals: txValues.submitAmount.decimals,
      htlcCreationHash: record.htlcCreationHash,
      htlcCreationVout: record.htlcCreationVout,
      htlcExpirationTimestamp: record.htlcExpirationTimestamp,
      htlcVersion: record.htlcVersion,
      senderPubKey: record.senderPubKey,
      htlcAddress: lockIntent.htlcAddress,
      htlcAmountSats: lockAmountSats,
      htlcLockId: lockIntent.lockId,
      options: JSON.stringify({
        feeId,
        chargeFeeAtTarget: !feeFromOrigin
      })
    })
  })
```

Make sure the decimals for the `bigint` amounts are all the same. You may need to convert the value for `feeTotalBigint` to the same decimals as the `submitAmount` before passing it to the backend.

Success Response:

* `height`: number
* `txIndex`: number
* `code`: number: error code; will be zero when successful
* `transactionHash`: string
* `events`: Event\[]
  * `type`: string
  * `attributes`: Attribute\[]
    * `key`: string
    * `value`: string
* `rawLog`?: string
* `data`?: MsgData\[]
* `msgResponses`: Uint8Array
* `gasUsed`: bigint
* `gasWanted`: bigint

### Get Transaction Id

The transaction Id will be needed to fetch the transaction status. The following code can be used to extract the Id from the `submit` response.

```typescript
export function getTransactionId(submitResult: any): number {
  let txId = -1;
  if (submitResult?.code !== 0) {
    return txId;
  }

  for (const event of submitResult.events) {
    if (event.type === "transaction_requested") {
      for (const attr of event.attributes) {
        if (attr.key === "txId") {
          txId = attr.value;
        }
      }
    }
  }

  return txId;
}
```

## Validation

If provided, the Kima Backend will use the url defined in the ENV var `COMPLIANCE_URL` to get the risk score for the origin and target user addresses.

* `403`: one or more addresses failed compliance
* `500`: the compliance check itself failed or another internal error occurred


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.kima.network/kima-network/the-kima-sdk/use-kima-sdk-without-widget/submitting-transaction.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
