# Discover available services

Find main, extra, and special service choices before calculating a quote.

Company: Metfone Express
API version: v1
Requested language: en
Content language: en
Source: https://mfexpress-partner-docs.zhst.app/mfexpress/en/available-services

Endpoint: POST /pricing/get-service


```http
POST /tms-partner/api/v1/pricing/get-service
```

## Usage and important notes

Call this before get-all and create-order. Supply a complete product and route. Missing `fromLocation`, `toLocation`, or `product` can produce HTTP 500 instead of a clean HTTP 400.

Send weight in grams and dimensions in centimeters. `isDomestic` defaults to true. `customerCode` defaults to the token’s customer account. `partnerInfo` is an alternate discount identity and is normally unnecessary because `X-Client-Source` already identifies the partner. `orderService` changes the `isShow`, `isChosen`, and `isChangeable` flags of GTN/NTN/VTT; it does not change the price.

Map `mainPrice.code` to order `service`, and selected `extraPrices[].code` to `vas[]`. Respect automatically included `mainPrice.extraService[]` and `specialService[]`. `isShow=false` marks an internal service, not a selectable requirement. `isCalculated=false` means displayed rather than priced. If `mainPrice.isCalculatedAutomatically=false`, use `manualPrice` when calling get-all. Use **beforeVatPrice**, not VAT-inclusive `price`, for order fee amounts.

## Authentication headers



| Header | Requirement | Value / meaning |
| --- | --- | --- |
| X-Api-Token | Required | `${API_TOKEN}`: environment-specific token issued by TMS |
| X-Client-Source | Required | `${PARTNER_CODE}`: partner code paired with the token |
| Content-Type | With a JSON body | application/json |
| Accept | Required by source | application/json |
| Accept-Language | Optional | `vn`, `en`, `my`, `km`, `lo` |



## Request fields

Recommended operational inputs; no fields have @NotNull validation. Missing locations/product may cause 500 rather than 400.

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `product` | object | See description | Recommended product object. No @NotNull validation is documented for pricing. |
| `product.weight` | number | See description | Recommended weight in grams. |
| `product.type` | string | See description | Recommended goods type. Values: `GOODS`, `DOCUMENT`. |
| `product.price` | number | See description | Declared goods value; currency is not specified for this request in the source. |
| `product.moneyCollection` | number | See description | COD influences service selection only; it does not change the quoted amount or persist COD on an order. |
| `product.length` | number | See description | Length in cm. |
| `product.width` | number | See description | Width in cm. |
| `product.height` | number | See description | Height in cm. |
| `fromLocation` | array | See description | Recommended sender components, levels 0–3 and 999. |
| `fromLocation[].id` | string | See description | Use the identifier returned by the API, not the illustrative value. |
| `fromLocation[].code` | string | See description | Use the identifier returned by the API, not the illustrative value. |
| `fromLocation[].name` | string | See description | Location name or street address. |
| `fromLocation[].type` | string | See description | NATIONAL, PROVINCE, DISTRICT, VILLAGE or OTHER according to level. |
| `fromLocation[].level` | number | See description | 0 country; 1 province; 2 district; 3 village; 999 street/detail. |
| `toLocation` | array | See description | Recommended recipient components, levels 0–3. |
| `toLocation[].id` | string | See description | Use the identifier returned by the API, not the illustrative value. |
| `toLocation[].code` | string | See description | Use the identifier returned by the API, not the illustrative value. |
| `toLocation[].name` | string | See description | Location name or street address. |
| `toLocation[].type` | string | See description | NATIONAL, PROVINCE, DISTRICT, VILLAGE or OTHER according to level. |
| `toLocation[].level` | number | See description | 0 country; 1 province; 2 district; 3 village; 999 street/detail. |
| `isDomestic` | boolean | See description | Domestic=true, international=false. Defaults to true. Default: `true`. |
| `customerCode` | string | See description | Internal customer code; defaults to the account associated with X-Api-Token. |
| `partnerInfo` | object | See description | Optional discount identity; X-Client-Source normally suffices. Uses snake_case. |
| `partnerInfo.id` | number | See description | Internal partner ID. |
| `partnerInfo.partner_code` | string | See description | Partner code. |
| `partnerInfo.partner_name` | string | See description | Partner name. |
| `partnerInfo.email` | string | See description | Partner email. |
| `partnerInfo.type` | string | See description | Partner type, e.g. PARTNER. |
| `orderService` | object | See description | Service preferences; UNKNOW is the source spelling. |
| `orderService.senderService` | string | See description | Changes display/default/lock flags of GTN/NTN/VTT, not price. Values: `GTCH`, `VTT`, `GTN`, `UNKNOW`. |
| `orderService.receiverService` | string | See description | Recipient preference with the same flag-only effect. Values: `NTCH`, `NTN`, `VTT`, `UNKNOW`. |



## Example JSON body

