KashierDevelopersKashier Developers
Accept payments

Product catalog

Create and manage the products and categories used to build itemized payment links and checkout pages

Kashier keeps a per-merchant product catalog — products and the categories that organize them — under /v2/products and /v2/category. It's the same catalog used when a payment page or payment link is built from line items instead of a single flat amount, and every stock-affecting change to a product is recorded on an append-only timeline you can inspect after the fact.

Scope of this page

This page covers the merchant-facing CRUD subset of /v2/products and /v2/category — the routes that require merchant authentication. Two /v2/category routes are intentionally left out: GET /v2/category/paymentPage/:ppLink/summary and GET /v2/category/simple are public and take no merchant credentials. The first is consumed by the checkout page itself to render a payment page's categories; the second is a read-only lookup that takes a merchantId query parameter. Neither is part of managing your catalog.

Product fields

These fields come from the verified products-and-services-management data model. The exact wire format for a given response isn't independently confirmed on every route below — where that matters, the "Try it" panel is the fastest way to check.

FieldTypeSettable via APINotes
productNamestringyesPart of a per-merchant merchantId + currency + productName uniqueness constraint — you can't have two products with the same name in the same currency.
productDescriptionstringyesFree-text description.
productReferencestringyesYour own SKU/reference.
unitPricenumberyesMinimum 0.
currencystringyesDefaults to EGP.
quantitynumberyesStock quantity. Minimum 0.
productImagestringyesObject key for the product image; echoed back as productImageUrl, a full static.kashier.io URL.
isVariantbooleanyesWhether the product has size variants. Defaults to false.
variantsTypestring (size)yesVariant dimension, when isVariant is true.
isShippablebooleanyesDefaults to false.
dimensions.height / .width / .length / .weight / .notesnumber / stringyesShipping dimensions.
productVariants[]arrayyesEmbedded size variants, each with variantType, name, quantity, unitPrice (minimum 0.1), variantReference, status, variantDimensions.
categories[]array of category IDsyesCategories this product belongs to.
productStatusstring (available | outOfStock)system-managedDerived from stock levels.
reservedQuantity / purchasedQuantity / totalRevenuenumbersystem-managedRunning totals maintained by the service.
merchantId / createdByUserId / creationDatesystem-managedSet from the authenticated request.

Category fields

FieldTypeSettable via APINotes
namestringyesRequired.
slugstringsystem-managedDerived from name, and unique per merchant (merchantId + slug) — two of your categories can't resolve to the same slug, so names have to differ.
numberOfProductsnumbersystem-managedDenormalized count of products tagged with this category; not a live join, so treat it as approximate.
merchantId / createdByUserId / createdAt / updatedAtsystem-managed

List merchant products

Returns the merchant's products.

curl --location 'https://test-api.kashier.io/v2/products/' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 with the merchant's products — individual items follow the Product fields shape above. Query parameters (pagination, search, filters) and the exact list envelope aren't confirmed here — use the "Try it" panel above against a test account to inspect a live response.

Create product

Creates a new product in the merchant's catalog.

Body parameters

See Product fields for the full settable set. productName, currency and isVariant are required by the create schema; unitPrice is required for a non-variant product. A minimal example:

curl --location 'https://test-api.kashier.io/v2/products/' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "productName": "Wireless Mouse",
    "productReference": "SKU-1001",
    "currency": "EGP",
    "unitPrice": 350,
    "quantity": 100,
    "isVariant": false
  }'

Two uniqueness constraints to work around

productReference is optional, but it is your merchant-wide SKU and reusing one is rejected with Validation failed / SKU must be unique — the panel below leaves it out for that reason, so add your own value when you need one. productName is constrained too, on merchantId + currency + productName, so change the name in the panel before sending: running it twice with the same name and currency is rejected as a duplicate.

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 201 with the created product, in the Product fields shape — including the system-managed fields (productStatus, merchantId, timestamps, and so on).

Get product details

Fetch a single product by ID.

curl --location 'https://test-api.kashier.io/v2/products/:id' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 with the product in the Product fields shape.

Update product

Update fields on an existing product.

Body parameters

Same settable fields as Create product — see Product fields.

curl --location --request PUT 'https://test-api.kashier.io/v2/products/:id' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "unitPrice": 375,
    "quantity": 80
  }'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns the updated product in the same shape as Get product details.

Get product timeline

Returns the append-only audit/inventory timeline for a single product — every stock created / added / reduced / reserved / purchased / updated event, in order.

curl --location 'https://test-api.kashier.io/v2/products/:id/timeline' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 with a list of timeline entries. Per the underlying schema, each entry carries operation (created | reduced | added | purchased | updated | reserved), numOfUnit (the quantity delta), actionDate, actionBy (userId, email, fullName of who made the change), and — when the event came from a sale — customPurchasedAttributes linking back to the transactionId, orderId, and payment page (ppId) that consumed the stock. The exact envelope (pagination, wrapper key) isn't confirmed here — use the "Try it" panel above against a test account.

Assign categories to product

Adds or removes categories on one or more products, in bulk.

Body parameters

