For developers & resellers

Like3s API — two standards, one platform.

Integrate Like3s into your system the way that fits best. v1 is a modern REST API; v2 follows the SMM Panel standard — migrating from another panel only takes a URL change.

Introductionv1

Like3s API v1 is a modern REST API — JSON, Bearer API key, meaningful HTTP status codes. Ideal for new projects, mobile apps, or long-term integrations. It returns VND by default; send the header Accept-Currency: USD to receive USD (converted at the live rate).

Base URL

api.like3s.vn

HTTPS required · TLS 1.2+

Prefix

/api/v1

REST · JSON · UTF-8

Rate limit

120 / min

20,000 / day per API key

Pagination

Cursor-based

Orders & transactions

POSThttps://api.like3s.vn/api/v1/orders

Authentication

Every request must include a Bearer API key in the Authorization header. Keys are created in Dashboard → API Keys; each key is tied to one account and can be restricted by IP and scope.

Standard headers
Authorization:   Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF
Content-Type:    application/json
Accept:          application/json
Accept-Currency: VND                                       // optional · VND | USD · default VND
Idempotency-Key: a8d3f1e2-b4c5-6789-0123-456789abcdef     // optional for POST /orders
                                                           // REQUIRED for POST /orders/bulk and /orders/{id}/refill
Never commit your API key to git. The key is a random 40-character base62 string (A–Z, a–z, 0–9) with no prefix. The system only stores the SHA-256 hash — if you lose the key you must rotate it (issue a new one).

Currency & conversion

By default, every money field (balance, rate, charge, refunded) is returned in VND. Send the header Accept-Currency: USD to receive USD — the backend converts from VND at the internal rate (updated every 4 hours).

Example
GET /api/v1/account/balance
Accept-Currency: USD

// → { "balance": 51.2345, "currency": "USD" }

GET /api/v1/account/balance
// (no header)

// → { "balance": 1286420, "currency": "VND" }
The currency field is always present in the response — check it instead of assuming the unit.

Errors & HTTP status

v1 uses standard HTTP status codes. The error body always has the shape { code, message }.

StatusCodeMeaning
200OKRequest succeeded, the body contains the resource.
400INVALID_STATUS · VALIDATIONMalformed body or invalid query parameter.
401UNAUTHORIZEDAPI key missing / invalid / revoked.
402INSUFFICIENT_BALANCEWallet balance is not enough to hold the order amount.
404NOT_FOUNDOrder / service / variant does not exist or does not belong to the account.
409IDEMPOTENCY_CONFLICTThe Idempotency-Key was already used for a different request.
422SERVICE_UNAVAILABLEService is temporarily paused — retry later or pick an equivalent variant.
429RATE_LIMITEDRate limit exceeded. Read the Retry-After header.
500INTERNAL_ERRORServer error. Logged & alerted to on-call.
Error body · example
{
  "code":    "INSUFFICIENT_BALANCE",
  "message": "Wallet balance is 12,400 ₫ — the order requires 95,000 ₫."
}

Rate limit

Each API key is limited to 120 requests / minute and 20,000 requests / day. Reseller accounts can request a higher limit. When you exceed the limit, the server returns 429 Too Many Requests with a Retry-After header.

Every successful response includes the headers below so the client can throttle proactively — no need to guess the remaining quota:

Response headers
X-RateLimit-Limit:     120          // max quota in the 1-minute window
X-RateLimit-Remaining: 118          // remaining in the current window
X-RateLimit-Reset:     1747387260   // epoch seconds until the next window
Watch X-RateLimit-Remaining as it nears 0 and pause until X-RateLimit-Reset — far cheaper than getting a 429 and retrying.

List platforms

Returns all available platforms (Facebook, Instagram, TikTok, YouTube, Twitter, Shopee...). Use it to build a picker menu or a client-side filter.

GET/api/v1/platforms

Request

curl
curl "https://api.like3s.vn/api/v1/platforms" \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF"

Response

200 OK
Body
[
  {
    "id":      1,
    "code":    "FACEBOOK",
    "slug":    "facebook",
    "name":    "Facebook",
    "iconUrl": "https://cdn.like3s.vn/platforms/facebook.svg"
  },
  {
    "id":      2,
    "code":    "INSTAGRAM",
    "slug":    "instagram",
    "name":    "Instagram",
    "iconUrl": "https://cdn.like3s.vn/platforms/instagram.svg"
  }
  // ...
]

