> For the complete documentation index, see [llms.txt](https://docs.blockz.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.blockz.fi/api/submit-intent/approvals/signing-an-intent-for-bitcoin.md).

# Signing an Intent for Bitcoin

On Bitcoin, intent approval is performed by **signing a PSBT (Partially Signed Bitcoin Transaction)** that authorizes an HTLC deposit.

Blockz generates the transaction based on the accepted quote and intent parameters. The user signs only the inputs they control while preserving any existing partial signatures. The signed PSBT is then submitted as the approval for the intent.

Funds remain under user control until execution, and the resolver can only execute the swap according to the parameters defined in the authorized transaction.

#### PSBT Signing Process

The signing procedure typically consists of the following steps:

1. Parse the Base64-encoded PSBT into a structured PSBT object.
2. Decode the private key from its serialized format (for example, hex) into a usable signing key.
3. Iterate over the input indices that require signing.
4. For each input, retrieve the referenced UTXO data from the PSBT (amount, script, and Taproot-related fields if applicable).
5. Compute the appropriate signature hash and produce a Taproot (Schnorr) witness signature.
6. Insert the generated signatures into the corresponding PSBT input fields without modifying other transaction data.
7. Serialize the updated PSBT back into Base64 format for submission.

***

#### Script to sign a PSBT with HotPot Golang SDK

```go
package main

import (
	"fmt"
	"log"

	"github.com/BoostyLabs/hotpot-sdk-go/crypto/bitcoin"
	"github.com/BoostyLabs/hotpot-sdk-go/types"
)

func main() {
	var (
		signerPrivateKeyHex = os.Getenv("PRIVATE_KEY")

		// NOTE: mocking crateIntent response since psbt and inputs are part of it.
		approvalToSign = types.ApprovalToSign{
			ApprovalMechanism: types.ApprovalToSignTypeHtlc,
			Htlc: &types.ApprovalToSignHtlc{
				Psbt:   "your-psbt-base64", // Replace with your base64-encoded PSBT.
				Inputs: []int{0, 1, 2},     // Indices of the inputs you need to sign.
			},
		}
	)

	// 1. Initialize the signer
	signer, err := bitcoin.NewSigner(signerPrivateKeyHex)
	if err != nil {
		log.Fatalf("failed to create signer: %v", err)
	}

	// 2. Sign the deposit transaction
	signedPsbtBase64, err := bitcoin.SignDepositTx(signer, approvalToSign.Htlc.Psbt, approvalToSign.Htlc.Inputs)
	if err != nil {
		log.Fatalf("failed to sign deposit tx: %v", err)
	}

	// 3. Use the signed PSBT as an approval.
	// NOTE: signedPsbtBase64 should be provided back to the protocol via `add-approval` api call.
	fmt.Println("Signed PSBT Base64:", signedPsbtBase64)
	intentApproval = types.NewHtlcIntentApproval(signedPsbtBase64)
	// Propagate approval to the HotPot API and fetch the status.
}
```

***

#### Signing with TypeScript

Most Bitcoin wallets expose a `signPsbt` method that performs the necessary cryptographic operations internally.

Using **Sats Connect**, a wallet can sign a Base64-encoded PSBT for the inputs controlled by the user and return a signed PSBT ready to be submitted as the approval.

```ts
import { request, RpcErrorCode } from "sats-connect";

/**
 * Signs a Base64 PSBT (or with another Sats Connect compatible wallet).
 *
 * @param psbtBase64 Base64-encoded PSBT from the HotPot API response
 * @param signInputs Map: address -> input indexes to sign, from the HotPot API response
 * @returns signed PSBT (Base64)
 */
export async function signPsbt(
  psbtBase64: string,
  signInputs: Record<string, number[]>
): Promise<string> {
  const response = await request("signPsbt", {
    psbt: psbtBase64,
    signInputs,
    broadcast: false,
  });

  if (response.status === "success") {
    // The wallet returns the signed PSBT (still Base64).
    return response.result.psbt;
  }

  throw new Error(`PSBT signing failed: ${response.error.message ?? "Unknown error"}`);
}
```

Note: The signed PSBT Base64 should be provided back to the protocol (for example via the `add-approval` API call) as the approval.
