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.
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
- Find a membership (filter by type, duration, group).
- Generate a pricing quote for the membership.
- Create a member and assign the membership with the pricing quote.
- Collect card details securely using Cardstream Hosted Payment Fields.
- Submit payment via the
api/payment/payendpoint.- 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-groupInput: 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/membershipsReturns 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-membershipsInput: 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.
siteId- must match the pricing request.primaryMember- includes profile, address, contact details, bank details, user fields, and signed agreements.linkedMembers- optional array of dependants.pricingQuote- the exact response from step 3.
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/payInput: memberId, salesInvoiceIds, and paymentMethod (with hosted-fields token or stored card).๐ Pay for sales invoices.
Request contract
The payment request contract is:
| Property | Notes |
|---|---|
salesInvoiceIds | Required array, duplicates get rejected. |
memberId | Required and validated against invoices returned by Payment Service. |
paymentMethods | Required list but Gladstone APIs currently restrict to a single payment method. |
paymentProvider | Enum depicting available payment providers |
amount | Must be >= outstanding invoice total. |
paymentToken or cardId | For non-zero invoices, one of these must be provided. |
saveCardToWallet / saveRcpCard | Flags passed for tokenisation. |
threeDSecureChallengeReference/Response | Only used for subsequent 3DS submissions. |
threeDSecureChallengeOptionalField | Browser specifications and fields |
deviceInformation | Time 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)
- When
responseStatusisThreeDSecureChallengeRequired, the HTTP status is still 200.threeDSecureChallengeUrlpoints to Cardstream's ACS andthreeDSecureChallengeFieldscontains the form fields to POST (always includesthreeDSRef). - The ThreeDSecure Challenge needs to be completed by the client side.
- 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/payendpoint
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
- For Recurring Card Payment (RCP) memberships, set both
saveCardToWalletandsaveRcpCardtotrueso Gladstone API retains the token and marks it as the default card. - Zero-priced invoices skip the provider call but still mark invoices as paid. This is logged by the Payment APIs and returns
PaymentSuccessfulwithtransactionId = null. ErrorDoNotRepeatTransactionindicates the provider collected funds but invoice processing failed. Investigate manually before retrying to avoid double-charging.PaymentMethodscurrently supports a single payment method.- Use the wallet endpoints (Section 9) to promote a card saved during checkout to the default RCP card.
8. Example End-to-End Sequence
- Fetch tag groups (member types, durations, membership types) from Configuration.
POST /api/memberships/membership-types-by-tag-groupto display bookable memberships.POST /api/pricing/membershipsto obtain a signed pricing quote.POST /api/memberships/add-members-with-membershipsto create the member and receivememberId/salesInvoiceIds.- Capture hosted fields in browser, tokenise the card, and use returned Payment token.
POST /api/payment/paywith the token, invoice IDs, and device/browser metadata.- If 3DS is required, prompt the client to complete the challenge in the browser and the resubmit to the same endpoint with ThreeDsRef response.
- (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.
| Endpoint | Purpose |
|---|---|
GET /api/members/{memberId}/rcp-card | Returns the current default recurring card (rcpCardId, verified). |
PUT /api/members/{memberId}/rcp-card | Sets the default recurring card: { "rcpCardId": "<CardStreamId>" }. |
GET /api/members/{memberId}/wallet/gladstonepay | Retrieves full wallet metadata (cards, tokens, RTUS status). |
POST /api/members/{memberId}/wallet/card | Adds 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
PaymentSuccessfulThreeDSecureChallengeRequiredPaymentFailedInvalidPaymentTokenServiceUnavailableInvalidRequestInvalidConfigurationInternalServerErrorErrorDoNotRepeatTransaction
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.