BetalingenAbonnementen

Abonnementsplan

Een abonnementsplan stelt een handelaar in staat factureringsvoorwaarden te publiceren die gebruikers kunnen accepteren. Nadat een gebruiker zich heeft geabonneerd, kan de handelaar of een goedgekeurde puller tot het planbedrag per factureringsperiode innen.

Deze handleiding toont de volledige flow als bouwstenen. De handelaar creëert een plan, de abonnee accepteert het, en de handelaar of puller int betalingen van de resulterende abonnements-PDA.

Installeren

pnpm add @solana/subscriptions @solana/kit @solana/kit-plugin-rpc @solana/kit-plugin-signer @solana-program/token

Een Plan Creëren

De handelaar is eigenaar van het plan. De plan-PDA wordt afgeleid van het handelaarsadres en planId.

import { address, createClient } from '@solana/kit';
import { solanaLocalRpc } from '@solana/kit-plugin-rpc';
import { signer } from '@solana/kit-plugin-signer';
import { findPlanPda, subscriptionsProgram } from '@solana/subscriptions';
const merchantClient = createClient()
.use(signer(merchantSigner))
.use(solanaLocalRpc({ rpcUrl: 'http://127.0.0.1:8899' }))
.use(subscriptionsProgram());
const planId = 1n;
const tokenMint = address('TOKEN_MINT_ADDRESS_HERE');
const amount = 5_000_000n;
const periodHours = 720n;
const metadataUri = 'https://example.com/plan.json';
const destinations = [merchantSigner.address];
const pullers = [address('PULLER_WALLET_ADDRESS_HERE')];
await merchantClient.subscriptions.instructions
.createPlan({
planId,
mint: tokenMint,
amount,
periodHours,
endTs: 0n,
destinations,
pullers,
metadataUri,
})
.sendTransaction();
const [planPda] = await findPlanPda({
owner: merchantSigner.address,
planId,
});

Een Plan Bijwerken

De handelaar kan muteerbare planvelden bijwerken na aanmaak. Bestaande abonnees behouden de voorwaarden die zij hebben geaccepteerd, terwijl nieuwe abonnees de huidige planvoorwaarden accepteren.

Een aantal regels zijn van toepassing:

  • Een eindige endTs kan alleen worden ingekort, nooit verlengd of gewist (PlanEndTsCannotExtend).
  • Bij een Sunset plan kun je pullers verwijderen (de nieuwe set moet een subset zijn van de huidige) om een gecompromitteerde puller in te trekken; status, endTs en metadata blijven bevroren.
  • Wijzigingen werken tijdens de laatste factureringsperiode van een plan, zolang endTs ongewijzigd blijft.
import { PlanStatus } from '@solana/subscriptions';
const updatedMetadataUri = 'https://example.com/updated-plan.json';
const updatedPullers = [address('NEW_PULLER_WALLET_ADDRESS_HERE')];
await merchantClient.subscriptions.instructions
.updatePlan({
owner: merchantSigner,
planPda,
status: PlanStatus.Active,
endTs: 0n,
pullers: updatedPullers,
metadataUri: updatedMetadataUri,
})
.sendTransaction();

Abonneren

De abonnee accepteert de huidige planvoorwaarden. De abonnements-PDA wordt afgeleid van de plan-PDA en het adres van de abonnee.

import { createClient } from '@solana/kit';
import { solanaLocalRpc } from '@solana/kit-plugin-rpc';
import { signer } from '@solana/kit-plugin-signer';
import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS } from '@solana-program/token';
import {
fetchMaybeSubscriptionAuthority,
findSubscriptionAuthorityPda,
findSubscriptionDelegationPda,
subscriptionsProgram,
} from '@solana/subscriptions';
const subscriberClient = createClient()
.use(signer(subscriberSigner))
.use(solanaLocalRpc({ rpcUrl: 'http://127.0.0.1:8899' }))
.use(subscriptionsProgram());
const [subscriberAta] = await findAssociatedTokenPda({
mint: tokenMint,
owner: subscriberSigner.address,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
});
const [subscriptionAuthorityPda] = await findSubscriptionAuthorityPda({
user: subscriberSigner.address,
tokenMint,
});
const subscriptionAuthority = await fetchMaybeSubscriptionAuthority(
subscriberClient.rpc,
subscriptionAuthorityPda,
);
if (!subscriptionAuthority.exists) {
await subscriberClient.subscriptions.instructions
.initSubscriptionAuthority({
tokenMint,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
userAta: subscriberAta,
})
.sendTransaction();
}
await subscriberClient.subscriptions.instructions
.subscribe({
merchant: merchantSigner.address,
planId,
tokenMint,
})
.sendTransaction();
const [subscriptionPda] = await findSubscriptionDelegationPda({
planPda,
subscriber: subscriberSigner.address,
});

Een Betaling Innen

De merchant of een gewhitelistte puller ondertekent de inning. Wanneer het plan gebruikmaakt van een bestemming-allowlist, moet de eigenaar van de ontvanger token account worden vermeld in destinations.

const receiverAta = address('MERCHANT_TOKEN_ACCOUNT_ADDRESS_HERE');
await merchantClient.subscriptions.instructions
.transferSubscription({
caller: merchantOrPullerSigner,
delegator: subscriberSigner.address,
tokenMint,
subscriptionPda,
planPda,
amount: 200_000n,
receiverAta,
tokenProgram: TOKEN_PROGRAM_ADDRESS,
})
.sendTransaction();

Annuleren en Intrekken

Annuleren markeert het abonnement als eindigend. Intrekken sluit de abonnements- PDA nadat de annuleringstermijn is verstreken. De abonnee ondertekent beide transacties.

await subscriberClient.subscriptions.instructions
.cancelSubscription({
subscriber: subscriberSigner,
planPda,
subscriptionPda,
})
.sendTransaction();
// Run this after the cancelled subscription's expiresAtTs has elapsed.
await subscriberClient.subscriptions.instructions
.revokeSubscription({
authority: subscriberSigner,
planPda,
subscriptionPda,
})
.sendTransaction();

Een Abonnement Hervatten

Een geannuleerd abonnement kan opnieuw worden geactiveerd voordat het wordt ingetrokken. Zodra het is ingetrokken, wordt het abonnementsaccount gesloten en moet de abonnee opnieuw abonneren. Hervatten vereist het SubscriptionAuthority van de abonnee voor de mint van het plan, dat het programma valideert (eigenaar, mint en init_id) en afwijst als het verouderd of opnieuw geïnitialiseerd is.

await subscriberClient.subscriptions.instructions
.resumeSubscription({
subscriber: subscriberSigner,
planPda,
tokenMint,
})
.sendTransaction();

Opmerkingen

  • amount is in basiseenheden. Voor een token met 6 decimalen betekent 5_000_000 5 tokens.
  • De TypeScript SDK haalt live plantermijnen op tijdens subscribe wanneer u deze weglaat.
  • De Rust SubscribeBuilder heeft de verwachte plantermijnen nodig. Haal het planaccount op en decodeer het eerst, geef die velden vervolgens door via SubscribeData.
  • Alleen de handelaar of een wallet vermeld in pullers kan betalingen innen.
  • De abonnee ondertekent setup-, annulerings- en intrekkingstransacties. De handelaar of goedgekeurde puller ondertekent incassotransacties.

Is this page helpful?

Inhoudsopgave

Pagina Bewerken
© 2026 Solana Foundation. Alle rechten voorbehouden.