Skip to content

Use vendors as wishlist items

A member’s wishlist holds listings by default, but it can also hold vendors: a “Follow this shop” button on a vendor page, a “My favourite makers” screen in an app. Both kinds of item live in the same wishlist and go through the same four Front API endpoints; the type parameter tells them apart.

Action Request
Add POST /front_api/v1/wishlists with {"item_id": …, "type": "vendor"}
Check GET /front_api/v1/wishlists/{item_id}/check?type=vendor
List GET /front_api/v1/wishlists?type=vendor
Remove DELETE /front_api/v1/wishlists/{item_id}?type=vendor

item_id is the vendor’s user id. Every call needs a signed-in member: a Bearer token in an app, or the storefront session in a theme. See Authentication.

  1. Show the current state. When the vendor page loads, ask whether the member already follows the vendor:

    Terminal window
    curl "https://acme.mykreezalid.com/front_api/v1/wishlists/4242/check?type=vendor" \
    -H "Authorization: Bearer $TOKEN"
    { "success": true, "vendor_id": 4242, "exists": true }

    For a visitor who is not signed in, the answer is {"success": false, "code": "X001", "error": "No authenticated user"}: show the button in its “follow” state and send them to the login page on click.

  2. Follow on click:

    Terminal window
    curl -X POST https://acme.mykreezalid.com/front_api/v1/wishlists \
    -H "Authorization: Bearer $TOKEN" \
    -H "Content-Type: application/json" \
    -d '{"item_id": 4242, "type": "vendor"}'
    { "success": true, "message": "Vendor added successfully" }
  3. Unfollow on the second click:

    Terminal window
    curl -X DELETE "https://acme.mykreezalid.com/front_api/v1/wishlists/4242?type=vendor" \
    -H "Authorization: Bearer $TOKEN"
    { "success": true, "message": "vendor deleted successfully from wishlist" }

In a theme, the same calls run from the page’s JavaScript with the member’s session, no token needed:

follow-button.js
const API = '/front_api/v1/wishlists';
async function call(url, init = {}) {
const res = await fetch(url, {
credentials: 'same-origin',
headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
...init,
});
if (res.status === 403) return { success: false, needsLogin: true };
return res.json();
}
export async function initFollowButton(button) {
const vendorId = button.dataset.vendorId;
const state = await call(`${API}/${vendorId}/check?type=vendor`);
let following = state.success && state.exists;
button.setAttribute('aria-pressed', String(following));
button.addEventListener('click', async () => {
const result = following
? await call(`${API}/${vendorId}?type=vendor`, { method: 'DELETE' })
: await call(API, { method: 'POST', body: JSON.stringify({ item_id: Number(vendorId), type: 'vendor' }) });
if (result.needsLogin || state.code === 'X001') {
window.location.href = '/login';
return;
}
if (result.success) {
following = !following;
button.setAttribute('aria-pressed', String(following));
}
});
}

The add and remove calls answer 200 with success and a message. Branch on success, and use message to tell the cases apart:

message Meaning
Vendor added successfully The vendor is now in the wishlist.
vendor_already_in_user_wishlist Nothing changed: the member already follows this vendor. Treat it as a success in a toggle.
vendor_not_found No user has this id on the marketplace.
vendor deleted successfully from wishlist The vendor was removed.
vendor_not_in_your_wishlist Nothing to remove.
No authenticated user Status 403: no member is signed in.

The listing equivalents read Listing added successfully, listing_already_in_user_wishlist, listing_not_found and so on.

GET /front_api/v1/wishlists?type=vendor returns the member’s followed vendors, 20 per page, with pagination. Each entry carries vendor_id and the vendor’s public profile in user:

{
"wishlists": [
{
"vendor_id": 4242,
"user": {
"id": 4242,
"url_key": "atelier-lune",
"business_name": "Atelier Lune",
"image": "https://…",
"average_rating": 4.8,
"review_count": 37,
"listing_count": 52
}
}
],
"pagination": { "currentPage": 1, "nextPage": false, "…": "…" }
}

Vendors whose account is deactivated, banned or deleted drop out of the list on their own; the entry is not removed from the wishlist, so the check endpoint still answers "exists": true for them.

Link each entry to the vendor’s public page, and load its listings or reviews with GET /front_api/v1/directories/{user_id} and GET /front_api/v1/reviews/user/{user_id}.

  • The item is any user. Adding checks only that a user with this id exists on the marketplace, not that they are a vendor. Show the button on vendor pages only.
  • One entry per vendor. Adding a vendor twice does not duplicate it.
  • Listings and vendors are separate. Following a vendor does not add their listings, and GET /wishlists without type lists only listings, limited to those that are published and approved.