<!-- Source: https://docs.paxeer.app/sdk-quickstarts/ -->

# SDK quickstarts

Register a principal, fund an account, send a payment, and independently verify receipts with the Paxeer X SDKs.

## Register, fund, send, verify

Choose a public principal flow or a human payment journey before selecting a client. `agent.register` registers an agent with the daemon; `lx_register` creates the public principal binding. They serve different workflows. Fund through an authenticated faucet claim and submit signed canonical activities with a scoped LayerX key.

## Rust

Use the typed `RpcClient` for registration, funding requests, and canonical activity submission. Sign the binding digest returned by `register::binding` before calling register. Funding requires the identity session authorization on the gateway request.

### Registration binding

```
use layerx_sdk::register::{binding, TENANT};
use layerx_sdk::rpc::RpcClient;

fn register(rpc: &RpcClient, public_key: [u8; 32], signature: &[u8; 64])
    -> Result<layerx_sdk::register::Registration, layerx_sdk::rpc::RpcError>
{
    let _digest = binding(TENANT, &public_key);
    rpc.register(public_key, signature)
}
```

### Authenticated funding

```
use layerx_sdk::rpc::{FaucetGrant, RpcClient, RpcError};

fn request_funds(rpc: &RpcClient, did: &str, public_key: &[u8; 32])
    -> Result<FaucetGrant, RpcError>
{
    rpc.request_funds(did, public_key)
}
```

### Client and payment example

```
use layerx_sdk::rpc::{Commitment, RpcClient, RpcError};

fn send(rpc: &RpcClient, canonical: &[u8]) -> Result<serde_json::Value, RpcError> {
    rpc.send_activity(canonical, Commitment::Executed)
}
```

### Client and payment example

```
use layerx_sdk::production::SecretBytes;
use layerx_sdk::programs::LayerXKeyCredential;
use layerx_sdk::rpc::RpcClient;

fn connect(endpoint: &str, key_id: &str, secret: &[u8]) -> Result<RpcClient, layerx_sdk::rpc::RpcError> {
    let secret = SecretBytes::new(secret).map_err(|_| layerx_sdk::rpc::RpcError::InvalidRequest)?;
    let credential = LayerXKeyCredential::new(key_id, secret).map_err(layerx_sdk::rpc::RpcError::Configuration)?;
    RpcClient::connect(endpoint, Some(credential))
}
```

### Local receipt verification

```
use layerx_proof::receipt::AuthorizedBatch;
use layerx_sdk::production::verify_receipt;

fn verify(
    receipt: &[u8],
    batch_id: [u8; 32],
    asset: [u8; 32],
    previous_state_root: [u8; 32],
    resulting_state_root: [u8; 32],
    sequencer_public_key: [u8; 32],
) -> Result<layerx_proof::receipt::VerifiedReceipt, layerx_sdk::production::ReceiptVerificationFailure> {
    let authorised = AuthorizedBatch::new(
        batch_id,
        asset,
        previous_state_root,
        resulting_state_root,
        sequencer_public_key,
    );
    verify_receipt(receipt, &authorised)
}
```

## TypeScript

Use `JsonRpcClient` for native submission and reads. Use public JSON-RPC for registration and faucet methods; `ProductionClient` provides human and agent operation interfaces with an appropriate transport.

### Client and payment example

```
import { JsonRpcClient, LayerXKeyCredential, SecretBytes } from "@sidiora/layerx-sdk";
import type { Commitment } from "@sidiora/layerx-sdk";

export function openRpc(endpoint: string, keyId: string, secret: Uint8Array): JsonRpcClient {
  return new JsonRpcClient(endpoint, new LayerXKeyCredential(keyId, new SecretBytes(secret)));
}

export function send(
  rpc: JsonRpcClient,
  canonical: Uint8Array,
  commitment: Commitment = "executed",
): Promise<Record<string, unknown>> {
  return rpc.sendActivity(canonical, commitment);
}
```

### Client and payment example

