Skip to content

Online Payment & Card Registration

Resamania provides a universal payment widget that abstracts the complexity of different PSPs into a single interface. This widget supports both one-shot payment (settling a sale) and card registration (webcard).

NOTE

A legacy integration (PSP-specific) is available for partners already in production with that approach. See the legacy documentation if needed.

Supported PSPs

PSPOne-shotWallet
Stripe
Payline
GlobalPayment
XplorPay / Snap

Integration Modes

Three approaches are available depending on your technical stack:

ModeDescriptionRecommended for
Native iframeThe widgetUrl returned by the API can be embedded directly in an HTML <iframe>. Communication (success/failure) goes through window.postMessage.Any web project with a bit of JS
Direct redirectHTTP redirect to the PSP's payment page — your backend redirects the user.Stacks without client-side JS (PHP, etc.)
React component<WidgetIframe /> via @resamania/payment-react — wraps the iframe and exposes onActionSuccess / onActionFailure callbacks. The package is installed via HTTP URL.React / Next.js applications

IMPORTANT

The mode is determined by the presence or absence of validUrl / cancelUrl in the POST /payable_objects request body:

  • Without validUrl or cancelUrl → the API generates a widgetUrl to embed as an iframe
  • With validUrl and cancelUrl → the API returns a redirectUrl to the PSP

Required Headers

All requests to the Resamania API must include these headers:

