By the end of this guide, you'll have a working Stripe account, two sets of API keys (test + live), webhook endpoints in both environments pointing at your Cabintale account, and you'll know how to test the full flow locally with the Stripe CLI before going live.
What you'll need
- A Stripe account (free at stripe.com; activation for live mode requires bank details + business info)
- ~15 minutes for the setup, plus 5 more for the local test
- The cabintale Payment gateway dialog open in another tab (Settings → Payment gateways → Setup) — see Payment gateways
- Test mode set up and tested with
4242 4242 4242 4242 - Live mode ready to flip to when you're done testing
- A clear understanding of the two distinct webhook signing secrets (Stripe Dashboard's and Stripe CLI's)
Stripe is just a payment processor — pricing is yours
Cabintale doesn't pre-create products in Stripe. Every Checkout session is built ad-hoc with the exact amount your booking computes (nights × rate, deposit amount, balance, whatever). You don't need to set up a product catalog in Stripe; you don't need fixed prices.
What Stripe gives you:
- A hosted checkout page that accepts cards (and other methods you enable) in the guest's language and currency
- Webhook events that tell Cabintale when a payment succeeds, fails, or expires
- A dashboard for settlement details and disputes (refunds you do directly inside cabintale — see Refunds and cancellations)
That's it. Cabintale handles everything else.
Step 1: Sign up at Stripe
Go to stripe.com and create an account.
You can start in Test mode without activating your business — Test mode lets you do realistic end-to-end flows with test cards (no real money). When you're ready to take real payments, you'll need to activate (provide bank details, business info, ID).
Step 2: Toggle Test mode
Top-right of the Stripe Dashboard → toggle "Test mode" (sandbox/dev switch).
When the toggle is on:
- All API keys, webhooks, customers, payments, and dashboards are separate from live data
- Test cards work; real cards are rejected
- You can break things freely
When the toggle is off, you're looking at the live environment — same UI, separate data.
Test and Live are completely separate. Different keys, different webhook endpoints, different signing secrets, different Customers, different Payments. Nothing crosses over. You set them up once each.
Step 3: Find your API keys
In Stripe Dashboard → Developers (left sidebar) → API keys.
You'll see:
- Publishable key — starts with
pk_test_…(test) orpk_live_…(live). Safe to share. - Secret key — starts with
sk_test_…/sk_live_…. Click Reveal test key to see it. Never share this; treat it like a password.
Copy both. Paste them into the cabintale dialog in the matching mode (Test mode currently selected → paste test keys; flip to Live mode → paste live keys).
Stripe sometimes only shows the secret once. If that happens, click Reveal test key (test) or Reveal live key (live) to view it again. For live, Stripe may force you to email yourself the key — copy it before closing the modal.
Step 4: Create an event destination (webhook)
Stripe renamed webhooks to event destinations. In Stripe Dashboard → Developers → Webhooks, click Add destination. A three-step wizard opens.
1. Select events
- Event destination scope — choose Your account.
- API version — leave the default (e.g.
2020-08-27). - Under Events, use the search box to find and tick these five:
checkout.session.completed(critical — marks bookings as paid)checkout.session.expired(unlocks dates when guests don't finish in time)payment_intent.succeeded(redundant safety net)payment_intent.payment_failed(marks failed attempts)charge.refunded(syncs refunds back to cabintale — issued from the cabintale UI or from the Stripe Dashboard, both work)
- Click Continue.
2. Choose destination type
Pick Webhook endpoint (not Amazon EventBridge or Azure Event Grid). Click Continue.
3. Configure destination
- Destination name — anything you'll recognise, e.g. Cabintale production.
- Endpoint URL — paste the URL from the cabintale dialog's "Our webhook URL" section. It looks like:
https://admin.cabintale.com/api/webhooks/stripe/abc123-def4-...
This URL is unique to your Cabintale account. The token at the end is what tells our server which account the events belong to.
- Description — optional.
- Click Create destination.
On the destination page, find the Signing secret (starts with whsec_…), click the eye icon to reveal it, and copy it.
Switch back to the cabintale dialog → paste it into Webhook signing secret. Click Save.
Older Stripe accounts may still show the classic Add endpoint button instead of the destination wizard. The fields are the same — endpoint URL, events, signing secret — just on a single screen.
Step 5: Test the connection
Cabintale runs a connection test automatically on Save (it calls Stripe's API with your secret key). Result shows as a flash message at the top of /settings.
You can also re-test anytime by clicking Settings on the Stripe card → opening the dialog → Test connection button next to the saved-keys panel.
Result:
- Connection OK — green badge, you're good
- Connection failed — red badge with a Stripe error message; usually wrong secret key, or wrong mode
Step 6: End-to-end test booking (Test mode)
Set up a property to Accept payments — see Accept payments. Use Test mode Stripe keys.
Then:
- Open the public widget URL (use View public widget on the Widget edit page)
- Pick dates → Make a reservation
- Fill out the form → Pay now
- Stripe Checkout opens in a new tab
- Use a test card:
- Success:
4242 4242 4242 4242 - Decline:
4000 0000 0000 0002 - Authentication required (3DS):
4000 0025 0000 3155 - Any future expiry, any 3-digit CVC, any zip
- Success:
- After payment, Stripe redirects to
/payments/success(cabintale) - Open the booking in admin → confirm it's
paidand the Payments table shows the gateway transaction
If something fails, check Stripe Dashboard → Developers → Webhooks → click your endpoint → Recent deliveries. You'll see every event Stripe tried to send, the response code, and the request body. 200 = good. Anything else = something on cabintale's side; the page logs detail there.
Local development with Stripe CLI
Stripe webhooks can't reach localhost. The Stripe CLI bridges that — it takes events from Stripe and forwards them to your local cabintale.
Install
brew install stripe/stripe-cli/stripe
stripe login
stripe login opens a browser window — authorize it, then come back to the terminal.
Forward webhooks
stripe listen --forward-to http://admin.cabintale.local:8888/api/webhooks/stripe/{your_account_webhook_token}
Replace {your_account_webhook_token} with the UUID from the cabintale dialog's webhook URL — just copy the URL and run it.
CLI prints:
> Ready! Your webhook signing secret is whsec_abc123…
This signing secret is different from Stripe Dashboard's. It's CLI-generated. Paste this one into the cabintale Test mode webhook signing secret field. The dashboard one is for the dashboard endpoint; the CLI one is for the CLI's forwarder.
Leave stripe listen running. Now any test booking made on your local widget triggers events that flow through Stripe → CLI → your localhost.
Trigger fixture events directly
Without making a real test booking, you can replay events:
stripe trigger checkout.session.completed
Useful for testing webhook handler edge cases. For realistic flows, just go through the actual booking dialog with the test card.
Resend a specific event
If you need to replay a specific event (e.g. one that 5xx'd):
stripe events resend evt_1XXXXXXXXXXXX
(The event ID comes from the stripe listen log output or Stripe Dashboard → Events.)
Going live
When you're ready to take real payments:
- Toggle Stripe Dashboard out of Test mode
- Activate your account if you haven't (bank details, ID)
- Developers → API keys → copy live
sk_live_…andpk_live_… - Developers → Webhooks → Add a NEW endpoint pointing at the same cabintale URL (you have to add a separate endpoint for live mode — they're independent)
- Pick the same events as in Step 4 above
- Copy the live signing secret
- Open the cabintale dialog → flip to Live mode → paste live keys → save
- Open one of your properties and verify it's still on Accept payments. Make a small test booking with a real card — yourself, or a friend with a small charge.
You can leave Test mode keys saved in the dialog too — flipping mode in cabintale switches which set is used for new Checkout sessions, and lets you go back to testing without losing your live keys.
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
| "Invalid API key" on Test connection | Typo or whitespace in the secret key | Re-copy from Stripe Dashboard → API keys; paste with no leading/trailing spaces |
| Webhooks return 200 in Stripe but cabintale doesn't update | Wrong signing secret on cabintale (most likely cause) | Copy the signing secret from Stripe → your webhook endpoint → Signing secret reveal; paste into cabintale |
| Webhooks return 4xx in Stripe Dashboard | Either invalid signature (wrong cabintale signing secret) or unknown account token (wrong webhook URL) | Re-paste both values; confirm the webhook URL in Stripe matches cabintale's exactly |
| Webhooks return 5xx in Stripe Dashboard | Something on cabintale's side; check Laravel log | Open storage/logs/laravel.log for the timestamp of the failed delivery; common cause: queue/cache/database not configured locally |
stripe listen runs but events don't reach cabintale | Wrong forward URL, or cabintale dev server not running | Run curl http://admin.cabintale.local:8888/service-widget-ping — if it doesn't return ok, your Laravel app isn't reachable on that URL |
| Test mode works, live mode doesn't | Different keys + different webhook between modes | Verify you set up a SEPARATE webhook endpoint in Live mode (Stripe doesn't share endpoints across modes) and pasted the live signing secret |
| Stripe Checkout shows in English when widget is in Czech | Cabintale wasn't passing locale (older bookings) or widget language wasn't set | New bookings honor widget language automatically. For older bookings, the Stripe-side language depends on the locale param at session-creation time. |
Stripe documentation pointers
- API keys: https://docs.stripe.com/keys
- Webhooks: https://docs.stripe.com/webhooks
- Test cards: https://docs.stripe.com/testing
- CLI: https://docs.stripe.com/stripe-cli
- Checkout locales: https://docs.stripe.com/payments/checkout/customization/appearance#supported-languages
Related guides
- Payment gateways (cabintale-side setup) — Payment gateways
- Accept payments on a property — Accept payments on a property