SDK.DEVFRIDGE.COOL

SDK

Subscription gating via on-chain timelocks

The DevFridge SDK lets any site gate access behind a Fridge timelock. Instead of recurring payments, users lock your project’s token on devfridge.cool. As long as qualifying locks meet the required duration and amount, and remain above the renewal threshold, the subscription is valid.

When remaining days drop below the threshold (e.g. 29 days for a monthly plan), the user must create a new lock. Longer locks = fewer renewals, incentivizing long-term commitment and reducing sell pressure.

How it works

  1. Developer configures plans with minLockDays, renewalThresholdDays, and optionally minLockAmount.
  2. User connects wallet and locks tokens on devfridge.cool.
  3. SDK fetches all on-chain locks via scan.devfridge.cool/api/sdk/check, filters locks that individually meet minLockDays, sums their amounts, and checks against minLockAmount.
  4. active is true only when qualifying locks satisfy both duration and amount requirements. daysRemaining and needsRenewal are computed from the best qualifying lock, not the global best lock.
  5. When daysRemaining <= renewalThresholdDays, the SDK flags needsRenewal: true and provides a renewal URL.
  6. Users who lock for longer periods skip multiple renewal cycles entirely.

Example: monthly plan

ConfigValue
minLockDays60
renewalThresholdDays29
Active subscription windowDay 60 → Day 30 (31 days of access)
Renewal triggered at≤ 29 days remaining
User locks for 180 days?Active for 151 days before renewal prompt

Quick start

1. Add the script

<script src="https://sdk.devfridge.cool/sdk/devfridge-sdk.js"></script>

Or install via npm / import:

// ESM import from your bundle
import { DevFridgeSDK } from "https://sdk.devfridge.cool/sdk/devfridge-sdk.js";

2. Configure plans

const fridge = new DevFridgeSDK({
  tokenMint: "YOUR_TOKEN_MINT_ADDRESS",
  plans: {
    basic:   { minLockDays: 14, renewalThresholdDays: 7 },
    pro:     { minLockDays: 60, renewalThresholdDays: 29, minLockAmount: 10_000_000_000_000 },
    //                                                     ↑ 10M tokens × 10^6 decimals
  }
});

3. Check subscription

const status = await fridge.checkSubscription(walletAddress);

if (status.active && !status.needsRenewal) {
  // Full access
  showContent();
} else if (status.active && status.needsRenewal) {
  // Access granted but prompt renewal
  showContent();
  showRenewalBanner(status.renewalUrl);
} else {
  // No active lock — gate access
  showPaywall(fridge.getLockUrl(60));
}

Configuration

new DevFridgeSDK({
  // Required
  tokenMint: string,       // Your token's SPL mint address
  plans: {                 // At least one plan
    [name: string]: {
      minLockDays: number,          // Minimum lock duration to qualify
      renewalThresholdDays: number, // When to flag needsRenewal
      minLockAmount?: number,       // Minimum token amount to qualify (raw units)
    }
  },

  // Optional
  scannerUrl: string,  // Default: "https://scan.devfridge.cool"
  fridgeUrl: string,   // Default: "https://devfridge.cool"
  cacheTTL: number,    // Response cache in ms (default: 60000)
})

Plan guidelines

Plan typeSuggested minLockDaysSuggested renewalThresholdDaysminLockAmount
Weekly147optional
Monthly6029optional
Quarterly12029optional
Annual40029optional

renewalThresholdDays must be strictly less than minLockDays. minLockAmount is optional — when set, the SDK sums amounts only from locks whose individual duration ≥ minLockDays, then checks the sum against minLockAmount (in raw token units, i.e. with decimals applied). Short-duration locks never contribute to the qualifying amount, preventing gaming via a small long lock combined with a large short lock.

API reference

checkSubscription(walletAddress)

Returns a Promise resolving to:

{
  active: boolean,          // true only if qualifying locks meet duration AND amount
  plan: string | null,      // Matched plan name, or null if none qualifies
  daysRemaining: number,    // Days until best *qualifying* lock expires
  needsRenewal: boolean,    // true when active AND daysRemaining <= threshold
  renewalUrl: string | null,// URL to devfridge.cool (when renewal needed or not active)
  totalLockAmount: number,  // Sum of qualifying lock amounts (duration-filtered)
  wallet: string,           // The checked wallet
  locks: Lock[],            // All locks (active + expired)
  activeLocks: Lock[],      // Only active locks
  bestLock: Lock | null,    // Lock with furthest unlockAt (global, unfiltered)
}

