Calculate membership pricing

POST /api/pricing/memberships

Success: 200 OK

Overview

Returns a signed pricing quote for one or more memberships that people want to join: what each membership costs today, its recurring payments, its start and end dates and its cooling-off period. Use it when someone has chosen a membership type and you need the price to show them and the quote you must send back when you create the membership.

It is step 5 of the Joining flow. Take membership type ids from Get membership types grouped by tag, price them here, then pass the whole response, unaltered, as pricingQuote to Create members with memberships (new members) or Create a membership for a member (existing members). Those pages explain how long a quote stays valid.

The response is signed. timeStamp and signature cover the whole object, so store the response exactly as you received it and send it back verbatim. Change, round, reformat or drop any field, including ones you do not use, and the quote is rejected when you create the membership.

One request can price several people at once: each entry in members is one person, identified by an order key you choose, with the memberships they want. Every membership line in the response carries that order key back.

Endpoint

POST {base_url}/api/pricing/memberships

{base_url} is the environment URL issued to your integration. See Authenticating with Gladstone APIs.

Request body

FieldTypeRequiredDescription
siteIdstringYesThe site the memberships are being sold at. It must exist (404 Site ID {siteId} does not exist), and every requested membership type must be available there, or the request fails with 400 listing the ones that are not. It also sets the currency of every amount in the quote, and is echoed in the response as siteId.
startDatestring (date-time)YesThe date the memberships start, for example 2026-11-01T00:00:00Z. Only the date part is used. It cannot be before today's date in UTC (Start Date cannot be in the past), before a membership type's earliest start date, after a membership type's fixed end date, or, for membership types with no future earliest start date, before the site's opening date. See Errors for each case. Get earliest start date for membership returns a date that passes these checks.
membersarray of objectYesOne entry per person being priced. Each entry is priced separately and adds its own lines to memberships in the response.
members[].memberIdinteger (int32)NoThe existing member this person is, when they already have a member record. A member's own price level can then decide their price (see Notes). Omit it, or send 0, for someone who is not yet a member, which is the usual case when joining. Must be 0 or greater, or the request fails validation. A positive value must be a member that exists, or the request fails with 404 At least one member in the request does not exist.
members[].orderKeyinteger (int16)YesA number you choose to identify this person within the request, from 1 up. It must be unique across members (The order key for each member request must be unique); 0 or below fails with OrderKeys must be greater than 0. It is returned on each of this person's lines as memberships[].orderKey, and is how you later say which member receives which quote line.
members[].membershipsarray of objectYesThe memberships this person is buying. Must contain at least one entry, and every entry must have an id, or the request fails with At least one member request contains null or has no memberships. When one person buys two or more memberships, a single price level is chosen for all of them.
members[].memberships[].idstringYesThe membership type id, for example ASUBDD0001, from membershipTypes[].id on Get membership types grouped by tag. Case-insensitive: it is upper-cased before use. A membership type that does not exist returns 404 At least one membership type in the request does not exist.
members[].memberships[].promotionCodestringNoA promotion code to discount the price. All or nothing: if any membership in the request carries a code, every membership in the request, for every person, must carry the same code, or the request fails with 400 (see Errors). Leading and trailing spaces are ignored. Omit it on every membership to price without a promotion. A membership type the code holds no discount for is priced without one.

Sample request

cURL
curl -X POST '{base_url}/api/pricing/memberships' \
  -H 'Authorization: Bearer ***' \
  -H 'X-Use-SSO: true' \
  -H 'Content-Type: application/json' \
  -d '{
  "siteId": "WIN",
  "startDate": "2026-11-01T00:00:00Z",
  "members": [
    {
      "memberId": 0,
      "orderKey": 1,
      "memberships": [
        {
          "id": "ASUBDD0001"
        }
      ]
    }
  ]
}'

Response fields

Every amount is a string with exactly two decimal places, for example "35.00": parse it as a decimal, not a float. Every currency is the currency configured for the requested site.

