REST API
Read and write your marketplace's listings, categories, users, messages and orders from your own app, website or script.
Every Yclas marketplace comes with a REST API. Developers use it to build mobile apps, show your listings on another website, sync data with other systems or automate jobs such as creating paid orders.
This page is the full reference, written for developers. If you only want to connect a ready-made service, you don’t need it.
Before you start
- Base address. Every request goes to your marketplace’s own address followed by
/api/v1/, for examplehttps://www.your-marketplace.com/api/v1/categories. Use your custom domain if you have one, and always use HTTPS. - A key. Use one of these:
- A scoped key (recommended, on the Marketplace plan): create one in Add-ons › API keys with only the permissions your app needs. See API keys and permissions and Scoped keys below.
- The site key: in Settings › General, open Advanced and copy the API key. Every marketplace gets a random key when it is created. You can replace it with your own value and click Save changes; the old key stops working straight away.
- Which plan. Every plan includes the REST API with the site key (the basic API). The Full API, with scoped keys, webhook subscriptions, the MCP server and higher limits, is part of the Marketplace plan. No separate sign-up is needed.
- Your site’s own developer page.
/api/docson your site (for examplehttps://www.your-marketplace.com/api/docs) lists every endpoint with the permission it needs, every webhook event and every MCP tool, generated from your site itself. Administrators reach it from the API & webhook docs link at the top of Add-ons. It becomes public once you switch on webhooks or the MCP server, or create a scoped key; until then only your administrators can see it. Search engines are asked not to index it. - OpenAPI. The same API is described as an OpenAPI 3.1 file at
/api/openapi.jsonon your site, for code generators, Postman and AI tools. It lists every endpoint with the permission it needs, and every webhook event. The same people who can read/api/docscan download it. - Rate limit. Requests are limited per minute: 120 per key by default, which you can change. See Rate limits below.
The site key opens the whole REST API: with it anyone can list your orders (including buyers’ email addresses) and create orders marked as paid. Keep it on a server or inside a compiled app, never in a public web page’s JavaScript, and change it in Settings › General if it leaks. For anything new, prefer a scoped key with only the permissions you need.
Three levels of access
| Level | How you prove it | What it opens |
|---|---|---|
| Public | Nothing | Categories, locations, custom field definitions and vehicle data. |
| API key | The site key or a scoped key (see below) | Listings, users, orders, blog posts, pages, FAQs, translations, and signing members in or up. A scoped key only opens what its permissions allow. |
| User token | user_token parameter |
Acting as one member: their listings, favourites, messages and profile. |
You get a user token when a member signs in or registers through the API (see Sign in and sign up). Each member has one token, and it stays the same until it is regenerated, so store it securely in your app and send it with every request made on the member’s behalf. Requests that use a user token don’t need the API key.
Send the user token as a query or body parameter (user_token=…). A user_token HTTP header is not read reliably,
and many servers drop headers with underscores in their names.
Sending the key
| Key | How to send it |
|---|---|
| Site key | An apikey parameter, or an apikey HTTP header. |
Scoped key (starts with yck_) |
Authorization: Bearer yck_… (recommended), an apikey header, or an apikey parameter. |
Scoped keys
A scoped key only opens the parts of the API its permissions allow. Each permission covers one group of endpoints:
| Endpoints | Read permission | Write permission |
|---|---|---|
Listings (/listings) |
listings:read |
listings:write |
Users (/users) |
users:read |
users:write |
Sign in and sign up (/auth) |
users:write |
|
Orders (/orders) |
orders:read |
orders:write |
Blog, pages, FAQs and translations (/blog, /pages, /faqs, /translation) |
content:read |
content:write |
Webhook subscriptions (/webhooks) |
webhooks:manage |
webhooks:manage |
The read permission only covers actions that read: listing, showing one item, orders/products, and the
translation and export actions. Everything else needs the write permission, whatever the HTTP method, so
GET /api/v1/orders/create needs orders:write just like POST /api/v1/orders.
Without users:read, email addresses are removed from the answers, for example the buyer’s email in orders.
A missing permission returns 403 with This API key does not have the orders:write scope (or the permission
needed). The public endpoints and the user-token endpoints work as before.
The site key keeps the API it always had (listings, users, orders and content) but nothing newer: it can’t subscribe to webhooks and it doesn’t work with the MCP server.
How requests work
Addresses and methods
/api/v1/<resource>(/<action>)(/<id>)(.<format>)
The HTTP method picks the action when you don’t name one:
| Method | Action | Example |
|---|---|---|
GET |
List, or show one item when you add an id | GET /api/v1/categories/3 |
POST |
Create | POST /api/v1/ads |
PUT |
Update | PUT /api/v1/ads/12 |
DELETE |
Delete | DELETE /api/v1/favorites/12 |
A named action works with any method, so POST /api/v1/auth/login and GET /api/v1/auth/login do the same thing.
If your client or hosting can’t send PUT or DELETE, send a GET with ?method=PUT (or DELETE, POST), or
send the real method in an X-HTTP-Method-Override header.
Sending data
Send parameters in the query string, as a form body (application/x-www-form-urlencoded or multipart/form-data
for file uploads) or as JSON with Content-Type: application/json. Query and body parameters are merged.
Output formats
Responses are JSON by default. Add an extension for another format:
| Format | Example |
|---|---|
| JSON (default) | /api/v1/categories/3 or /api/v1/categories/3.json |
| XML | /api/v1/categories/3.xml |
| CSV | /api/v1/categories.csv |
| HTML (a readable dump, for debugging) | /api/v1/categories.html |
Add attachment=name to download the response as name.<format>. For JSONP, add callback=yourFunction.
Filtering
Most lists accept any of the item’s database fields as a filter: GET /api/v1/categories?id_category_parent=1.
| Filter | Meaning | Example |
|---|---|---|
field=value |
Equal to | id_user=5 |
field>=value |
Greater than or equal to | price>=100 |
field<=value |
Less than or equal to | price<=500 |
field!=value |
Not equal to | status!=40 |
field__between=a,b |
Between two values, inclusive | price__between=100,500 |
Unknown fields are ignored. Private fields (passwords, tokens, email addresses, IP addresses, wallet balances and the like) can never be used to filter or sort.
Searching, sorting and choosing fields
| Parameter | What it does | Example |
|---|---|---|
q |
Text search, on the endpoints that support it (listings, categories, locations, blog). | q=mountain+bike |
sort |
Comma-separated fields; a leading - sorts newest/highest first. |
sort=-published,title |
fields |
Return only these fields. | fields=id_ad,title,price |
Pagination
Listings, your own listings, users, orders, blog posts and messages are paginated with page (starting at 1) and
items_per_page (10 by default). Every list also returns:
- an
X-Total-Countheader with the total number of matching items; - a
Linkheader with thenext,last,firstandprevious_pageaddresses, where they exist.
Categories, locations, pages and FAQs always return everything in one response.
You can combine all of these: GET /api/v1/listings?q=bike&id_category=7&price<=500&sort=-published&page=2&items_per_page=20&apikey=…
Errors
Errors come back with a matching HTTP status and a body like this:
{"code": 401, "error": "Wrong Api Key"}
| Status | Typical cause |
|---|---|
401 |
Missing or wrong API key or user token, or wrong email and password. |
403 |
A scoped key without the permission this request needs, or the site key on webhook subscriptions. |
404 |
The item doesn’t exist, isn’t yours or isn’t published, or a list has no results (No records found). |
405 |
The method isn’t supported for that address. |
429 |
Too many requests in this minute. See Rate limits. |
500 |
Validation failed. The messages are joined with ` - , for example Category must not be empty - Title must not be empty - `. |
503 |
The marketplace is in maintenance mode: {"ERROR": "Maintenance mode"}. |
An empty list is a 404, not an empty array, so treat No records found as “zero results” in your app.
If your client can’t read error statuses, add suppressResponseCodes=true: every response is then 200 and the
real code is in a responseCode field.
Rate limits
Every request counts towards a limit per minute, set by the site owner in Add-ons › API keys › Rate limit (120 by default). A scoped key is counted on its own; the site key is counted per caller’s internet address at 5 times the limit; requests with a user token are counted per member; and the public endpoints below are counted per address at 5 times the limit. See API keys: Rate limit.
Each counted response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset (when the minute
ends, as a Unix time). Over the limit the answer is 429 with a Retry-After header in seconds: wait that long
before trying again.
Public endpoints
No key needed.
Categories
| Request | Returns |
|---|---|
GET /api/v1/categories |
All categories, with icon, price (formatted) and translate_name. Filter, sort and search (q looks in name and description). |
GET /api/v1/categories/{id} |
One category, plus parents, siblings (its own id and those of its subcategories) and customfields. |
GET /api/v1/categories/all |
The whole tree in a nested format. |
GET /api/v1/categories/count |
Number of listings per category. Add id_location to count only one location. |
Useful filters: id_category_parent=1 (children of category 1), parent_deep=1 (top level), has_image=1.
Locations
| Request | Returns |
|---|---|
GET /api/v1/locations |
All locations, with icon, translate_name and location_parent_name. Filter, sort and search. |
GET /api/v1/locations/{id} |
One location, plus siblings (its own id and those of its sub-locations). |
GET /api/v1/locations/all |
The whole tree in a nested format. |
If Automatically Sort All Locations Alphabetically is on in Settings › General, the list is always sorted
by name and your sort is ignored.
Custom fields
These describe the custom fields your forms use: type, label, options and which categories they apply to.
| Request | Returns |
|---|---|
GET /api/v1/customfields |
Every listing custom field (same as /customfields/ads). |
GET /api/v1/customfields/category/{id} |
The listing fields that apply to one category. |
GET /api/v1/customfields/categories/{id}-{id}-{id} |
The fields for several categories at once, ids separated by hyphens. |
GET /api/v1/customfields/user |
Every user custom field. |
In listings, a custom field’s value is stored as cf_<name>, for example cf_mileage.
Vehicle data
When vehicle data is switched on, the brand, model and generation lists behind its drop-downs
are available too: GET /api/v1/autodatabrands, /autodatabrands/{id} (with its models),
/autodatamodels, /autodatamodels/{id} (with its generations), /autodatagenerations and
/autodatagenerations/{id}.
Endpoints that need the API key
Sign in and sign up
| Request | Parameters | Returns |
|---|---|---|
GET /api/v1/auth or /api/v1/auth/login |
email, password, optional device_id |
The member, including user_token. |
POST /api/v1/auth |
name, email, optional password (one is generated if you leave it out), optional cf_… user custom fields |
The new member, including user_token. |
GET /api/v1/auth/social |
social_network (google or facebook), token, optional device_id |
The member, including user_token. Creates the member if needed. |
GET /api/v1/auth/login?email=member@example.com&password=…&apikey=YOUR_KEY
{"user": {"id_user": "42", "name": "Ana", "user_token": "06f8bbb8c7da102e5decf0820fb0d6c0b282d637", "image": "https://…", …}}
device_id stores the device’s push-notification id on the member, for mobile apps.
For social sign-in, token is an access token your app got from Google or Facebook. The provider must be set
up in social login, and the marketplace checks the
token with the provider: a Google token must have been issued to the same client ID, and Facebook needs the app
secret saved in the settings. The member’s identity, email and name always come from the provider. If an account
with that email already exists and the provider hasn’t confirmed the email, sign-in is refused with 409 and the
member has to sign in with their password.
Common errors: Wrong Api Key, Wrong user name or password, User already exists, Invalid social login.
Listings
Published listings, as visitors see them. Expired listings and past events are left out.
| Request | Returns |
|---|---|
GET /api/v1/listings |
Published listings, newest first. Each has price (formatted), thumb, url and customfields (with each field’s value). Paginated. |
GET /api/v1/listings/{id} |
One published listing, with all images, its category, location, the seller’s public user profile and customfields. |
qsearches listing titles.id_categoryandid_locationinclude subcategories and sub-locations.- Add
latitudeandlongitudeto get adistancefor each listing (listings without coordinates are left out), andsort=distanceto show the nearest first. - Any other listing field works as a filter:
id_user=5,price__between=100,500,cf_condition=new.
GET /api/v1/listings?latitude=41.40&longitude=2.20&sort=distance&items_per_page=20&apikey=YOUR_KEY
Listing status values: 0 not published, 1 published, 20 waiting for email confirmation, 30 spam, 40
sold, 50 unavailable.
Users
| Request | Returns |
|---|---|
GET /api/v1/users |
Active members’ public profiles. Filter, sort, paginated. |
GET /api/v1/users/{id} |
One member’s public profile. Send that member’s user_token too and you get their full profile, as at sign-in. |
A public profile contains the id, name, description, role, location, dates, rating, phone, address, coordinates,
language, user custom fields (cf_…) and image. Email addresses are never included.
Orders
| Request | Returns |
|---|---|
GET /api/v1/orders |
All orders, newest first, each with the buyer’s user (id and email), product name and coupon. Filter, sort, paginated. |
GET /api/v1/orders/{id} |
One order. |
GET /api/v1/orders/products |
The product ids you can use when creating an order. |
POST /api/v1/orders |
Creates an order and marks it as paid. |
Useful filters: id_user, id_ad, id_product, status (0 created, 1 paid, 5 refused, 10 waiting for
confirmation, 99 refunded), paymethod, created, pay_date.
To create an order, send id_user, id_ad and id_product. Optional: amount (otherwise the normal price is
used), currency, featured_days (for featuring), paymethod (defaults to API) and txn_id (your payment
provider’s transaction id). Because the order is confirmed as paid, the purchase takes effect immediately, exactly
as if the member had paid on your site. Use it to record payments taken somewhere else.
| Product id | Product |
|---|---|
1 |
Post in a paid category |
2 |
Move a listing back to the top |
3 |
Feature a listing (send featured_days) |
4 |
Buy the item (marketplace checkout) |
5 |
Application fee |
6 |
Custom |
7 |
Add money to the wallet |
| other | A membership plan, by its plan id |
Blog posts, pages and FAQs
| Request | Returns |
|---|---|
GET /api/v1/blog |
Published blog posts, newest first, each with its url. q searches title and text. Paginated. |
GET /api/v1/blog/{id} |
One post. |
GET /api/v1/pages |
Published pages, in menu order. |
GET /api/v1/pages/{id} |
One page. |
GET /api/v1/faqs |
Published FAQ entries, in order. |
GET /api/v1/faqs/{id} |
One FAQ entry. |
Filter by locale to get one language, for example locale=es_ES.
Translations
Fetch the wording of your site in each language, including your own edits from Language and translations, to use in an app.
| Request | Returns |
|---|---|
GET /api/v1/translation |
Your site’s languages, each with its name and last_update_apps / last_update_messages (Unix time of your last edit, or null). |
GET /api/v1/translation/translate/{locale} |
Every translated text for that language, as "original": "translation". |
GET /api/v1/translation/translate/{locale}?q=Search |
The translation of one text. |
GET /api/v1/translation/export/{locale} |
Downloads the translation as a .po file, or .mo with mo=1. |
Add all=1 to include texts that aren’t translated yet (with an empty translation), and file=apps for the
texts used by the mobile apps instead of the website’s (file=messages, the default). An unknown locale falls back
to en_US. Compare the last_update_… times with the time you last downloaded to know when to fetch again.
Webhook subscriptions (REST hooks)
Instead of the site owner adding a webhook in the panel, an app such as a Zapier integration can
subscribe itself, on the Marketplace plan. This needs a scoped key with webhooks:manage, plus the read permission
of each event it subscribes to (users:read for user.created, orders:read for order.paid, messages:read for
message.created, listings:read for the rest). Webhooks must be switched on in Add-ons › Webhooks.
| Request | Parameters | Returns |
|---|---|---|
GET /api/v1/webhooks |
The webhooks this key subscribed. | |
POST /api/v1/webhooks |
url (or target_url / hookUrl), event or events (comma-separated), optional description |
The new webhook with its id and signing secret (201). |
DELETE /api/v1/webhooks/{id} |
Unsubscribes it. | |
GET /api/v1/webhooks/events |
The events you can subscribe to. | |
GET /api/v1/webhooks/sample?event=ad.created |
event |
The latest real record for that event, in the same shape as a delivery. |
A site can have up to 5 webhooks added this way, on top of the owner’s own. A subscribed webhook gets email addresses
only if its key has users:read, and private messages only with messages:read. Revoking the key pauses its
webhooks. Deliveries, retries and the signature are the same as for any webhook: see
What the app receives.
Endpoints that need a user token
These act as the signed-in member. Send user_token with every request.
The member’s listings
| Request | Parameters | Returns |
|---|---|---|
GET /api/v1/ads |
Filters, sort, pagination | The member’s own listings in any status, newest first. |
GET /api/v1/ads/{id} |
One of the member’s listings, with images, category, location and custom fields. | |
POST /api/v1/ads |
See below | Posts a new listing. |
PUT /api/v1/ads/{id} |
Any of the fields below | Updates the listing. |
DELETE /api/v1/ads/{id} |
Deactivates the listing (it isn’t deleted). Returns true. |
|
POST /api/v1/ads/image/{id} |
image (file upload) |
Adds a photo after the existing ones. |
DELETE /api/v1/ads/delete_image/{id} |
num_image |
Removes photo number num_image. |
POST /api/v1/ads/set_primary_image/{id} |
num_image |
Makes that photo the main one. |
Listing fields you can send when creating or updating:
| Field | Notes |
|---|---|
title |
Required, 2–145 characters. |
description |
Required unless you turned descriptions off. |
id_category |
Required. |
id_location, price, address, phone, website, latitude, longitude, stock |
Optional. |
locale |
The listing’s language, for example en_UK. Matters on multilingual sites. |
cf_<name> |
Any listing custom field. Fields marked for administrators only are accepted only from administrators and moderators. |
Any other field is ignored. The owner, status, featured dates and counters are set by the marketplace itself, so you can’t publish, feature or move a listing to another member through the API.
A new listing goes through the same rules as one posted on your site: spam checks, banned words, moderation, confirmation emails and paid categories. The answer tells you what to show the member:
{"message": "Please pay before we publish your listing.", "checkout_url": "https://…/ad/checkout/123", "ad": {…}}
message is the text to show (it depends on the marketplace’s moderation setting). When checkout_url isn’t
empty, open it so the member can pay. Changing the category of a listing in a paid category can also return a
checkout_url.
Administrators can update and deactivate any listing with their own token. Setting stock to 0 marks a listing
as unavailable, and raising it again republishes it.
Favourites
| Request | Returns |
|---|---|
GET /api/v1/favorites |
The member’s favourites that are still published, newest first, each with the listing’s title (ad), price and image. |
POST /api/v1/favorites/{id_ad} |
Adds the listing to favourites. |
DELETE /api/v1/favorites/{id_ad} |
Removes it. |
Messages
These use your marketplace’s messaging system. Messages are grouped in threads,
and a thread is identified by the id of its first message (id_message_parent).
| Request | Returns |
|---|---|
GET /api/v1/messages |
The member’s threads, newest first, each with user_from, user_to (name, last sign-in, picture) and the ad it is about (title, price, status, picture), if any. Paginated. |
GET /api/v1/messages/unread |
Only threads with unread messages for the member. |
GET /api/v1/messages/{id_message_parent} |
Every message in a thread, oldest first. Messages to the member are marked as read. |
POST /api/v1/messages |
Sends a message (see below). Returns the message. |
Filter threads with id_ad (messages about one listing) or id_user_from (threads started by one member).
A thread with no id_ad is a direct message between members.
To send a message, always include message and one of:
| Send | To |
|---|---|
id_ad (and optional price, an offer) |
Contact the seller of a published listing. |
id_user |
Message a member directly. |
id_message_parent (and optional price) |
Reply in an existing thread. |
If the member already has an open thread with that seller about that listing (or with that member), the message is added to it instead of starting a new one.
Profile
| Request | Parameters | Returns |
|---|---|---|
PUT /api/v1/profile |
See below | User updated, or the validation errors with 400. |
POST /api/v1/profile/picture |
profile_image (file upload) |
true. |
DELETE /api/v1/profile/picture_delete |
optional num_image (default 1) |
true. |
PUT /api/v1/profile accepts name, email, description, password, phone, id_location, address,
latitude, longitude, subscriber (1 to receive newsletters, 0 not to), digest_interval
(never, daily, weekly or monthly) and the member’s
user custom fields as cf_<name>, except those marked for administrators only and the
verified badge (cf_verifiedbadge). Any other field, such as the role or status, is ignored.
To read the member’s own profile, use GET /api/v1/users/{id} with their user_token.
Tips
- Cache what rarely changes. Categories, locations, custom fields and translations change only when you edit them, so fetch them once per session rather than on every screen.
- Build links with
url. Listings, blog posts, pages and FAQs include their public address, which already follows your marketplace’s URL settings. - Prices come formatted.
pricein listings and categories is formatted for display in your site’s currency and format. In favourites and messages it is the plain number. - Test safely. Create a test member and a test category, and use them while you develop; switch them off when you are done.
Related guides
- API keys and permissions — scoped keys for each app.
- Webhooks — get events pushed to your app as they happen.
- Connect an AI assistant — the MCP server.
- General settings — where the site key lives.
- Custom fields — the extra listing fields the API returns as
cf_…. - Social login — needed for
auth/social. - Messaging between members — the conversations behind the messages endpoints.
Updated 22 October 2026 · Suggest an edit