Skip to content

SDK Integration Quickstart

Integrate Tributary SDK for programmatic control over recurring payments on Solana.

Choose Your SDK

SDK Best For
@tributary-so/sdk Full protocol control, all payment types
@tributary-so/payments Stripe-compatible checkout, quick integration

Core SDK (@tributary-so/sdk)

Installation

pnpm install @tributary-so/sdk @solana/web3.js @solana/spl-token @coral-xyz/anchor

Setup

import { Tributary } from '@tributary-so/sdk';
import { Connection, PublicKey } from '@solana/web3.js';
import { AnchorProvider, Wallet } from '@coral-xyz/anchor';

const connection = new Connection('https://api.mainnet-beta.solana.com');
const wallet: Wallet = /* your connected wallet */;
const tributary = new Tributary(connection, wallet);

Create Subscription

import { BN } from "@coral-xyz/anchor";
import { PaymentFrequency, createMemoBuffer } from "@tributary-so/sdk";

const tokenMint = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"); // USDC
const recipient = new PublicKey("...");
const gateway = new PublicKey("...");

const instructions = await tributary.createSubscriptionInstruction(
  tokenMint,
  recipient,
  gateway,
  new BN(1000000), // 1 USDC
  true, // autoRenew
  12, // maxRenewals
  { monthly: {} } as PaymentFrequency,
  createMemoBuffer("Monthly subscription", 64),
  undefined, // startTime
  new BN(12000000), // approvalAmount (12 USDC)
  true // executeImmediately
);

const tx = new Transaction().add(...instructions);
const signature = await provider.sendAndConfirm(tx);

Create Milestone Payment

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

const milestoneAmounts = [
  new BN(25000000), // $25 - Planning
  new BN(50000000), // $50 - Development
  new BN(25000000), // $25 - Delivery
];
const milestoneTimestamps = [
  new BN(Math.floor(Date.now() / 1000) + 86400 * 7), // 1 week
  new BN(Math.floor(Date.now() / 1000) + 86400 * 21), // 3 weeks
  new BN(Math.floor(Date.now() / 1000) + 86400 * 35), // 5 weeks
];

const instructions = await tributary.createMilestonePaymentPolicy(
  tokenMint,
  recipient,
  gateway,
  milestoneAmounts,
  milestoneTimestamps,
  0, // Release condition: 0=time-based
  createMemoBuffer("Website project", 64)
);

Create Pay-as-you-go

const maxAmountPerPeriod = new BN(100000000); // $100 per month
const maxChunkAmount = new BN(10000000); // $10 max per claim
const periodLengthSeconds = new BN(86400 * 30); // 30 days

const instructions = await tributary.createPayAsYouGoPaymentPolicy(
  tokenMint,
  recipient,
  gateway,
  maxAmountPerPeriod,
  maxChunkAmount,
  periodLengthSeconds,
  createMemoBuffer("API usage", 64)
);

Execute Payment

const userPaymentPda = tributary.getUserPaymentPda(wallet.publicKey, tokenMint);
const policyPda = tributary.getPaymentPolicyPda(userPaymentPda.address, 1);

const executeInstructions = await tributary.executePayment(
  policyPda.address,
  recipient,
  tokenMint,
  gateway
);

const tx = new Transaction().add(...executeInstructions);
const signature = await provider.sendAndConfirm(tx);

Query Subscriptions

// Get all user payments
const userPayments = await tributary.getAllUserPaymentsByOwner(
  wallet.publicKey
);

// Get policies by user
const policies = await tributary.getPaymentPoliciesByUser(wallet.publicKey);

// Get policies where user is recipient
const receivedPolicies = await tributary.getPaymentPoliciesByRecipient(
  wallet.publicKey
);

// Get specific policy
const policy = await tributary.getPaymentPolicy(policyPda.address);

Manage Policies

// Pause subscription
await tributary.changePaymentPolicyStatus(policyPda.address, { paused: {} });

// Resume subscription
await tributary.changePaymentPolicyStatus(policyPda.address, { active: {} });

// Cancel subscription
await tributary.deletePaymentPolicy(policyPda.address);

Key Methods

Method Description
createSubscriptionInstruction() Create subscription
createMilestonePaymentPolicy() Create milestone payment
createPayAsYouGoPaymentPolicy() Create pay-as-you-go
executePayment() Execute a payment
getAllUserPaymentsByOwner() Get user payments
getPaymentPoliciesByUser() Get user's policies
getPaymentPoliciesByRecipient() Get received payments
changePaymentPolicyStatus() Pause/resume
deletePaymentPolicy() Cancel

Payments SDK (@tributary-so/payments)

Stripe-compatible SDK for quick checkout integration.

Installation

pnpm install @tributary-so/payments @tributary-so/sdk @solana/web3.js

Setup

import { PaymentsClient } from "@tributary-so/payments";
import { Connection } from "@solana/web3.js";
import { Tributary } from "@tributary-so/sdk";

const connection = new Connection("https://api.mainnet-beta.solana.com");
const tributary = new Tributary(connection, wallet);
const stripe = new PaymentsClient(connection, tributary);

Create Checkout Session

const session = await stripe.checkout.sessions.create({
  payment_method_types: ["tributary"],
  line_items: [{ description: "Pro Plan", unitPrice: 10.0, quantity: 1 }],
  paymentFrequency: "monthly",
  mode: "subscription",
  success_url: "https://yourapp.com/success",
  cancel_url: "https://yourapp.com/cancel",
  tributaryConfig: {
    gateway: "GATEWAY_PUBLIC_KEY",
    recipient: "RECIPIENT_PUBLIC_KEY",
    trackingId: "user_123_pro",
    autoRenew: true,
  },
});

// Redirect to checkout
window.location.href = session.url;

Check Subscription Status

const status = await stripe.subscriptions.checkStatus({
  trackingId: "user_123_pro",
  userPublicKey: "USER_PUBLIC_KEY",
  tokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
});

// status.status: "pending" | "created" | "active" | "failed"
// status.paymentCount: number of payments
// status.nextPaymentDue: timestamp

One-Time Payment

const session = await stripe.checkout.sessions.create({
  mode: "payment",
  line_items: [
    { description: "Premium Feature", unitPrice: 50.0, quantity: 1 },
  ],
  tributaryConfig: {
    recipient: "RECIPIENT_PUBLIC_KEY",
    trackingId: "order_12345",
  },
});

// Check status
const status = await stripe.payments.oneTime.checkStatus("order_12345");
// status.status: "pending" | "paid" | "expired"

Quick Active Check

const isActive = await stripe.subscriptions.isActive({
  trackingId: "user_123_pro",
  userPublicKey: "USER_PUBLIC_KEY",
});
// Returns: boolean

Error Handling

try {
  const instructions = await tributary.createSubscriptionInstruction(/*...*/);
  // Process
} catch (error) {
  console.error("Failed:", error);
  // Handle appropriately
}

Important Notes

  • Wallet Connection: Ensure wallet is connected and funded
  • Token Accounts: SDK handles ATA creation automatically
  • Approvals: Use approvalAmount for delegation
  • Network Fees: Account for Solana transaction fees
  • Testing: Use devnet (https://api.devnet.solana.com)

Next Steps