List services

Returns every available "service" — each service corresponds to one orderable variant. The id field is exactly the value you pass as service when creating an order.

GET/api/v1/services

Request

curl "https://api.like3s.vn/api/v1/services" \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF"

Response

200 OK
Body
[
  {
    "id":        103,                          // variantId · used as "service" in POST /orders
    "packageId": 27,
    "name":      "FB post likes — Basic package",
    "type":      "DEFAULT",                    // service-type
    "category":  "Basic package",              // package name
    "rate":      21000,                        // price per 1000 units
    "min":       100,
    "max":       50000,
    "refill":    true,
    "currency":  "VND"
  }
  // ...
]
FieldTypeRequiredDescription
idintegerNoVariant ID. Used as service in POST /orders.
packageIdintegerNoThe package this variant belongs to (several variants can share one package).
namestringNoDisplay name (combines packageName + variantLabel).
typestringNoService-type: DEFAULT, MINUTES, REACTIONS_SINGLE, SUBSCRIPTION, ...
categorystringNoPackage name — groups variants together in the UI.
ratenumberNoPrice per 1000 units, in the requested currency.
min / maxintegerNoThe allowed quantity range.
refillbooleanNoWhether the service supports refills (auto-monitored for 30 days).
currencystringNoVND by default, or USD if you send Accept-Currency: USD.

Service detail

GET/api/v1/services/{id}

Get a single variant by id. The response shape matches the list endpoint. Returns 404 if the variant does not exist / is unavailable.

Service by slug

GET/api/v1/services/by-slug/{slug}

Resolve a service by slug — matching the FE URL /dich-vu/{slug}. Returns the service with all packages and variants nested — enough to render the order form in a single round-trip.

Request

curl
curl "https://api.like3s.vn/api/v1/services/by-slug/tang-like-bai-viet-facebook" \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF"

Response

200 OK
Body
{
  "id":               12,
  "slug":             "tang-like-bai-viet-facebook",
  "name":             "Facebook post likes",
  "platformCode":     "FACEBOOK",
  "platformSlug":     "facebook",
  "descriptionShort": "Real, safe, long-lasting likes.",
  "defaultPackageId": 27,
  "packages": [
    {
      "id":               27,
      "serviceId":        12,
      "name":             "Basic package",
      "descriptionShort": "Mixed real likes, delivered 100/hour",
      "type":             "DEFAULT",
      "unitLabel":        "like",
      "allowScheduled":   true,
      "variants": [
        {
          "id":     103,
          "label":  null,
          "rate":   21000,
          "min":    100,
          "max":    50000,
          "refill": true,
          "cancel": true,
          "data":   {}
        }
      ]
    },
    {
      "id":               28,
      "serviceId":        12,
      "name":             "Premium package",
      "descriptionShort": "100% real likes, held ≥ 30 days",
      "type":             "DEFAULT",
      "unitLabel":        "like",
      "allowScheduled":   true,
      "variants": [
        { "id": 104, "label": null, "rate": 49000, "min": 50, "max": 20000, "refill": true, "cancel": true, "data": {} }
      ]
    }
  ]
}
A DEFAULT variant has data: {}. MINUTES/REACTIONS_SINGLE have a discriminator inside data (e.g. { "duration_min": 60 }, { "reaction": "LIKE" }) — copy it verbatim into typeData when calling POST /orders.

Package by id

GET/api/v1/packages/{id}

Get a single package with its variants nested. Handy when you already saved a packageId earlier (e.g. from /services/by-slug) and want to fetch it again without the slug.

Response

200 OK
Body
{
  "id":               27,
  "serviceId":        12,
  "name":             "Basic package",
  "descriptionShort": "Mixed real likes, delivered 100/hour",
  "type":             "DEFAULT",
  "unitLabel":        "like",
  "allowScheduled":   true,
  "variants": [
    {
      "id":     103,
      "label":  null,
      "rate":   21000,
      "min":    100,
      "max":    50000,
      "refill": true,
      "cancel": true,
      "data":   {}
    }
  ]
}

