Your first call in five minutes
Choose your environment#
Every example on this site — here, in the guides and in the API reference — is rewritten to the environment you pick, and the choice follows you until you change it.
You need two things: an API key, and the base URL above.
curl https://sandbox-api.biklo.com/v1/me \
-H "Authorization: Bearer bk_test_your_key_here"
{
"api_version": "v1",
"environment": "test",
"is_sandbox": true,
"seller": { "user_id": 22, "name": "Bike Shop SRL", "is_company": true },
"key": { "scopes": ["catalog.read", "products.read", "products.write"] },
"rate_limits": { "per_minute": 60, "per_day": 5000 }
}
If that returns 401, check three things in order: the header is Authorization: Bearer …,
the key starts with bk_test_ for the sandbox, and you are calling
sandbox-api.biklo.com rather than api.biklo.com. The environment is part of the
key — a test key sent to production is rejected on purpose, so you find out
immediately rather than after writing to the wrong marketplace.
Step one: an address to ship from#
Before a single product, the seller needs an address. The default one is where the courier collects: when an order is placed we snapshot it as the parcel's origin, and without it the order has nowhere to ship from and cannot be fulfilled.
It also fills in your listings. With no city_id in a product payload, every product
you create or update takes the city, county and street of this address — so the listing
and the waybill always agree.
curl -X POST https://sandbox-api.biklo.com/v1/addresses \
-H "Authorization: Bearer $KEY" \
-H "Content-Type: application/json" \
-d '{
"city_id": 1,
"street": "Bulevardul Decebal 14",
"postal_code": "200001"
}'
{
"id": 4812,
"street": "Bulevardul Decebal 14",
"postal_code": "200001",
"city": { "id": 1, "name": "Craiova" },
"county": { "id": 1, "name": "Dolj" },
"country_code": "RO",
"is_default": true
}
city_id comes from GET /v1/geo/cities — a city name is never accepted, because the
courier needs the id. The street must contain a number, and the postal code has to
fit both the country's format and the county; GET /v1/geo/address-rules spells both
out. We reject what a courier would have rejected later.
Your first address is the default automatically. Add more with the same call, and move
the flag with POST /v1/addresses/{id}/default — that one call decides where every
future order ships from, and moves your catalogue's location on the next product sync.
If you already have an address from the dashboard,
GET /v1/addresseswill show it and there is nothing to do. Check anyway: publishing without one succeeds, looks correct, and fails on the first real order.
The three calls behind every integration#
1 — Find the category. Listings live on leaves.
curl "https://sandbox-api.biklo.com/v1/categories?lang=ro" -H "Authorization: Bearer $KEY"
2 — Read what that category requires. A product is rejected until every required attribute is supplied, and the ids you send come from here.
curl "https://sandbox-api.biklo.com/v1/categories/4291/attributes?lang=ro" -H "Authorization: Bearer $KEY"
3 — Push the product. external_id is your id; sending the same one twice
updates rather than duplicating.
curl -X POST https://sandbox-api.biklo.com/v1/products \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{
"external_id": "ERP-1001",
"title": "Bicicleta MTB Hardtail 29 inch",
"description": "A hardtail mountain bike in very good condition, barely used.",
"category_id": 4291,
"price": { "amount": 249900, "currency": "RON" },
"stock": 4,
"attributes": [
{ "field_id": 32, "option_id": 226 },
{ "field_id": 47, "option_id": 422 }
]
}'
249900 is minor units — 2 499,00 RON. Every amount in this API works that way.
Then what#
Import the Postman collection — every endpoint, with a
worked example and a saved response — set the api_key variable, and you have the
whole surface to click through.
Next: Sync your catalog and Orders end to end.
