Payments

Payment API Guide

Use this guide to take a payment through the Gladstone Payments API, from selecting a membership to submitting the final payment request.


0. Prerequisites

You will need to pass in the Authorization header for each call to Gladstone APIs, which is a Bearer token issued for your tenant. You can generate the token by following the Authentication guide.

We have created a sample web application that demonstrates the recommended payment flow and provides a practical reference for integrating with the Gladstone Payments API. If you would like to explore the implementation or step through the payment flow, you can download the application using the link below.

Download

Example Only: This application is provided as a reference to help you understand and test the payment flow. It is not intended to be used as-is in a production environment.


1. End-to-End Payments Flow summary

  1. Find a membership (filter by type, duration, group).
  2. Generate a pricing quote for the membership.
  3. Create a member and assign the membership with the pricing quote.
  4. Collect card details securely using Cardstream Hosted Payment Fields.
  5. Submit payment via the api/payment/pay endpoint.
  6. Handle 3DS challenge if required, and resubmit.

The remainder of this document walks through each of these steps in detail.


2. Membership Selection

Step 2.1 - Get Member Types

GET /api/configuration/tag-groups/{MEMBER_TYPES}

Retrieves available member categories (Adult, Senior, etc.).

๐Ÿ‘‰ Get tag group by ID or key.

Implementation notes: The tag keys you choose here from the response of the above call i.e., (Tag.Key) feeds directly into the memberships request in step 2.4.

Step 2.2 - Get Membership Durations

GET /api/configuration/tag-groups/{MEMBERSHIP_DURATIONS}?filters={TYPE_ID}

Returns durations (Monthly, Annual, etc.) for the chosen type.

Implementation notes: Pass the (Tag.Key) from Step 2.1 via the filters query string so the result only contains valid durations. Example filter: filters=MEMBER_TYPES:1.

Step 2.3 - Get Membership Types

GET /api/configuration/tag-groups/{MEMBERSHIP_TYPES}

Retrieves membership style (Individual, Group, etc.).

Implementation notes: The tag group returned here is the same tagGroupKey that the memberships request in step 2.4 requires.

Step 2.4 - Get Memberships by Tag Group

POST /api/memberships/membership-types-by-tag-group

Input: Selected member type, duration, membership type.

Output: Available Memberships.

๐Ÿ‘‰ Get membership types grouped by tag.

Implementation notes: The data returned from API response in steps 2.1, 2.2 and 2.3 would be used in this API call. Example payload looks similar to the following.

{
  "tagKeys": ["MEMBER_TYPE_ADULT", "MEMBERSHIP_DURATION_MONTHLY", "MEMBERSHIP_GROUP_GYM"],
  "tagGroupKey": "SITE_DEFAULT",
  "siteId": "SITE01",
  "includeHeadlinePrice": true,
  "isWebBookable": true
}

The response includes each membership's id, description, translations, price levels, and headline pricing information PriceBreakdown. The next steps assume the chosen id, orderKey, and priceLevelId are retained for the pricing and membership-creation requests.


3. Pricing a Membership

POST /api/pricing/memberships

Returns a pricing quote (signature + timestamp).

โš ๏ธ

You must pass this object unchanged into the membership creation step below.

๐Ÿ‘‰ Pricing API docs.

Implementation notes: Example payload looks similar to the following:

{
  "siteId": "SITE01",
  "startDate": "2024-10-01T00:00:00Z",
  "members": [
    {
      "orderKey": 1,
      "memberId": null,
      "memberships": [
        {
          "id": "MEMBERSHIP_TYPE_KEY",
          "promotionCode": null
        }
      ]
    }
  ]
}

Response:

{
  "timeStamp": "2024-10-01T12:00:00Z",
  "signature": "af05ec...",
  "siteId": "SITE01",
  "overview": {
    "now": { "amount": "45.00", "currency": "GBP" },
    "recurring": { "amount": "45.00", "currency": "GBP" }
  },
  "memberships": [
    {
      "orderKey": 1,
      "id": "MEMBERSHIP_TYPE_KEY",
      "pricing": {
        "now": { "totalPrice": { "amount": "45.00", "currency": "GBP" } },
        "recurring": { "totalPrice": { "amount": "45.00", "currency": "GBP" } }
      }
    }
  ]
}