FieldTypeDescription
siteIdstringThe siteId you sent.
promotionCodestringThe promotion code the quote was priced under, as the tenant has set it up, without any leading or trailing spaces you sent. Null when no code was sent.
overviewobjectTotals across every membership in the quote, for a basket summary.
overview.nowobjectThe total payable today across all memberships: the sum of every memberships[].pricing.now.totalPrice.amount.
overview.now.amountstringThe amount.
overview.now.currencystringThe currency code, for example GBP.
overview.now.discountobjectAlways null on the overview. Discounts are reported on each membership's lines.
overview.recurringobjectThe combined recurring payments of every membership that has them. Null when no membership in the quote has a recurring payment schedule, for example when every membership is paid for in full up front.
overview.recurring.headlinePriceobjectThe combined regular recurring amount: the sum of each recurring membership's pricing.recurring.headlinePrice. Before any promotion discount; discount is null.
overview.recurring.headlinePrice.amountstringThe amount.
overview.recurring.headlinePrice.currencystringThe currency code.
overview.recurring.headlinePrice.discountobjectAlways null here.
overview.recurring.frequencystringHow often recurring payments are taken, taken from the first recurring membership in the quote, for example Monthly.
overview.recurring.schedulearray of objectThe first four recurring payment dates across all memberships, in date order. Payments on the same date are combined.
overview.recurring.schedule[].datestring (date-time)The payment date.
overview.recurring.schedule[].totalPriceobjectThe total due on that date, as amount, currency and discount (null).
overview.recurring.schedule[].breakdownarray of objectThe individual payments due on that date. Same shape as memberships[].pricing.recurring.schedule[].payments[].
membershipsarray of objectOne entry for each membership requested, for each person, in request order.
memberships[].orderKeyinteger (int16)The orderKey of the person this line was priced for. A person buying two memberships has two lines with the same key.
memberships[].idstringThe membership type id, upper-cased.
memberships[].descriptionstringThe membership type's name, for display.
memberships[].coolingOffPeriodinteger (int32)The cooling-off period, during which a new membership can be cancelled. It is one setting for the whole tenant, so every line in a quote carries the same value. Null when the tenant has not configured one. See the DMCCA guide for how to present it.
memberships[].translationsarray of objectTranslations of the membership type's name, when the tenant has configured any. Each entry has type, culture (the language the text is in) and text.
memberships[].startDatestring (date-time)The membership's start date: the date part of the startDate you sent.
memberships[].endDatestring (date-time)The date the membership's term ends. A membership type with a fixed end date ends then. Otherwise, for a membership paid in full up front, it is the start date plus the membership type's duration in days or months, less one day.
memberships[].pricingobjectThe price of this membership.
memberships[].pricing.nowobjectWhat is payable today for this membership.
memberships[].pricing.now.totalPriceobjectThe total payable today for this membership, including any one-off joining fees and any part-month charge, after any promotion discount. discount is always null here; discounts are on the breakdown lines.
memberships[].pricing.now.totalPrice.amountstringThe amount.
memberships[].pricing.now.totalPrice.currencystringThe currency code.
memberships[].pricing.now.breakdownarray of objectOne line for each product that makes up the membership, with the amount of it payable today.
memberships[].pricing.now.breakdown[].priceLevelIdstringThe price level the membership was priced at. The same on every line of the membership.
memberships[].pricing.now.breakdown[].includesFirstFullPaymentbooleanOnly meaningful on a pro-rata line: true when the amount due today includes a full month's payment, for example when startDate falls on the membership's regular payment day. false on every other line.
memberships[].pricing.now.breakdown[].productIdstringThe product this line charges for.
memberships[].pricing.now.breakdown[].typestringWhat kind of charge this is: one-off (a single charge such as a joining fee), regular (the membership's regular price) or pro-rata (a pro-rata direct debit membership's charge for the period up to its regular payment day).
memberships[].pricing.now.breakdown[].descriptionstringThe product's name, for display.
memberships[].pricing.now.breakdown[].translationsarray of objectTranslations of the product's name. Same shape as memberships[].translations.
memberships[].pricing.now.breakdown[].priceobjectThe amount of this product payable today.
memberships[].pricing.now.breakdown[].price.amountstringThe amount, after any promotion discount.
memberships[].pricing.now.breakdown[].price.currencystringThe currency code.
memberships[].pricing.now.breakdown[].price.discountobjectThe promotion discount applied to this line. Null when none applies.
memberships[].pricing.now.breakdown[].price.discount.priceBeforeDiscountstringWhat the line would have cost without the discount.
memberships[].pricing.now.breakdown[].price.discount.discountValuestringThe amount taken off.
memberships[].pricing.now.breakdown[].price.discount.discountIdinteger (int32)The discount that was applied.
memberships[].pricing.recurringobjectThe membership's recurring payments. Always present, but populated only for a direct debit or recurring card payment (RCP) membership. For any other membership, headlinePrice and frequency are null and schedule is empty.
memberships[].pricing.recurring.membershipIdinteger (int32)Always null in this response, because the membership does not exist yet.
memberships[].pricing.recurring.headlinePriceobjectThe regular recurring amount: the sum of the membership's regular products at its start date, before any promotion discount (discount is null). This is the "£x a month" figure. Discounted payments appear in schedule.
memberships[].pricing.recurring.headlinePrice.amountstringThe amount.
memberships[].pricing.recurring.headlinePrice.currencystringThe currency code.
memberships[].pricing.recurring.frequencystringHow often recurring payments are taken, for example Monthly.
memberships[].pricing.recurring.schedulearray of objectThe recurring payments for this membership's term, by date.
memberships[].pricing.recurring.schedule[].datestring (date-time)The payment date.
memberships[].pricing.recurring.schedule[].paymentsarray of objectThe payments due on that date.
memberships[].pricing.recurring.schedule[].payments[].priceobjectThe payment amount, after any promotion discount, as amount, currency and discount. discount has the same fields as on a breakdown line and is null when no discount applies to that date.
memberships[].pricing.recurring.schedule[].payments[].paymentMethodobjectThe payment method the payment is taken by: the membership type's first configured payment method.
memberships[].pricing.recurring.schedule[].payments[].paymentMethod.idstringThe payment method id.
memberships[].pricing.recurring.schedule[].payments[].paymentMethod.descriptionstringThe payment method's name, for display.
memberships[].pricing.recurring.schedule[].payments[].paymentMethod.translationsarray of objectTranslations of the payment method's name. Same shape as memberships[].translations.
timeStampstringWhen the quote was created, in UTC, in ISO 8601 round-trip format. Quote validity is measured from it.
signaturestringA Base64 signature over the rest of the quote. You cannot generate or check it; send it back unchanged with the quote.

