Skip to content

Selling to an Existing Customer

The following documentation describes the setup, via API, of a sale to an existing customer only.
Sales to people unknown to the club, for example on an unauthenticated portal, follow a specific process.

INFO

Retrieve the corresponding scenario in the Bruno collection available here : Selling a product

CAUTION

It is essential that you are familiar with the terms defined in the glossary before reading this documentation.

WARNING

In the case of integration with a payment provider, it is important to perform this action only when the provider has validated the payment (and not to add payment intents).

High-Level Sales Process

The sales process for an existing contact is structured as follows:

  1. Identify the contact
  2. Retrieve the catalog corresponding to the contact
  3. Sell one or more products to the contact
  4. Verify the validity of the sale
  5. Validate the sale and record the payment

Identify the contact

Several pieces of information related to the contact targeted by the sale must be collected beforehand. This information will then be used when retrieving the catalog.

Retrieve the contact tags

Tags are listed as a table in the description of a contact object, under the property tags.

bash
GET `/{clientToken}/contacts/{contactId}`
bash
GET `/demoapi/contacts/1234`
json
{  
   "@context":"/clienttoken/contexts/Contact",
   "@id":"/clienttoken/contacts/1234",
   "@type":"http://schema.org/Person",
   "number":"4110012692",
// ...
   "tags":[                          // <-- liste des mots clés de l'utilisateur
      {  
         "@id":"/clienttoken/contact_tags/416202",
         "@type":"ContactTag",
         "name":"abonnement",        // <-- mot clé #1
         "validFrom":"2019-05-07",
         "validThrough":"2019-06-07"
      },
      {  
         "@id":"/clienttoken/contact_tags/416245",
         "@type":"ContactTag",
         "name":"vip",               // <-- mot clé #2
         "validFrom":"2019-05-07",
         "validThrough":"2019-06-07"
      }
   ],
// ...
}

Retrieve the customer's debt amount

WARNING

If a customer has a debt, it is very likely that the sale of a product will be refused, especially if it is a subscription product.

It is therefore imperative that you first ensure that the contact has no outstanding debt.

And if they do, invite them to settle their debt before proceeding further (see dedicated documentation).

bash
GET `/{clientToken}/stats/accounts/contacts/:contactId`
bash
GET `/demoapi/stats/accounts/contacts/1234`
json5
{
  // ...
  "totalRealDebt": 10000, // <-- la valeur de la dette actuelle du contact
  // ...
}

Retrieve the contact's catalog

Before starting a sale, it is necessary to list the products that the contact will be able to purchase. To do this, we will query the API by providing the sale context.

GET /{clientToken}/products

parameterdescriptionexample
context[channel]Sales channel, allowed values are club, web, terminal. The catalog may vary depending on the sales channel.web
context[club]Club where the sale takes place. The catalog may vary depending on the club./clientToken/clubs/123
context[contactTag]Contact's tags. The catalog may vary depending on the tags (e.g., 'VIP' or 'students').tagname
context[debt]Customer's debt (in cents). Some clubs restrict offers for customers with high debt.600
context[date]Desired purchase date. Some products are not available year-round (e.g., back-to-school promotions).2019-04-15
typeProduct category. It is possible to filter by category. Allowed values: subscription, subscription_option, badge, counter, package, countermark, test_session, regularsubscription see category mappings below
pagePage number. The response contains 30 results per page, so pagination is supported.1
bash
GET /{clientToken}/products?context[channel]=club&context[club]=/{clientToken}/clubs/123&context[contactTag][]=tag-1&context[contactTag][]=tag-2&context[contactId]=/{clientToken}/contacts/123&context[debt]=0&context[date]=2019-04-02&type=badge&page=1

Product Categories

Here are the existing categories:

  • subscription: "subscription" products
  • subscription_option: "subscription option" products
  • badge: "badge" products
  • counter: "session booklets" products
  • package: packaged formula products
  • countermark: "countermark" products
  • test_session: "trial session" products
  • regular: "shop" products

Selling one or more products to the contact

To start a sale, you must first create the cart that will hold the items you want to sell. Only a few basic pieces of information are needed at creation:

  • The contact to whom the sale is made (contactId)
  • The club where the sale takes place (clubId, clubCode)

