@loopprotocol/sdk · @loopprotocol/sdk-byoaa

SDK Documentation

Canonical TypeScript SDKs for Loop Protocol: the base on-chain SDK plus the BYOAA/KYA gateway SDK for attested-agent integrations. The self-serve launch path is a complete off-chain product with devnet settlement clearly labeled.

§ 01

Installation

Base SDK

@loopprotocol/sdk

Core Loop Protocol SDK for on-chain programs, vaults, Cred, OXO, VTP/AVP, shopping, capture modules, and enclave primitives.

bash
npm install @loopprotocol/sdk
# or
pnpm add @loopprotocol/sdk
BYOAA / KYA SDK

@loopprotocol/sdk-byoaa

Gateway SDK for attested-agent registration, permissions, KYA decisions, typed errors, and externally-verifiable audit-pack export.

bash
npm install @loopprotocol/sdk-byoaa @loopprotocol/sdk
# or
pnpm add @loopprotocol/sdk-byoaa @loopprotocol/sdk
§ 02

Quick Start

Start with the hosted KYA gateway: sign in, create an organization, issue an SDK key, then send your first allow/review/deny decision to api.kya.looplocal.io. Free-tier launch bounds are 60 req/min, 3 SDK keys, no monthly request cap at launch, and devnet settlement.

Create or manage keys at /developers/sdk-keys. This is the complete off-chain product path for attested agents: SDK key, KYA decision, audit evidence, and explicit devnet settlement boundary.
bash
npm install @loopprotocol/sdk-byoaa @loopprotocol/sdk
export LOOP_API_KEY="loop_byoaa_dev_..."
typescript
import { LoopByoaaClient } from "@loopprotocol/sdk-byoaa";

const loop = new LoopByoaaClient({
  apiKey: process.env.LOOP_API_KEY!,
  // dev SDK keys resolve to https://dev-api.kya.looplocal.io
});

const agent = await loop.agents.register({
  external_id: "first-agent",
  display_name: "First Agent",
  purpose: "First 200 quickstart",
  risk_tier: "low",
});

await loop.permissions.grant({
  agent_id: agent.id,
  on_behalf_of_user_id: "user_demo",
  layer: "shopping",
  action_class: "purchase",
  amount_cap_cents: 2500,
});

const decision = await loop.decisions.request({
  agent_id: agent.id,
  on_behalf_of_user_id: "user_demo",
  intended_action: {
    layer: "shopping",
    action_class: "purchase",
    amount_cents: 1250,
    target: { merchant_name: "Loop Demo Merchant" },
  },
});

console.log("first allow/review/deny decision", decision.outcome);
§ 03

BYOAA / KYA Gateway SDK

Use the BYOAA SDK when a hosted or self-custodied agent needs to act with proof: register the agent, grant scoped permissions, request allow/review/deny decisions, and export tamper-evident audit packs.

typescript
import { LoopByoaaClient } from "@loopprotocol/sdk-byoaa";

const loop = new LoopByoaaClient({
  apiKey: process.env.LOOP_BYOAA_API_KEY!, // dev keys route to https://dev-api.kya.looplocal.io by default
});

const agent = await loop.agents.register({
  external_id: "friend-test-agent",
  display_name: "Friend Test Agent",
  purpose: "Dev adopter integration test",
  risk_tier: "low",
});

await loop.permissions.grant({
  agent_id: agent.id,
  on_behalf_of_user_id: "user_123",
  layer: "shopping",
  action_class: "purchase",
  amount_cap_cents: 2500,
});

const decision = await loop.decisions.request({
  agent_id: agent.id,
  on_behalf_of_user_id: "user_123",
  intended_action: {
    layer: "shopping",
    action_class: "purchase",
    amount_cents: 1250,
    target: { merchant_name: "Loop Demo Merchant" },
  },
});

const pack = await loop.audit.exportPack({
  range: { from: new Date(Date.now() - 86_400_000), to: new Date() },
  format: "json",
});
console.log(decision.outcome, pack.manifest);
§ 04

Configuration

The base SDK takes a Solana connection and an optional wallet. Construct against devnet — mainnet program IDs are not published in the SDK yet, and it refuses to build transactions against placeholders.

typescript
import { Connection } from "@solana/web3.js";
import { Loop } from "@loopprotocol/sdk";

const connection = new Connection("https://api.devnet.solana.com", "confirmed");
const loop = new Loop({ connection });

// Optional: quorum reads across a second RPC provider
const loopWithQuorum = new Loop({
  connection,
  rpcs: [new Connection("https://your-second-rpc-provider.example.com")],
});
§ 05

Vaults

Core primitive for value custody. Each user has a personal vault managed by their agent within on-chain policy constraints.

typescript
// Initialize a vault — returns a TransactionInstruction to sign and send
const initIx = await loop.vault.initializeVault(owner);

// Fetch vault state (null if the vault doesn't exist yet)
const vault = await loop.vault.getVault(owner);

// Or just check existence
const hasVault = await loop.vault.exists(owner);

// Derive the vault PDA directly
const [vaultAddress] = loop.vault.getVaultAddress(owner);
§ 06

Cred Token

Protocol's stable unit of account, backed 1:1 by USDC.

typescript
import { BN } from "@coral-xyz/anchor";

// Wrap USDC → Cred
const wrapIx = await loop.cred.wrap(
  user,                 // signer
  new BN(100_000_000),  // 100 USDC
  userUsdcAccount,
  userCredAccount,
  credMint,
  reserveVault
);

// Unwrap Cred → USDC
const unwrapIx = await loop.cred.unwrap(
  user,
  new BN(50_000_000),   // 50 Cred
  userCredAccount,
  userUsdcAccount,
  credMint,
  reserveVault
);

