Skip to main content
GET
/
api
/
billing
/
subscription
curl -X GET https://www.wiseyield.co/api/billing/subscription \
  -H "Authorization: Bearer wy_YOUR_API_KEY"
{
  "subscription": {
    "id": "sub_abc123",
    "userId": "user_xyz789",
    "subscriptionId": "sub_1234567890",
    "customerId": "cus_9876543210",
    "priceId": "price_harvest_monthly",
    "plan": "harvest",
    "status": "active",
    "currentPeriodStart": "2025-11-01T00:00:00.000Z",
    "currentPeriodEnd": "2025-12-01T00:00:00.000Z",
    "cancelAtPeriodEnd": false,
    "createdAt": "2025-10-01T10:00:00.000Z",
    "updatedAt": "2025-11-01T00:00:00.000Z"
  }
}

Documentation Index

Fetch the complete documentation index at: https://docs.wiseyield.co/llms.txt

Use this file to discover all available pages before exploring further.

Endpoint

GET https://www.wiseyield.co/api/billing/subscription

Authentication

Requires a valid API key with billing:read scope.

Response

Returns the user’s subscription object or null if no subscription exists.
subscription
object | null
curl -X GET https://www.wiseyield.co/api/billing/subscription \
  -H "Authorization: Bearer wy_YOUR_API_KEY"
{
  "subscription": {
    "id": "sub_abc123",
    "userId": "user_xyz789",
    "subscriptionId": "sub_1234567890",
    "customerId": "cus_9876543210",
    "priceId": "price_harvest_monthly",
    "plan": "harvest",
    "status": "active",
    "currentPeriodStart": "2025-11-01T00:00:00.000Z",
    "currentPeriodEnd": "2025-12-01T00:00:00.000Z",
    "cancelAtPeriodEnd": false,
    "createdAt": "2025-10-01T10:00:00.000Z",
    "updatedAt": "2025-11-01T00:00:00.000Z"
  }
}

Errors

401
error
Unauthorized - Missing or invalid API key
500
error
Internal Server Error - Failed to fetch subscription

Subscription Plans

5 Plan Tiers with different feature limits:

Seed (€22/month)

  • 1 farm
  • 50 AI requests/month
  • 30 chat messages/month
  • Basic analytics
  • Email support

Sprout (€49/month)

  • 3 farms
  • 200 AI requests/month
  • 100 chat messages/month
  • Team collaboration (5 members)
  • Farm budgeting
  • 7 farms
  • 500 AI requests/month
  • 300 chat messages/month
  • Vision AI Full (50 scans/mo)
  • Market Intelligence (20 queries/mo)
  • Task templates

Grove (€149/month)

  • 15 farms
  • 1,000 AI requests/month
  • 1,000 chat messages/month
  • Financial AI Insights
  • P&L reports, invoices
  • Priority support

Summit (€299+/month)

  • Unlimited farms
  • Unlimited AI requests
  • Unlimited chat messages
  • API access
  • Dedicated support
  • SLA guarantee

Subscription Statuses

Use Cases

Check Subscription Status

