diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 64beee87..afd6c0cb 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -31,6 +31,15 @@ jobs:
node-version-file: ".nvmrc"
cache: npm
+ - name: Run rumdl
+ uses: rvben/rumdl-action@v0
+ with:
+ version: latest
+ path: "."
+ file_types: "md,mdx"
+ changed_files_only: true
+ fail_on_error: true
+
- name: Install dependencies
run: npm ci
diff --git a/.rumdl.toml b/.rumdl.toml
new file mode 100644
index 00000000..0703b4dc
--- /dev/null
+++ b/.rumdl.toml
@@ -0,0 +1,48 @@
+[global]
+# Keep legacy long lines and preserve alignment in code examples.
+disable = ["MD013", "MD034", "MD064"]
+
+# Enable table formatting/fixing support.
+extend-enable = ["MD060"]
+
+# Keep this empty for now; URL auto-fixing is covered by disabled MD034.
+unfixable = []
+
+[MD004]
+# Enforce '-' as the single bullet style across docs.
+style = "dash"
+
+[MD046]
+# Require fenced code blocks globally.
+style = "fenced"
+
+[per-file-flavor]
+# Parse MDX files with MDX-aware rules.
+"**/*.mdx" = "mdx"
+
+[per-file-ignores]
+# Historical changelog entries use legacy heading/list structures.
+"src/content/changelog/*.md" = ["MD001", "MD036"]
+
+# README uses custom HTML header layout and no leading H1.
+"README.md" = ["MD033", "MD041"]
+
+# Existing docs use inline HTML for embeds/widgets and should stay unchanged.
+"src/content/docs/online-payments/apm/apple-pay.mdx" = ["MD033"]
+"src/content/docs/online-payments/apm/google-pay.mdx" = ["MD033"]
+"src/content/docs/online-payments/checkouts/card-widget.mdx" = ["MD033"]
+"src/content/docs/terminal-payments/sdks/android-sdk.mdx" = ["MD033"]
+
+# Plugin pages use raw URL constants/props for MDX components.
+"src/content/docs/online-payments/plugins/prestashop.mdx" = ["MD034"]
+"src/content/docs/online-payments/plugins/woocommerce.mdx" = ["MD034"]
+
+# Legacy iOS SDK page has dense mixed MDX/Steps/list patterns.
+# Keep it build-safe by scoping rule ignores until the page is refactored.
+"src/content/docs/terminal-payments/sdks/ios-sdk.mdx" = ["MD004", "MD007", "MD012", "MD030", "MD031", "MD032", "MD040", "MD046", "MD049", "MD051", "MD060", "MD069"]
+
+# Legacy mixed Tabs+code snippets trigger MD046 false positives after formatting.
+"src/content/docs/online-payments/guides/refund.mdx" = ["MD046", "MD051"]
+"src/content/docs/online-payments/guides/single-payment.mdx" = ["MD046"]
+"src/content/docs/online-payments/guides/tokenization-with-payment-sdk.mdx" = ["MD046"]
+"src/content/docs/online-payments/sdks/react-native.mdx" = ["MD046"]
diff --git a/AGENTS.md b/AGENTS.md
index c58ee356..4aeadc31 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -42,6 +42,13 @@ For files in `src/content/docs/`, include frontmatter at the top of every page.
CI relies on `npm run check`. When editing MDX content, preview via `npm run dev` to verify navigation, sidebar ordering, and snippet rendering. There is no Jest-style test suite; document any manual verification steps in the pull request if behavior changes or APIs are added.
+## Markdown Linting Guidelines
+
+- Prefer fixing markdown issues in content first instead of adding linter exceptions.
+- Run `npm run lint:markdown` and `npm run build` after markdown-heavy changes to catch MDX parsing regressions early.
+- `rumdl` can produce impractical suggestions for complex MDX (for example mixed Tabs/Steps/components); in such cases, adding scoped ignores in `.rumdl.toml` is acceptable.
+- Every new ignore must be narrowly scoped (per-file/per-rule) and include a short comment explaining why it is needed.
+
## Validation Matrix
Run at least the following commands before submitting changes:
diff --git a/package-lock.json b/package-lock.json
index 035f6e6e..f492c871 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -45,6 +45,7 @@
"react-content-loader": "^7.1.2",
"react-dom": "^19.2.4",
"react-final-form": "^7.0.0",
+ "rumdl": "0.1.30",
"sass": "^1.97.3",
"starlight-image-zoom": "^0.13.0",
"starlight-links-validator": "^0.19.2",
@@ -5148,6 +5149,125 @@
"win32"
]
},
+ "node_modules/@rumdl/cli-darwin-arm64": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-darwin-arm64/-/cli-darwin-arm64-0.1.30.tgz",
+ "integrity": "sha512-ht15pcW+L31iDp5T/Tvl+U78kgpiZyPfFYsrvRvhot1M5+eBrt5kBaEXAXDi03tKaKK0ZdCqKQHwfpUaAuZZQA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-darwin-x64": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-darwin-x64/-/cli-darwin-x64-0.1.30.tgz",
+ "integrity": "sha512-69hsCnEk81GiJwzcaqe8fxKMHtL+47j3criOvLjxaAtPCsfrvxkd2KSnJKj/5zElTY7pb7nL0V4Z6uy6+m00tQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-linux-arm64": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-linux-arm64/-/cli-linux-arm64-0.1.30.tgz",
+ "integrity": "sha512-t16rv7VY0l/4MzXV29aZpnCeIsq1ZFPN9ss/C4/6EJtkBrdng6nRE5yLWFDC7G1DdyyD/IX8adp/rGKh0INQBQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-linux-arm64-musl": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-linux-arm64-musl/-/cli-linux-arm64-musl-0.1.30.tgz",
+ "integrity": "sha512-pthBOeO7cFxtwKD7PFmfShapfqu7vlzynwOo1hFv9lYkmj0mWcMjbsfC1I0AWmPaM5kWi0Ta58K+36b9E77wNA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-linux-x64": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-linux-x64/-/cli-linux-x64-0.1.30.tgz",
+ "integrity": "sha512-tDPaWiwxOgOe4uroRQCbrO+gNXgdHHO/5BJqc7Qnqu4tlabEB0P+NSXlVo7NAwZgHarCB1wasljFcNvLjAN70Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-linux-x64-musl": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-linux-x64-musl/-/cli-linux-x64-musl-0.1.30.tgz",
+ "integrity": "sha512-CDGUBmatxye06D0abeWAbtvXKqVm0RyBd1abtQyVt6070HNvZuS2SXkI3W8oDF1sIFjaVIp0nI4szXlAmZOe2Q==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@rumdl/cli-win32-x64": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/@rumdl/cli-win32-x64/-/cli-win32-x64-0.1.30.tgz",
+ "integrity": "sha512-W6nQZPQRCeN+0nbEbIWdpLSxqkEsDNkGAMaUilMukynmqiT2orJqHHwp9vJmKf1vRg8B8PlxVnL7meumfRk5bg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/@shikijs/core": {
"version": "3.22.0",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.22.0.tgz",
@@ -15722,6 +15842,28 @@
"points-on-path": "^0.2.1"
}
},
+ "node_modules/rumdl": {
+ "version": "0.1.30",
+ "resolved": "https://registry.npmjs.org/rumdl/-/rumdl-0.1.30.tgz",
+ "integrity": "sha512-vGeJ5oI6LMYbDq9Om6+km1TswecEKPFB0GqAbDfHe3/fzzT8WiAY2lYgLN39e7lzp4GQhzRfnT5OSfiqsILugQ==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "rumdl": "bin/rumdl"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "optionalDependencies": {
+ "@rumdl/cli-darwin-arm64": "0.1.30",
+ "@rumdl/cli-darwin-x64": "0.1.30",
+ "@rumdl/cli-linux-arm64": "0.1.30",
+ "@rumdl/cli-linux-arm64-musl": "0.1.30",
+ "@rumdl/cli-linux-x64": "0.1.30",
+ "@rumdl/cli-linux-x64-musl": "0.1.30",
+ "@rumdl/cli-win32-x64": "0.1.30"
+ }
+ },
"node_modules/run-parallel": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
diff --git a/package.json b/package.json
index da206083..3a0caeae 100644
--- a/package.json
+++ b/package.json
@@ -32,9 +32,12 @@
"precheck": "astro sync",
"check": "astro check",
"prelint": "astro sync",
- "lint": "npx eslint",
- "format": "npm run format:src && npm run format:content",
- "format:content": "prettier --write \"**/*.{md,mdx,astro}\"",
+ "lint": "npm run lint:src",
+ "lint:src": "npx eslint",
+ "lint:markdown": "chmod +x node_modules/@rumdl/cli-*/rumdl 2>/dev/null || true && rumdl check .",
+ "format": "npm run format:src && npm run format:astro && npm run format:markdown",
+ "format:astro": "npx prettier --write \"**/*.astro\"",
+ "format:markdown": "chmod +x node_modules/@rumdl/cli-*/rumdl 2>/dev/null || true && rumdl fmt .",
"format:src": "npx prettier --write \"**/*.{js,jsx,ts,tsx,mjs,css,json}\"",
"linkcheck": "CHECK_LINKS=true astro build",
"test": "vitest run"
@@ -76,6 +79,7 @@
"react-content-loader": "^7.1.2",
"react-dom": "^19.2.4",
"react-final-form": "^7.0.0",
+ "rumdl": "0.1.30",
"sass": "^1.97.3",
"starlight-image-zoom": "^0.13.0",
"starlight-links-validator": "^0.19.2",
diff --git a/src/content/docs/online-payments/3ds.mdx b/src/content/docs/online-payments/3ds.mdx
index 9765ea69..e86b9236 100644
--- a/src/content/docs/online-payments/3ds.mdx
+++ b/src/content/docs/online-payments/3ds.mdx
@@ -7,7 +7,6 @@ sidebar:
import { Aside } from '@astrojs/starlight/components';
-
-
## Configuring Hosted Checkout
### Redirecting Users After Successful Payment
@@ -88,7 +86,6 @@ When creating a checkout, simply provide a `redirect_url` parameter to include a
Differently from what's stated in our [API docs](/api/checkouts/create), the absence of this parameter does not affect the availability of payment methods in Hosted Checkouts.
-
## Hosted Checkout Status Pages
With Hosted Checkout, your payment flow is covered from start to finish. All successful payments are presented with a success page, informing users of the completed payment. Hosted Checkout also accommodates other payment outcomes:
@@ -101,18 +98,14 @@ With Hosted Checkout, your payment flow is covered from start to finish. All suc
-
- Expired session page is shown for all unpaid checkouts after session expiration or checkout expiration (currently 30 minutes).
-
- Not found page is shown for all URLs that do not match any existing session in our system.
-
-
-3. Once the user accepts your authorization request, the authorization server redirects the user back to your application by using the registered URI you specified in the `redirect_uri` at the initial GET request.
- The response will return the `code` parameter, which is mandatory for retrieving an access token.
+3. Once the user accepts your authorization request, the authorization server redirects the user back to your application by using the registered URI you specified in the `redirect_uri` at the initial GET request.
+
+ The response will return the `code` parameter, which is mandatory for retrieving an access token.
4. To retrieve the access token, the app makes a request to the `https://api.sumup.com/token` endpoint with a `Content-Type: application/x-www-form-urlencoded` header.
@@ -148,17 +147,17 @@ Note that refresh tokens can be invalidated due to factors other than expiration
Authorization scopes define what an application is allowed to do on a merchant's behalf. A required set of scopes may be passed as a space-separated list in the authorization request. When scopes are omitted, the default ones are granted. If additional scopes are required, a new `access_token` has to be collected via the [Authorization code flow](#authorization-code-flow).
-| Scope name | Default | Access Level | Description |
-| -------------------------------- | ------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| transactions.history | yes | merchant | Allows to view the transactions and transaction history for a specific merchant user's account. |
-| user.app-settings | yes | merchant | Allows to view and modify the SumUp mobile application settings for a specific merchant user's account. |
-| user.profile_readonly | yes | merchant | Allows viewing account details for a specific merchant user's account. |
-| user.profile | no | merchant | Allows modifying account details for a specific merchant user's account. |
-| user.subaccounts | no | merchant | Allows viewing and modifying account details of a sub-account created for a specific merchant user's account. Sub-accounts are user accounts for employees of a merchant and can be granted different permissions by the holder of the main merchant user's account. |
-| user.payout-settings | no | merchant | Allows to view and modify the payout settings for a specific merchant user's account. |
-| products | no | merchant | Allows to view and modify the product store for a specific merchant user's account. This includes the products, shelves, prices, and VAT rates available in the merchant's product store. |
-| `restricted` payments | no | feature | Allows to make payments by creating and processing payment checkouts. Requires verification by SumUp before it can be granted. |
-| `restricted` payment_instruments | no | feature | Allows to save customers and tokenize their payment cards for a specific merchant user's account. Requires verification by SumUp before it can be granted. |
+| Scope name | Default | Access Level | Description |
+| -------------------------------- | ------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| transactions.history | yes | merchant | Allows to view the transactions and transaction history for a specific merchant user's account. |
+| user.app-settings | yes | merchant | Allows to view and modify the SumUp mobile application settings for a specific merchant user's account. |
+| user.profile_readonly | yes | merchant | Allows viewing account details for a specific merchant user's account. |
+| user.profile | no | merchant | Allows modifying account details for a specific merchant user's account. |
+| user.subaccounts | no | merchant | Allows viewing and modifying account details of a sub-account created for a specific merchant user's account. Sub-accounts are user accounts for employees of a merchant and can be granted different permissions by the holder of the main merchant user's account. |
+| user.payout-settings | no | merchant | Allows to view and modify the payout settings for a specific merchant user's account. |
+| products | no | merchant | Allows to view and modify the product store for a specific merchant user's account. This includes the products, shelves, prices, and VAT rates available in the merchant's product store. |
+| `restricted` payments | no | feature | Allows to make payments by creating and processing payment checkouts. Requires verification by SumUp before it can be granted. |
+| `restricted` payment_instruments | no | feature | Allows to save customers and tokenize their payment cards for a specific merchant user's account. Requires verification by SumUp before it can be granted. |
Restricted scopes must be enabled by SumUp for your application. To do that, [contact us](/contact).
@@ -166,7 +165,7 @@ Restricted scopes must be enabled by SumUp for your application. To do that, [co
This flow follows [the RFC 6749 Client Credentials Grant](https://datatracker.ietf.org/doc/html/rfc6749#section-4.4)
-In the Client Credentials flow, your application requests an access token without requesting authorization from the merchant. As a result, when you use this flow, your application is not authorized to access any data associated with
+In the Client Credentials flow, your application requests an access token without requesting authorization from the merchant. As a result, when you use this flow, your application is not authorized to access any data associated with
the merchant user's account, such as transactions, saved customers, or tokenized payment cards. In other words, you can only process payments for merchant accounts with an access token obtained via this grant flow.
To request an access token, the app needs to make a request to the `https://api.sumup.com/token` endpoint as defined in the OAuth 2.0 Client Credentials protocol. This flow does not grant a Refresh Token.
@@ -175,9 +174,9 @@ To request an access token, the app needs to make a request to the `https://api.
Check the following resources to build your integration:
-* [OAuth 2.0 App Registration Guide](/tools/authorization/register-app/)
-* [{ iossdkname } Guide](/terminal-payments/sdks/ios-sdk/)
-* [{ androidreadersdkname } Guide](https://github.com/sumup/sumup-android-sdk)
-* [PHP SDK Guide](/tools/sdks/php-sdk/)
-* [React Native SDK](/terminal-payments/sdks/react-native-sdk/)
-* [Cloud API for the Solo Card Reader](/terminal-payments/cloud-api/)
+- [OAuth 2.0 App Registration Guide](/tools/authorization/register-app/)
+- [{ iossdkname } Guide](/terminal-payments/sdks/ios-sdk/)
+- [{ androidreadersdkname } Guide](https://github.com/sumup/sumup-android-sdk)
+- [PHP SDK Guide](/tools/sdks/php-sdk/)
+- [React Native SDK](/terminal-payments/sdks/react-native-sdk/)
+- [Cloud API for the Solo Card Reader](/terminal-payments/cloud-api/)
diff --git a/src/content/docs/tools/authorization/register-app.mdx b/src/content/docs/tools/authorization/register-app.mdx
index fc34a547..d80ebbc2 100644
--- a/src/content/docs/tools/authorization/register-app.mdx
+++ b/src/content/docs/tools/authorization/register-app.mdx
@@ -11,10 +11,10 @@ Register an OAuth application to integrate with SumUp and generate client creden
This guide covers registering a client application and obtaining credentials through these steps:
-1. [Log in to your account](#1-log-in-to-your-account)
-2. [Create an OAuth application](#2-create-an-o-auth-application)
-3. [Generate client credentials](#3-generate-client-credentials)
-4. [Access client credentials](#4-access-client-credentials)
+1. [Log in to your account](#1-log-in-to-your-account)
+2. [Create an OAuth application](#2-create-an-oauth-application)
+3. [Generate client credentials](#3-generate-client-credentials)
+4. [Access client credentials](#4-access-client-credentials)
## Prerequisites
@@ -44,19 +44,19 @@ Log in to [your SumUp account](/auth/login). Log in to your SumUp account. **Acc
For security reasons, SumUp manually verifies the following scope grants:
- * `payments` - required to process payments.
- * `payment_instruments` - required to store customer data and tokenize cards.
+ - `payments` - required to process payments.
+ - `payment_instruments` - required to store customer data and tokenize cards.
- [Contact us](/contact) to request those scopes to be granted to your app.
+ [Contact us](/contact) to request those scopes to be granted to your app.
- SumUp does not recommend direct OAuth 2.0 integration and does not expose detailed authorization endpoint documentation for that reason.
+ SumUp does not recommend direct OAuth 2.0 integration and does not expose detailed authorization endpoint documentation for that reason.
Please use a library that handles OAuth 2.0 protocol. We highly recommend that you use one of the [existing reputable implementations](https://openid.net/developers/certified-openid-connect-implementations/).
-
+
- The app requests user consent to access their data in line with the scopes granted here. For detailed information, see [OAuth2 Authorization Code Flow](/tools/authorization/authorization/).
+ The app requests user consent to access their data in line with the scopes granted here. For detailed information, see [OAuth2 Authorization Code Flow](/tools/authorization/authorization/).
### 3. Generate Client Credentials
@@ -69,7 +69,7 @@ Click on **Create client secret** to open the following form:
Provide the following details:
| Name | Required | Description |
-| -----| -------- | ---------- |
+| ----- | -------- | ---------- |
| Client name | Yes | A descriptive name for your client application. |
| Application type | Yes | Type: Web, Android, iOS, or Other. |
| Authorized redirect URL | Yes | Redirect URL for post-authentication. When merchant users authenticate with SumUp and authorize your client app to access their account data, they are redirected to this path in your application. You can add multiple URLs; separate with a comma. |
@@ -118,4 +118,3 @@ Store your client secret keys securely and never reveal them publicly. If you su
You have registered a client application and downloaded OAuth client credentials.
You can now use one of the [OAuth2 authorization flows](/tools/authorization/authorization/#authorization-flows) to obtain an access token and start making payments with either a [payment card entered by a customer](/online-payments/guides/single-payment/) or with a token for a [recurring payment](/online-payments/guides/tokenization-with-payment-sdk).
-