Skip to content

Hooks

For full control over the UI, use hooks directly. Each hook manages its own loading/error state and returns an async function you call when ready.

useTributarySDK

Returns an initialized Tributary SDK instance (or null if the wallet isn't connected). All other payment hooks depend on this internally — use it when you need raw SDK access.

import { useTributarySDK } from "@tributary-so/sdk-react";

function MyComponent() {
  const sdk = useTributarySDK();

  if (!sdk) return <p>Connect your wallet</p>;

  // Use sdk.createSubscription(), sdk.createMilestone(), etc. directly
  const policies = await sdk.getUserPolicies(wallet.publicKey);
}

Returns: Tributary | null


useCreateSubscription

Creates a subscription policy. Handles instruction building, transaction signing, and on-chain confirmation.

import {
  useCreateSubscription,
  PaymentInterval,
} from "@tributary-so/sdk-react";
import { PublicKey, BN } from "@solana/web3.js";

function SubscribeForm() {
  const { createSubscription, loading, error } = useCreateSubscription();

  const handleSubscribe = async () => {
    const result = await createSubscription({
      amount: new BN(10_000_000), // 10 USDC
      token: new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"),
      recipient: new PublicKey("RECIPIENT_WALLET"),
      gateway: new PublicKey("CwNybLVQ3sVmcZ3Q1veS6x99gUZcAF2duNDe3qbcEMGr"),
      interval: PaymentInterval.Monthly,
      memo: "Pro plan",
      executeImmediately: true,
    });

    console.log("Subscription created:", result.txId);
  };

  return (
    <button onClick={handleSubscribe} disabled={loading}>
      {loading ? "Creating..." : "Subscribe $10/mo"}
    </button>
  );
}

Parameters: CreateSubscriptionParams

Field Type Required Description
amount BN Yes Amount per cycle
token PublicKey Yes Token mint
recipient PublicKey Yes Recipient wallet
gateway PublicKey Yes Gateway address
interval PaymentInterval Yes Billing frequency
custom_interval number No Seconds (required for Custom)
maxRenewals number No Cap on renewals
memo string No On-chain memo
startTime Date No First payment date
approvalAmount BN No Token delegation amount
executeImmediately boolean No Charge first payment now

Returns: { createSubscription, loading, error }


useCreateMilestone

Creates a milestone payment with up to 4 deliverable phases. Each milestone has its own amount and due timestamp.

import { useCreateMilestone } from "@tributary-so/sdk-react";
import { BN } from "@coral-xyz/anchor";

function MilestoneForm() {
  const { createMilestone, loading, error } = useCreateMilestone();

  const handleCreate = async () => {
    const result = await createMilestone({
      milestoneAmounts: [
        new BN(3_000_000),
        new BN(3_000_000),
        new BN(4_000_000),
      ],
      milestoneTimestamps: [
        new BN(Math.floor(Date.now() / 1000) + 86400 * 30),
        new BN(Math.floor(Date.now() / 1000) + 86400 * 60),
        new BN(Math.floor(Date.now() / 1000) + 86400 * 90),
      ],
      releaseCondition: 0, // time-based release
      token: USDC_MINT,
      recipient: RECIPIENT,
      gateway: GATEWAY,
      memo: "Website redesign project",
      executeImmediately: true,
    });

    console.log("Milestones created:", result.txId);
  };

  return (
    <button onClick={handleCreate} disabled={loading}>
      {loading ? "Creating..." : "Start Project"}
    </button>
  );
}

Parameters: CreateMilestoneParams

Field Type Required Description
milestoneAmounts BN[] Yes Amount per milestone (max 4)
milestoneTimestamps BN[] Yes Unix timestamps for each milestone
releaseCondition number Yes 0=time-based, 1=manual, 2=automatic
token PublicKey Yes Token mint
recipient PublicKey Yes Recipient wallet
gateway PublicKey Yes Gateway address
memo string No On-chain memo
approvalAmount BN No Token delegation amount
executeImmediately boolean No Release first milestone now

Returns: { createMilestone, loading, error }


useCreatePayAsYouGo

Creates a pay-as-you-go policy with a spending cap per period. The provider claims incrementally as the user consumes.

import { useCreatePayAsYouGo } from "@tributary-so/sdk-react";
import { BN } from "@coral-xyz/anchor";

function PayGoForm() {
  const { createPayAsYouGo, loading, error } = useCreatePayAsYouGo();

  const handleCreate = async () => {
    const result = await createPayAsYouGo({
      maxAmountPerPeriod: new BN(50_000_000), // 50 USDC per day
      maxChunkAmount: new BN(1_000_000), // Max 1 USDC per claim
      periodLengthSeconds: new BN(86400), // Daily period
      token: USDC_MINT,
      recipient: RECIPIENT,
      gateway: GATEWAY,
      memo: "API usage",
    });

    console.log("Pay-as-you-go created:", result.txId);
  };

  return (
    <button onClick={handleCreate} disabled={loading}>
      {loading ? "Creating..." : "Enable Usage Billing"}
    </button>
  );
}

Parameters: CreatePayAsYouGoParams

Field Type Required Description
maxAmountPerPeriod BN Yes Spending cap per period
maxChunkAmount BN Yes Maximum per individual claim
periodLengthSeconds BN Yes Period duration in seconds
token PublicKey Yes Token mint
recipient PublicKey Yes Recipient wallet
gateway PublicKey Yes Gateway address
memo string No On-chain memo
approvalAmount BN No Token delegation amount

Returns: { createPayAsYouGo, loading, error }


useCheckoutSession

Generates checkout URLs or redirects users to the hosted Tributary checkout page. Works for both one-time payments and subscriptions. No wallet connection required — the checkout page handles that.

import { useCheckoutSession } from "@tributary-so/sdk-react";

function CheckoutButton() {
  const { generateUrl, initiate } = useCheckoutSession(
    "https://checkout.tributary.so"
  );

  const opts = {
    mode: "subscription" as const,
    tokenMint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
    recipient: "YOUR_WALLET_ADDRESS",
    gateway: "CwNybLVQ3sVmcZ3Q1veS6x99gUZcAF2duNDe3qbcEMGr",
    amount: 10, // 10 USDC
    paymentFrequency: "monthly",
    trackingId: "user-pro-plan",
    memo: "Pro subscription",
  };

  return (
    <div>
      <button onClick={() => initiate(opts)}>Pay with Checkout</button>
      <a href={generateUrl(opts)}>Share payment link</a>
    </div>
  );
}

Parameters: CheckoutOptions

Field Type Required Description
mode "payment" \| "subscription" Yes Payment type
tokenMint string Yes Token mint address
recipient string Yes Recipient wallet
gateway string No Gateway address
amount number Yes Payment amount
trackingId string No Your reference ID
successPath string No Redirect path after success
cancelPath string No Redirect path after cancel
paymentFrequency string No Frequency for subscriptions
autoRenew boolean No Auto-renew (default: true)
maxRenewals number \| null No Cap renewals
memo string No Payment memo

Returns: { generateUrl, initiate }

  • generateUrl(opts) — returns a checkout URL string
  • initiate(opts) — redirects the browser to the checkout page

useTributaryToken

Verifies a Tributary JWT token (e.g., from a checkout callback) and decodes its payload. Use this to confirm an active subscription on the client side.

import { useTributaryToken } from "@tributary-so/sdk-react";

function SuccessPage() {
  const { token, payload, loading, error } = useTributaryToken();

  if (loading) return <p>Verifying...</p>;
  if (error) return <p>Verification failed: {error}</p>;
  if (!payload) return <p>No token found</p>;

  return (
    <div>
      <h1>Subscription Active</h1>
      <p>Status: {payload.status}</p>
      <p>Tracking ID: {payload.trackingId}</p>
    </div>
  );
}

The hook reads the token from the URL query parameter ?token= by default. Pass a token string explicitly to override.

const { payload } = useTributaryToken(myJwtToken);

Parameters: token?: string, baseUrl?: string

Returns: { token, payload, loading, error }

Field Type Description
token string \| null Raw JWT string
payload TributaryJWTPayload \| null Decoded and verified payload
loading boolean Verification in progress
error string \| null Verification error message

useActionCode

Integrates with Action Codes for transaction relay via action codes. This enables mobile wallet flows where a user scans a code instead of connecting a browser wallet.

import { useActionCode } from "@tributary-so/sdk-react";

function MobilePay() {
  const {
    actionCode,
    resolvedPubkey,
    resolveActionCode,
    clearActionCode,
    submitTransaction,
  } = useActionCode();

  const handleScan = async (code: string) => {
    const result = await resolveActionCode(code);
    if (result.success) {
      console.log("Resolved wallet:", result.pubkey.toString());
    }
  };

  const handlePay = async () => {
    const { txSig } = await submitTransaction({
      amount: new BN(10_000_000),
      token: USDC_MINT,
      gateway: GATEWAY,
      interval: PaymentInterval.Monthly,
      executeImmediately: true,
    });
    console.log("Paid:", txSig);
  };

  return <button onClick={() => handleScan("...")}>Scan & Pay</button>;
}

Returns: { actionCode, resolvedPubkey, resolveActionCode, clearActionCode, submitTransaction }

Field Type Description
actionCode string \| null Current action code
resolvedPubkey PublicKey \| null Resolved wallet from the code
resolveActionCode (code: string) => Promise<{success, pubkey?}> Resolve an action code to a pubkey
clearActionCode () => void Reset state
submitTransaction (params) => Promise<{ txSig: string }> Build, sign, and relay a subscription