Account & balance

Two endpoints to read the account tied to the API key in use — full details or just the balance.

GET/api/v1/account
200 OK
Response · GET /api/v1/account
{
  "id":       42,
  "email":    "user@example.com",
  "balance":  1286420,        // available balance (holds deducted)
  "currency": "VND"
}
GET/api/v1/account/balance

A lightweight version — returns only the available balance.

200 OK
Response · GET /api/v1/account/balance
{
  "balance":  1286420,
  "currency": "VND"
}
balance already excludes the amount held for in-flight orders — this is the money you can actually use to create new orders.

Wallet transactions

GET/api/v1/account/transactions

The account's wallet transaction history — semantic events (DEPOSIT / SPEND / REFUND / BONUS / ADJUSTMENT), NOT the raw ledger. Each event has a pre-built title + description you can render straight into the UI without parsing reference.

Query parameters

FieldTypeRequiredDescription
cursorstringNoOpaque cursor from the previous response's nextCursor. Omit / leave empty for the first page.
limitintegerNoItems per page. Default 50, max 200.

Response

200 OK
Body
{
  "items": [
    {
      "id":           8472,
      "code":         "TXN-0008472",
      "kind":         "SPEND",
      "status":       "SUCCESS",
      "amount":       -21000,
      "balanceAfter": 1265420,
      "currency":     "VND",
      "title":        "Order FB post likes — Basic package #48294",
      "description":  "1,000 likes · 21.00 ₫/like · facebook.com/like3s/posts/123",
      "orderId":      48294,
      "createdAt":    "2026-05-16T10:42:18+07:00"
    },
    {
      "id":           8401,
      "code":         "TXN-0008401",
      "kind":         "DEPOSIT",
      "status":       "SUCCESS",
      "amount":       500000,
      "balanceAfter": 1286420,
      "currency":     "VND",
      "title":        "Wallet top-up",
      "description":  "Vietcombank · Reference: NAP1234567",
      "orderId":      null,
      "createdAt":    "2026-05-15T22:15:03+07:00"
    }
  ],
  "nextCursor": "MjAyNi0wNS0xNVQyMjoxNTowMyswNzowMHw4NDAx"
}
FieldTypeRequiredDescription
kindstringNoDEPOSIT (top-up) · SPEND (order) · REFUND · BONUS · ADJUSTMENT (support adjustment).
statusstringNoSUCCESS · PENDING · FAILED. Currently always SUCCESS.
amountnumberNoTransaction amount (signed — negative for debits). In the requested currency.
balanceAfternumberNoThe available balance after the transaction — matches GET /account/balance.
title / descriptionstringNoPre-built captions — render straight into the UI.
orderIdinteger | nullNoWhen kind = SPEND | REFUND: the related order id, used to correlate with GET /orders/{id}.
nextCursorstring | nullNoPass into ?cursor= for the next page. null = end.
The system only returns events that are user-visible — internal wallet steps (capturing a hold into a debit) are hidden for a clean semantic feed. balanceAfter is always the available balance (already excluding funds held for in-flight orders).

Create order

The most important endpoint. Supports Idempotency-Key for safe retries — a duplicate-key request returns the existing order instead of creating a new one.

POST/api/v1/orders

Body parameters

FieldTypeRequiredDescription
serviceintegerYesThe variant ID from GET /api/v1/services.
linkstringYesPublic URL of the post / channel / video. Max 1000 characters.
quantityintegerYesThe amount to add. Must be within the service's [min, max] range.
typeDataobjectNoDiscriminator depending on type: { "reaction": "LIKE" } for REACTIONS_SINGLE, { "duration_min": 60 } for MINUTES. Omit for DEFAULT.
startTimestring (ISO-8601)NoSchedule a future start. null = run now.

Request

curl "https://api.like3s.vn/api/v1/orders" \
  -X POST \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: a8d3f1e2-b4c5-6789-..." \
  -d '{
    "service":  103,
    "link":     "https://facebook.com/like3s/posts/123",
    "quantity": 1000
  }'

Response

