Skip to content

Devnet only: test USDC, not real money.

Docs menuGrant access

Your server

Grant access

Unlock what a customer paid for only after your server has checked with SolLoop. The browser can be lied to; the API can't.

The flow

  1. Your page listens for solloop:connected to learn the customer's wallet, and for solloop:subscribed to know when to ask.
  2. It sends the wallet address to your server, alongside your own user.
  3. Your server looks the wallet up in SolLoop's API, with your secret API key.
  4. If it has an active subscription to the right plan, your server links the wallet to the user and grants access.

In the page

in the page
const widget = document.querySelector('solloop-subscribe');

widget.addEventListener('solloop:connected', (event) => {
  // The customer's wallet address. Keep it: your server checks it next.
  wallet = event.detail.address;
});

widget.addEventListener('solloop:subscribed', async () => {
  // A hint for your UI, not proof of payment. Ask your server to check.
  await fetch('/api/solloop/claim', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ wallet }),
  });
});

On your server

Create an API key under Developers in the dashboard and keep it on your server. It is shown once.

on your server
// On your server. SOLLOOP_API_KEY is an sk_test_ or sk_live_ key: never
// send it to a browser.
export async function hasAccess(wallet, planId) {
  const response = await fetch(
    `https://api.solloop.app/v1/subscribers/${wallet}`,
    { headers: { Authorization: `Bearer ${process.env.SOLLOOP_API_KEY}` } },
  );
  if (response.status === 404) return false;
  if (!response.ok) throw new Error(`SolLoop API answered ${response.status}`);

  const subscriber = await response.json();
  // "cancelling" has cancelled but paid through the end of the period.
  return (
    subscriber.planId === planId &&
    (subscriber.status === 'active' || subscriber.status === 'cancelling')
  );
}

GET /v1/subscribers/:address returns the wallet's most recent subscription to any of your plans, so check planId as well as status. The subscription is recorded within seconds of the widget's solloop:subscribed. If you get a 404 straight after it, try again after a moment.

Which statuses get access

StatusAccessWhy
activeYesPaying every period.
cancellingYesPaid up to the end of the current period.
expiredNoThe subscription ended.
invalidatedNoThe customer revoked it from their wallet.

Keeping access in step with payment

Checking once at sign-up isn't enough for a subscription that renews. Either check again when access matters (for example, when a session starts), or let webhooks tell you: extend access on payment.confirmed and remove it on subscription.expired.