```
import { ProductionClient, SecretBytes, idempotencyKey } from "@sidiora/layerx-sdk";

export async function pay(
  layerx: ProductionClient,
  source: string,
  destination: string,
  money: { amount: string; currency: string },
  paymentKey: string,
) {
  const quote = await layerx.human("move.quote", { source, destination, money });
  return layerx.human("move.commit", { quote_id: quote.quote_id }, { idempotencyKey: idempotencyKey(paymentKey) });
}
```

### Local receipt verification

```
import { verifyReceipt } from "@sidiora/layerx-sdk";
import type { AuthorizedReceiptBatch, ReceiptVerification } from "@sidiora/layerx-sdk";

export function verify(
  canonicalReceipt: Uint8Array,
  authorized: AuthorizedReceiptBatch,
): Promise<ReceiptVerification> {
  return verifyReceipt(canonicalReceipt, authorized);
}
```

## Python

`PaymentRpc.call` sends public method names directly. Registration uses lowercase hexadecimal key and signature values. Faucet calls use a Bearer identity session; signed activity calls use the LayerX-Key header.

### Public registration

```
from layerx_sdk import PaymentRpc

def register(rpc: PaymentRpc, signer_public_key: str, registration_signature: str) -> dict:
    return rpc.call("lx_register", [signer_public_key, registration_signature])
```

### Authenticated funding

```
from layerx_sdk import PaymentRpc

def request_funds(endpoint: str, session_token: str, did: str, signer_public_key: str) -> dict:
    rpc = PaymentRpc(endpoint, {"Authorization": f"Bearer {session_token}"})
    return rpc.call("lx_requestFunds", [did, signer_public_key])
```

### Client and payment example

```
from layerx_sdk import PaymentRpc

def send(rpc: PaymentRpc, canonical_hex: str, commitment: str = "executed") -> dict:
    return rpc.send(canonical_hex, commitment)
```

### Client and payment example

```
from layerx_sdk import IdempotencyKey, ProductionClient

def pay(layerx: ProductionClient, source, destination, money, payment_key):
    quote = layerx.human("move.quote", {"source": source, "destination": destination, "money": money})
    return layerx.human("move.commit", {"quote_id": quote["quote_id"]}, idempotency_key=IdempotencyKey(payment_key))
```

### Local receipt verification

```
from layerx_sdk import (
    AuthorizedReceiptBatch,
    LocalSignatureVerifier,
    ReceiptVerification,
    verify_receipt,
)

def verify(
    canonical_receipt: bytes,
    authorized_batch: AuthorizedReceiptBatch,
    signatures: LocalSignatureVerifier,
) -> ReceiptVerification:
    return verify_receipt(canonical_receipt, authorized_batch, signatures)
```

## Go

Use `NewHumanHTTPTransport` and `Client.Human` for a quote followed by an idempotent commit. Agent catalog operations require an agent-plane transport.

### Client and payment example

```
package main

import (
	"context"
	"net/http"

	layerx "github.com/Sidiora-Labs/LayerX-Network/platform/sdk/go"
)

type Money struct {
	Amount   string `json:"amount"`
	Currency string `json:"currency"`
}

type MoveQuoteRequest struct {
	Source      string `json:"source"`
	Destination string `json:"destination"`
	Money       Money  `json:"money"`
}

type MoveQuote struct {
	QuoteID string `json:"quote_id"`
}

type MoveCommitRequest struct {
	QuoteID string `json:"quote_id"`
}

type Journey struct {
	JourneyID string `json:"journey_id"`
	State     string `json:"state"`
}

func pay(ctx context.Context, apiURL, apiToken, source, destination, paymentKey string, money Money) (Journey, error) {
	authorize := func(request *http.Request) error {
		request.Header.Set("Authorization", "Bearer "+apiToken)
		return nil
	}
	transport, err := layerx.NewHumanHTTPTransport(apiURL, nil, authorize)
	if err != nil {
		return Journey{}, err
	}
	client, err := layerx.NewClient(transport, nil)
	if err != nil {
		return Journey{}, err
	}
	key, err := layerx.NewIdempotencyKey(paymentKey)
	if err != nil {
		return Journey{}, err
	}
	var quote MoveQuote
	if err := client.Human(ctx, layerx.HumanOperationMoveQuote, MoveQuoteRequest{Source: source, Destination: destination, Money: money}, &quote, layerx.CallOptions{}); err != nil {
		return Journey{}, err
	}
	var journey Journey
	if err := client.Human(ctx, layerx.HumanOperationMoveCommit, MoveCommitRequest{QuoteID: quote.QuoteID}, &journey, layerx.CallOptions{IdempotencyKey: key}); err != nil {
		return Journey{}, err
	}
	return journey, nil
}
```