getLockUrl(days?)

Returns a URL to devfridge.cool pre-filled with the token mint. Pass days to suggest a lock duration.

getScanUrl()

Returns the scan page URL: scan.devfridge.cool/t/<mint>

getBadgeUrl(opts?)

Returns the badge image URL. Options: theme ("dark" | "light"), style ("full" | "compact").

getBadgeHtml(opts?)

Returns an <a><img> HTML string linking to the scan page with a live badge image. Embed directly into your page.

startPolling(walletAddress, callback, intervalMs?)

Polls subscription status every intervalMs (default 60s). Calls callback(status) only when the status changes. Returns a stop() function.

REST API

The SDK calls this endpoint. You can also call it directly for server-side checks.

GET https://scan.devfridge.cool/api/sdk/check?wallet=<WALLET>&mint=<MINT>

Response:

{
  "wallet": "...",
  "mint": "...",
  "locks": [...],           // All locks for this wallet+mint
  "activeLocks": [...],     // Only locks with unlockAt > now
  "bestLock": { ... },      // Lock with furthest unlockAt
  "daysRemaining": 45,      // Days until bestLock expires
  "ts": 1724234567          // Server unix timestamp
}

CORS is enabled (access-control-allow-origin: *). Rate limit: 100 requests/minute per IP.

Badge integration

Show real-time lock status on your site with the Fridge badge:

// Get embeddable HTML
const html = fridge.getBadgeHtml({ theme: "dark", style: "compact" });
document.getElementById("badge-container").innerHTML = html;

// Or use the URL directly
const url = fridge.getBadgeUrl({ theme: "light", style: "full" });
// → https://scan.devfridge.cool/api/badge?mint=...&theme=light&style=full

The badge updates automatically (60s cache). It shows FRIDGED, EXPIRED, or OPEN status, the locked amount, and unlock time.

Full examples

Vanilla JavaScript

<!DOCTYPE html>
<html>
<head>
  <script src="https://sdk.devfridge.cool/sdk/devfridge-sdk.js"></script>
</head>
<body>
  <div id="app">Connect wallet to continue</div>
  <div id="badge"></div>

  <script>
    const fridge = new DevFridgeSDK({
      tokenMint: "YOUR_MINT_HERE",
      plans: {
        monthly: {
          minLockDays: 60,
          renewalThresholdDays: 29,
          minLockAmount: 10_000_000_000_000, // optional: 10M tokens × 10^6
        }
      }
    });

    // Show badge
    document.getElementById("badge").innerHTML =
      fridge.getBadgeHtml({ theme: "dark" });

    async function onWalletConnect(walletAddress) {
      const status = await fridge.checkSubscription(walletAddress);

      if (!status.active) {
        document.getElementById("app").innerHTML =
          '<h2>Lock tokens to subscribe</h2>' +
          '<p>Lock for at least 60 days to get monthly access.</p>' +
          '<a href="' + fridge.getLockUrl(60) + '">Lock on DevFridge</a>';
        return;
      }

      if (status.needsRenewal) {
        document.getElementById("app").innerHTML =
          '<h2>Welcome back!</h2>' +
          '<p>Your ' + status.plan + ' plan has ' +
          status.daysRemaining + ' days left.</p>' +
          '<p>Please <a href="' + status.renewalUrl +
          '">renew your lock</a> to maintain access.</p>' +
          '<div id="content"><!-- premium content --></div>';
        return;
      }

      document.getElementById("app").innerHTML =
        '<h2>Welcome!</h2>' +
        '<p>Plan: ' + status.plan + ' &mdash; ' +
        status.daysRemaining + ' days remaining</p>' +
        '<div id="content"><!-- premium content --></div>';
    }
  </script>
</body>
</html>

React

import { useEffect, useState } from "react";
import { DevFridgeSDK } from "https://sdk.devfridge.cool/sdk/devfridge-sdk.js";