200 OK
Body
{
  "id":            48294,
  "service":       103,
  "link":          "https://facebook.com/like3s/posts/123",
  "quantity":      1000,
  "charge":        21000,                     // VND · held from the wallet
  "refunded":      0,
  "currency":      "VND",
  "status":        "PENDING",
  "startCount":    null,
  "remains":       1000,
  "failureReason": null,
  "createdAt":     "2026-05-16T10:42:18+07:00"
}

Bulk create orders

POST/api/v1/orders/bulk

Create 1–50 orders at once sharing the same service, quantity, typeData and startTime — only links is a list. Handy when pushing the same service to many posts / channels.

Idempotency-Key is required. Replaying the same key returns the existing batch; calling again with the same key but a different number of links → 409 IDEMPOTENCY_CONFLICT. Creation is atomic: if one link fails (e.g. insufficient balance on the 35th order) the whole batch rolls back — no order is saved.

Body parameters

FieldTypeRequiredDescription
serviceintegerYesVariant ID — applied to every link.
linksarray<string>Yes1–50 links. Each link max 1000 characters. Duplicate links within the batch → DUPLICATE_LINK.
quantityintegerYesQuantity applied to every order in the batch.
typeDataobjectNoService-type discriminator (see POST /orders). Applied to every order.
startTimestring (ISO-8601)NoSchedule a start for every order. null = run now.

Request

curl
curl "https://api.like3s.vn/api/v1/orders/bulk" \
  -X POST \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: batch-2026-05-16-001" \
  -d '{
    "service":  103,
    "links": [
      "https://facebook.com/like3s/posts/1",
      "https://facebook.com/like3s/posts/2",
      "https://facebook.com/like3s/posts/3"
    ],
    "quantity": 500
  }'

Response

200 OK
Body
{
  "orders": [
    { "id": 48311, "service": 103, "link": "https://facebook.com/like3s/posts/1",
      "quantity": 500, "charge": 10500, "refunded": 0, "currency": "VND",
      "status": "PENDING", "startCount": null, "remains": 500,
      "failureReason": null, "createdAt": "2026-05-16T10:50:02+07:00" },
    { "id": 48312, "service": 103, "link": "https://facebook.com/like3s/posts/2",
      "quantity": 500, "charge": 10500, "refunded": 0, "currency": "VND",
      "status": "PENDING", "startCount": null, "remains": 500,
      "failureReason": null, "createdAt": "2026-05-16T10:50:02+07:00" },
    { "id": 48313, "service": 103, "link": "https://facebook.com/like3s/posts/3",
      "quantity": 500, "charge": 10500, "refunded": 0, "currency": "VND",
      "status": "PENDING", "startCount": null, "remains": 500,
      "failureReason": null, "createdAt": "2026-05-16T10:50:02+07:00" }
  ],
  "totalCharge": 31500,
  "currency":    "VND"
}
The order of orders matches request.links (index ↔ index). After creation, each order is processed independently — one rejected order only marks itself FAILED + auto-refunds; the others are unaffected.

List orders

GET/api/v1/orders

Get the account's orders — cursor pagination to page through long datasets efficiently (orders are partitioned by month, so offsets are expensive). Fixed sort, newest first.

Query parameters

FieldTypeRequiredDescription
cursorstringNoOpaque cursor from the previous response's nextCursor. Omit for the first page.
limitintegerNoItems per page. Default 50, max 200.
statusstringNoFilter by status (uppercase): PENDING, PROCESSING, IN_PROGRESS, COMPLETED, PARTIAL, CANCELED, FAILED.

Response

200 OK
Body
{
  "items": [
    {
      "id":          48294,
      "service":     103,
      "link":        "https://facebook.com/like3s/posts/123",
      "quantity":    1000,
      "charge":      21000,
      "refunded":    0,
      "currency":    "VND",
      "status":      "PROCESSING",
      "startCount":  128,
      "remains":     358,
      "failureReason": null,
      "createdAt":   "2026-05-16T10:42:18+07:00"
    }
    // ...
  ],
  "nextCursor": "MjAyNi0wNS0xNlQwOToxNTozMCswNzowMHw0ODI2OA"
}
nextCursor is an opaque string — don't parse it. Pass it back verbatim into ?cursor= for the next page. When nextCursor is null, you've reached the end.

Order detail

GET/api/v1/orders/{id}

Get a single order by id. The response shape matches an item in the list. Returns 404 if the order does not belong to the account.