Creating Member with Membership (next step) requires this object as it is. Do not modify signature or timeStamp.


4. Creating Member with Membership

POST /api/memberships/add-members-with-memberships

Input: member details, membership details, and pricing quote.

Output: memberIds and salesInvoiceIds (needed for payment).

Implementation notes: Gladstone APIs validate the request against the following values.

Sample request skeleton:

{
  "siteId": "SITE01",
  "primaryMember": {
    "orderKey": 1,
    "profile": {
      "titleId": "MR",
      "firstName": "Alex",
      "lastName": "Doe",
      "email": "alex@example.com",
      "dateOfBirth": "1990-01-01"
    },
    "addressDetails": {
      "address1": {
        "addressLine1": "1 Sample Street",
        "townCity": "Bristol",
        "postalCode": "BS1 1AA",
        "country": "GB",
        "isPrimary": true
      }
    },
    "contactDetails": {
      "mobile": { "number": "+441234567890", "isPrimary": true }
    },
    "optInMarketing": true,
    "signedAgreements": {
      "privacyPolicy": true,
      "termsAndConditions": true,
      "healthCommitmentStatement": true
    }
  },
  "linkedMembers": [],
  "pricingQuote": {}
}

Replace the empty pricingQuote object with the complete response from step 3 before sending the request.

Response:

{
  "membersCreated": [
    {
      "orderKey": 1,
      "memberId": 123456,
      "salesInvoiceIds": [78901]
    }
  ],
  "membershipsCreated": [{ "membershipId": 555 }],
  "timeStamp": "2024-10-01T12:05:00Z",
  "signature": "..."
}

Persist the memberId and every salesInvoiceId. Gladstone's payment APIs validate these values before contacting the payment provider, and you will use them in Step 6 below.


5. Collecting Payment Details

Card details must never reach your servers. Use Cardstream Hosted Payment Fields.

Step 5.1 - Load Hosted Fields Library

<script src="https://gateway.example.com/sdk/web/v1/js/hostedfields.min.js"></script>

Requires jQuery.

Step 5.2 - Example Hosted Field HTML

<form id="payment-form">
  <input type="hostedfield:cardNumber" name="card-number" />
  <input type="hostedfield:cardExpiryDate" name="expiry-date" />
  <input type="hostedfield:cardCVV" name="cvv" />
</form>

๐Ÿ“š More Examples

Step 5.3 - Initialising the Form

var form = new window.hostedFields.classes.Form(document.getElementById('payment-form'), {
  autoSetup: true,
  autoSubmit: false,
  merchantID: "<YOUR_MERCHANT_ID>",
  tokenise: '.add-to-token'
});

form.getPaymentDetails().then(result => {
  if (result.success) {
    const token = result.paymentToken;
    // send token to /api/payment/pay
  }
});

6. Submitting Payment

POST /api/payment/pay

Input: memberId, salesInvoiceIds, and paymentMethod (with hosted-fields token or stored card).๐Ÿ‘‰ Pay for sales invoices.

Request contract

The payment request contract is:

PropertyNotes
salesInvoiceIdsRequired array, duplicates get rejected.
memberIdRequired and validated against invoices returned by Payment Service.
paymentMethodsRequired list but Gladstone APIs currently restrict to a single payment method.
paymentProviderEnum depicting available payment providers
amountMust be >= outstanding invoice total.
paymentToken or cardIdFor non-zero invoices, one of these must be provided.
saveCardToWallet / saveRcpCardFlags passed for tokenisation.
threeDSecureChallengeReference/ResponseOnly used for subsequent 3DS submissions.
threeDSecureChallengeOptionalFieldBrowser specifications and fields
deviceInformationTime zone, capabilities, and resolution for device fingerprinting.

Device information values can be found here: https://guides.gitbook.io/integrationguide/gateway-functionality/features/advanced-data/device-information-fields

Example request. Use the payment token created in Step 5 as the paymentToken value.