Additional non-mandatory information can be provided at creation, but you will need to fill them in before final validation. This information will be used for invoicing:

  • Additional contact information (contactFamilyName, contactGivenName, contactNumber)
  • Their address (address)

Creating the sale

Required information in the request:

parameterdescriptionexample
contactIdIdentifier of the contact targeted by the sale. This is an IRI, not just a numeric ID/{clientToken}/contacts/12345
contactFamilyNameContact's family name.Doe
contactGivenNameContact's given name.John
contactNumberContact's number.423456
clubIdClub identifier in the form of an IRI/{clientToken}/clubs/1
clubCodeClub codeABCDE
address[addressCountry]CountryFrance
address[addressLocality]CityLa Madeleine
address[postalCode]Postal code59110
address[streetAddress]Address41 rue du Général de Gaulle
bash
POST `/{clientToken}/sales`
bash
curl --location --globoff '/demoapi/sales' \
--data '{
    "contactId": "/demoapi/contacts/1",
    "contactFamilyName": "Doe", 
    "contactGivenName": "John", 
    "contactNumber": "1", 
    "clubId": "/demoapi/clubs/1",
    "clubCode": "ABCDE", 
    "address": { 
        "addressCountry": "France",
        "addressLocality": "La Madeleine",
        "postalCode": "59110",
        "streetAddress": "41 Rue du Général de Gaulle"
    }
}'
json
{  
   "@context":"/clientToken/contexts/Sale",
   "@id":"/clientToken/sales/373969",  // <-- identifiant du panier
   "@type":"Sale",
  // ...
}

Adding an item to the cart

Some important details before adding an item to the cart.

Behaviors

Like any sales API, we have a catalog composed of products and a cart composed of items. On top of these classic notions are behaviors (behaviors). They are responsible for the fitness business logic and the implications related to the purchase of various products (adding a subscription, crediting sessions, etc.).

Among these behaviors, some require details from the buyer (for example, buying a subscription requires a start date) and others require no details at all (for example, buying a water bottle or a towel involves no questions).

Refer to the documentation dedicated to product behaviors.

Selling a product

To sell a product, you need to add it to the cart. You will therefore need the identifier of the previously created cart. See cart creation.

Additionally, depending on the behaviors associated with the product, you will have to provide the expected details. Adding an item to the cart always goes through the same API endpoint; only the parameters vary depending on the behaviors.

POST /{clientToken}/sales/{saleId}/articles

parameterdescriptionexample
offerIdIdentifier of the product offer you want to sell. This is an IRI, not just a numeric ID./{clientToken}/offers/4321
implementation(optional) details related to the behavior of the added product. See below for expected formats
implementations(optional) details related to multiple behaviors of the product in case of packages. See below for expected formats

Verify the validity of the sale

Some products in the sale may not be compatible with the contact. For example, an offer with an age restriction contradicted by the birth date. Adding it to the sale is not prevented since you might want to modify the contact later. However, if you do not check the sale’s integrity before submitting it, you risk errors.

WARNING: Warning: Settling (via a payment) an incompatible sale will charge the client’s account — the sale will not be settled (allocated): the club will have to redo the sale and allocate the payment.

GET /{client_token}/sales/{id}/check

This endpoint returns

204

The sale is valid

400

The sale contains errors

404

Invalid sale ID / sale not found

Validate the sale and record the payment

To validate a sale, you can either:

  • Add the payment
  • Defer the payment of the sale

Know the register and the amount to collect

Before recording a payment, some information to gather:

  • amount to collect
  • register on which to record the payment

To do this, simply query our cart.

GET /{clientToken}/sales/{saleId}

parameterdescriptionexample
saleIdCart identifier456

Example request

GET /{clientToken}/sales/1

json5
{
  // ...
  "checkoutId": "/clientToken/checkouts/1234", // <-- identifiant de la caisse
  "totalTI": 1100,                              // <-- montant à encaisser en centimes
  // ...
}

Validate the sale by adding a payment

WARNING

Be careful, these calls create payments in the application, so it is important to understand that each call creates a payment with accounting links behind it.