Sample response

200 OK
{
  "siteId": "WIN",
  "promotionCode": null,
  "overview": {
    "now": {
      "amount": "45.00",
      "currency": "GBP",
      "discount": null
    },
    "recurring": {
      "headlinePrice": {
        "amount": "35.00",
        "currency": "GBP",
        "discount": null
      },
      "frequency": "Monthly",
      "schedule": [
        {
          "date": "2026-12-01T00:00:00Z",
          "totalPrice": {
            "amount": "35.00",
            "currency": "GBP",
            "discount": null
          },
          "breakdown": [
            {
              "price": {
                "amount": "35.00",
                "currency": "GBP",
                "discount": null
              },
              "paymentMethod": {
                "id": "string",
                "description": "string",
                "translations": []
              }
            }
          ]
        }
      ]
    }
  },
  "memberships": [
    {
      "orderKey": 1,
      "id": "ASUBDD0001",
      "description": "string",
      "coolingOffPeriod": null,
      "translations": [],
      "startDate": "2026-11-01T00:00:00Z",
      "endDate": "2027-10-31T00:00:00Z",
      "pricing": {
        "now": {
          "totalPrice": {
            "amount": "45.00",
            "currency": "GBP",
            "discount": null
          },
          "breakdown": [
            {
              "priceLevelId": "string",
              "includesFirstFullPayment": false,
              "productId": "string",
              "type": "one-off",
              "description": "string",
              "translations": [],
              "price": {
                "amount": "10.00",
                "currency": "GBP",
                "discount": null
              }
            },
            {
              "priceLevelId": "string",
              "includesFirstFullPayment": false,
              "productId": "string",
              "type": "pro-rata",
              "description": "string",
              "translations": [],
              "price": {
                "amount": "35.00",
                "currency": "GBP",
                "discount": null
              }
            }
          ]
        },
        "recurring": {
          "membershipId": null,
          "headlinePrice": {
            "amount": "35.00",
            "currency": "GBP",
            "discount": null
          },
          "frequency": "Monthly",
          "schedule": [
            {
              "date": "2026-12-01T00:00:00Z",
              "payments": [
                {
                  "price": {
                    "amount": "35.00",
                    "currency": "GBP",
                    "discount": null
                  },
                  "paymentMethod": {
                    "id": "string",
                    "description": "string",
                    "translations": []
                  }
                }
              ]
            }
          ]
        }
      }
    }
  ],
  "timeStamp": "2026-10-15T09:30:00.0000000Z",
  "signature": "string"
}

