Skip to main content

Aksal Black Partner APIs

These endpoints allow Aksal to retrieve Aksal Black customer information: discount tier, active program challenges, and purchase history.

Authentication​

  • Uses signature authentication
HeaderDescription
X-SIGNATUREThe signature header of the request

See 2-security.md for signature generation details.

Base path​

/api/v1/partner/aksal/

Customer identifier​

All endpoints below use the same path parameter, identifier, to look up an enrolled Aksal Black customer. It accepts either:

Value typeDescriptionExample
Aksal Black card numberThe customer's Aksal Black card numberAKSAL-BLACK-0001
Aksal Black IDThe customer's Aksal Black ID, as returned by the enrollment endpointBLK2000001
Mobile phone numberThe customer's mobile number on file0611223344, +212611223344, or 212611223344

Spaces in the value are ignored. For phone numbers, local Moroccan formats starting with 0 are normalized to the international +212 format before lookup.

Endpoints​

1) Black card tier​

Retrieve the discount tier and customer summary for an Aksal Black customer.

GET /api/v1/partner/aksal/black-card/<identifier>/tier
ParameterTypeDescription
identifierstringThe Aksal Black card number, the Aksal Black ID, or the customer's mobile phone number (see above)

Sample request (card number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/AKSAL-BLACK-0001/tier

Sample request (mobile phone number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/0611223344/tier

Status Code: 200

{
"tier_code": "aksal_gold_tier",
"first_name": "Ahmed",
"last_name": "Benali",
"customer_phone_number": "+212611223344",
"balance": "250.50",
"discount_pct": "15.00",
"label_fr": "Tier Or",
"label_ar": "الدرجة الذهبية",
"label_en": "Gold Tier",
"description_fr": "Bénéficiez de 15% de réduction sur tous vos achats Aksal.",
"description_ar": "استمتع بخصم 15% على جميع مشترياتك في أكسال.",
"description_en": "Enjoy 15% off on all your Aksal purchases.",
"progress": {
"percentage": 40,
"accumulated_mad": "80000.00",
"remaining_mad": "120000.00"
},
"remaining_for_next_tier": "120000.00",
"next_tier_labels": {
"label_fr": "Tier Platine",
"label_ar": "الدرجة البلاتينية",
"label_en": "Platinum Tier"
},
"is_employee": false
}
FieldTypeDescription
tier_codestringStable, machine-readable tier identifier shared across environments, such as aksal_entry_tier, aksal_silver_tier, aksal_gold_tier, aksal_platinum_tier, aksal_diamond_tier, or aksal_employee_tier.
first_namestringCustomer first name
last_namestringCustomer last name
customer_phone_numberstringCustomer mobile number in international format
balancedecimalCustomer points wallet balance
discount_pctdecimalDiscount percentage for this tier. Can be null if not yet configured.
label_frstringTier name in French
label_arstringTier name in Arabic
label_enstringTier name in English
description_frstringTier description in French. Can be null.
description_arstringTier description in Arabic. Can be null.
description_enstringTier description in English. Can be null.
progressobjectBackend-authoritative progress within the current tier's configured annual progression range. See below.
remaining_for_next_tierstringLegacy all-time-spend calculation retained for backward compatibility. New consumers should use progress.remaining_mad for annual tier progress. null when there is no next tier.
next_tier_labelsobjectLabels of the next tier (label_fr, label_ar, label_en). null when there is no next tier.
is_employeebooleantrue when the customer holds the aksal_black_employees tag, false otherwise.

progress uses approved sales from the Aksal brand configuration over the configured rolling annual window (currently 365 days). Amounts are clamped to the current tier range, so all three values describe the same progression interval.

FieldTypeDescription
percentageintegerProgress from 0 to 100, rounded to the nearest whole percentage.
accumulated_madstringMAD accumulated after the current tier's lower threshold, capped at the next threshold.
remaining_madstringMAD remaining before the next tier.

Special cases:

  • Entry customers use aksal_entry_tier and progress from MAD 0 to the Silver threshold.
  • Diamond customers return percentage: 100, with accumulated_mad and remaining_mad set to null because there is no next tier.
  • Employee customers return null for all progress values because their tier is not spend-based.
  • Missing brand, window, stable-code, or threshold configuration returns null for all progress values rather than reporting a misleading zero.

Status Code: 404

Returned when no customer is found for the given identifier, the customer is not enrolled in Aksal Black, or no tier has been assigned yet.

{
"detail": "No customer found."
}
{
"detail": "No tier assigned for this card."
}

2) Black card challenges​

Retrieve active challenges tagged for the Aksal Black program, along with each customer's remaining run window.

GET /api/v1/partner/aksal/black-card/<identifier>/challenges
ParameterTypeDescription
identifierstringThe Aksal Black card number, the Aksal Black ID, or the customer's mobile phone number (see above)

Sample request (card number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/AKSAL-BLACK-0001/challenges

Sample request (mobile phone number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/0611223344/challenges

Status Code: 200

[
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name_fr": "Défi Aksal Black",
"name_ar": "تحدي أكسال بلاك",
"name_en": "Aksal Black Challenge",
"description_fr": "Effectuez 3 achats en 48 heures.",
"description_ar": "قم بـ 3 مشتريات خلال 48 ساعة.",
"description_en": "Make 3 purchases within 48 hours.",
"remaining_run_window_hours": 36.5,
"bonus_amount": "50.00"
}
]
FieldTypeDescription
uuiduuidChallenge identifier
name_frstringChallenge name in French
name_arstringChallenge name in Arabic
name_enstringChallenge name in English
description_frstringChallenge description in French. Can be null.
description_arstringChallenge description in Arabic. Can be null.
description_enstringChallenge description in English. Can be null.
remaining_run_window_hoursdecimalHours remaining in the customer's current run window. When the customer has no active in-progress run, this equals the challenge's configured run window duration.
bonus_amountdecimalPoints bonus awarded when the challenge is completed. 0 if no bonus is configured.

Only active challenges tagged with aksal_black (challenge tags) are returned. Returns an empty array when no matching challenges exist.

Status Code: 404

Returned when no customer is found for the given identifier or the customer is not enrolled in Aksal Black.

{
"detail": "No customer found."
}

3) Black card history​

Retrieve purchase history and spending statistics for an Aksal Black customer. Only approved sales at brands linked to the customer's tier are included.

GET /api/v1/partner/aksal/black-card/<identifier>/history
ParameterTypeDescription
identifierstringThe Aksal Black card number, the Aksal Black ID, or the customer's mobile phone number (see above)

Sample request (card number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/AKSAL-BLACK-0001/history

Sample request (mobile phone number)

GET https://app.kenzup.com/api/v1/partner/aksal/black-card/0611223344/history

Status Code: 200

{
"total_sale_amount": "350.00",
"total_sale_amount_current_year": "150.00",
"total_sale_amount_current_month": "150.00",
"number_of_purchases_current_year": 2,
"number_of_purchases_current_month": 2,
"history": [
{
"created_at": "2025-06-15T12:00:00Z",
"brand_name": "Marjane",
"shop_system_name": "marjane-casablanca-01",
"earned_points": "10.00",
"burned_points": "0.00"
}
]
}
FieldTypeDescription
total_sale_amountdecimalTotal approved sale amount across all time (tier brands only)
total_sale_amount_current_yeardecimalTotal approved sale amount for the current calendar year
total_sale_amount_current_monthdecimalTotal approved sale amount for the current calendar month
number_of_purchases_current_yearintegerNumber of approved purchases in the current calendar year
number_of_purchases_current_monthintegerNumber of approved purchases in the current calendar month
historyarrayList of individual approved sales (see below)

Each item in history:

FieldTypeDescription
created_atdatetimeSale creation timestamp
brand_namestringBrand name of the shop
shop_system_namestringShop system identifier
earned_pointsdecimalPoints earned on this sale
burned_pointsdecimalPoints burned on this sale

Status Code: 404

Returned when no customer is found for the given identifier, the customer is not enrolled in Aksal Black, or no tier has been assigned yet.

{
"detail": "No customer found."
}
{
"detail": "No tier assigned for this card."
}

Common errors​

Status Code: 403

Returned when the signature is invalid or the client_id is not authorized.

Outbound webhooks​

Kenzup POSTs sale.created, tier.changed, and challenge.completed to AKSAL_WEBHOOK_URL for Aksal Black customers. Production uses https://api.aksal.ma/api/kenzup/webhook; staging uses https://api.staging.aksalblack.ma/api/kenzup/webhook. Nothing is sent until AKSAL_WEBHOOK_URL is set. points.expiring is not sent.

The JSON body is {customer, entity_id, event, occurred_at} with keys sorted alphabetically and no extra whitespace. customer is the Black card number, or the customer's phone number when no card is stored. entity_id is required for challenge.completed and optional elsewhere. tier.changed is sent for every tier move, including downgrades and first enrollment. Signing reuses the inbound X-SIGNATURE scheme with AKSAL_SERVICE_CLIENT_ID and RSA_PRIVATE_KEY. Any 2xx is an ack; non-2xx is retried for about 24 hours.

Export the public key with python manage.py export_rsa_public_key.