Stripe Payment Gateway

Content Type: Module
Categories: Utility

Overview

Stripe Payment Gateway

This module helps to integrate with Stripe payment gateway (https://stripe.com/en-in).

The following features are part of this module,

  1. Price: Create Price
  2. Invoice: Generate Invoice, Generate Invoice Line items & Finalize Invoice
  3. Payment Link: Generate Payment Link, Generate Payment link - Donate
  4. Products: List Products
  5. Customer: Create Customer

Check the Module ReadMe Snippet for more details and Examples

If webhooks(https://stripe.com/docs/webhooks) are created in Stripe, then

Create REST Service and create a POST Service and add the ‘StripeSignature’ Java action to check the signature for validation.

 

 

Documentation

Typical usage scenario


You are building a Mendix web app that has to take money. You do not want card data anywhere near your own runtime, you do not want to write a Java connector, and you already have a Stripe account. This module gives you the Mendix side of that job: microflows that call the Stripe REST API with your secret key, import mappings that turn Stripe's JSON responses into Mendix objects you can bind to a page, and a Java action that verifies the signature on incoming Stripe webhooks so your app can trust what Stripe tells it.


• Taking a card payment in a Mendix web app. Build a Stripe Payment Link from a price and quantity (SUB_PaymentLink), then send the customer to the hosted Stripe page. Card details are entered on Stripe's page, never in your app.

• Selling from a product catalogue. Read your Stripe products with SUB_GetProductList and create prices against them with ACT_GeneratePrice_Stripe, including tiered pricing and expand options.

• Raising a one-off invoice. ACT_Invoice creates the invoice end to end: header, line items, then finalise. The finalised response carries Hosted_invoice_url and Invoice_pdf, which you can mail or link from a page.

• Recurring pricing for subscription-style billing. The price entity carries the full recurring block, so recurring prices can be created from Mendix. Note the limitation: the module creates prices, not subscriptions.

• Keeping a Stripe customer record alongside your own. ACT_Customer_Create creates the Stripe customer and returns the id you store against your own entity.

• Reconciling payment status through webhooks. A published REST endpoint receives Stripe's POST, the StripeSignature Java action verifies the Stripe-Signature header against your endpoint secret using stripe-java, and your microflow only acts on the event when verification passes. Invalid signatures are answered with HTTP 400.


The underlying problem this solves is the gap betw Stripe's form-encoded REST API: assembling


Typical usage scenario


You are building a Mendix web app that has to takedata anywhere near your own runtime, you do not want to write a Java connector, and you already have a Stripe account. This module gives you the Mendix side of that job: microflows

that call the Stripe REST API with your secret keytripe's JSON responses into Mendix objects you canbind to a page, and a Java action that verifies the signature on incoming Stripe webhooks so your app can trust what Stripe tells

it.


• Taking a card payment in a Mendix web app. Build price and quantity (SUB_PaymentLink), then send the customer to the hosted Stripe page. Card details are entered on Stripe's page, never in your app.

• Selling from a product catalogue. Read your StrictList and create prices against them withACT_GeneratePrice_Stripe, including tiered pricing and expand options.

• Raising a one-off invoice. ACT_Invoice creates t, line items, then finalise. The finalised responsecarries Hosted_invoice_url and Invoice_pdf, which you can mail or link from a page.

• Recurring pricing for subscription-style billinge full recurring block, so recurring prices can becreated from Mendix. Note the limitation: the module creates prices, not subscriptions.

• Keeping a Stripe customer record alongside your tes the Stripe customer and returns the id you store against your own entity.

• Reconciling payment status through webhooks. A pes Stripe's POST, the StripeSignature Java actionverifies the Stripe-Signature header against your endpoint secret using stripe-java, and your microflow only acts on the event when

verification passes. Invalid signatures are answer


The underlying problem this solves is the gap betw Stripe's form-encoded REST API: assemblingapplication/x-www-form-urlencoded bodies, attaching bearer authentication from a key you must not leave lying about in plain text,

mapping deeply nested JSON responses back into enthook actually came from Stripe. All of that isalready modelled here, with example pages showing how the pieces fit together.


Features and limitations


Stripe operations covered. Every call is a plain Mendix Call REST service action against @CONST_BaseURL (default

https://api.stripe.com), with Content-Type: applicnd Authorization: Bearer <secret key>.


ACT_Invoice chains header, line item and finalise "raise and issue an invoice" case. The payment linkbody includes line_items[0][price], line_items[0][quantity], currency, after_completion[type]=redirect and after_completion[redirect][url]; the standard vari_codes=true, and the donate variant setssubmit_type=donate.


Entities


• StripeConfiguration — the only persistable entity. Attributes Name and SecretKey, where SecretKey holds the value encrypted by

the Encryption module.

• Helper — non-persistable input object for the example flows: PriceID, Quantity, Currency, RedirectURL, CustomerID, Amount,

Description, CustomerName, CustomerEmail.

• PriceAPI (with Tires and Expand) — the request model for creating a price: unit amount, currency, billing scheme, custom unit

amount, tiers, recurring block, tax behaviour and

• Response models, all non-persistable, populated by six import mappings: Customer_Root, Root/Data/JsonObject (product list),

PaymentLink_Root (with Url), Invoice_Root, Invoicee_Root (with Number, Status, Hosted_invoice_url,Invoice_pdf, Payment_intent).

• RESTService — a single JSONValue attribute used event JSON back to the microflow.


Module roles: Administrator and User. Only Adminisnfiguration.


Webhook endpoint


• Published REST service SripeService, path rest/s.

• Resource InvoicePaid, HTTP POST, handled by microflow ACT_InvoicePaid.

• Full URL: https://<your-app>/rest/sripeservice/v

• The microflow finds the Stripe-Signature header, passes the raw request content, the header value and the endpoint secret to the StripeSignature Java action, and only continues wh HTTP 200 on success, HTTP 400 on a failedsignature.

• The Java action calls Webhook.constructEvent frohe HMAC-SHA256 signature and the timestamptolerance, deserialises the event data object, logs the event type, and writes the event JSON onto the RESTService object.

• Authentication on the service is set to Basic an module roles. See Configuration — you must decidedeliberately how Stripe is meant to satisfy that.


Pages and examples — StripeConfiguration_NewEdit plus the Snip_StripeConfiguration_Overview snippet; SNIP_StripeAPITest with

buttons for create price, get product list, generatomer, generate invoice and donate; helper pages for customer, invoice, payment link, price, tiers and expand; two in-model readme snippets.


Limitations


• Not covered by this module: Checkout Sessions, PaymentIntents, SetupIntents, Charges, Refunds, Subscriptions, Subscription

Schedules, Coupons, Disputes, Payouts, Connect, Bating or listing webhook endpoints through the API.Refunds and disputes are handled in the Stripe dashboard.

• Prices, not subscriptions. Recurring prices can /v1/subscriptions, so the subscription itself mustbe created by Stripe (for example through a Payment Link in subscription mode) or by a call you add.

• Product creation is inline only. There is no stanew product can only be created as product_datawhile creating a price. Products are otherwise read-only.

• Invoices are created and finalised, not collecteid or delete call, and no invoice list or retrieve.

• No pagination or filtering. GET /v1/products is called without limit or starting_after, so you get Stripe's default page only.

• The bundled stripe-java library is used for webhtbound calls are modelled REST calls; noStripe-Version header is sent, so requests run against your account's default Stripe API version.

• Test versus live mode is decided entirely by theh, no separate test and live configuration record,and no indication in the UI of which mode is active. The response entities do carry Stripe's Livemode flag.

• PCI scope. Card data is entered on Stripe's hostmodule never receives or stores a card number, CVCor expiry. That keeps you in the lightest SAQ category available for your setup, but the module makes no compliance claim on your

behalf and includes no Stripe.js or Elements integ

• The webhook example handles one path. ACT_InvoicePaid verifies the signature and logs; the Java action branches on

payment_intent.succeeded, payment_method.attached only. Turning a verified event into a status updateon your own data is work you do.

• No retry, idempotency or error mapping. Stripe e to a Mendix error entity, Idempotency-Key is notsent, and there is no retry or backoff.

• Currency and amount handling is caller-supplied. in the minor unit as integers; the module does noconversion or validation.

• English only. Page captions are en_US.

• Web only. The example pages are web pages; there is no native or offline support.


Dependencies


Read this before you import. The module calls Encryption.Encrypt and Encryption.Decrypt. Those microflows are not part of the package, so importing into an app without the Encrecutive errors and the app will not run:


- The selected microflow Encryption.Encrypt no lonT_SaveStripeConfiguration

- The selected parameter Encryption.Encrypt.Plain no longer exists — same activity

- The selected microflow Encryption.Decrypt no lonT_DecrptStripeSecretKey

- The selected parameter Encryption.Decrypt.Encrypted no longer exists — same activity


This is a prerequisite, not a fault. Import Encryption first and the four errors disappear without you changing anything.


Installation


1. Install the Encryption module first. Import it,nstant as that module's documentation requires,before you store any key.

2. Import this module — App Explorer, right-click e, select PaymentGatewayStripe.mpk. With Encryptionpresent there should be no errors.

3. Confirm the jars landed. userlib must contain sn-2.10.1.jar. The webhook Java action will notcompile without them. If your app already ships a different gson version, keep one copy only and make sure it is compatible with

stripe-java 22.4.0.

4. Assign module roles. Administrator for whoever manages the Stripe key, User for the roles that may trigger payment flows.

5. Add a configuration page. Create a page in youreConfiguration_Overview on it, and add it tonavigation. The module ships the snippet and StripeConfiguration_NewEdit, not a finished overview page.

6. Optional — add the test page. Create a page, drand give it to an administrator.

7. Get your Stripe API keys. Dashboard → Developers → API keys, with Test mode on, copy the secret key (sk_test_…). The publishable

key is not used by this module.

8. Store the key in your app. Run the app, open the Stripe Configuration page as an administrator, click New, name the record,

paste the secret key, save. ACT_SaveStripeConfiommit. Create exactly one record.

9. Register the webhook endpoint in Stripe. Dashboard → Developers → Webhooks → Add endpoint. URL:

https://<your-app-domain>/rest/sripeservice/v1/ts, for example invoice.paid,payment_intent.succeeded, payment_method.attached. Save, then reveal and copy the Signing secret (whsec_…).

10. Put your own signing secret into the webhook flect the StripeSignature Java action call andreplace the endpointSecret argument with your own value. The shipped model has a literal placeholder secret in that field — see

Configuration and Known bugs.

11. Settle the webhook authentication question. The published REST service requires Basic or Session authentication for the two

module roles. Decide how Stripe is meant to auation off for that service and rely on signatureverification. Do this deliberately, not by accident.

12. Run in test mode end to end before you swap in


Configuration


Recommended hardening while you are in there: replace the literal endpointSecret with your own constant so the secret is set per environment rather than baked into the model, and crets separate.


Currency, amounts and redirect URLs. There is no cmount, quantity and the post-payment redirect URLare supplied per call on the Helper object or the PriceAPI object. Amounts go to Stripe in the minor unit, as integers. There are

no success and cancel URL constants; the payment lirect][url] from Helper/RedirectURL.


Recommended first run, in test mode


1. Stripe dashboard in Test mode; store the sk_tes

2. Open your test page and click Get Product List. A successful response proves key storage, decryption and outbound connectivity in one go.

3. Create a price against an existing product, then generate a payment link from that price with a redirect URL pointing back at your app.

4. Pay the link with Stripe's test card 4242 4242 4242 4242, any future expiry and any CVC.

5. Check that Stripe delivered the webhook (Develont → recent deliveries) and that your appanswered 200. A 400 means the signing secret in ACT_InvoicePaid does not match the endpoint.

6. Only then switch the dashboard to live, take thendpoint's signing secret, and repeat the samechecks.


Known bugs

None


Frequently Asked Questions


Why do I see errors immediately after importing the module?

Because the Encryption module is missing. The fourncrypt, Encryption.Decrypt or their parameters. Import Encryption and the errors clear without any edit to this module.


Which Stripe key do I store, and where do test and live keys differ?

Store the secret key, not the publishable one. In in live mode sk_live_. The module has no modeswitch, so the key you store decides everything, and each mode's webhook endpoint has its own signing secret.


Do I need to configure the webhook, and how?

Only if you want your app to react to Stripe eventthttps://<your-app>/rest/sripeservice/v1/InvoicePaid, copy the signing secret, and paste it into the endpointSecret argument in ACT_InvoicePaid. Until you do, every delivery is r


Are webhook signatures really verified?

Yes. StripeSignature calls Webhook.constructEvent from stripe-java 22.4.0, which checks the HMAC-SHA256 signature in the Stripe-Signature header against your endpoint secr tolerance. The microflow only continues when itreturns true, and returns HTTP 400 otherwise.


What does this mean for PCI compliance?

Card details are entered on Stripe's hosted Paymenr, CVC or expiry ever reaches your Mendix runtime or database. That is the lightest PCI position available, but the scope assessment for your business is yours to make with your acquirer; this module makes no compliance claim annts integration.


Where is my Stripe secret key stored, and can the Encrypted in the StripeConfiguration entity, readable only by Administrator?

Decrypted server-side inside microflows and sent as a bearer token from the runtime. Never placed in a che decrypt microflow cannot be called from a page.


Can I take a subscription payment with this?

You can create the recurring price, but the module never calls /v1/subscriptions. Create the subscription through a Stripe Payment Link in subscription mode or add the call yourselfo keep your app in step.


Can I issue a refund from Mendix?

No. There is no refund, dispute or payout call. Refunds are done in the Stripe dashboard or through a call you add.


Why does my Stripe call suddenly fail with an authentication error after I edited the configuration record?

Almost certainly the double-encryption defect: savng the plain key encrypts the ciphertext again. Open the record, paste the full secret key from the Stripe dashboard, and save.


Can I keep separate configuration records for test and live?

Not safely. ACT_DecrptStripeSecretKey retrieves a th no constraint and no sort, so with severalrecords the key that is used is not predictable. Keep one record per environment.


Which pages do I actually need to add to navigation?

One page of your own carrying Snip_StripeConfigurarator can store the key. Everything else is examplematerial you can copy from or ignore.


Do I have to keep the bundled jars?

Yes, for the webhook path. stripe-java-22.4.0.jar the StripeSignature Java action compiles and runsagainst. The outbound REST calls do not need them, but removing them breaks the build.


Issues, suggestions and feature requests: https://github.com/bharathidas/StripePaymentGateway/issues

Releases

Version: 4.0.0
Framework Version: 10.24.17
Release Notes:

**Stripe Payment Gateway** — now supported on Mendix Studio Pro **10.24.17**


Rebuilt from Studio Pro 10.24.8 to **10.24.17** (LTS). No functional changes — this release only updates Studio Pro compatibility.


**Prerequisite** — import this before Stripe Payment Gateway, or the module will show 4 unresolved references:

- `Encryption` — the Stripe secret key is stored encrypted and decrypted before every API call


Bundled Java libraries: `stripe-java-22.4.0.jar`, `gson-2.10.1.jar`. Java 11.


---


### Action required after import


**Replace the webhook signing secret.** `ACT_InvoicePaid` passes a literal `whsec_…` value to the `StripeSignature` Java action as `endpointSecret`. Until you replace it with the signing secret from your own Stripe endpoint, **every webhook delivery fails signature verification and is answered with HTTP 400**. Move it to a constant of your own so it can be set per environment rather than baked into the model.


### Known issues in this release


- **Re-saving the Stripe configuration double-encrypts the key.** `ACT_SaveStripeConfiguration` encrypts `SecretKey` unconditionally and writes it back to the same attribute, while the edit page binds that attribute. Saving an existing record without retyping the plain key encrypts the ciphertext again; the decrypt runs once, so every later Stripe call fails with an authentication error. Always paste the full plain secret key before saving.

- **Form bodies are not URL-encoded.** Values are concatenated straight into `application/x-www-form-urlencoded` bodies, so a customer name or e-mail containing `&`, `=`, `+` or a space corrupts the request.

- **`StripeSignature` can throw a NullPointerException** when the account's Stripe API version is newer than `stripe-java` 22.4.0 can deserialise — Stripe sees a 500 rather than a clean 400.

- **The published service is spelled `SripeService`**, so the webhook URL to register in Stripe is `https:///rest/sripeservice/v1/InvoicePaid`.

- **No configuration overview page**, despite the in-model readme naming one. Place the `Snip_StripeConfiguration_Overview` snippet on a page of your own.

- **`SUB_PaymentLink_Donate_QR` is dead** — excluded, hardcoded values, and it opens a page that does not exist.

- **The payment link URL is not surfaced** by `SUB_PaymentLink`; wire the redirect or display yourself. `SUB_PaymentLink_Donate` does return it.


Webhook signatures **are** genuinely verified via `Webhook.constructEvent` before the flow proceeds, and the secret key is never exposed to the browser.


Import `PaymentGatewayStripe.mpk` via *App Explorer > Import module package* in Studio Pro 10.24.17 or higher.

Version: 3.0.0
Framework Version: 10.24.8
Release Notes:

Modified the Data grid to Data grid 2 and added customer flow

Version: 2.0.0
Framework Version: 9.24.18
Release Notes: **Stripe Payment Gateway** This module helps to integrate with Stripe payment gateway [] (https://stripe.com/en-in). The following features are part of this module, 1. **Price**: Create Price 2. **Invoice**: Generate Invoice, Generate Invoice Line items & Finalize Invoice 3. **Payment Link**: Generate Payment Link, Generate Payment link - Donate 4. **Products**: List Products Check the Module ReadMe Snippet for more details and Examples If webhooks [] (https://stripe.com/docs/webhooks) are created in Stripe, then Create REST Service and create a POST Service and add the ‘**StripeSignature**’ Java action to check the signature for validation. ![Screenshot_1](https://user-images.githubusercontent.com/23263603/197320069-d37dad10-c7f9-4193-ae86-8cc8bba47bad.png) ![Screenshot_2](https://user-images.githubusercontent.com/23263603/197320074-6b97fa5d-64bb-4148-b5ff-b7de5703002d.png) ![Screenshot_3](https://user-images.githubusercontent.com/23263603/197320076-c930ffb2-e682-4bb8-8cba-4d299aa0ece3.png)
Version: 1.1.0
Framework Version: 9.12.4
Release Notes: **Stripe Payment Gateway** This module helps to integrate with Stripe payment gateway [] (https://stripe.com/en-in). The following features are part of this module, 1. **Price**: Create Price 2. **Invoice**: Generate Invoice, Generate Invoice Line items & Finalize Invoice 3. **Payment Link**: Generate Payment Link, Generate Payment link - Donate 4. **Products**: List Products Check the Module ReadMe Snippet for more details and Examples If webhooks [] (https://stripe.com/docs/webhooks) are created in Stripe, then Create REST Service and create a POST Service and add the ‘**StripeSignature**’ Java action to check the signature for validation. ![Screenshot_1](https://user-images.githubusercontent.com/23263603/197320069-d37dad10-c7f9-4193-ae86-8cc8bba47bad.png) ![Screenshot_2](https://user-images.githubusercontent.com/23263603/197320074-6b97fa5d-64bb-4148-b5ff-b7de5703002d.png) ![Screenshot_3](https://user-images.githubusercontent.com/23263603/197320076-c930ffb2-e682-4bb8-8cba-4d299aa0ece3.png)
Version: 1.0.0
Framework Version: 9.12.4
Release Notes: **Stripe Payment Gateway** This module helps to integrate with Stripe payment gateway [] (https://stripe.com/en-in). The following features are part of this module, 1. **Price**: Create Price 2. **Invoice**: Generate Invoice, Generate Invoice Line items & Finalize Invoice 3. **Payment Link**: Generate Payment Link, Generate Payment link - Donate 4. **Products**: List Products Check the Module ReadMe Snippet for more details and Examples If webhooks [] (https://stripe.com/docs/webhooks) are created in Stripe, then Create REST Service and create a POST Service and add the ‘**StripeSignature**’ Java action to check the signature for validation. ![Screenshot_1](https://user-images.githubusercontent.com/23263603/197320069-d37dad10-c7f9-4193-ae86-8cc8bba47bad.png) ![Screenshot_2](https://user-images.githubusercontent.com/23263603/197320074-6b97fa5d-64bb-4148-b5ff-b7de5703002d.png) ![Screenshot_3](https://user-images.githubusercontent.com/23263603/197320076-c930ffb2-e682-4bb8-8cba-4d299aa0ece3.png)