API Documentation
Seller API pagination and filters update
Seller-facing list endpoints keep backward compatibility. Old requests without query parameters still work. New clients may request larger paginated slices where supported.
limit: supported values include30,50,500; API-side maximum is100000for bulk reads.page: 1-based page number./orders: supportsstatus,date,limit,page./orders/statistics: returns seller statistics forday,week,month, oryearending at a selecteddate./payout/history: supportsdate_from,date_to,requisites,status,limit,page./products/categories: seller-facing categories exclude service category777/ SoftStore./products:include_category_counts=1returns real seller category counts when available./products:availability=on|off|allfilters enabled/disabled seller products by the productstatusfield.
Complete REST API documentation.
POST /auth/api-key/create
Exchange a raw seller API key for a short-lived JWT access token. Use this endpoint before any protected API method.
curl -X POST https://api.softstore.app/api/v1/auth/api-key/create \
-H "X-API-KEY: YOUR_RAW_SELLER_API_KEY" \
-H "Content-Type: application/json" \
-d "{}"
Response Schema
| access_token | string |
| expires_in | integer |
Error Responses
{
"status": "error",
"message": "error api key"
}
Invalid raw API keys return HTTP 401 with message: "error api key" Missing X-API-KEY returns message: "API key required". Protected endpoints without JWT return message: "Authorization header required".
Request Overview
This endpoint allows sellers to create a new product or service offer in their inventory. The offer will be attached to the authenticated seller account.
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id_categories | integer | Yes | Existing active category identifier. Category catalog_type decides whether the offer is a product or service. |
| id_sup_categories | integer|null | Only for services | Active selectable service subcategory from /products/categories. Must be omitted or null for normal product categories. |
| type | string | No | Optional client hint: product or service. If provided, it must match the selected category type. |
| name | string | Yes | Product title (3-255 chars) |
| meta_title | string | Yes | SEO meta title |
| meta_description | string | Yes | SEO meta description |
| ru_title | string | No | Optional Russian product title. Used on softstore.app when lang=ru; falls back to meta_title when empty. Must be unique per seller when provided. |
| ru_description | string | No | Optional Russian product description. Used on softstore.app when lang=ru; falls back to meta_description when empty. |
| tags | string | Yes | Comma-separated tags list |
| text_page | string | Yes | Full English product page text (minimum 10 chars). Used by default and when lang=en. |
| ru_text_page | string | No | Optional Russian product page text. Used on softstore.app when lang=ru; falls back to text_page when empty. |
| price | integer | Yes | Product price (1 - 9,999,999) |
| count | integer | Yes | Available stock quantity |
| uuid | string | Yes | External product identifier (must be unique) |
| features | string | Yes | Minimum 3 comma-separated features |
| discount | integer | No | Optional product discount |
| opt_price | string | No | Bulk discount percentages, comma-separated integers. Example: 5,10,20. Max 10 levels, max discount 90%. |
| opt_count | string | No | Bulk quantity thresholds matching opt_price. Example: 10,100,200. |
| api_key | string | No | Optional external API integration key |
| automated_message | string | No | Optional automated message sent to the buyer in the order chat after purchase. Maximum 1000 characters. |
| special_offer | string | No | Comma-separated product IDs for the public Special offer block. Maximum 3 products, same seller only, no self-reference. Categories may differ. |
| comment_status | integer | No | Set 1 when buyer comment is required during checkout. Default: 0. |
| comment_placeholder | string | Conditional | Label text above the checkout comment input. Required when comment_status=1. Max 300 chars, no HTML/script/control chars. |
| comment_input_placeholder | string | Conditional | Placeholder inside the checkout comment input. Required when comment_status=1. Max 100 chars, no HTML/script/control chars. |
| gift_available | integer | No | Set 1 to allow Gift creation for this product. Default: 0. |
| regex | string | No | Optional strict buyer-comment validation: email, url, int, phone, or a validated custom regex (max 200 chars). Invalid or unsafe expressions reject product creation. |
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| message | string | Success confirmation message |
| id | string | Generated internal product ID |
Validation Rules
- Category ID must exist in available categories list
- Product name must be unique
- UUID must be unique
- Features field requires minimum 3 values
- Price cannot be less than 1
- Stock count cannot be negative
- Text description must contain at least 10 characters
- automated_message is optional and cannot exceed 1000 characters
- special_offer is optional, accepts up to 3 comma-separated product IDs, and all referenced products must belong to the same seller
Request Example
curl -X POST https://api.softstore.app/api/v1/products \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id_categories": 1,
"name": "Windows 11 Pro Key",
"meta_title": "Windows License",
"meta_description": "Official activation key",
"ru_title": "Лицензия Windows",
"ru_description": "Официальный ключ активации",
"tags": "windows,key,microsoft",
"text_page": "Official Windows activation key with secure delivery after successful payment.",
"ru_text_page": "Официальный ключ активации Windows с безопасной выдачей после успешной оплаты.",
"price": 500,
"count": 100,
"uuid": "ext-123456",
"features": "Lifetime activation,Instant delivery,Official key",
"automated_message": "Thank you for your order. Delivery instructions will be sent here automatically.",
"special_offer": "6a8977d9d7f8d,6a8977d9d7f87"
}'
Service example:
curl -X POST https://api.softstore.app/api/v1/products \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id_categories": 702,
"id_sup_categories": 6,
"type": "service",
"name": "API integration setup",
"meta_title": "API integration setup",
"meta_description": "Service offer for API integration setup",
"tags": "api,integration,service",
"text_page": "Describe deliverables, terms, warranty and communication flow in English.",
"ru_text_page": "Опишите состав услуги, условия, гарантию и порядок общения на русском языке.",
"price": 15000,
"count": 5,
"uuid": "service-api-setup-001",
"features": "Scope agreed before start,Order chat support,Delivery through SoftStore"
}'
$response = $api->createProduct([
'id_categories' => $categoryId,
'name' => 'Test Product ' . rand(1000,9999),
'meta_title' => 'Test Meta Title',
'meta_description' => 'Test Meta Description',
'tags' => 'test,api,product',
'text_page' => 'This is a test product description',
'price' => rand(100,1000),
'count' => rand(1,1000),
'uuid' => 'ext-' . uniqid(),
'features' => 'Feature 1,Feature 2,Feature 3',
'automated_message' => 'Thank you for your order. Delivery instructions will be sent here automatically.'
]);
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/products',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
id_categories: 1,
name: "Windows 11 Pro Key",
meta_title: "Windows License",
meta_description: "Official key",
tags: "windows,key",
text_page: "Official product description",
price: 500,
count: 100,
uuid: "ext-123456",
features: "Feature 1,Feature 2,Feature 3",
automated_message: "Thank you for your order. Delivery instructions will be sent here automatically."
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Product created",
"id": "69f8bd078449b",
"type": "product"
}
}
Error Responses
{
"status": "error",
"message": "Field 'name' is required"
}
{
"status": "error",
"message": "Product with this UUID already exists"
}
{
"status": "error",
"message": "Invalid category id"
}
Request Overview
This endpoint updates an existing product that belongs to the authenticated seller. Only the product owner can update product data.
wait automatically.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Product internal ID |
Fields Without Moderation
Updating these fields does not trigger moderation.
| Field | Type | Description |
|---|---|---|
| price | integer | Product price |
| discount | integer | Product discount percentage |
| opt_price | string | Bulk discount percentages, comma-separated. Empty value removes bulk discounts. |
| opt_count | string | Bulk quantity thresholds, comma-separated. Must match opt_price count. |
| count | integer | Available stock quantity |
| status | string | Status "active" or "off" |
| api_key | string | External API integration key |
| api_url | string | External API URL |
| automated_message | string | Optional automated order chat message, up to 1000 characters |
| special_offer | string | Optional comma-separated product IDs for Special offer. Maximum 3 products, same seller only, does not trigger repeat moderation by itself. |
| comment_status | integer (0 or 1) | Require buyer information during checkout. |
| comment_placeholder | string | Label above the buyer information field, maximum 300 characters. |
| comment_input_placeholder | string | Placeholder inside the buyer information field, maximum 100 characters. |
| gift_available | integer (0 or 1) | Allow buyers to purchase a Gift code for this product. |
| regex | string | Optional strict buyer-comment expression. Changing this field alone does not trigger repeat moderation. |
Fields That Trigger Moderation
Updating these fields will automatically send the product back to moderation.
| Field | Type | Description |
|---|---|---|
| name | string | Product name |
| meta_title | string | SEO title |
| meta_description | string | SEO description |
| ru_title | string | Optional Russian title for lang=ru |
| ru_description | string | Optional Russian description for lang=ru |
| tags | string | Product tags |
| text_page | string | English product page text |
| ru_text_page | string | Optional Russian product page text for lang=ru |
| uuid | string | External product UUID |
| features | string | Comma-separated product features |
| id_categories | integer | Product category ID |
Restricted Fields
- rating
- status_moderation
Request Example
curl -X POST https://api.softstore.app/api/v1/products/update/69f46db161e76 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"price": 999,
"discount": 15,
"count": 200,
"api_key": "new-api-key",
"api_url": "https://example.com/api",
"automated_message": "Updated automated order chat message.",
"special_offer": "6a8977d9d7f8d,6a8977d9d7f87",
"comment_status": 1,
"comment_placeholder": "Your account login",
"comment_input_placeholder": "login, email or account ID",
"gift_available": 1,
"name": "Updated Product Name",
"ru_title": "Обновленное название товара",
"ru_description": "Обновленное краткое описание товара",
"text_page": "Updated English product page text",
"ru_text_page": "Обновленный русский текст страницы товара",
"tags": "updated,test,product",
"features": "Feature A,Feature B,Feature C",
"id_categories": 8
}'
$response = $api->updateProduct('69f46db161e76', [
'price' => rand(100,999),
'discount' => rand(0,30),
'count' => rand(1,500),
'api_key' => 'new-api-key',
'api_url' => 'https://example.com/api',
'automated_message' => 'Updated automated order chat message.',
'name' => 'Updated Product',
'text_page' => 'Updated description',
'tags' => 'update,test',
'features' => 'Feature 1,Feature 2,Feature 3',
'id_categories' => 8
]);
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/products/update/69f46db161e76',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
price: 999,
discount: 15,
count: 300,
automated_message: "Updated automated order chat message.",
name: "Updated Product",
text_page: "Updated product description",
tags: "update,test",
features: "Feature 1,Feature 2,Feature 3"
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Product updated",
"moderation": true
}
}
Error Responses
{
"status": "error",
"message": "Product not found or access denied"
}
{
"status": "error",
"message": "Invalid price"
}
{
"status": "error",
"message": "UUID already exists"
}
{
"status": "error",
"message": "No fields to update"
}
Request Overview
This endpoint permanently deletes an existing product from the authenticated seller inventory.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Internal product ID returned after product creation |
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| message | string | Deletion confirmation message |
Validation Rules
- User must be authenticated via JWT token
- Product must exist
- Product must belong to authenticated seller
- Deleted products cannot be restored
Request Example
curl -X DELETE https://api.softstore.app/api/v1/products/69f8bd078449b \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$productId = "69f8bd078449b";
$response = $api->deleteProduct($productId);
print_r($response);
const productId = "69f8bd078449b";
const response = await fetch(
`https://api.softstore.app/api/v1/products/${productId}`,
{
method: 'DELETE',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Product deleted"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Product not found"
}
{
"status": "error",
"message": "Delete failed or access denied"
}
Request Overview
Retrieve full information about a specific product that belongs to the authenticated seller account.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Internal product identifier |
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| product.id | string | Internal product ID |
| product.name | string | Product name |
| product.price | integer | Product price |
| product.count | integer | Available stock quantity |
| product.discount | integer | Applied discount percentage |
| product.uuid | string | External product UUID |
| product.status_moderation | string | Moderation status |
| product.created_at | datetime | Creation date |
Validation Rules
- User must be authenticated
- Product must exist
- Product must belong to authenticated seller
- Invalid product ID returns error
Request Example
curl -X GET https://api.softstore.app/api/v1/products/info/69f8bd078449b \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$productId = "69f8bd078449b";
$response = $api->getProduct($productId);
print_r($response);
const productId = "69f8bd078449b";
const response = await fetch(
`https://api.softstore.app/api/v1/products/info/${productId}`,
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"product": {
"id": "69f8bd078449b",
"name": "Windows 11 Pro Key",
"price": 500,
"count": 100,
"discount": 10,
"uuid": "ext-123456",
"status_moderation": "approved",
"created_at": "2026-05-05 12:30:00"
}
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Product not found"
}
{
"status": "error",
"message": "Access denied"
}
Request Overview
Returns a paginated list of products that belong to the authenticated seller account.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| page | integer | No | Pagination page number (default: 1) |
| limit | integer | No | Items per page. Allowed values: 30, 50, 500. Default: 30 |
| availability | string | No | Filter by product availability: all, on / enabled (status=active), off / disabled (not active). Default: all |
| category | integer | No | Filter by category ID |
| sort | string | No | Sort field: default, price, created, quantity, sales, discount, opt |
| direction | string | No | Sort direction: high_to_low or low_to_high |
| include_category_counts | integer | No | Set to 1 to include category_counts for category dropdowns |
| search | string | No | Search products by name |
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| products | array | List of seller products |
| products[].id | string | Product internal ID |
| products[].name | string | Product title |
| products[].price | integer | Product price |
| products[].count | integer | Available quantity |
| products[].status_moderation | string | Moderation status |
| pagination.total | integer | Total products count |
| pagination.page | integer | Current page |
| pagination.limit | integer | Current limit |
Validation Rules
- User must be authenticated
- Page value must be greater than 0
- Limit value must be within allowed range
- Invalid filters may return empty result
Request Example
curl -X GET "https://api.softstore.app/api/v1/products?page=1&limit=30&sort=price&direction=high_to_low&category=12&availability=on&include_category_counts=1" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$response = $api->getProducts([
'page' => 1,
'limit' => 30,
'sort' => 'price',
'direction' => 'high_to_low',
'category' => 12,
'availability' => 'on',
'include_category_counts' => 1
]);
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/products?page=1&limit=30&sort=price&direction=high_to_low&category=12&availability=on&include_category_counts=1',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"products": [
{
"id": "69f8bd078449b",
"name": "Windows 11 Pro Key",
"price": 500,
"count": 100,
"status": "active",
"status_moderation": "approved"
}
],
"pagination": {
"total": 150,
"page": 1,
"limit": 20
}
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Invalid pagination parameters"
}
Request Overview
This endpoint returns the full list of available product and service categories that sellers can use when creating or updating offers.
id_categories during product/service creation or update.
Categories with catalog_type=service use the expanded RU/EN
service taxonomy. Pass only a selectable child
subcategories[].id as id_sup_categories.
Deprecated umbrella categories, including freelancer-services,
are not returned and must not be used in new integrations.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| data | array | Array of available categories |
| id | integer | Category internal identifier |
| name | string | Category title |
| slug | string | Category URL slug |
| name_en / slug_en | string | English taxonomy fallback fields for RU/EN interfaces |
| catalog_type | string | product or service. This is the source of truth for offer type. |
| has_subcategories | integer | 1 when sellers must choose a service subcategory |
| subcategories | array | Service subcategory tree with RU/EN titles, parent_id, is_new, is_selectable, status and sort order |
| status | string | Category status |
Business Logic
- Returns only active categories
- Inactive categories may be hidden from sellers
- Deprecated umbrella categories such as Freelancer Services are hidden from API, LK and public catalog
- Category IDs are required for product/service creation
- Service categories return a hierarchical taxonomy: group rows have
is_selectable=0, leaf rows haveis_selectable=1 - Service creation/update requires a valid active selectable leaf subcategory ID
- Normal products must omit service subcategory IDs
- Use this endpoint before creating marketplace integrations
Request Example
curl -X GET https://api.softstore.app/api/v1/products/categories \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$response = $api->getCategories();
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/products/categories',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": [
{
"id": 1,
"name": "Software Keys",
"slug": "software-keys",
"status": "active"
},
{
"id": 2,
"name": "Gaming Accounts",
"slug": "gaming-accounts",
"status": "active"
},
{
"id": 3,
"name": "Subscriptions",
"slug": "subscriptions",
"status": "active"
}
]
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Categories not found"
}
Request Overview
This endpoint sends an existing product to manual moderation. Uploading or replacing the product image also returns the product to pending moderation. After submitting, moderators will review product content, image, pricing, category selection and marketplace compliance.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Accept: application/json
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id_product | string | Yes | Internal product identifier |
Response Parameters
| Field | Type | Description |
|---|---|---|
| status | string | Response status |
| message | string | Moderation submission result |
| moderation_status | string | Current moderation state |
Moderation Rules
- Product must belong to authenticated seller
- Product must exist
- Product cannot already be under active moderation
- A product must have an image before it can be sent to moderation
- Uploading/replacing an image sets moderation back to pending
- Moderators may reject invalid products
- Rejected products can be fixed and resubmitted later
Request Example
curl -X POST https://api.softstore.app/api/v1/products/moderation \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id_product": "69f8bd078449b"
}'
$response = $api->sendProductToModeration([
'id_product' => '69f8bd078449b'
]);
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/products/moderation',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
id_product: "69f8bd078449b"
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Product submitted for moderation",
"moderation_status": "pending"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Product not found"
}
{
"status": "error",
"message": "Product is already under moderation"
}
{
"status": "error",
"message": "Access denied"
}
Request Overview
Returns seller order statistics for a selected period ending at a selected date. The response is ready for dashboard charts and contains both aggregate metrics and daily series points.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Query Parameters
| Field | Type | Required | Description |
|---|---|---|---|
| period | string | False | day, week, month, or year. Default: day. |
| date | string | False | Selected end date in YYYY-MM-DD format. Week/month/year ranges count backward from this date. |
Request Example
curl -X GET "https://api.softstore.app/api/v1/orders/statistics?period=week&date=2026-08-10" \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
Success Response
{
"status": "success",
"data": {
"period": "week",
"date": "2026-08-04",
"date_to": "2026-08-10",
"selected_date": "2026-08-10",
"metrics": {
"orders": 179,
"paid_orders": 3,
"unpaid_orders": 176,
"revenue": 2461,
"avg_check": 820.33,
"conversion_percent": 1.68,
"growth_percent": 100,
"products": 39
},
"series": [
{
"date": "2026-08-07",
"orders": 41,
"paid_orders": 1,
"revenue": 1890
}
]
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Invalid date format. Use YYYY-MM-DD."
}
Request Overview
This endpoint returns the full order history for the authenticated seller. It allows sellers to monitor all purchases made for their products. Buyer email addresses are exposed only in seller webhook callback payloads after successful payment. Regular seller API responses and the seller dashboard do not expose buyer email addresses.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| status | string | False | Orders status: wait / paid / cancel / dispute |
| date | string | False | Orders date Y-M-D |
Response Parameters
| Field | Type | Description |
|---|---|---|
| id_order | string | Unique order identifier |
| id_product | string | Purchased product ID |
| amount | string | Total order amount |
| status_order | string | Current order status (wait / paid / cancel / dispute) |
| data_create | string | Order creation date |
| time_create | string | Order creation time |
| count | string | Purchased quantity |
Business Logic
- Returns only seller-owned orders
- Does not expose buyer email addresses in regular API responses
- Buyer email is available in the seller webhook callback payload after successful payment
- Requires valid JWT authorization
- Orders are returned as full history list
- Use
/orders/info/{id}for detailed order information
Request Example
curl -X GET https://api.softstore.app/api/v1/orders \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$response = $api->getOrders();
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/orders',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": [
{
"id_order": "3fb0a629f15a0bdd7ce4b69f9a164911",
"id_product": "69f362be33c2a",
"amount": "9408",
"status_order": "wait",
"data_create": "2026-05-02",
"time_create": "17:28:49",
"count": "16"
},
{
"id_order": "4b51c4d77809743fdd172713feb02300",
"id_product": "777156470",
"amount": "640",
"status_order": "paid",
"data_create": "2026-04-28",
"time_create": "13:46:13",
"count": "5"
}
]
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
Request Overview
This endpoint returns detailed information about a specific order. Sellers can only access orders that belong to their own account.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique order identifier |
Response Parameters
| Field | Type | Description |
|---|---|---|
| id | string | Internal database ID |
| title | string | Name product |
| id_user | string | Registered buyer ID (if available) |
| guest_id | string | Guest buyer identifier |
| buyer_type | string | Buyer type (guest / registered) |
| comment | string | Comment for order |
| id_product | string | Purchased product ID |
| id_seller | string | Seller identifier |
| id_order | string | Public order identifier |
| status_order | string | Order status |
| data_create | string | Order creation date |
| time_create | string | Order creation time |
| amount | string | Total payment amount |
| count | string | Purchased quantity |
| payment_system | string | Payment provider name |
Business Logic
- Seller can only access their own orders
- Order must exist
- Requires valid JWT token
- Returns order payment and delivery metadata; buyer email is delivered through the payment webhook callback
Request Example
curl -X GET https://api.softstore.app/api/v1/orders/info/4b51c4d77809743fdd172713feb02300 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$response = $api->infoOrder(
'4b51c4d77809743fdd172713feb02300'
);
print_r($response);
const orderId = "4b51c4d77809743fdd172713feb02300";
const response = await fetch(
`https://api.softstore.app/api/v1/orders/info/${orderId}`,
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"id": "94",
"id_user": "0",
"title": "Test Name",
"guest_id": "70df52e8ca9741105f5d3ccaee808edd",
"buyer_type": "guest",
"id_product": "777156470",
"id_seller": "1774966755",
"id_order": "4b51c4d77809743fdd172713feb02300",
"email": "ads@frogs-wallet.biz",
"status_order": "paid",
"data_create": "2026-04-28",
"time_create": "13:46:13",
"amount": "640",
"count": "5",
"payment_system": "cyberpay"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Order not found or access denied"
}
Overview
This endpoint allows sellers to deliver digital products after receiving a successful payment webhook notification.
{token} is automatically generated by SoftStore
and included inside webhook notification payload.
Delivery Flow
1. Customer purchases product
↓
2. Payment completed
↓
3. SoftStore sends webhook to seller API
↓
4. Seller receives delivery_url
↓
5. Seller sends digital product to delivery_url
↓
6. Buyer receives product via email
Webhook Notification Example
{
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"id_product": "69f36497dc78f",
"email": "buyer@example.com",
"comment": "buyer_login@example.com",
"payment_status": "paid",
"signature": "df595764abc185bbf31c5c6334cfade65379feb6",
"delivery_url": "https://api.softstore.app/api/v1/orders/delivery/TOKEN",
"token": "d487c01d834dcb296c4f7b5a02e0b0d9df320bb153778d6c20cd26e2c50b40bf"
}
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| text | string | Yes | Product delivery message / activation key / credentials |
| download | string (https url) | No | Optional download link for digital file delivery |
Delivery Types
Product keys, credentials, license codes, instructions
Files, archives, software installers, ebooks etc.
Request Examples
curl -X POST \
https://api.softstore.app/api/v1/orders/delivery/TOKEN_HERE \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"text":"Windows 11 activation key: XXXXX-XXXXX",
"download":"https://cdn.example.com/windows.zip"
}'
$response = $api->deliverOrder($token, [
'text' => 'Windows license key: XXXXX',
'download' => 'https://cdn.example.com/file.zip'
]);
print_r($response);
await fetch(deliveryUrl, {
method: "POST",
headers: {
"Authorization": "Bearer YOUR_JWT_TOKEN",
"Content-Type": "application/json"
},
body: JSON.stringify({
text: "Your license key: XXXXX",
download: "https://cdn.example.com/file.zip"
})
});
Success Response
{
"status": "success",
"data": {
"message": "Product delivered successfully",
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"delivered": true
}
}
Error Responses
| HTTP | Error | Description |
|---|---|---|
| 401 | Unauthorized | Invalid JWT token |
| 404 | Order not found | Invalid delivery token |
| 409 | Order already delivered | Product already sent |
| 422 | Invalid download URL | Only HTTPS links allowed |
Request Overview
This endpoint returns full information about the authenticated seller account. It allows marketplace sellers to retrieve profile information, financial balance, API settings, moderation status and public store details.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Response Parameters
| Field | Type | Description |
|---|---|---|
| id | integer | Internal seller record ID |
| id_user | integer | Telegram/User account identifier |
| name | string | Store name |
| balance | integer | Current seller balance |
| img | string | Seller profile image URL |
| description | string | Store description |
| api_url | string | Connected external API URL |
| data_create | string | Account registration date |
| rating | integer | Seller marketplace rating |
| api_key | string | Seller API key |
| status_moderation | integer | Seller moderation status |
Business Logic
- JWT token must be valid
- Seller account must exist
- Only current authenticated seller data is returned
- API key is returned for integration usage
- Balance reflects current available funds
Request Example
curl -X GET https://api.softstore.app/api/v1/seller \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
<?php
require_once "sellerApi.php";
$api = new SellerApi(
'https://api.softstore.app/api/v1',
'YOUR_API_KEY'
);
// create JWT token
$api->createApiKey();
// get seller info
$response = $api->getSellerInfo();
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/seller',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"id": 1,
"id_user": 1774966755,
"name": "My shop 777",
"balance": 19056,
"img": "https://img.softstore.app/uploads/example.png",
"description": "Best shop ever 777",
"api_url": "https://api.soft-shop.com",
"data_create": "10.04.2026",
"rating": 0,
"api_key": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"status_moderation": 0
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Seller not found"
}
Request Overview
This endpoint allows sellers to update their store profile information. Only specific fields are allowed for editing. The system validates all incoming data before saving changes.
name, description and
api_url fields can be updated.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Accept: application/json
Allowed Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| name | string | No | Store name (3-100 characters) |
| description | string | No | Store description (10-1000 characters) |
| api_url | string | No | External API URL |
Validation Rules
- Name must contain 3 to 100 characters
- Name cannot contain dangerous symbols
- Description must contain 10 to 1000 characters
- HTML/script tags are automatically sanitized
- API URL must be valid
- Unknown fields are rejected
- Empty update requests are rejected
Restricted Fields
- balance
- rating
- api_key
- status_moderation
- id_user
Request Example
curl -X POST https://api.softstore.app/api/v1/seller/profile \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "My New Store Name",
"description": "Updated store description for customers",
"api_url": "https://example-api.com"
}'
<?php
require_once "sellerApi.php";
$api = new SellerApi(
'https://api.softstore.app/api/v1',
'YOUR_API_KEY'
);
// create JWT
$api->createApiKey();
// update seller profile
$response = $api->updateSellerProfile([
'name' => 'Updated Store Name',
'description' => 'Updated description text',
'api_url' => 'https://example-api.com'
]);
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/seller/profile',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: "Updated Store Name",
description: "Updated description text",
api_url: "https://example-api.com"
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"id": 1,
"name": "Updated Store Name",
"description": "Updated description text",
"api_url": "https://example-api.com"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Invalid JSON"
}
{
"status": "error",
"message": "Name must be between 3 and 100 characters"
}
{
"status": "error",
"message": "Description too short (min 10)"
}
{
"status": "error",
"message": "Invalid API URL"
}
{
"status": "error",
"message": "Field 'balance' is not allowed"
}
{
"status": "error",
"message": "No valid data to update"
}
{
"status": "error",
"message": "Profile not updated"
}
Request Overview
This backward-compatible endpoint replaces the primary product image.
Images are uploaded using multipart/form-data.
The image will be linked to the authenticated seller product.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: multipart/form-data
Form Data Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| img | file | Yes | Product image file |
| id_product | string | Yes | Product internal ID |
Validation Rules
- JWT token must be valid
- Product must exist
- Product must belong to authenticated seller
- Image file is required
- Only image MIME types are accepted
- Invalid uploads are rejected
Request Example
curl -X POST https://api.softstore.app/api/v1/products/img \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "img=@product-image.png" \
-F "id_product=69f8bd078449b"
<?php
require_once "sellerApi.php";
$api = new SellerApi(
'https://api.softstore.app/api/v1',
'YOUR_API_KEY'
);
// create JWT
$api->createApiKey();
// upload image
$response = $api->uploadProductImage(
'69f8bd078449b',
'/home/user/product-image.png'
);
print_r($response);
const formData = new FormData();
formData.append('img', fileInput.files[0]);
formData.append('id_product', '69f8bd078449b');
const response = await fetch(
'https://api.softstore.app/api/v1/products/img',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN'
},
body: formData
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Product image uploaded",
"url": "https://img.softstore.app/uploads/products/example.png"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Image file required"
}
{
"status": "error",
"message": "Product not found or access denied"
}
{
"status": "error",
"message": "Invalid image format"
}
Product gallery
Add one or more JPEG, PNG or WebP files to a seller-owned product. A product supports up to five images. The first ordered image is always primary and remains available in the legacy img/image field.
Upload
curl -X POST https://api.softstore.app/api/v1/products/images \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "id_product=PRODUCT_ID" \
-F "images[]=@front.webp" \
-F "images[]=@back.webp"
Files: maximum 5 MB each; maximum 5 stored images in total. Changing the gallery sends the product back to moderation.
Reorder / select primary
POST /api/v1/products/images/reorder
Content-Type: application/json
{"id_product":"PRODUCT_ID","image_ids":[103,101,102]}
Send every current image ID exactly once. The first ID becomes primary.
Delete
POST /api/v1/products/images/delete
Content-Type: application/json
{"id_product":"PRODUCT_ID","image_id":103}
Product response
{
"img": "https://img.softstore.app/uploads/.../primary.webp",
"images": [
{"id":101,"url":"https://img.softstore.app/uploads/.../primary.webp","position":1,"is_primary":true}
]
}
Request Overview
This endpoint allows sellers to upload or update their profile image. The uploaded image becomes the public avatar/logo of the seller store.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: multipart/form-data
Form Data Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| img | file | Yes | Seller profile image file |
Validation Rules
- JWT token must be valid
- Image file is required
- Only valid image formats are allowed
- Invalid uploads will be rejected
- Old profile image may be replaced automatically
Request Example
curl -X POST https://api.softstore.app/api/v1/seller/img \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-F "img=@seller-avatar.png"
<?php
require_once "sellerApi.php";
$api = new SellerApi(
'https://api.softstore.app/api/v1',
'YOUR_API_KEY'
);
// create JWT
$api->createApiKey();
// upload seller image
$response = $api->uploadSellerImage(
'/home/user/seller-avatar.png'
);
print_r($response);
const formData = new FormData();
formData.append('img', fileInput.files[0]);
const response = await fetch(
'https://api.softstore.app/api/v1/seller/img',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN'
},
body: formData
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Profile image uploaded",
"url": "https://img.softstore.app/uploads/sellers/avatar.png"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Image file required"
}
{
"status": "error",
"message": "Invalid image format"
}
{
"status": "error",
"message": "Upload failed"
}
Request Overview
Create a withdrawal request from seller internal balance. This endpoint requires Google Authenticator OTP verification.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Accept: application/json
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| amount | integer | Yes | Payout amount (min: 1000) |
| payment_system | string | Yes | usdt / card / payment_account |
| wallet | string | Yes | Wallet address / card number / bank account |
| cod | string | Yes | 6-digit Google Authenticator OTP code |
Validation Rules
- JWT token must be valid
- Seller account must exist
- Amount must be between 1000 and 1000000
- Seller balance must be sufficient
- OTP code must be valid
- Only supported payout systems allowed
Request Example
curl -X POST https://api.softstore.app/api/v1/payout \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"payment_system": "usdt",
"wallet": "TRC20_WALLET_ADDRESS",
"cod": "123456"
}'
<?php
$response = file_get_contents(
'https://api.softstore.app/api/v1/payout',
false,
stream_context_create([
'http' => [
'method' => 'POST',
'header' => [
'Authorization: Bearer YOUR_JWT_TOKEN',
'Content-Type: application/json'
],
'content' => json_encode([
'amount' => 5000,
'payment_system' => 'usdt',
'wallet' => 'TRC20_WALLET_ADDRESS',
'cod' => '123456'
])
]
])
);
echo $response;
const response = await fetch(
'https://api.softstore.app/api/v1/payout',
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
amount: 5000,
payment_system: 'usdt',
wallet: 'TRC20_WALLET_ADDRESS',
cod: '123456'
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"id_order": "6fa81a21b1d44e9"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Invalid OTP code"
}
{
"status": "error",
"message": "Insufficient balance"
}
Request Overview
Retrieve full payout history for the authenticated seller. Returns withdrawal transactions created from seller balance.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| — | — | No | This endpoint does not require request body parameters |
Response Parameters
| Field | Type | Description |
|---|---|---|
| id_order | string | Payout transaction identifier |
| type | string | Transaction type (out) |
| amount | integer | Payout amount |
| status | string | Payout processing status |
| payment_system | string | Selected payout payment method |
| date_create | date | Creation date |
| time_create | time | Creation time |
Validation Rules
- User must be authenticated
- Seller account must exist
- Only own payout history is accessible
Request Example
curl -X GET https://api.softstore.app/api/v1/payout/history \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
<?php
require_once "sellerApi.php";
$api = new SellerApi(
"https://api.softstore.app/api/v1",
"YOUR_API_KEY"
);
// create JWT
$api->createApiKey();
// get payout history
$response = $api->getPayoutHistory();
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/payout/history',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": [
{
"id_order": "6fa81a21b1d44e9",
"type": "out",
"amount": 5000,
"status": "wait",
"payment_system": "usdt",
"date_create": "2026-05-17",
"time_create": "14:25:11"
}
]
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Seller not found"
}
Request Overview
Returns information about one Gift code by its exact key. The authenticated seller can access a Gift only when its product belongs to that seller.
Security: Bearer JWT is required. Unknown codes and codes belonging to another seller both return the same 404 Gift not found. Listing or searching by order, email, date, product, or activation status is not supported.
JSON Body
| Name | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Complete Gift key in format GIFT-0123456789ABCDEF. |
Example
curl -X POST https://api.softstore.app/api/v1/check/gift \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-d '{"key":"GIFT-0123456789ABCDEF"}'
Success Response
{
"status": "success",
"data": {
"id_order": "dc31f111000000000000000000000000",
"payment_status": "paid",
"id_product": "6a9335a225037",
"title": "App Store & iTunes (RU)",
"gift_status": "active",
"is_activated": false,
"created_at": "2026-09-14 08:00:00",
"activated_at": null,
"count": 1
}
}
Errors
401— missing or expired JWT.422— key parameter is missing.404— Gift is unknown, malformed, or belongs to another seller.429— rate limit exceeded.
Request Overview
Returns a list of chats that belong to the authenticated seller. Each chat is linked to a specific order.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
Response Parameters
| Field | Type | Description |
|---|---|---|
| id | string | Chat ID |
| id_order | string | Order identifier |
| title | string | Chat title |
| status_order | string | Current order status |
| amount | float | Order amount |
Request Example
curl -X GET https://api.softstore.app/api/v1/chat \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$response = $api->getChats();
print_r($response);
const response = await fetch(
'https://api.softstore.app/api/v1/chat',
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": [
{
"id": 15,
"id_order": "f87663f1ce0764d4c50c17bc39d536d9",
"title": "Order# f87663f1ce0764d4c50c17bc39d536d9",
"status_order": "paid",
"amount": 49.99
}
]
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
Request Overview
Returns detailed information about a specific chat. The chat must belong to an order owned by the authenticated seller.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Chat identifier |
Response Parameters
| Field | Type | Description |
|---|---|---|
| id | string | Chat ID |
| id_order | string | Associated order identifier |
| title | string | Chat title |
| data_create | date | Creation date |
| time_create | time | Creation time |
Validation Rules
- User must be authenticated using a valid JWT token
- Chat must exist
- Chat must belong to the authenticated seller
- Invalid chat ID returns an error response
Request Example
curl -X GET https://api.softstore.app/api/v1/chat/info/f87663f1ce0764d4c50c17bc39d536d9 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$chatId = 15;
$response = $api->getChatInfo($chatId);
print_r($response);
const chatId = 15;
const response = await fetch(
`https://api.softstore.app/api/v1/chat/info/${chatId}`,
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"id": 15,
"id_order": "f87663f1ce0764d4c50c17bc39d536d9",
"title": "Order# f87663f1ce0764d4c50c17bc39d536d9",
"data_create": "2026-06-12",
"time_create": "15:10:22"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Chat not found"
}
{
"status": "error",
"message": "Access denied"
}
Request Overview
Returns the complete message history for a specific chat. Messages are returned in chronological order, starting from the oldest message.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Chat identifier |
Response Parameters
| Field | Type | Description |
|---|---|---|
| id | integer | Message ID |
| id_chat | string | Chat identifier |
| id_user | integer | Message author ID |
| type_user | string | Message author role (buyer, seller, admin) |
| message | string | Message text |
| data_create | date | Message creation date |
| time_create | time | Message creation time |
Validation Rules
- User must be authenticated using a valid JWT token
- Chat must exist
- Chat must belong to the authenticated seller
- Maximum of 100 messages are returned per request
- Messages are sorted in ascending order by message ID
Request Example
curl -X GET https://api.softstore.app/api/v1/chat/messages/f87663f1ce0764d4c50c17bc39d536d9 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Accept: application/json"
$chatId = "f87663f1ce0764d4c50c17bc39d536d9";
$response = $api->getChatMessages($chatId);
print_r($response);
const chatId = "f87663f1ce0764d4c50c17bc39d536d9";
const response = await fetch(
`https://api.softstore.app/api/v1/chat/messages/${chatId}`,
{
method: 'GET',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
Accept: 'application/json'
}
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": [
{
"id": 1,
"id_chat": "f87663f1ce0764d4c50c17bc39d536d9",
"id_user": 55,
"type_user": "seller",
"message": "Hello, your order has been processed.",
"data_create": "2026-06-12",
"time_create": "15:10:22"
},
{
"id": 2,
"id_chat": "f87663f1ce0764d4c50c17bc39d536d9",
"id_user": 101,
"type_user": "buyer",
"message": "Thank you for the update.",
"data_create": "2026-06-12",
"time_create": "15:11:08"
}
]
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Chat not found"
}
{
"status": "error",
"message": "Access denied"
}
Request Overview
Sends a new message to an existing chat. The authenticated seller can send messages only to chats associated with their own orders.
Headers
Authorization: Bearer YOUR_JWT_TOKEN
Content-Type: application/json
Accept: application/json
URL Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Chat identifier |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| message | string | Yes | Message text to send |
Validation Rules
- User must be authenticated using a valid JWT token
- Chat must exist
- Chat must belong to the authenticated seller
- Message field is required
- Empty messages are not allowed
- Duplicate messages are automatically rejected
- Platform moderation rules may apply
Request Example
curl -X POST https://api.softstore.app/api/v1/chat/send/f87663f1ce0764d4c50c17bc39d536d9 \
-H "Authorization: Bearer YOUR_JWT_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"message": "Hello buyer, your order has been delivered."
}'
$chatId = "f87663f1ce0764d4c50c17bc39d536d9";
$response = $api->sendChatMessage(
$chatId,
[
'message' => 'Hello buyer, your order has been delivered.'
]
);
print_r($response);
const chatId = "f87663f1ce0764d4c50c17bc39d536d9";
const response = await fetch(
`https://api.softstore.app/api/v1/chat/send/${chatId}`,
{
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_JWT_TOKEN',
'Content-Type': 'application/json',
Accept: 'application/json'
},
body: JSON.stringify({
message: 'Hello buyer, your order has been delivered.'
})
}
);
console.log(await response.json());
Success Response
{
"status": "success",
"data": {
"message": "Message sent successfully"
}
}
Error Responses
{
"status": "error",
"message": "Unauthorized"
}
{
"status": "error",
"message": "Chat not found"
}
{
"status": "error",
"message": "Access denied"
}
{
"status": "error",
"message": "Message is required"
}
{
"status": "error",
"message": "Duplicate message"
}
{
"status": "error",
"message": "The message did not pass moderation"
}
Overview
SoftStore automatically sends webhook notifications
to your api_url after successful payment.
POST /seller/profile
Incoming Webhook Payload
{
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"id_product": "69f36497dc78f",
"email": "buyer@example.com",
"payment_status": "paid",
"comment": "@login",
"signature": "df595764abc185bbf31c5c6334cfade65379feb6",
"delivery_url": "https://api.softstore.app/api/v1/orders/delivery/TOKEN",
"token": "d487c01d834dcb296c4f7b5a02e0b0d9df320bb153778d6c20cd26e2c50b40bf"
}
Signature Verification
Signature formula:
email field contains the buyer email address for this paid order.
It is informational and is not included in signature generation, so existing webhook integrations remain compatible.
sha1( sha1(api_key) + id_order)
Webhook Verification Examples
$payload = json_decode(
file_get_contents('php://input'),
true
);
$apiKey = "YOUR_SECRET_API_KEY";
$expected = sha1(
sha1($apiKey) . $payload['id_order']
);
if ($expected !== $payload['signature']) {
http_response_code(403);
exit('Invalid signature');
}
$deliveryUrl = $payload['delivery_url'];
echo "Webhook verified";
const crypto = require("crypto");
app.post("/webhook", (req, res) => {
const payload = req.body;
// sha1(apiKey)
const hashedApiKey = crypto
.createHash("sha1")
.update(API_KEY)
.digest("hex");
const expected = crypto
.createHash("sha1")
.update(hashedApiKey + payload.id_order)
.digest("hex");
if (expected !== payload.signature) {
return res.status(403).json({
error: "Invalid signature"
});
}
const deliveryUrl = payload.delivery_url;
console.log("Valid webhook:", deliveryUrl);
res.json({
success: true
});
});
Recommended Flow
Receive webhook
↓
Validate signature
↓
Get delivery_url
↓
Generate product/license/file
↓
Send product to delivery_url
↓
Customer receives order
Webhook Errors
| Error | Description |
|---|---|
| Invalid signature | Webhook request is not trusted |
| Missing delivery_url | Webhook payload corrupted |
| Product generation failed | Seller internal delivery logic failed |
Overview
SoftStore sends an HTTP callback to the seller api_url
when a buyer writes a new message in a paid order chat.
This lets sellers receive buyer questions and answer them through the Chat API.
Incoming Payload
{
"type": "message",
"id_chat": "030a3c6f15f2744e58f2e24fd40d3466",
"text": "Hello. When will I receive my key?",
"payment_status": "paid",
"signature": "df595764abc185bbf31c5c6334cfade65379feb6"
}
| Field | Type | Description |
|---|---|---|
type |
string | Always message for buyer chat message callbacks. |
id_chat |
string | Order ID connected to this chat. Use it as {id} for chat API methods. |
text |
string | Buyer message text, trimmed and limited to 1000 characters. |
payment_status |
string | Order payment status. Chat callbacks are sent for paid orders. |
signature |
string | Webhook signature used to verify the request. |
Signature Verification
sha1( api_key + id_chat )
Recommended Security Rules
- Accept callbacks only from SoftStore server IP addresses when possible.
- Validate
signaturebefore reading or acting ontext. - Require
type === "message"andpayment_status === "paid". - Limit processing to
textvalues from 1 to 1000 characters. - Strip HTML, control characters and invisible characters before displaying messages.
- Do not pass buyer messages directly into AI agents, shell commands, SQL or internal tools.
- Use idempotency on
id_chat + text + signatureto avoid duplicate processing. - Return HTTP 200 quickly; process long tasks asynchronously.
Reply to the Buyer
curl -X POST https://api.softstore.app/api/v1/auth/api-key/create \
-H "X-API-KEY: RAW_SELLER_API_KEY"
curl -X POST https://api.softstore.app/api/v1/chat/send/030a3c6f15f2744e58f2e24fd40d3466 \
-H "Authorization: Bearer JWT_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "Hello. Your order is being processed. I will send the key here shortly."
}'
Webhook Handler Examples
<?php
$payload = json_decode(file_get_contents('php://input'), true);
$apiKey = 'RAW_SELLER_API_KEY';
if (($payload['type'] ?? '') !== 'message') {
http_response_code(400);
exit('Unsupported webhook type');
}
$expected = sha1($apiKey . $payload['id_chat']);
if (!hash_equals($expected, $payload['signature'] ?? '')) {
http_response_code(403);
exit('Invalid signature');
}
$text = trim((string)($payload['text'] ?? ''));
if ($text === '' || mb_strlen($text) > 1000) {
http_response_code(422);
exit('Invalid message text');
}
// Store or process the buyer message as plain text only.
$api = new SellerApi('https://api.softstore.app/api/v1', $apiKey);
$auth = $api->createApiKey();
if ($auth['status'] === 200) {
$api->sendChatMessage($payload['id_chat'], [
'message' => 'Hello. Your request has been received.'
]);
}
echo 'OK';
const crypto = require("crypto");
const express = require("express");
const SoftStoreSDK = require("./index");
const app = express();
app.use(express.json({ limit: "16kb" }));
const API_KEY = "RAW_SELLER_API_KEY";
const api = new SoftStoreSDK("https://api.softstore.app/api/v1", API_KEY);
app.post("/softstore-chat-callback", async (req, res) => {
const payload = req.body;
if (payload.type !== "message") {
return res.status(400).json({ error: "Unsupported webhook type" });
}
const expected = crypto
.createHash("sha1")
.update(API_KEY + payload.id_chat)
.digest("hex");
if (expected !== payload.signature) {
return res.status(403).json({ error: "Invalid signature" });
}
const text = String(payload.text || "").trim();
if (!text || text.length > 1000) {
return res.status(422).json({ error: "Invalid message text" });
}
await api.createApiKey();
await api.sendChatMessage(payload.id_chat, {
message: "Hello. Your request has been received."
});
res.json({ success: true });
});
Dialog Flow
Buyer sends message in order chat
↓
SoftStore validates and moderates the buyer message
↓
SoftStore sends POST webhook to seller api_url
↓
Seller validates signature and text
↓
Seller replies via POST /chat/send/{id_chat}
↓
Buyer sees seller response in the order chat
Overview
After successful payment SoftStore automatically sends
an HTTP webhook request to your configured
api_url.
Your server must:
- Receive webhook notification
- Validate webhook signature
- Request full order details
- Generate digital product/license
- Send product to customer
POST /seller/profile
Recommended Flow
Buyer pays product
↓
SoftStore confirms payment
↓
Webhook sent to seller api_url
↓
Seller validates signature
↓
Seller requests GET /orders/info/{id}
↓
Seller generates product/license
↓
Seller sends product via POST /orders/delivery/{token}
↓
Buyer receives product by email
Incoming Webhook Payload
{
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"id_product": "69f36497dc78f",
"payment_status": "paid",
"comment": "@login",
"signature": "df595764abc185bbf31c5c6334cfade65379feb6",
"delivery_url": "https://api.softstore.app/api/v1/orders/delivery/TOKEN",
"token": "d487c01d834dcb296c4f7b5a02e0b0d9df320bb153778d6c20cd26e2c50b40bf"
}
Signature Verification
Verify webhook authenticity before processing:
sha1(
sha1(api_key) + id_order
)
Get Order Information
Before delivering product you can request full order details:
GET /orders/info/{id_order}
This allows you to identify:
- Purchased product ID
- Quantity
- Customer email
- Order metadata
{
"status": "success",
"data": {
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"id_product": "69f36497dc78f",
"count": 3
}
}
Webhook Implementation Example
<?php
require_once "SellerApi.php";
$apiKey = "YOUR_API_KEY";
/*
|--------------------------------------------------------------------------
| Receive webhook
|--------------------------------------------------------------------------
*/
$payload = json_decode(
file_get_contents("php://input"),
true
);
if (!$payload) {
http_response_code(400);
exit("Invalid payload");
}
/*
|--------------------------------------------------------------------------
| Verify signature
|--------------------------------------------------------------------------
*/
$expected = sha1(
sha1($apiKey) . $payload['id_order']
);
if ($expected !== $payload['signature']) {
http_response_code(403);
exit("Invalid signature");
}
/*
|--------------------------------------------------------------------------
| Create API client
|--------------------------------------------------------------------------
*/
$api = new SellerApi(
"https://api.softstore.app/api/v1",
$apiKey
);
$api->createApiKey();
/*
|--------------------------------------------------------------------------
| Get full order info
|--------------------------------------------------------------------------
*/
$orderInfo = $api->infoOrder(
$payload['id_order']
);
print_r($orderInfo);
/*
|--------------------------------------------------------------------------
| Deliver product
|--------------------------------------------------------------------------
*/
$response = $api->deliverOrder(
$payload['token'],
[
"text" => "Windows License Key: XXXXX",
"download" =>
"https://cdn.yoursite.com/file.zip"
// or:
// "download" => false
]
);
print_r($response);
http_response_code(200);
echo "Delivered";
const express = require("express");
const crypto = require("crypto");
const axios = require("axios");
const app = express();
app.use(express.json());
const API_KEY = "YOUR_API_KEY";
app.post("/webhook", async (req, res) => {
try {
const payload = req.body;
/*
--------------------------------------
Verify signature
--------------------------------------
*/
const hashedApiKey = crypto
.createHash("sha1")
.update(API_KEY)
.digest("hex");
const expected = crypto
.createHash("sha1")
.update(
hashedApiKey + payload.id_order
)
.digest("hex");
if (expected !== payload.signature) {
return res.status(403).send(
"Invalid signature"
);
}
/*
--------------------------------------
Get JWT token
--------------------------------------
*/
const auth = await axios.post(
"https://api.softstore.app/api/v1/auth/api-key/create",
{},
{
headers: {
"X-API-KEY": API_KEY
}
}
);
const jwt =
auth.data.data.access_token;
/*
--------------------------------------
Get order details
--------------------------------------
*/
const orderInfo = await axios.get(
`https://api.softstore.app/api/v1/orders/info/${payload.id_order}`,
{
headers: {
Authorization:
`Bearer ${jwt}`
}
}
);
console.log(orderInfo.data);
/*
--------------------------------------
Deliver product
--------------------------------------
*/
const response = await axios.post(
`https://api.softstore.app/api/v1/orders/delivery/${payload.token}`,
{
text:
"Windows License Key: XXXXX",
download:
"https://cdn.yoursite.com/file.zip"
// or:
// download: false
},
{
headers: {
Authorization:
`Bearer ${jwt}`
}
}
);
console.log(response.data);
return res.status(200).send(
"Delivered"
);
} catch (error) {
console.error(
error.response?.data
);
return res.status(500).send(
"Delivery error"
);
}
});
app.listen(3000, () => {
console.log(
"Webhook server started"
);
});
Successful Delivery Response
{
"status": "success",
"data": {
"message": "Product delivered successfully",
"id_order": "030a3c6f15f2744e58f2e24fd40d3466",
"delivered": true
}
}
Delivery Errors
| HTTP Code | Error | Description |
|---|---|---|
| 401 | Unauthorized | Missing or invalid JWT token |
| 403 | Access denied | Order belongs to another seller |
| 404 | Order not found | Invalid delivery token |
| 409 | Order already delivered | Product already sent |
| 422 | Invalid download URL | Only HTTPS links allowed |
Subscribers API v1
Authenticated sellers can read only their own active subscribers, create scoped discounts and queue Email/Push campaigns. Raw email addresses and push tokens are never returned.
GET /api/v1/seller/subscribers?page=1&limit=50&date_from=2026-09-01&date_to=2026-09-30
GET /api/v1/seller/subscriber-statistics?period=month&date=2026-09-18
GET /api/v1/seller/subscriber-discounts
POST /api/v1/seller/subscriber-discounts
DELETE /api/v1/seller/subscriber-discounts/{id}
POST /api/v1/seller/subscriber-campaigns/preview
POST /api/v1/seller/subscriber-campaigns
GET /api/v1/seller/subscriber-campaigns/{id}
The public WEB/Android BFF returns only currently active promotions at GET https://app.softstore.app/api/app/v1/sellers/{id}/promotions. Seller API v1 keeps management methods protected by seller authentication.
Discount priority is product > category > all. Discounts do not stack. The selected subscriber percentage is applied after the regular/wholesale price. API v2 and app checkout responses add an optional subscriber_discount object; old clients can ignore it.
Campaigns are asynchronous and idempotent. Delivery rechecks the active subscription and available channel immediately before sending.
Overview
Official SDK libraries help sellers integrate with SoftStore faster without writing raw API requests manually.
Available SDKs include authentication, product management, order management, webhook processing, and automatic digital product delivery.
Available SDK Libraries
Generate Additional SDKs
Need another language?
Export our OpenAPI schema and generate your own SDK using:
- Java
- Python
- Go
- C#
- Ruby
- Swift
- Kotlin
- TypeScript
Quick Start Examples
<?php
require_once "SellerApi.php";
$api = new SellerApi(
"https://api.softstore.app/api/v1",
"YOUR_RAW_SELLER_API_KEY"
);
$response = $api->createApiKey(); // alias: authenticate()
if ($response["status"] !== 200) {
throw new RuntimeException(
$response["data"]["message"] ?? "API authentication failed"
);
}
print_r($api->getProducts());
const SellerSDK = require("./seller-sdk");
const api = new SellerSDK(
"https://api.softstore.app/api/v1",
"YOUR_RAW_SELLER_API_KEY"
);
async function init() {
const response = await api.createApiKey(); // alias: authenticate()
if (response.status !== 200) {
throw new Error(
response.data?.message || "API authentication failed"
);
}
console.log(await api.getProducts());
}
init();
Included Features
| Feature | Supported |
|---|---|
| JWT Authentication | ✔ |
| Raw API key error handling | ✔ |
| Create Products | ✔ |
| Update Products | ✔ |
| Delete Products | ✔ |
| Order Management | ✔ |
| Payout API | ✔ |
| Chat API | ✔ |
| Webhook Processing | ✔ |
| Automatic Delivery | ✔ |
| Image Uploads | ✔ |
JWT API Playground
Test authenticated requests directly from documentation.