Services & pricing
Your catalog — the menu buyers see on your storefront and order
from. Manage it at /dashboard/services; the
API surface is /api/v1/services (see endpoints below).
Anatomy of a service
- Slug — the service's URL segment (
/s/<storefront>/<slug>). Lowercase letters, digits, hyphens; 3–40 characters; unique within your workspace. - Name + description — what buyers see (description up to 5,000 characters).
- Pricing type — one of three, below.
- Active — inactive services disappear from your public page but keep their history. Use this instead of deleting.
- Sort order — controls the order on your storefront.
The three pricing types
fixed
One price for the whole job. priceIdr (whole rupiah) is required.
hourly
A per-hour rate. priceIdr is required and is displayed as
"Rp … per hour". When an order comes in, the hourly rate becomes the
order's starting quote — you then set the real total
once you know the scope.
package
1–5 named packages (think Basic / Standard / Premium), each with its
own priceIdr and optional description. Package names must be unique
within the service; a top-level priceIdr is not allowed. Buyers
pick a package on the order form, and that package's price becomes
the order's quote.
Prices are whole rupiah, up to Rp 2.000.000.000. Mixing fields that
don't belong to the pricing type (e.g. packages on a fixed
service) is rejected with VALIDATION_ERROR.
Tier service limits — enforced
How many services you can have depends on your plan: Free 3 · Starter 10 · Growth 30 · Business 100. The limit is enforced at creation — going past it returns:
{
"data": null,
"error": {
"code": "LIMIT_REACHED",
"message": "Your Free plan allows up to 3 services. Upgrade your plan to add more."
},
"meta": { "requestId": "req_…", "timestamp": "2026-06-11T03:00:00.000Z" }
}
with HTTP 403. Existing services are never touched when a plan
lapses — you just can't add more until you upgrade.
Deleting vs. deactivating
A service that has orders referencing it cannot be deleted — the API
returns 409 CONFLICT ("this service has orders — deactivate it
instead of deleting"). Flip active off instead: it vanishes from
your storefront, and the order history stays intact.
API
All behind API-key or session auth:
| Method + path | Does |
|---|---|
GET /api/v1/services |
All services, sort order first |
POST /api/v1/services |
Create (the tier gate lives here) |
GET /api/v1/services/:id |
One service |
PATCH /api/v1/services/:id |
Partial update — incl. reorder via sortOrder |
DELETE /api/v1/services/:id |
Delete (409 while orders reference it) |
Create a fixed-price service:
curl -X POST https://serront.com/api/v1/services \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"slug": "logo-design",
"name": "Logo design",
"description": "A custom logo, 3 concepts, 2 revisions.",
"pricingType": "fixed",
"priceIdr": 1500000
}'
Create a package service:
curl -X POST https://serront.com/api/v1/services \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"slug": "social-media",
"name": "Social media management",
"pricingType": "package",
"packages": [
{ "name": "Basic", "priceIdr": 750000, "description": "8 posts/month" },
{ "name": "Standard", "priceIdr": 1500000, "description": "16 posts/month" },
{ "name": "Premium", "priceIdr": 3000000, "description": "Daily posts + stories" }
]
}'
When you PATCH any pricing field, the merged result is re-validated
as a whole — switching pricingType to package without sending
packages fails coherently rather than half-saving.
See also
- Orders — what happens when someone orders a service.
- Billing & plans — the service limits per tier.