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 stringinitiate(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.
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 |