const fridge = new DevFridgeSDK({
  tokenMint: "YOUR_MINT_HERE",
  plans: {
    weekly:  { minLockDays: 14, renewalThresholdDays: 7 },
    monthly: { minLockDays: 60, renewalThresholdDays: 29, minLockAmount: 10_000_000_000_000 },
  }
});

function useSubscription(walletAddress) {
  const [status, setStatus] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!walletAddress) return;
    setLoading(true);
    const stop = fridge.startPolling(walletAddress, (s) => {
      setStatus(s);
      setLoading(false);
    });
    return stop;
  }, [walletAddress]);

  return { status, loading };
}

function App({ walletAddress }) {
  const { status, loading } = useSubscription(walletAddress);

  if (loading) return <p>Checking subscription...</p>;
  if (!status || !status.active) {
    return (
      <div>
        <h2>Subscribe</h2>
        <p>Lock tokens for at least 60 days to access this site.</p>
        <a href={fridge.getLockUrl(60)}>Lock on DevFridge</a>
        <div dangerouslySetInnerHTML={{
          __html: fridge.getBadgeHtml()
        }} />
      </div>
    );
  }

  return (
    <div>
      {status.needsRenewal && (
        <div className="renewal-banner">
          {status.daysRemaining} days left.
          <a href={status.renewalUrl}>Renew lock</a>
        </div>
      )}
      <h2>Premium content</h2>
      <p>Plan: {status.plan} — {status.daysRemaining} days remaining</p>
      {/* Your gated content here */}
    </div>
  );
}

Server-side check (Node.js)

// Server-side subscription verification
async function verifySubscription(wallet, mint, {
  minDays = 60,
  threshold = 29,
  minAmount = 0,     // raw token units (e.g. 10_000_000_000_000 for 10M × 10^6)
} = {}) {
  const res = await fetch(
    `https://scan.devfridge.cool/api/sdk/check?wallet=${wallet}&mint=${mint}`
  );
  const data = await res.json();
  const now = data.ts;

  // Filter locks that individually meet the duration requirement
  const qualifying = (data.activeLocks || []).filter((l) => {
    const duration = Math.floor((l.unlockAt - l.createdAt) / 86400);
    return duration >= minDays;
  });

  if (qualifying.length === 0) {
    return { valid: false, reason: "no_qualifying_lock" };
  }

  // Sum amounts only from qualifying locks
  const totalAmount = qualifying.reduce((s, l) => s + Number(l.amount), 0);
  if (minAmount > 0 && totalAmount < minAmount) {
    return { valid: false, reason: "amount_too_low", totalAmount };
  }

  // daysRemaining from the best qualifying lock
  const bestUnlock = Math.max(...qualifying.map((l) => l.unlockAt));
  const daysRemaining = Math.floor((bestUnlock - now) / 86400);
  if (daysRemaining <= 0) {
    return { valid: false, reason: "expired" };
  }

  return {
    valid: true,
    daysRemaining,
    totalAmount,
    needsRenewal: daysRemaining <= threshold,
  };
}

AI integration prompts

Copy-paste these prompts to your AI assistant (Claude, ChatGPT, etc.) to integrate DevFridge subscription gating into your project.

Prompt 1 — Basic setup

Integrate DevFridge SDK subscription gating into my site.

SDK script: https://sdk.devfridge.cool/sdk/devfridge-sdk.js
API docs: https://sdk.devfridge.cool

My token mint: [PASTE YOUR MINT HERE]

I want a monthly plan:
- minLockDays: 60 (user must lock for at least 60 days)
- renewalThresholdDays: 29 (prompt renewal at 29 days remaining)
- minLockAmount: 10_000_000_000_000 (optional: require at least 10M tokens × 10^6 decimals)

The SDK only counts locks whose individual duration >= minLockDays toward the
qualifying amount. Short locks never contribute.

Steps:
1. Add the SDK script tag to my HTML
2. After wallet connect, call fridge.checkSubscription(walletAddress)
3. If status.active && !status.needsRenewal → show content
4. If status.active && status.needsRenewal → show content + renewal banner with status.renewalUrl
5. If !status.active → show paywall with link to fridge.getLockUrl(60)
6. Add the Fridge badge with fridge.getBadgeHtml() so users can see lock status

Prompt 2 — React integration