200 OK
Response
{
  "id":            48294,
  "service":       103,
  "link":          "https://facebook.com/like3s/posts/123",
  "quantity":      1000,
  "charge":        21000,
  "refunded":      0,
  "currency":      "VND",
  "status":        "IN_PROGRESS",
  "startCount":    128,
  "remains":       358,
  "failureReason": null,
  "createdAt":     "2026-05-16T10:42:18+07:00"
}
FieldTypeRequiredDescription
statusstringNoPENDING · PROCESSING · IN_PROGRESS · COMPLETED · PARTIAL · CANCELED · FAILED
startCountinteger | nullNoThe count at the moment processing started (null before it runs).
remainsintegerNoThe amount left to deliver.
chargenumberNoThe amount held/deducted from the wallet (in the requested currency).
refundednumberNoThe amount refunded to the wallet when the order is PARTIAL / CANCELED / FAILED.
failureReasonstring | nullNoThe system reason when the order is FAILED.

Cancel order

POST/api/v1/orders/{id}/cancel

Request to cancel an order. The order moves to CANCELED (or PARTIAL if some was already delivered). The undelivered portion is refunded to the wallet.

200 OK
Response
{
  "id":            48294,
  "service":       103,
  "link":          "https://facebook.com/like3s/posts/123",
  "quantity":      1000,
  "charge":        21000,
  "refunded":      18900,           // undelivered portion refunded to the wallet
  "currency":      "VND",
  "status":        "CANCELED",
  "startCount":    128,
  "remains":       900,
  "failureReason": null,
  "createdAt":     "2026-05-16T10:42:18+07:00"
}
Cancellation is a request — whether the order can actually be canceled depends on its processing state. An order that's nearly done may continue to completion.

Request refill

POST/api/v1/orders/{id}/refill

Request a re-run of an order that is COMPLETED or PARTIAL — useful when likes/follows drop after delivery. Only applies to variants with refill: true that are still within the warranty period (snapshotted at order creation).

Idempotency-Key is required. Reusing the same key returns the existing request — safe for client retries. Rate limit is 24h per order: repeated calls for the same order allow only 1 refill request per 24 hours.
The order must have been completed for at least 24 hours before a request is accepted — this wait lets the engagement settle before topping up. Calling earlier returns REFILL_TOO_EARLY.

Request

curl
curl "https://api.like3s.vn/api/v1/orders/48294/refill" \
  -X POST \
  -H "Authorization: Bearer 3kQp7xN2hVfL8mYwB1tRzAcEgUjK5sDoXrM4nPiF" \
  -H "Idempotency-Key: refill-48294-001"

Response

200 OK
Body
{
  "id":            48294,
  "service":       103,
  "link":          "https://facebook.com/like3s/posts/123",
  "quantity":      1000,
  "charge":        21000,
  "refunded":      0,
  "currency":      "VND",
  "status":        "COMPLETED",
  "startCount":    128,
  "remains":       0,
  "failureReason": null,
  "createdAt":     "2026-05-16T10:42:18+07:00"
}

The order status does not change — the refill request is created in parallel; the system processes it asynchronously via a worker. Refills are free within the warranty period (the wallet is not charged).

CodeMeaning
REFILL_NOT_SUPPORTEDThe variant does not support refills (refill: false).
REFILL_TOO_EARLYThe order has not been completed for 24h — wait and call again.
WARRANTY_EXPIREDThe warranty period has ended (snapshotted at order creation).
REFILL_IN_PROGRESSA refill request is already being processed for this order — wait for it to finish.
REFILL_RATE_LIMITEDA refill was already requested for this order in the past 24h.
INVALID_STATUSOnly applies to COMPLETED or PARTIAL orders.

Coming soon

The capabilities below are in development — the exact endpoints and shapes may change before GA.

FeatureMeaning
Webhooks (order events)Subscribe to order.created / processing / progress / completed / partial / failed — requests signed with HMAC-SHA256. Configured via the Dashboard, not the API.
Scope-based API keysRestrict a key by scope (services:read / orders:create / account:read) — keys currently have full account access.
Official SDKsTypeScript, Python, PHP — auto-generated from the OpenAPI spec.
Like3s API Documentation | Like3s