### Local receipt verification

```
package main

import layerx "github.com/Sidiora-Labs/LayerX-Network/platform/sdk/go"

func verify(canonicalReceipt []byte, authorized layerx.AuthorizedBatch) (layerx.VerifiedReceipt, error) {
	return layerx.VerifyReceipt(canonicalReceipt, authorized)
}
```

## JVM

Configure `HttpProductionTransport` with the human origin and the agent origin. Human payments use `ProductionClient.human` and typed options.

### Client and payment example

```
import com.fasterxml.jackson.databind.JsonNode;
import com.sidiora.layerx.sdk.HttpProductionTransport;
import com.sidiora.layerx.sdk.IdempotencyKey;
import com.sidiora.layerx.sdk.ProductionClient;
import com.sidiora.layerx.sdk.SecretBytes;
import java.net.URI;
import java.nio.charset.StandardCharsets;
import java.util.Map;

public final class Pay {
    public static JsonNode pay(
        String apiUrl,
        String apiToken,
        String source,
        String destination,
        Map<String, String> money,
        String paymentKey
    ) {
        var credential = new HttpProductionTransport.BearerCredential(
            new SecretBytes(apiToken.getBytes(StandardCharsets.UTF_8)));
        var layerx = new ProductionClient(
            HttpProductionTransport.create(URI.create(apiUrl), URI.create(apiUrl), credential));
        var quote = layerx.human(
            "move.quote",
            Map.of("source", source, "destination", destination, "money", money),
            JsonNode.class,
            ProductionClient.Options.none()).toCompletableFuture().join();
        return layerx.human(
            "move.commit",
            Map.of("quote_id", quote.path("quote_id").asText()),
            JsonNode.class,
            ProductionClient.Options.idempotent(new IdempotencyKey(paymentKey)))
            .toCompletableFuture().join();
    }

    private Pay() {}
}
```

### Local receipt verification

```
import com.sidiora.layerx.sdk.verify.LocalVerifier;
import com.sidiora.layerx.sdk.verify.LocalVerifier.AuthorizedReceiptBatch;
import com.sidiora.layerx.sdk.verify.LocalVerifier.ReceiptVerification;

public final class Verify {
    public static ReceiptVerification verify(byte[] canonicalReceipt, AuthorizedReceiptBatch authorized) {
        return LocalVerifier.verifyReceipt(canonicalReceipt, authorized);
    }

    private Verify() {}
}
```

## Swift

Use `PlatformClient` with `HumanHTTPTransport` for a payment quote and commit. Access tokens and idempotency keys use dedicated types.

### Client and payment example

```
import Foundation
import LayerXSDK

func pay(
    serviceURL: URL,
    apiToken: String,
    source: String,
    destination: String,
    money: JSONValue,
    paymentKey: IdempotencyKey
) async throws -> JSONValue {
    let token = try AccessToken(Data(apiToken.utf8))
    let layerx = PlatformClient(transport: try HumanHTTPTransport(baseURL: serviceURL, accessToken: token))
    let quote = try await layerx.humanMoveQuote(.object([
        "source": .string(source),
        "destination": .string(destination),
        "money": money,
    ]))
    guard let quoteID = quote.objectValue?["quote_id"]?.stringValue else {
        throw PlatformSDKError(code: .invalidArgument, retry: .never)
    }
    return try await layerx.humanMoveCommit(.object(["quote_id": .string(quoteID)]), idempotencyKey: paymentKey)
}
```