Errors

Except where a validation problem document is described, the error body carries the message shown.

StatusMeaningWhen
400Bad requestA required field is missing or a value has the wrong type or range: a validation problem document (application/problem+json) with an errors map keyed by field name. Examples: no siteId (The SiteId field is required), no startDate, no orderKey, orderKey of 0 (OrderKeys must be greater than 0), a negative memberId, or a non-numeric orderKey (Could not convert string to integer: …).
400Bad requeststartDate is before today's date in UTC: Start Date cannot be in the past.
400Bad requestA person has no memberships, or a membership has no id: At least one member request contains null or has no memberships.
400Bad requestTwo people share an order key: The order key for each member request must be unique.
400Bad requeststartDate is before the site's opening date, and none of the requested membership types has an earliest start date in the future: The requested start date is before the Sites opening date.
400Bad requestA requested membership type is not sold at the site: The following memberships ({ids}) are not available at the site {siteId}.
400Bad requestThe promotion code is on some memberships but not all: When applying a Promotion Code, this must be applied against all memberships in the request. Different codes on different memberships: Only one Promotion Code can be used in the request for all memberships.
400Bad requestThe promotion code cannot be used: Promotion code {code} is not a valid promotion code, Promotion code {code} is not currently active (inactive, or its start date is in the future), Promotion code {code} is expired, or Promotion code {code} is not applicable to any of the memberships selected.
400Bad requestThe promotion code exists but none of its discounts can be used for these memberships at this site: There are no active and applicable discounts related to the promocode {code} that can be applied to any of the memberships.
400Bad requestThe price level found for the person cannot be bought for at least one product of the membership types, for example The default price level {priceLevelId} for the site {siteId} does not allow to be purchased in at least one of the products of the membership types {ids}. The equivalent messages for a price level taken from the member or the membership type name the member or the membership type instead. When no price level could be found at all, these messages are returned with 422.
404Not foundsiteId does not exist: Site ID {siteId} does not exist.
404Not foundA positive memberId is not a member: At least one member in the request does not exist.
404Not foundA membership type id does not exist: At least one membership type in the request does not exist.
422Unprocessable entitystartDate is before a membership type's earliest start date: The requested start date is before one or more memberships earliest start date. Membership Type(s): {ids}. Get a valid date from Get earliest start date for membership.
422Unprocessable entityA membership type's fixed end date has passed (The fixed end date has already passed for membership type(s): {ids}.), or startDate is after it (The requested start date must be on or before the fixed end date. Membership Type(s): {ids}).
422Unprocessable entityNo usable price level can be found for a membership, or its products have no price that can be bought. Messages include The membership type {id} and it's product {productId} has no prices with purchase allowed, so has not been configured correctly to provide a price., The membership type {id} configured with the price level {priceLevelId} is not allowed for purchase., The membership type {id} and its products have not been configured correctly to provide a price and Membership ID {id} has not been configured correctly to provide a price.
422Unprocessable entityThe membership type's setup is inconsistent: The duration has not been correctly configured for membership type {id}, The ProRata should not be set for a RCP membership. MembershipId: {id}, The default start day should not be set for a RCP membership. MembershipId: {id}, The default start day should be set for a DD membership. MembershipId: {id} or The cut off day must be after the fixed start day for the membership with ID {id}.
500Internal server errorAn unexpected server-side failure. No body is returned.

Every 422 here, and the price level 400, is a configuration problem at the tenant: retrying will not help. Show a generic "this membership cannot be bought online" message and report the text to the operator.

Notes

This page as markdown · All pages · llms.txt