Add DevFridge subscription gating to my React app.

SDK: https://sdk.devfridge.cool/sdk/devfridge-sdk.js
Token mint: [PASTE YOUR MINT HERE]

Create a useSubscription(walletAddress) hook that:
1. Instantiates DevFridgeSDK with my token mint and plans
2. Uses fridge.startPolling() in a useEffect to get real-time status
3. Returns { status, loading }

Create a <SubscriptionGate> component that:
- Shows a loading spinner while checking
- If not subscribed: shows a paywall with a link to fridge.getLockUrl()
- If subscribed but needs renewal: shows content + a renewal banner
- If subscribed: shows the children (gated content)
- Always shows the Fridge badge via fridge.getBadgeHtml()

Plans config:
  weekly:  { minLockDays: 14, renewalThresholdDays: 7 }
  monthly: { minLockDays: 60, renewalThresholdDays: 29, minLockAmount: 10_000_000_000_000 }

Note: the SDK sums only locks whose individual duration >= minLockDays.
status.totalLockAmount reflects the qualifying amount, not the total.

Prompt 3 — Server-side verification

Add server-side DevFridge subscription verification to my API.

Endpoint to call: GET https://scan.devfridge.cool/api/sdk/check?wallet=WALLET&mint=MINT

For each authenticated request:
1. Get the user's wallet address from their session
2. Call the SDK check endpoint with their wallet and my token mint: [PASTE MINT]
3. Filter activeLocks: keep only locks where (unlockAt - createdAt) / 86400 >= 60
4. Sum amounts of qualifying locks only
5. Verify: qualifying locks exist AND sum >= minLockAmount AND best qualifying unlockAt > now
6. If valid, proceed with the request
7. If not valid, return 403 with a message to lock tokens

IMPORTANT: do NOT use bestLock alone — it may not meet the duration requirement.
Always filter by individual lock duration before summing amounts.

Cache the result for 5 minutes per wallet to avoid excessive API calls.
Never trust client-side subscription checks alone for sensitive operations.

Prompt 4 — Custom plan configuration

Configure DevFridge SDK subscription plans for my project.

SDK docs: https://sdk.devfridge.cool
Token mint: [PASTE YOUR MINT HERE]

I want these subscription tiers:
- [DESCRIBE YOUR TIERS, e.g.:
  "Basic: 2 weeks access, Pro: 1 month access, VIP: 3 months access"]

Rules:
- minLockDays = how long the user must lock tokens (should be roughly
  2x the access period so there's always a buffer before renewal)
- renewalThresholdDays = when to prompt for a new lock
  (must be < minLockDays)
- minLockAmount = optional minimum token amount in raw units
  (e.g. 10_000_000_000_000 for 10M tokens with 6 decimals)
- Only locks whose individual duration >= minLockDays count toward the
  qualifying amount — short locks are excluded
- Longer locks mean the user doesn't need to renew as often
- A 180-day lock on a monthly plan (minLockDays: 60) gives ~151 days
  of access before the renewal prompt at 29 days remaining

Set up the DevFridgeSDK with these plans and create the UI to show
which plan the user qualifies for based on their lock duration and amount.

Key concepts

Why not auto-renew?

Traditional subscriptions require recurring on-chain transactions or off-chain billing infrastructure. With Fridge locks, the user makes one lock transaction. Longer locks automatically extend access without any renewal. A user who locks for 180 days on a monthly plan gets ~5 months of uninterrupted access from a single transaction.

Incentive alignment

Longer locks reduce sell pressure on the token, benefit the community, and give the user fewer renewal steps. The 2% claim fee on unlock also buys and burns $PASTA, adding deflationary pressure.

Security

Locks are enforced by the Fridge on-chain program (9RY54dNPYTzDyh3TfFqDdt2b2KMM56KW1tw9erRTGQo6). Nobody can withdraw before unlock_at, including the depositor. The SDK reads lock state via RPC — there is no centralized database that can be tampered with.

The SDK evaluates each lock individually: only locks whose original duration ≥ minLockDays contribute to the qualifying amount. This prevents gaming via short high-value locks combined with long low-value locks. For sensitive operations, always verify subscription server-side using the REST API rather than trusting client-side checks alone.

Try locking on DevFridge