http
Accept: application/json, text/plain, */*
Content-Type: application/ld+json
Authorization: Bearer {your_bearer_token}

NOTE

Content-Type: application/ld+json is required for the server to process the request correctly. Accept: application/json is needed to receive the response as flat JSON, including all business fields (such as widgetUrl).


Case 1: Online Payment (one-shot)

Flow — Widget mode (iframe / React)

1. Your backend   →  POST /{clientToken}/payable_objects   (without validUrl or cancelUrl)
                  ←  { id, widgetUrl, ... }

2. Your frontend  →  <iframe src="{widgetUrl}" />
                     or <WidgetIframe src={widgetUrl} />

3. The user pays in the iframe

4.                ←  window.postMessage / onActionSuccess(payload, { provider })
                      or onActionFailure(payload, { provider })

Flow — Direct redirect (PHP, etc.)

1. Your backend   →  POST /{clientToken}/payable_objects   (with validUrl and cancelUrl)
                  ←  { id, redirectUrl, ... }

2. Your backend   →  HTTP 302 to redirectUrl

3. The user pays on the PSP page

4. The PSP        →  Redirects to validUrl (success or failure) or cancelUrl (abandoned)

5. Your backend   →  PUT /{clientToken}/payable_objects/{id}/check
                  ←  { state: 'validated' | 'refused' | ... }

1. Create a payment object

POST /{clientToken}/payable_objects

Widget mode — do not send validUrl or cancelUrl:

json
{
  "contactId":      "/demoapi/contacts/2972926",
  "amount":         2500,
  "currency":       "EUR",
  "clubCode":       "CFF",
  "clubId":         "/demoapi/clubs/1398",
  "checkout":       "/demoapi/checkouts/1361",
  "payableObjects": {
    "sales":     ["/demoapi/sales/3558464"],
    "invoices":  [],
    "incidents": []
  },
  "useWebWallet": true
}

Redirect mode — send validUrl and cancelUrl:

json
{
  "contactId":      "/demoapi/contacts/2972926",
  "amount":         2500,
  "currency":       "EUR",
  "clubCode":       "CFF",
  "clubId":         "/demoapi/clubs/1398",
  "checkout":       "/demoapi/checkouts/1361",
  "payableObjects": {
    "sales":     ["/demoapi/sales/3558464"],
    "invoices":  [],
    "incidents": []
  },
  "validUrl":  "https://your-site.com/payment/return",
  "cancelUrl": "https://your-site.com/payment/cancel"
}

NOTE

useWebWallet: true instructs the API to save the card as a reusable payment method (webcard) at the time of payment. Only use this if the club has this feature enabled in its PSP configuration.

WARNING

The validUrl is called for both success and failure. Embed your own session identifier in this URL (e.g. ?sessionId=xxx) to retrieve the transaction on return — Resamania does not add any parameters automatically.

Fields returned depending on the mode:

FieldWidget modeRedirect modeDescription
idIRI of the payableObject (e.g. /demoapi/payable_objects/12345)
widgetUrlURL to embed as an iframe — contains the authentication token
redirectUrlURL to the PSP's payment page
tokenTransaction reference on the PSP side

2a. Native iframe

Embed the widgetUrl directly in an <iframe> and listen for postMessage events:

html
<iframe
  src="{widgetUrl}"
  style="width: 100%; min-height: 500px; border: none;"
></iframe>

<script>
window.addEventListener('message', (event) => {
  if (event.data?.type === 'ACTION_SUCCESS') {
    console.log('Payment accepted', event.data.payload)
  } else if (event.data?.type === 'ACTION_FAILURE') {
    console.error('Payment refused', event.data.payload)
  }
})
</script>

NOTE

The widgetUrl returned by the API already contains the authentication token (autologintoken) as a query param. Use it directly without modification.

2b. Direct redirect (PHP / server-side)

php
// Retrieve the redirectUrl from the response and redirect
header('Location: ' . $payableObject['redirectUrl']);
exit;

2c. React component

Install the package:

bash
npm install "https://payment.resamania.com/pkg/resamania-payment-react-0.0.0.tgz"
tsx
import { WidgetIframe } from '@resamania/payment-react'

function PaymentPage({ widgetUrl }) {
  const handleSuccess = (payload, { provider }) => {
    // Payment was accepted by the PSP.
    // Always verify the status server-side before confirming the order.
    console.log('Payment accepted via', provider, payload)
  }

  const handleFailure = (payload, { provider }) => {
    console.error('Payment refused via', provider, payload)
  }

  return (
    <WidgetIframe
      src={widgetUrl}
      style={{ width: '100%', minHeight: 500, border: 'none' }}
      onActionSuccess={handleSuccess}
      onActionFailure={handleFailure}
    />
  )
}

3. Check payment status

PUT /{clientToken}/payable_objects/{id}/check

Call server-side after a payment return (redirect) or to confirm a success reported by the widget. Queries the PSP in real time and updates the object's state.

WARNING

{id} is the numeric identifier of the payableObject (e.g. 12345), extracted from the IRI /demoapi/payable_objects/12345.

StateDescription
createdCreated, not yet presented to the user
pendingAwaiting confirmation from the PSP
requestedPayment being processed
validatedPayment accepted ✅
refusedPayment refused ❌
canceledTransaction canceled by the user

Case 2: Card Registration (Webcard)

The widget can register a payment card without an immediate charge — useful for SEPA mandates, recurring subscriptions, or pre-registration before purchase.

Flow

1. Your backend   →  POST /{clientToken}/web_wallets
                  ←  { widgetUrl, ... }

2. Your frontend  →  <WidgetIframe src={widgetUrl} />

3. The user enters their card

4.                ←  onActionSuccess(WebCard[], { provider })
                      or onActionFailure(payload, { provider })

1. Create a wallet

POST /{clientToken}/web_wallets

json
{
  "contactId": "/demoapi/contacts/2972926",
  "clubId":    "/demoapi/clubs/1398",
  "checkout":  "/demoapi/checkouts/1361"
}

The response contains a widgetUrl to pass directly to the <WidgetIframe /> component.

2. Display the registration form

tsx
import { WidgetIframe } from '@resamania/payment-react'

function WebCardPage({ widgetUrl }) {
  const handleSuccess = (webCards, { provider }) => {
    // webCards is an array of registered WebCards
    // [{ id, cardReference, state, createdAt, ... }]
  }

  return (
    <WidgetIframe
      src={widgetUrl}
      style={{ width: '100%', minHeight: 400, border: 'none' }}
      onActionSuccess={handleSuccess}
      onActionFailure={(payload, { provider }) => console.error(payload)}
    />
  )
}

WidgetIframe Component Reference

PropTypeDescription
srcstringwidgetUrl returned by the API (required)
styleCSSPropertiesInline styles for the iframe
classNamestringCSS class for the iframe
onActionSuccess(payload, context) => voidSuccess callback
onActionFailure(payload, context) => voidFailure callback

context contains: { provider: string } — the PSP used by the club.


Full Examples

Complete examples are available in the resamania2-partners repository:


Migrating from the Legacy Integration

If you are using the old PSP-specific integration (Stripe Elements, Payline redirect…), here are the changes:

Before (legacy integration)Now (Resamania Widget)
PSP-specific integrationOne widget, all PSPs
Managing clientSecret + publishableKey (Stripe)A single widgetUrl field returned by the API
@stripe/react-stripe-js@resamania/payment-react
Native PSP callbacksonActionSuccess / onActionFailure
No unified verificationPUT /payable_objects/{id}/check