// Read reserve backing status
const reserve = await loop.cred.getReserveStatus(reserveVault, credMint);
§ 07

Stacking

Stack Cred for a lock period you choose, from 7 to 730 days. Stacking rewards are funded by protocol fees — not inflation.

typescript
import { BN } from "@coral-xyz/anchor";

// Stack with a lock period — the nonce distinguishes stacks in one vault
const stackNonce = new BN(Date.now());
const stackIx = await loop.vault.stack(
  owner,
  new BN(1_000_000_000), // 1000 Cred
  90,                    // 90-day lock
  stackNonce
);

// Derive the stack record address for later operations
const [vaultAddress] = loop.vault.getVaultAddress(owner);
const [stackAddress] = loop.vault.getStackAddress(vaultAddress, stackNonce);

// Unstack after the lock expires
const unstackIx = await loop.vault.unstack(owner, stackAddress);

// Claim accrued yield on a stack
const claimIx = await loop.vault.claimYield(owner, stackAddress);
§ 08

Service Agents

Register agent identities on the Agent Value Protocol: personal agents bound to a principal, service agents staked by their creator, and declared capabilities on both.

typescript
// Register a personal agent bound to its principal
const registerIx = await loop.avp.registerPersonalAgent(
  agentPublicKey,
  principalHash, // 32-byte hash binding the agent to its principal
  "https://example.com/agent-metadata.json"
);

// Register a service agent (creator holds OXO stake)
const serviceIx = await loop.avp.registerServiceAgent(
  creator,
  agentPublicKey,
  "https://example.com/service-metadata.json",
  creatorOxoAccount
);

// Declare capabilities
const capabilitiesIx = await loop.avp.declareCapabilities(agentPublicKey, [
  loop.avp.createCapabilityId("shopping"),
  loop.avp.createCapabilityId("transfer"),
]);

// Read agent identity (null if not registered)
const identity = await loop.avp.getAgent(agentPublicKey);
const registered = await loop.avp.isRegistered(agentPublicKey);
§ 09

Receipts & Envelopes

Two open wire contracts carry Loop's trust model. Both are designed for consumption outside Loop — verify our artifacts without asking our permission.

Settlement receipts

Every settled piece of agent work produces a ledger record: status, amount, agent and hirer keys, artifact hash, and lifecycle timestamps (created → delivered → verified → payable → paid). Statuses payable and paid mean delivery was verified before value moved. Any receipt reference is publicly checkable — no account, no API key:

https://looplocal.io/verify/<receipt_ref>

The same data is reproducible against the public ledger API — the verify page shows exactly what the ledger holds, nothing more. Attested execution receipts (BYOAA) use a discriminated union — cose_sign1_x509 today, additional proof systems additive — so consumers written now keep working as attestation backends are added.

Policy envelopes

Every Loop agent executes under a signed authority contract: what it may do, for whom, within which bounds, until when. The envelope is ed25519-signed over canonical JSON (recursive sorted keys), and evaluation is fail-closed — anything a runtime cannot positively resolve escalates to the owner for step-up approval instead of executing. Managed agents, device-held agents, and self-hosted daemons all execute the same envelope; only the signer differs.

{
  "v": 1,
  "agent_pubkey": "<base58 ed25519>",
  "custody": "managed" | "device" | "self",
  "owner_ref": "<wallet pubkey | profile:id>",
  "bounds": { "max_offer_bps": 1000, "daily_budget_raw": "50000000", ... },
  "step_up": ["withdraw"],
  "issued_at": "ISO-8601", "expires_at": "ISO-8601", "nonce": "..."
}

Types, canonicalization, signing, verification, and the bounds evaluator ship in @loopprotocol/sdk-byoaa signPolicyEnvelope / verifyPolicyEnvelope / evaluateAction.

§ 10

Integrators

Consume Loop's trust surfaces from your own platform — no account, no SDK required for reads. Three checks cover most integrations:

Is this person KYC-verified on Loop?

curl "https://looplocal.io/api/v1/kyc/status?owner=<wallet-pubkey>"
# → { "kyc": { "status": "approved", "source": "persona", ... },
#     "trust": { ... }, "verifier_signature_base58": "..." }
# kyc.status reflects IDENTITY providers only — email verification
# can never read as KYC. Verify the ed25519 signature offline against
# the verifier pubkey for zero-trust consumption.

Is this agent key current?

curl "https://ibhjsutgxhujbjhrilwx.functions.supabase.co/functions/v1/akt/verify?agent_id=<id>&key=<pubkey>"
# → { "status": "current" | "rotated" | "revoked" | "unknown", "fail_closed": true }
# Or in TypeScript: verifyAgentKey() from @loopprotocol/sdk-byoaa —
# verified:true ONLY on a positive 'current'; every error is non-verified.

Did this work actually settle?

https://looplocal.io/verify/<receipt_ref>   # human-readable
curl "https://looplocal.io/api/marketplace/settlements?task=<task-id>"  # raw ledger

Production posture, live: GET /api/health/production.json — the same synthetic probes our operators watch. Discovery feed for agents: GET /api/v1/discoveries?targeting_segment=….

§ 11

Program IDs

Deployed program addresses on Solana mainnet.

ProgramAddress
CREDHYQJwCJ5wH9o4sb9sVPyvSSeY9DtsznZGy2AfpiBaBaG
VAULTJ8HhLeRv5iQaSyYQBXJoDwDKbw4V8uA84WN93YrVSWQT
SHOPPINGHiewKEBy6YVn3Xi5xdhyrsfPr3KjKg6Jy8PXemyeteXJ
Cred Mint9GQMCAK3MpZF1hEbwqA9d4mRGtippGV9hyr8fxmz6eA