Accept a payment
This is the shortest path from nothing to money arriving in your own wallet. Every request below
is plain HTTP, so it works from any language, from curl, and from an agent that can only make
web requests.
What you need
Section titled “What you need”- A Jorvi server URL. Everything below uses
$JORVI_APIfor it. - A Solana wallet you control, to receive money. Jorvi never holds funds, so payments settle directly from your customer’s wallet to this address.
-
Create an account
You get two API keys back. They are shown once and are not recoverable, because only a hash is stored. The response also sets a session cookie, which the next step needs.
Terminal window curl -i -X POST "$JORVI_API/v1/merchants" \-H 'content-type: application/json' \-d '{"name": "Harbour Lane Coffee","email": "you@example.com","password": "a-long-enough-password","acknowledged": true}'acknowledgedis required and must betrue. It records that you understand Jorvi never holds your money and cannot reverse a settled payment. Omit it and you getacknowledgement_required.Keep three things from the response:
keys.testis the one to use. Everything on this page works with it.keys.liveis the same account in live mode. On a devnet deployment it settles on the same test chain, so there is no reason to reach for it yet. It exists so the switch to mainnet is a key change rather than a new account.- the
jorvi_sessioncookie, which the next step needs. No API key can replace it.
-
Prove the wallet you want to be paid into
Anyone can type an address. A typed address is unverified and cannot receive live payments, because a typo would send your revenue somewhere you do not control and nothing on chain can bring it back.
Ask for a challenge:
Terminal window curl "$JORVI_API/v1/payout_wallet/challenge?address=$WALLET" \-H "cookie: jorvi_session=$SESSION"Sign the
messageit returns with that wallet’s key (an ordinary ed25519 signature over the UTF-8 bytes, base64 encoded), then:Terminal window curl -X POST "$JORVI_API/v1/payout_wallet" \-H 'content-type: application/json' \-H "cookie: jorvi_session=$SESSION" \-d '{"address":"'"$WALLET"'","message":"'"$MESSAGE"'","signature":"'"$SIGNATURE"'"}'Nothing moves and no fee is paid. This proves you hold the key, and it is off-chain and free.
-
Create something to sell
Terminal window curl -X POST "$JORVI_API/v1/products" \-H "authorization: Bearer $KEY" \-H 'content-type: application/json' \-d '{"name": "The Coffee Guide","sellMode": "once","mint": "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU","priceOnce": "3000000","periodSeconds": 3600,"contentTitle": "Members","contentBody": "The good stuff."}'-
sellMode: "once"sells it outright. Leave it out and the product is a subscription, which this deployment refuses. -
Prices are strings in atomic units. USDC has six decimals, so
"3000000"is 3.00 USDC. Never a float:3.00in JSON is a binary fraction and money is not. -
mintmust be a token the platform accepts. Ask for the list with your API key:Terminal window curl "$JORVI_API/v1/tokens" -H "authorization: Bearer $KEY"This route needs the key; without it you get
401 unauthenticated. Anything not on that list is refused withmint_not_allowed. -
Every field in that example is required, including on a one-time product:
name,sellMode,mint,priceOnce,periodSeconds,contentTitleandcontentBody. Omit any one and you getparameter_missingnaming it. -
periodSecondsmust be a whole number of hours, meaning a multiple of3600.1800and5400are both refused withparameter_invalid. It is required on a one-time product even though nothing recurs, which is a wart in the current API; pass3600and move on.
The response carries an
idand aurl.urlis a PATH, not a full address, which is something like/product/prod_a66095…. Join it to your server to get the link you share:$JORVI_API + url -> https://pay.example.com/product/prod_a66095…That page is a working checkout. Share it and you are selling; there is nothing else to build.
-
-
Let someone buy it
If you are happy with the hosted page, you are finished. To drive it yourself, open a purchase:
Terminal window curl -X POST "$JORVI_API/v1/products/$PRODUCT_ID/buy" \-H 'content-type: application/json' \-d '{"payer":"'"$PAYER_WALLET"'"}'You get back a
mandateId, aclientSecret, and aninstruction. Despite the name,instructionis a complete unsigned Solana transaction, base64 encoded, not a single instruction within one. Deserialize it, have the payer sign it in their own wallet, and send it back. Only they can sign it, and the platform never holds a key that could.Hand the signed transaction back:
Terminal window curl -X POST "$JORVI_API/v1/checkout/mandates/$MANDATE_ID/broadcast?client_secret=$SECRET" \-H 'content-type: application/json' \-d '{"signedTransaction":"'"$SIGNED"'"}'The response carries the
txSignaturethe chain returned. The money has moved: from the payer’s wallet to yours, with no stop in between. -
Check what they bought is unlocked
Terminal window curl "$JORVI_API/v1/products/$PRODUCT_ID/access?payer=$PAYER_WALLET&client_secret=$SECRET"Returns
entitledand, when entitled, the gatedcontentBody.The
client_secretis required. Without a proof this route answers401 wallet_proof_requiredrather than saying whether that wallet has paid: entitlement is not readable by anyone who can guess an address.
What just happened
Section titled “What just happened”The payer signed one transaction, paying their own network fee, moving their own tokens directly to your wallet. Jorvi built the transaction and broadcast it. At no point did it hold your money, and at no point could it have.
Where to go next
Section titled “Where to go next”- Errors, every code the API returns and what to do about each.
- Webhooks, how to be told a payment happened instead of polling.
- Integration options: hosted page, embedded button, or driving it yourself, and how to choose.