For a €50 sale, if two API calls to "add a payment" of €50 are made, the client will have an overpayment of €50 which can be used to settle other purchases, even if the client has not actually paid €100. It is crucial to secure these calls properly.

When adding a payment, several pieces of information are required:

  • The contact making the payment (contactId, contactFamilyName, contactGivenName, contactNumber)
  • The club where the payment is made (clubId, clubCode, checkout)
  • The amount of the payment (amount)
  • The payment method, among:
    • CBWeb, for an online card payment
    • cash, for a cash payment
    • cheque, for a cheque payment
    • card, for an on-site card payment

POST /{clientToken}/sales/{saleId}/payments

parameterdescriptionexample
contactIdIdentifier of the contact making the payment/{clientToken}/contacts/456
contactFamilyNameLast name of the contact making the paymentDoe
contactGivenNameFirst name of the contact making the paymentJohn
contactNumberContact number of the contact making the payment98765
amountPayment amount in cents4995
meanPayment methodCBWeb
clubIdClub identifier as an IRI/{clientToken}/clubs/1
clubCodeClub codeABCDE
checkoutClub register identifier as an IRI/{clientToken}/checkouts/2
paymentCardsDetails of card payments, only if mean=card
paymentCards[][amount]Card payment amount in cents (only if mean=card)4995
paymentCards[][network]Card network among CBGroup, AmEx, Payline, and External (only if mean=card)AmEx
chequesDetails of cheque payments, only if mean=cheque
cheques[][amount]Cheque amount in cents (only if mean=cheque)4995
cheques[][bank]Bank name (only if mean=cheque)Banque populaire
cheques[][code]Cheque number (only if mean=cheque)1234567890
cheques[][depositDesiredDate]Desired deposit date (only if mean=cheque)2019-01-31
cheques[][owner]Name of the cheque owner (only if mean=cheque)John Doe

Example of a Web payment

bash
curl '/{clientToken}/sales/1/payments'
json5
{
    "contactId": "/{clientToken}/contacts/1",
    "contactFamilyName": "Doe",
    "contactGivenName": "John",
    "contactNumber": "1",
    "amount": 5000,
    "mean": "CBWeb",
    "clubId": "/{clientToken}/clubs/1",
    "clubCode": "AA1",
    "checkout": "/{clientToken}/checkouts/1"
}
json5
{
    "contactId": "/{clientToken}/contacts/1",
    "contactFamilyName": "Doe",
    "contactGivenName": "John",
    "contactNumber": "1",
    "amount": 5000,
    "mean": "card",
    "clubId": "/{clientToken}/clubs/1",
    "clubCode": "AA1",
    "checkout": "/{clientToken}/checkouts/1",
    "paymentCards": [
        {
            "amount": 5000,
            "network": "CBGroup",
        }
    ]
}
json5
{
    "contactId": "/{clientToken}/contacts/1",
    "contactFamilyName": "Doe",
    "contactGivenName": "John",
    "contactNumber": "1",
    "amount": 5000,
    "mean": "cheque",
    "clubId": "/{clientToken}/clubs/1",
    "clubCode": "AA1",
    "checkout": "/{clientToken}/checkouts/1",
    "cheques": [ // A remplir uniquement pour les paiements en chèques
        {
            "amount": 5000,
            "bank": "Crédit du nord",
            "code": "1234567890",
            "depositDesiredDate": "2019-04-15", 
            "owner": "John Doe" 
        }
    ]
}

Validate the sale by deferring the payment

It is allowed to validate a sale by deferring the payment. The contact will owe the amounts of the sale before the indicated date.

parameterdescriptionexample
dateDate from which the payment will be considered "overdue"2019-02-28
bash
POST `/{clientToken}/sales/{saleId}/postpone_due`
json
{
    "date": "2019-02-28"
}

Validate the sale without payment / Complimentary products

If — and only if — you create a sale with a zero amount (0€, free product),

You can then complete the sale by applying a validation transition.

bash
`POST /{client_token}/sales/{id}/transitions`
json
{
    "transition": "validate"
}

The sale will then be recorded, and the (potential) product behaviors will be executed.