Skip to content

Build a mobile app

Kreezalid storefronts are responsive, but a marketplace can also have its own native app. This guide shows how to split the work between the app, a small back end of yours and the Kreezalid APIs so that the app never holds an administrator secret.

Part Talks to Does
The app (iOS, Android, React Native, Flutter…) Front API directly, and your back end Sign-up and login, account, cart, the member’s orders, wishlist, a vendor’s own listings.
Your back end Admin API, with the credentials stored server-side Serves the catalog to the app, receives webhooks and turns them into push notifications.
Kreezalid — The marketplace: data, rules, emails, checkout pages.

Create an account with POST /front_api/v1/account/create. Pass the group_id the member joins, a customer group or a vendor group, taken from Settings → Users → Groups:

Terminal window
curl -X POST https://acme.mykreezalid.com/front_api/v1/account/create \
-H "Content-Type: application/json" \
-d '{
"email": "jane@example.com",
"password": "correct horse battery staple",
"first_name": "Jane",
"last_name": "Doe",
"group_id": 2
}'
{
"code": 201,
"success": true,
"user": {
"object": "User",
"id": 5120,
"email": "jane@example.com",
"first_name": "Jane",
"group": { "object": "Group", "id": 2, "name": "Customers", "alias": "customers" },
"can_post_listing": false
}
}

The member receives the marketplace’s welcome email, or a confirmation email when the marketplace requires email validation. In that case the account stays inactive, and login fails, until the link in the email is clicked.

Then log in and keep the token:

auth.js
const BASE = 'https://acme.mykreezalid.com/front_api/v1';
export async function login(email, password) {
const res = await fetch(`${BASE}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
body: JSON.stringify({ email, password }),
});
const body = await res.json();
if (res.status !== 200 || body.status !== 'success') {
throw new Error(body.message || 'Login failed');
}
return body.data.token; // store it in the Keychain / Keystore
}
export async function api(path, token, init = {}) {
const res = await fetch(`${BASE}${path}`, {
...init,
headers: {
...init.headers,
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
if (res.status === 403) throw new Error('SESSION_EXPIRED'); // send the user back to login
return res.json();
}

The token lasts one year and cannot be refreshed: when a call answers 403, ask the member to log in again. Logging out of the app means deleting the token from the device. Forgotten passwords go through POST /front_api/v1/account/forgot-password, which emails a reset link.

The Front API does not browse the marketplace catalog. Give your back end an endpoint that reads it with the Admin API, keeps only what the app displays, and caches it:

server/catalog.mjs
const ADMIN = 'https://acme.mykreezalid.com/api/v1';
const auth = Buffer.from(`${process.env.KREEZALID_API_KEY}:${process.env.KREEZALID_API_SECRET}`).toString('base64');
// GET /app/catalog?category=812&page=1 → what the app's list screen needs
export async function catalog({ category, page = 1 }) {
const qs = new URLSearchParams({
status: 'published',
admin_status: 'approved',
page: String(page),
limit: '24',
fields: 'id,title,price,price_with_currency,cover,medias,owner,category',
});
if (category) qs.set('category_id', String(category));
const res = await fetch(`${ADMIN}/listings?${qs}`, { headers: { Authorization: `Basic ${auth}` } });
const { listings, pagination } = await res.json();
return {
items: listings.map((l) => ({
id: l.id,
title: l.title,
price: l.price_with_currency,
image: l.cover ?? l.medias?.[0]?.src ?? null,
vendor: l.owner?.public_name,
})),
hasMore: pagination.nextPage,
};
}

Read categories for the navigation with GET /front_api/v1/categories, which needs no token, and a vendor’s public profile with GET /front_api/v1/directories/{user_id}.

The cart is fully available in the Front API:

  1. Create a cart once per device or per member, with an empty body, and keep its url_key:

    Terminal window
    curl -X POST https://acme.mykreezalid.com/front_api/v1/carts -H "Authorization: Bearer $TOKEN"
    {
    "status": "success",
    "message": "Cart created successfully",
    "cart": { "id": 7781, "object": "Cart", "customer_id": 5120, "tmp_customer_id": null, "url_key": "q8Zt3k…" }
    }
  2. Add listings:

    Terminal window
    curl -X POST https://acme.mykreezalid.com/front_api/v1/carts/q8Zt3k… \
    -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" \
    -d '{"listing_id": 645646, "quantity": 1}'
  3. Show it with GET /front_api/v1/carts/{url_key}: it returns one order per vendor, the totals (subtotal_amount, shipping_amount, checkout_amount…) and each order’s items.

  4. For each order, list the delivery options with GET /carts/{url_key}/orders/{order_id}/available-shipping-methods and pick one with PATCH /carts/{url_key}/orders/{order_id}/shipping-method.

  5. Save the address with POST /account/checkout-addresses, then attach it to the cart with PUT /carts/{url_key}/checkout-addresses/{checkout_address_id}.

Payment is not part of the Front API. Two options:

  • open the marketplace’s checkout in an in-app browser, where the marketplace’s payment provider takes the payment;
  • take the payment with your own provider in the app, then let your back end record it with the Admin API. See Record orders paid outside Kreezalid.

The member’s orders, as a customer and, for vendors, as a seller, come from GET /front_api/v1/orders; one order from GET /front_api/v1/orders/{id}.

For push notifications, subscribe your back end to the order webhooks it cares about, such as order.status.accepted or order.status.shipped, look up the customer in data.customer.id, and push to the devices you registered for that user.

When the member’s group can post listings (can_post_listing: true in GET /auth/me), the app can manage their catalog: GET /front_api/v1/listings lists their listings, POST /listings/add creates one and PATCH /listings/{id}/edit updates one.

  • The app contains no Admin API credentials, in code or configuration.
  • The base URL is the marketplace’s primary address, and is configurable without a new app release.
  • A 403 on any Front API call sends the member to the login screen.
  • Every response is checked for its success or status field, not only its HTTP code. See Errors.
  • Your back end verifies webhook signatures.