### Local receipt verification

```
import Foundation
import LayerXSDK

func verify(canonicalReceipt: Data, authorized: AuthorizedReceiptBatch) async throws -> ReceiptVerification {
    try await LocalVerifier.verifyReceipt(canonicalReceipt, authorized: authorized)
}
```

## .NET

Use `PlatformClient` with `HumanHttpTransport`, `AccessToken`, and `IdempotencyKey` for the human payment flow.

### Client and payment example

```
using System.Text;
using LayerX.Sdk;

static async Task<JsonValue> Pay(
    Uri apiUrl,
    string apiToken,
    string source,
    string destination,
    JsonValue money,
    string paymentKey)
{
    using var token = new AccessToken(Encoding.UTF8.GetBytes(apiToken));
    var layerx = new PlatformClient(new HumanHttpTransport(apiUrl, accessToken: token));
    var quote = await layerx.HumanMoveQuoteAsync(JsonValue.Object(new Dictionary<string, JsonValue>
    {
        ["source"] = JsonValue.String(source),
        ["destination"] = JsonValue.String(destination),
        ["money"] = money,
    }));
    IReadOnlyDictionary<string, JsonValue> fields = quote is JsonValue.ObjectValue record
        ? record.Value
        : new Dictionary<string, JsonValue>();
    string quoteId = fields.TryGetValue("quote_id", out var found) && found is JsonValue.StringValue text
        ? text.Value
        : string.Empty;
    return await layerx.HumanMoveCommitAsync(
        JsonValue.Object(new Dictionary<string, JsonValue> { ["quote_id"] = JsonValue.String(quoteId) }),
        new IdempotencyKey(paymentKey));
}
```

### Local receipt verification

```
using LayerX.Sdk;

static ValueTask<ReceiptVerification> Verify(
    ReadOnlyMemory<byte> canonicalReceipt,
    AuthorizedReceiptBatch authorized) =>
    LocalVerifier.VerifyReceiptAsync(canonicalReceipt, authorized);
```

## Trust the batch authorization

Every local receipt verifier takes five independently trusted 32-byte batch facts: batch ID, asset identity, previous state root, resulting state root, and sequencer public key. Supplying these from the same untrusted response as the receipt does not establish independent trust. Python also takes a caller-provided signature verifier implementing Ed25519 and recoverable secp256k1 verification.

Success-only verification refuses a nonzero result code. Use the outcome-verification entry point when inspecting a refused execution. Treat `executed`, `batched`, and `finalised` as distinct commitments.

## Programs terminal evidence

A Programs CALL receipt commits to one runtime terminal. Verify the receipt outcome first, then hash the terminal payload and call graph against their receipt commitments. Terminal kinds distinguish success (1), failure (2), and resource exhaustion (3).

Encoding 4 carries applied transfer legs. Each canonical leaf is 115 bytes; the verifier bounds the list at 256 legs, checks canonical nonzero fields and the applied-legs digest, and reconstructs the transfer Merkle root. Truncated payloads, trailing bytes, mutated amounts, and mismatched roots are refused.

| SDK | Terminal verification entry point |
| --- | --- |
| Python | `decode_and_verify_program_terminal` |
| TypeScript | `decodeAndVerifyProgramTerminal` |
| Go | `verifyProgramTerminal` |
| JVM | `ProgramsClient.verifyTerminal` |
| Swift | `verifyTerminal` |
| .NET | `ProgramsClient.VerifyTerminal` |

Transfer evidence reports `reconstructed` when the terminal locally rebuilds the transfer root. Historical receipts can report `recorded_terminal_root_not_locally_reconstructable`; preserve that distinction in application output. Protocol 3 occupancy verification proves payer DID account derivations against the settlement and refuses a paid occupancy charge without a proven payment account.

Continue with [XDK API families](https://docs.paxeer.app/xdk), [Programs](https://docs.paxeer.app/programs), and [MCP tools](https://docs.paxeer.app/mcp).