{
  "salesInvoiceIds": [78901],
  "memberId": 123456,
  "paymentMethods": [
    {
      "paymentProvider": "GladstonePay",
      "amount": 45.00,
      "paymentToken": "TOKEN_FROM_CARDSTREAM",
      "saveCardToWallet": true,
      "saveRcpCard": false,
      "deviceInformation": {
        "timeZone": "0",
        "capabilities": "javascript",
        "screenResolution": "1170x2532"
      },
      "threeDSecureChallengeOptionalField": {
        "browserAcceptHeader": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
        "browserLanguage": "en-GB",
        "browserTimeZone": "0",
        "browserUserAgent": "Mozilla/5.0 ...",
        "browserJavascriptEnabledVal": "true",
        "browserScreenHeight": "1170",
        "browserScreenWidth": "2532",
        "browserScreenColorDepth": "24"
      }
    }
  ]
}

Response payload

A successful HTTP 200 response returns this shape:

{
  "responseStatus": "PaymentSuccessful",
  "transactionId": "CARDSTREAM-TXN-ID",
  "message": null,
  "threeDSecureChallengeUrl": null,
  "threeDSecureChallengeFields": {}
}

Other statuses include PaymentFailed, ThreeDSecureChallengeRequired, InvalidPaymentToken, ServiceUnavailable, InvalidRequest, InvalidConfiguration, InternalServerError, and ErrorDoNotRepeatTransaction.

Handling 3-D Secure (3DS)

  1. When responseStatus is ThreeDSecureChallengeRequired, the HTTP status is still 200. threeDSecureChallengeUrl points to Cardstream's ACS and threeDSecureChallengeFields contains the form fields to POST (always includes threeDSRef).
  2. The ThreeDSecure Challenge needs to be completed by the client side.
  3. Once the challenge is done, add the returned value to the property threeDSecureChallengeResponse, and add the threeDSRef to the property threeDSecureChallengeReference. Post these in a second request to inform the payment provider of the result of the 3D Secure challenge via api/payment/pay endpoint

Important: Reuse the same salesInvoiceIds and memberId for every attempt. InvoiceService treats repeated calls as part of one transaction and will reject mismatched payloads.


7. Special Notes


8. Example End-to-End Sequence

  1. Fetch tag groups (member types, durations, membership types) from Configuration.
  2. POST /api/memberships/membership-types-by-tag-group to display bookable memberships.
  3. POST /api/pricing/memberships to obtain a signed pricing quote.
  4. POST /api/memberships/add-members-with-memberships to create the member and receive memberId/salesInvoiceIds.
  5. Capture hosted fields in browser, tokenise the card, and use returned Payment token.
  6. POST /api/payment/pay with the token, invoice IDs, and device/browser metadata.
  7. If 3DS is required, prompt the client to complete the challenge in the browser and the resubmit to the same endpoint with ThreeDsRef response.
  8. (Optional) Add the card to the wallet using (POST /api/members/{id}/wallet/card) and set it as the default RCP card (PUT /api/members/{id}/rcp-card) as listed in Step 9.

9. Wallet & Recurring Card APIs

Following are some of the other endpoints that Gladstone APIs expose to interact with the wallet and handle recurring card payments.

EndpointPurpose
GET /api/members/{memberId}/rcp-cardReturns the current default recurring card (rcpCardId, verified).
PUT /api/members/{memberId}/rcp-cardSets the default recurring card: { "rcpCardId": "<CardStreamId>" }.
GET /api/members/{memberId}/wallet/gladstonepayRetrieves full wallet metadata (cards, tokens, RTUS status).
POST /api/members/{memberId}/wallet/cardAdds or verifies a card using paymentToken, optional 3DS fields, and device info. Returns cardId, walletId, and potential 3DS requirements.
DELETE /api/members/{memberId}/wallet/gladstonepay/{cardId}Removes a stored card (ensure it is not the active RCP card).

10. Payment Response Status Reference

GladstonePay APIs extend the list with 3DS-specific failures (InvalidThreeDSRef, InvalidThreeDSDetails, InvalidThreeDSURL, etc.). It is adviced to treat these as terminal errors that require a new challenge cycle or updated 3DS data.


For troubleshooting or Payments API related queries, please contact Gladstone Support.

This page as markdown ยท All pages ยท llms.txt