KeyRequiredDescription
categoryIdsyesArray of category IDs to apply. Get them from Get all categories.
productIdsyesArray of product IDs to apply them to. Get them from List merchant products.
operationyesassign or unassign.
curl --location --request PUT 'https://test-api.kashier.io/v2/products/assign/categories' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "categoryIds": ["507f1f77bcf86cd799439011"],
    "productIds": ["507f1f77bcf86cd799439012"],
    "operation": "assign"
  }'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200. Invalid IDs are rejected with 400 {"message":"Invalid category IDs"}.

No 'Try it' panel for this one

Both IDs have to be real objects in your own catalog, and the call rewrites the categories[] of every product you name — there is no placeholder pair that produces a valid, harmless request. Run the curl above with IDs from your own account instead. The route adds to a product's existing categories[] (or removes from it, with operation: "unassign") and notifies the payment-pages service of the change; the field names above come from Kashier's request-validation schema, but confirm the behaviour on a test product before relying on it in production.

Change product categories

A second, related route for managing a product's categories, alongside Assign categories to product.

Body parameters

The same categoryIds and productIds arrays as Assign categories to product, both required — but no operation, which is the one structural difference between the two routes.

KeyRequiredDescription
categoryIdsyesArray of category IDs.
productIdsyesArray of product IDs.
curl --location --request PUT 'https://test-api.kashier.io/v2/products/categories/change' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "categoryIds": ["507f1f77bcf86cd799439011"],
    "productIds": ["507f1f77bcf86cd799439012"]
  }'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

No 'Try it' panel for this one

Same reason as Assign categories to product: the call needs real product and category IDs from your own catalog and rewrites the products it names, so there is no safe placeholder body to ship. If your integration depends on whether this route replaces a product's category set or adds to it, verify that behaviour on a test product first — the two routes are close enough in name that you should not assume.

Export merchant products

Downloads the merchant's product catalog as a file.

curl --location 'https://test-api.kashier.io/v2/products/export' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --output products.xlsx

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Export merchant products asynchronously

Same export, run as a background job instead of a synchronous download — useful for large catalogs. Rather than returning the file directly, it queues the export and is intended to email a download link once the file is ready.

curl --location 'https://test-api.kashier.io/v2/products/export-async' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 acknowledging the export job was queued. The exact acknowledgment body and delivery mechanism for the finished file aren't confirmed here — use the "Try it" panel above against a test account.

Upload product file

Uploads a file associated with the merchant's catalog (for example, a product image — productImage is stored as an object key and served back via productImageUrl).

curl --location 'https://test-api.kashier.io/v2/products/upload/' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --form 'file=@"/path/to/file"'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Confirm the multipart field name before you integrate

The upload is merchant-scoped and stores the file in Kashier's object storage. The file field name above is a placeholder — confirm the multipart field name and the accepted file types against a test account before integrating.

Get all categories

Returns the merchant's product categories.

Query parameters

sortBy is required. It is validated before authentication, so calling the route without it returns 400 {"message":"\"sortBy\" is required"} even with a valid secret key.

KeyRequiredDescription
sortByyesField to sort by, for example name or createdAt.
sortTypenoSort order: 1 ascending, -1 descending.
pagenoPage number.
limitnoResults per page.
qnoSearch query.
from / tonoDate range, DD-MM-YYYY.
curl --location 'https://test-api.kashier.io/v2/category/?sortBy=createdAt&sortType=-1&page=1&limit=20' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 with the merchant's categories — individual items follow the Category fields shape above, alongside pagination. Use the "Try it" panel above against a test account to see the exact list envelope.

Create product category

Creates a new category.

Body parameters

KeyDescription
nameCategory name. Required, and unique per merchant once slugified — see Category fields. Change the name in the panel below before sending, or a second run is rejected as a duplicate.
curl --location 'https://test-api.kashier.io/v2/category/' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Electronics"
  }'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 201 with the created category, in the Category fields shape — including the system-managed slug (derived from name) and numberOfProducts (starts at 0).

Get category details

Fetch a single category by ID.

curl --location 'https://test-api.kashier.io/v2/category/:id' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 with the category in the Category fields shape.

Update product category

Update a category's name.

Body parameters

KeyDescription
nameNew category name. Changing it re-derives slug.
curl --location --request PUT 'https://test-api.kashier.io/v2/category/:id' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "Electronics & Accessories"
  }'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns the updated category in the same shape as Get category details.

Delete product category

Delete a category.

curl --location --request DELETE 'https://test-api.kashier.io/v2/category/:id' \
  --header 'Authorization: YOUR_TEST_SECRET_KEY'

Headers

KeyDescription
AuthorizationThe Authorization is a secret key that is used to identify the merchant. You can obtain it from Kashier's dashboard. Learn more about Authorization.

Response

Returns a 200 confirming deletion. The exact response body isn't confirmed here — use the "Try it" panel above against a test account.

Products deleted from a category

Deleting a category doesn't delete the products tagged with it — numberOfProducts is a denormalized counter, not an ownership relationship. Whether a deleted category's ID is also stripped from each product's categories[] is something to verify against a test account if your integration depends on it.

On this page