Save as `request.json`. Replace every `${…}` string and example ID with actual environment values before sending. cURL with `--data @request.json` **does not interpolate variables inside JSON files**. Identities are synthetic.
```json
{
  "product": {
    "weight": 100,
    "type": "GOODS",
    "price": 50,
    "moneyCollection": 50,
    "length": 10,
    "width": 10,
    "height": 10
  },
  "fromLocation": [
    {
      "name": "Example warehouse, Street A",
      "type": "OTHER",
      "level": 999
    },
    {
      "id": "5025963",
      "code": "120211",
      "name": "Voat Phnum",
      "type": "VILLAGE",
      "level": 3
    },
    {
      "id": "4059553",
      "code": "1202",
      "name": "Doun Penh",
      "type": "DISTRICT",
      "level": 2
    },
    {
      "id": "4025120",
      "code": "PNP",
      "name": "Phnom Penh",
      "type": "PROVINCE",
      "level": 1
    },
    {
      "type": "NATIONAL",
      "name": "Cambodia",
      "code": "KH",
      "level": 0
    }
  ],
  "toLocation": [
    {
      "name": "Example recipient, Street B",
      "type": "OTHER",
      "level": 999
    },
    {
      "id": "5025109",
      "code": "010201",
      "name": "បន្ទាយនាង",
      "type": "VILLAGE",
      "level": 3
    },
    {
      "id": "4059452",
      "code": "0102",
      "name": "មង្គលបូរី",
      "type": "DISTRICT",
      "level": 2
    },
    {
      "id": "4025109",
      "code": "BAN",
      "name": "Banteay Meanchey",
      "type": "PROVINCE",
      "level": 1
    },
    {
      "type": "NATIONAL",
      "name": "Cambodia",
      "code": "KH",
      "level": 0
    }
  ],
  "isDomestic": true,
  "orderService": {
    "senderService": "GTN",
    "receiverService": "NTN"
  }
}
```


## cURL example

`BASE_URL` must include `/tms-partner/api/v1`. Load the token and partner code from your private environment; never paste secrets into documentation or AI prompts.
```bash
curl --request POST "${BASE_URL}/pricing/get-service" \
  --header "X-Api-Token: ${API_TOKEN}" \
  --header "X-Client-Source: ${PARTNER_CODE}" \
  --header "Accept-Language: en" \
  --header "Accept: application/json" \
  --header "Content-Type: application/json" \
  --data @request.json
```


## Example response

```json
[
  {
    "totalPrice": 20000,
    "totalPriceAfterDiscount": 18000,
    "discount": 2000,
    "totalDiscountAmount": 2000,
    "discountType": "AMOUNT",
    "property": {
      "calculatedWeight": 100,
      "convertedWeight": 200,
      "perimeter": 30,
      "distance": null
    },
    "mainPrice": {
      "code": "CCN",
      "name": "Express",
      "price": 8000,
      "priceAfterDiscount": 6000,
      "discount": 2000,
      "beforeVatPrice": 7273,
      "vatPrice": 727,
      "field": "KL",
      "calculatedWeight": 100,
      "extraService": [
        "GTN"
      ],
      "specialService": [],
      "isCalculatedAutomatically": true
    },
    "extraPrices": [
      {
        "code": "GTN",
        "name": "Delivery to address",
        "price": 8000,
        "beforeVatPrice": 7273,
        "vatPrice": 727,
        "priceAfterDiscount": 8000,
        "discount": 0,
        "field": "CC",
        "isShow": true,
        "isChosen": false,
        "isChangeable": true,
        "isCalculated": true
      },
      {
        "code": "NTN",
        "name": "Pickup at address",
        "price": 2000,
        "beforeVatPrice": 1818,
        "vatPrice": 182,
        "priceAfterDiscount": 2000,
        "discount": 0,
        "field": "CC",
        "isShow": true,
        "isChosen": false,
        "isChangeable": true,
        "isCalculated": true
      }
    ],
    "specialPrices": [],
    "leadTime": 0
  }
]
```


## Response fields



| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `[].totalPrice` | number | See description | Total before the reported discount. |
| `[].totalPriceAfterDiscount` | number | See description | Total after discount; difference is totalDiscountAmount. |
| `[].property` | object | See description | Calculation inputs returned by pricing. |
| `[].property.calculatedWeight` | number | See description | Actual weight used for pricing, grams. |
| `[].property.convertedWeight` | number | See description | Volumetric weight, grams. |
| `[].property.perimeter` | number | See description | Parcel perimeter. |
| `[].property.distance` | number / null | See description | Distance when a distance-based service applies; otherwise null. |
| `[].mainPrice` | object | See description | Fields depend on whether this is mainPrice or an extra/special price. |
| `[].mainPrice.code` | string | See description | Service code; mainPrice.code becomes order.service; extraPrices[].code becomes order.vas[]. |
| `[].mainPrice.name` | string | See description | Service name. |
| `[].mainPrice.price` | number | See description | Listed service price; extra service list prices include VAT. |
| `[].mainPrice.priceAfterDiscount` | number | See description | Service amount after discount. |
| `[].mainPrice.discount` | number | See description | Service-specific discount amount. |
| `[].mainPrice.beforeVatPrice` | number | See description | Pre-VAT fee to map to detailedFees.serviceFee[].fee. |
| `[].mainPrice.vatPrice` | number | See description | VAT amount. |
| `[].mainPrice.field` | string | See description | Calculation classification: KL/TH/CC/KG/KC/CV/CV_KL. |
| `[].mainPrice.calculatedWeight` | number | See description | Weight used by the main service. |
| `[].mainPrice.extraService` | array | See description | Automatically included extra services. |
| `[].mainPrice.specialService` | array | See description | Automatically included special services. |
| `[].mainPrice.isCalculatedAutomatically` | boolean | See description | true: automatic Drools calculation; false: provide manualPrice to get-all. |
| `[].mainPrice.isShow` | boolean | See description | Extra service visible for selection; false means internal and need not be submitted. |
| `[].mainPrice.isChosen` | boolean | See description | Extra service selected by default. |
| `[].mainPrice.isChangeable` | boolean | See description | Whether the user may toggle the extra service; otherwise locked by orderService. |
| `[].mainPrice.isCalculated` | boolean | See description | Whether the extra service is priced or only displayed. |
| `[].extraPrices` | array | See description | Extra-service prices. |
| `[].extraPrices[].code` | string | See description | Service code; mainPrice.code becomes order.service; extraPrices[].code becomes order.vas[]. |
| `[].extraPrices[].name` | string | See description | Service name. |
| `[].extraPrices[].price` | number | See description | Listed service price; extra service list prices include VAT. |
| `[].extraPrices[].priceAfterDiscount` | number | See description | Service amount after discount. |
| `[].extraPrices[].discount` | number | See description | Service-specific discount amount. |
| `[].extraPrices[].beforeVatPrice` | number | See description | Pre-VAT fee to map to detailedFees.serviceFee[].fee. |
| `[].extraPrices[].vatPrice` | number | See description | VAT amount. |
| `[].extraPrices[].field` | string | See description | Calculation classification: KL/TH/CC/KG/KC/CV/CV_KL. |
| `[].extraPrices[].calculatedWeight` | number | See description | Weight used by the main service. |
| `[].extraPrices[].extraService` | array | See description | Automatically included extra services. |
| `[].extraPrices[].specialService` | array | See description | Automatically included special services. |
| `[].extraPrices[].isCalculatedAutomatically` | boolean | See description | true: automatic Drools calculation; false: provide manualPrice to get-all. |
| `[].extraPrices[].isShow` | boolean | See description | Extra service visible for selection; false means internal and need not be submitted. |
| `[].extraPrices[].isChosen` | boolean | See description | Extra service selected by default. |
| `[].extraPrices[].isChangeable` | boolean | See description | Whether the user may toggle the extra service; otherwise locked by orderService. |
| `[].extraPrices[].isCalculated` | boolean | See description | Whether the extra service is priced or only displayed. |
| `[].specialPrices` | array | See description | Special-service prices. |
| `[].specialPrices[].code` | string | See description | Service code; mainPrice.code becomes order.service; extraPrices[].code becomes order.vas[]. |
| `[].specialPrices[].name` | string | See description | Service name. |
| `[].specialPrices[].price` | number | See description | Listed service price; extra service list prices include VAT. |
| `[].specialPrices[].priceAfterDiscount` | number | See description | Service amount after discount. |
| `[].specialPrices[].discount` | number | See description | Service-specific discount amount. |
| `[].specialPrices[].beforeVatPrice` | number | See description | Pre-VAT fee to map to detailedFees.serviceFee[].fee. |
| `[].specialPrices[].vatPrice` | number | See description | VAT amount. |
| `[].specialPrices[].field` | string | See description | Calculation classification: KL/TH/CC/KG/KC/CV/CV_KL. |
| `[].specialPrices[].calculatedWeight` | number | See description | Weight used by the main service. |
| `[].specialPrices[].extraService` | array | See description | Automatically included extra services. |
| `[].specialPrices[].specialService` | array | See description | Automatically included special services. |
| `[].specialPrices[].isCalculatedAutomatically` | boolean | See description | true: automatic Drools calculation; false: provide manualPrice to get-all. |
| `[].specialPrices[].isShow` | boolean | See description | Extra service visible for selection; false means internal and need not be submitted. |
| `[].specialPrices[].isChosen` | boolean | See description | Extra service selected by default. |
| `[].specialPrices[].isChangeable` | boolean | See description | Whether the user may toggle the extra service; otherwise locked by orderService. |
| `[].specialPrices[].isCalculated` | boolean | See description | Whether the extra service is priced or only displayed. |
| `[].discount` | number | See description | Discount value. |
| `[].totalDiscountAmount` | number | See description | Total discount amount. |
| `[].discountType` | string | See description | AMOUNT: fixed amount; PERCENT: percentage. Values: `AMOUNT`, `PERCENT`. |
| `[].leadTime` | number | See description | Lead-time value shown in the source; unit is unspecified. |



## Error handling

See [HTTP codes and source limitations](reference). HTTP success does not prove COD, fees, or cancellation are correct; inspect the documented business fields. Do not assume create-order retries are safe.

