Skip to content

Sandbox

Two ways to test, and they answer different questions.

Keys are prefixed by mode. sk_test_ never touches mainnet.

const jorvi = new Jorvi(process.env.JORVI_SECRET_KEY!); // sk_test_...

Test mode gives you two helpers that do not exist in live mode.

Fund a wallet so a payer has something to pay with:

await jorvi.test.fund({ owner: payerWalletAddress, mint: usdcMintAddress, amount: '10000000' });

Move time forward, which is the one that matters for recurring payments. A monthly mandate is otherwise untestable without waiting a month:

await jorvi.test.advance(2592000); // 30 days

That is how you exercise the second charge, the third, a retry after a failure, and the point where a mandate completes, in a few seconds rather than a quarter.

Test mode tells you whether your integration is right. It cannot tell you whether the on-chain behaviour is right, because the interesting rules live in the Solana program, not in the API.

A dockerised local validator runs the real Subscriptions and Allowances program on your machine, with no network and no faucet.

That is what lets you test the paths that matter and are otherwise hard to reach:

  • a charge that exceeds the per-period cap, which the chain rejects
  • an authorization the payer has revoked, after which every charge fails
  • terms that do not match what was signed

Each of those fails on-chain. The cap is not enforced by our backend, so a mock of our backend cannot tell you the truth about any of them.

  1. A first charge succeeds and the webhook signature verifies.
  2. A retried request with the same idempotency key does not create a second charge.
  3. A charge above the cap fails, and your code handles the failure rather than assuming success.
  4. A revoked mandate fails every subsequent charge.
  5. A refund returns to the payer, and one exceeding the received amount is rejected.