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
- Your page listens for
solloop:connectedto learn the customer's wallet, and forsolloop:subscribedto know when to ask. - It sends the wallet address to your server, alongside your own user.
- Your server looks the wallet up in SolLoop's API, with your secret API key.
- If it has an active subscription to the right plan, your server links the wallet to the user and grants access.
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. 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
| Status | Access | Why |
|---|---|---|
| active | Yes | Paying every period. |
| cancelling | Yes | Paid up to the end of the current period. |
| expired | No | The subscription ended. |
| invalidated | No | The 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.