async function getSubscriptionStatus() {
  const response = await fetch('/api/billing/subscription', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  const { subscription } = await response.json();

  if (!subscription) {
    return { hasSubscription: false, plan: 'expired' };
  }

  return {
    hasSubscription: true,
    plan: subscription.plan,
    status: subscription.status,
    isActive: subscription.status === 'active',
    renewsAt: subscription.currentPeriodEnd
  };
}

// Usage
const status = await getSubscriptionStatus();
if (!status.hasSubscription) {
  showUpgradePrompt();
}

Check Feature Access

async function canAccessFeature(feature) {
  const response = await fetch('/api/billing/subscription', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  const { subscription } = await response.json();
  const plan = subscription?.plan || 'expired';

  const features = {
    expired: ['basic_analytics'],
    seed: ['basic_analytics', 'single_farm'],
    sprout: ['basic_analytics', 'multiple_farms', 'export', 'farm_budgeting'],
    harvest: ['advanced_analytics', 'vision_ai', 'market_intelligence', 'task_templates'],
    grove: ['advanced_analytics', 'financial_ai', 'pnl_reports', 'invoices'],
    summit: ['advanced_analytics', 'api_access', 'dedicated_support', 'sla']
  };

  return features[plan]?.includes(feature) || false;
}

// Usage
if (await canAccessFeature('advanced_analytics')) {
  showAdvancedAnalytics();
}

Check Renewal Date

async function getDaysUntilRenewal() {
  const response = await fetch('/api/billing/subscription', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  const { subscription } = await response.json();

  if (!subscription) return null;

  const renewDate = new Date(subscription.currentPeriodEnd);
  const now = new Date();
  const daysRemaining = Math.ceil((renewDate - now) / (1000 * 60 * 60 * 24));

  return {
    renewDate,
    daysRemaining,
    willCancel: subscription.cancelAtPeriodEnd
  };
}

Check Payment Status

async function isPaymentHealthy() {
  const response = await fetch('/api/billing/subscription', {
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });

  const { subscription } = await response.json();

  if (!subscription) return true; // No subscription (expired)

  const healthyStatuses = ['active', 'trialing'];
  return healthyStatuses.includes(subscription.status);
}

// Usage
const healthy = await isPaymentHealthy();
if (!healthy) {
  showPaymentWarning();
}

Best Practices

Cache Subscription Data: Cache subscription status locally and refresh periodically to reduce API calls.
Handle Null Gracefully: subscription: null means no active subscription (expired). Don’t treat it as an error.
Check Before Paid Features: Always verify subscription status before showing paid features.
Show Renewal Dates: Display currentPeriodEnd to users so they know when they’ll be charged.
Past Due Status: Subscriptions with status: "past_due" still have access but payment failed. Prompt user to update payment method.
Cancel At Period End: If cancelAtPeriodEnd: true, subscription will end at currentPeriodEnd. Show this clearly to user.

Integration Examples

Subscription Status Card

function SubscriptionStatusCard() {
  const [subscription, setSubscription] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function loadSubscription() {
      try {
        const response = await fetch('/api/billing/subscription', {
          headers: { 'Authorization': `Bearer ${apiKey}` }
        });

        const { subscription } = await response.json();
        setSubscription(subscription);
      } finally {
        setLoading(false);
      }
    }

    loadSubscription();
  }, []);

  if (loading) return <div>Loading...</div>;

  const plan = subscription?.plan || 'expired';
  const status = subscription?.status || 'active';

  return (
    <div className="subscription-card">
      <h2>Current Plan</h2>
      <PlanBadge plan={plan} />
      <StatusBadge status={status} />

      {subscription && (
        <>
          <p>Renews: {new Date(subscription.currentPeriodEnd).toLocaleDateString()}</p>

          {subscription.cancelAtPeriodEnd && (
            <div className="warning">
              Your subscription will end on {new Date(subscription.currentPeriodEnd).toLocaleDateString()}
            </div>
          )}

          {status === 'past_due' && (
            <div className="error">
              Payment failed. Please update your payment method.
            </div>
          )}
        </>
      )}

      {!subscription && (
        <button onClick={() => router.push('/pricing')}>
          Upgrade Plan
        </button>
      )}
    </div>
  );
}

Feature Gate Component

function FeatureGate({ feature, plan, children, fallback }) {
  const [hasAccess, setHasAccess] = useState(false);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function checkAccess() {
      try {
        const response = await fetch('/api/billing/subscription', {
          headers: { 'Authorization': `Bearer ${apiKey}` }
        });

        const { subscription } = await response.json();
        const userPlan = subscription?.plan || 'expired';

        const planHierarchy = ['expired', 'seed', 'sprout', 'harvest', 'grove', 'summit'];
        const requiredIndex = planHierarchy.indexOf(plan);
        const userIndex = planHierarchy.indexOf(userPlan);

        setHasAccess(userIndex >= requiredIndex);
      } finally {
        setLoading(false);
      }
    }

    checkAccess();
  }, [plan]);

  if (loading) return <div>Loading...</div>;

  return hasAccess ? children : (fallback || <UpgradePrompt requiredPlan={plan} />);
}

// Usage
<FeatureGate feature="advanced_analytics" plan="grove">
  <AdvancedAnalyticsDashboard />
</FeatureGate>

Plan Comparison Hook

function useSubscription() {
  const [subscription, setSubscription] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchSubscription() {
      try {
        const response = await fetch('/api/billing/subscription', {
          headers: { 'Authorization': `Bearer ${apiKey}` }
        });

        const { subscription } = await response.json();
        setSubscription(subscription);
      } finally {
        setLoading(false);
      }
    }

    fetchSubscription();
  }, []);

  const plan = subscription?.plan || 'expired';

  return {
    subscription,
    loading,
    plan,
    isPro: ['harvest', 'grove', 'summit'].includes(plan),
    isEnterprise: plan === 'summit',
    hasAccess: (requiredPlan) => {
      const hierarchy = ['expired', 'seed', 'sprout', 'harvest', 'grove', 'summit'];
      return hierarchy.indexOf(plan) >= hierarchy.indexOf(requiredPlan);
    }
  };
}

// Usage in component
function Dashboard() {
  const { plan, isPro, hasAccess } = useSubscription();

  return (
    <div>
      <h1>Dashboard - {plan} Plan</h1>

      {hasAccess('grove') && <AdvancedFeatures />}
      {isPro && <PrioritySupport />}
    </div>
  );
}