SETUP GUIDES · PAYMENTS
Receiving payment events in your app
Let Claspine tell your app when a customer pays, renews, fails a payment or cancels.
Your app needs to know when to give a customer access and when to take it away. Claspine sends a short, signed message (a callback) to your app whenever something changes, and keeps retrying for about three days if your app is down. You can also ask for the current state at any time with payments.getSubscription(subject), which is useful right after a customer returns from checkout.
Words you’ll see
- Webhook
- A message the provider sends to Claspine when something happens (for example a payment succeeds), so Claspine learns about it right away.
- Signing secret
- A secret shared between the provider and Claspine. Each webhook message is signed with it, so Claspine can prove the message really came from the provider.
- Test mode and live mode
- Payment providers keep two separate worlds: test mode, where nothing is really charged and you use test cards, and live mode, where real money moves. Each has its own keys.
Before you start
- Payments set up as in “Connect your Stripe account”.
- An https address in your app that can receive POST requests, for example
https://api.example.com/spine/payments.
Steps
- In the Claspine console open Payments → Tell your app, paste your callback URL and click Save payment settings.
- Claspine shows a signing secret (starts with
spcb_) once. Copy it and store it in your app’s environment, for example asSPINE_CALLBACK_SECRET. - In your app, read the request body as raw text (before any JSON parsing) and check it with the SDK, as in the example below. If the check fails, answer with status 400 and ignore the message.
- Act on the event: for
subscription.updated, give access whendata.entitledis true and remove it when it is false. Fororder.updated, fulfil the order whendata.statusisCAPTURED. - Answer with any 2xx status quickly (within 10 seconds). Do slow work afterwards. Any other answer makes Claspine retry later.
- Click Send test event on the Payments page and watch it appear under Recent events with “HTTP 200”.
import express from 'express';
import { verifyWebhookSignature } from '@grahmur-org/claspine-client';
const app = express();
app.post('/spine/payments', express.text({ type: '*/*' }), async (req, res) => {
let event;
try {
event = await verifyWebhookSignature(req.body, req.get('Spine-Signature'), process.env.SPINE_CALLBACK_SECRET);
} catch {
return res.sendStatus(400); // not from Claspine, or tampered with
}
if (event.type === 'subscription.updated') {
await setAccess(event.data.subject, event.data.entitled); // your code
}
res.sendStatus(200);
}); What goes where in Claspine
| Console field | Value |
|---|---|
| Payments → CALLBACK URL | Your app’s https address that receives the events. |
| Your app’s environment | The spcb_… signing secret shown once when you save the URL. |
Keep it safe
- Always check the signature. Without it, anyone could send your app a fake “payment succeeded”.
- The same event can arrive more than once (for example after a retry). Make your handler safe to run twice: setting access to the same value twice is fine.
- Each event says whether it is
testorlive. Make sure test events never unlock anything in your production app. - If the secret leaks, click Create new secret and update your app right away.
Claspine stores the values encrypted, never shows them again in full, and never sends them to your app or SDK.
If something goes wrong
- Recent events shows “Could not reach your endpoint”.
- The URL must be public and use https. Addresses inside private networks are refused for safety.
- Your app always rejects the signature.
- Pass the raw body text, not JSON that was parsed and turned back into text; the bytes must match exactly. Also check the secret is the latest one.