Skip to content

API Internals

jsem-nerad edited this page Nov 12, 2025 · 1 revision

API Internals

Understanding how the Strava.cz API works behind the scenes.

Note: This documentation is based on reverse engineering the Strava.cz web application. Information may change as the service updates.

API Overview

The Strava.cz API is a JSON-based REST API accessed through:

  • Base URL: https://app.strava.cz
  • API Endpoint: https://app.strava.cz/api
  • Protocol: HTTPS only
  • Format: JSON request/response

Authentication Flow

1. Login Request

Endpoint: POST /api/login

Request Payload:

{
    "cislo": "3753",
    "jmeno": "vojtech.nerad",
    "heslo": "YourPassword123",
    "zustatPrihlasen": false,
    "environment": "W",
    "lang": "EN"
}

Parameters:

Parameter Type Description Example
cislo string Canteen number "3753"
jmeno string Username "vojtech.nerad"
heslo string Plaintext password "Password123"
zustatPrihlasen boolean Stay logged in false
environment string Environment type "W"
lang string Language code "EN"

Response (Success):

{
    "sid": "01C6FCF02A7146159BC5F245A57AF29F",
    "s5url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "cislo": "3753",
    "jmeno": "vojtech.nerad",
    "uzivatel": {
        "konto": "0.00",
        "jmeno": "Vojtěch Nerad",
        "email": "email@example.com",
        "id": "vojtech.nerad",
        "mena": "",
        "nazevJidelny": "Školní jídelna, Praha 5 - Smíchov...",
        "vs": "12142"
    }
}

Important Fields:

Field Description Usage
sid Session ID Must be included in all subsequent requests
s5url Web service endpoint Used for meal operations
uzivatel.konto Account balance Current balance in Kč

2. Session Management

All authenticated requests must include:

  • sid - Session identifier
  • cislo - Canteen number
  • s5url or url - Web service endpoint

⚠️ Security Note: Passwords are sent as plaintext. This is a limitation of the Strava.cz service.

Menu Operations

Fetch Menu

Endpoint: POST /api/objednavky

Request Payload:

{
    "cislo": "3753",
    "sid": "01C6FCF02A7146159BC5F245A57AF29F",
    "s5url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "lang": "EN",
    "konto": 0,
    "podminka": "",
    "ignoreCert": "false"
}

Response Structure:

{
    "table0": [
        {
            "datum": "15.11.2025",
            "druh_popis": "Polévka",
            "nazev": "Vývar s kuskusem",
            "cena": "0",
            "pocet": 0,
            "veta": "75",
            "alergeny": [...],
            "omezeniObj": {
                "den": "",
                "obj": "",
                "zm": "",
                "bur": ""
            }
        }
    ],
    "table1": [...],
    "table2": [...]
}

Data Structure:

  • Each tableX represents one day
  • Each table contains array of meals
  • Meals include soups and main dishes

Key Fields:

Field Description Example Values
datum Date "15.11.2025" (dd.mm.yyyy)
druh_popis Meal type "Polévka", "Oběd 1"
nazev Meal name "Vývar s kuskusem"
cena Price "40.00" (string)
pocet Order count 0 (not ordered) / 1 (ordered)
veta Meal ID "75" (unique identifier)
alergeny Allergens Array of allergen codes
omezeniObj.den Restriction "" (orderable), "CO" (restricted), "T" (optional), "VP" (holiday)

Empty/Invalid Meals

Meals are considered invalid if:

  • nazev equals druh_popis (generic name)
  • delsiPopis and alergeny are both empty
  • omezeniObj.den contains "VP" (no school)

Ordering Operations

Add/Change Meal

Endpoint: POST /api/pridejJidloS5

Request Payload:

{
    "cislo": "3753",
    "sid": "01C6FCF02A7146159BC5F245A57AF29F",
    "url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "veta": "7",
    "pocet": 1,
    "lang": "EN",
    "ignoreCert": "false"
}

Parameters:

Parameter Type Description Values
veta string Meal ID "7", "75", etc.
pocet integer Order count 0 (cancel) / 1 (order)

Response:

{
    "produkt": [
        {
            "$": {
                "Veta": "7",
                "Pocet": "1",
                "Druh": "O2",
                "NelzeObj": "",
                "NelzeZm": ""
            }
        }
    ],
    "konto": "0.00"
}

Note: This only stages the change, doesn't save it yet.

Save Order

Endpoint: POST /api/saveOrders

Request Payload:

{
    "cislo": "3753",
    "sid": "01C6FCF02A7146159BC5F245A57AF29F",
    "url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "xml": null,
    "lang": "EN",
    "ignoreCert": "false"
}

Response:

{
    "produkty": [
        {
            "veta": "7",
            "pocet": 1,
            "burza": {...}
        }
    ],
    "konto": "0.00"
}

Important:

  • Updated balance returned in konto
  • List of all meal states in produkty

Cancel Order Changes

Endpoint: POST /api/nactiVlastnostiPA

Request Payload:

{
    "sid": "01C6FCF02A7146159BC5F245A57AF29F",
    "url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "cislo": "3753",
    "ignoreCert": "false",
    "lang": "EN",
    "getText": true,
    "checkVersion": true,
    "resetTables": true,
    "frontendFunction": "refreshInformations"
}

Usage: Reverts unsaved changes (rollback mechanism)

Logout

Endpoint: POST /api/logOut

Request Payload:

{
    "sid": "E9D5B96FE3D14DED8E543B33A4D910F2",
    "cislo": "3753",
    "url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "lang": "EN",
    "ignoreCert": "false"
}

Response: Empty (status 200 indicates success)

Error Responses

Error Structure

{
    "number": 35,
    "message": "Nedostatečný zůstatek na kontě"
}

Common Error Codes:

Code Meaning English
35 Nedostatečný zůstatek Insufficient balance
555 Chyba v API callu API call error

Headers

Required Headers

The library uses these headers for all requests:

{
    "User-Agent": "Mozilla/5.0 ...",
    "Accept": "*/*",
    "Accept-Language": "en-US,en;q=0.9,cs;q=0.6",
    "Accept-Encoding": "gzip, deflate, br, zstd",
    "Content-Type": "text/plain;charset=UTF-8",
    "Origin": "https://app.strava.cz",
    "Referer": "https://app.strava.cz/en/prihlasit-se?jidelna",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-origin"
}

Rate Limiting

  • No documented rate limits
  • Recommended: Don't make excessive requests
  • Use reasonable delays between operations

Data Mapping

MealType Detection

API druh_popis Library MealType
"Polévka" MealType.SOUP
"Oběd 1", "Oběd 2", etc. MealType.MAIN
Other MealType.UNKNOWN (filtered)

OrderType Detection

API omezeniObj.den Library OrderType
"" (empty) OrderType.NORMAL
"CO" OrderType.RESTRICTED
"T" OrderType.OPTIONAL
"VP" Filtered out (holiday)

Date Format Conversion

API Format: "15.11.2025" (dd.mm.yyyy)

Library Format: "2025-11-15" (yyyy-mm-dd)

Conversion:

unformatted = "15.11.2025"
formatted = f"{unformatted[6:10]}-{unformatted[3:5]}-{unformatted[0:2]}"
# Result: "2025-11-15"

Implementation Details

Session Initialization

Before making API requests, the library:

  1. Creates a requests.Session() object
  2. Makes initial GET to /en/prihlasit-se?jidelna
  3. Sets default headers
  4. Performs login POST

This ensures cookies and session state are properly maintained.

Order Transaction Flow

  1. Stage Changes: Call pridejJidloS5 for each meal

    • Sets pocet=1 to order
    • Sets pocet=0 to cancel
  2. Commit: Call saveOrders to persist

    • All staged changes are saved
    • Balance is updated
  3. Verify: Refresh menu and check order status

    • Call objednavky to get updated menu
    • Verify pocet values match expected state
  4. Rollback (on error): Call nactiVlastnostiPA

    • Reverts to last saved state
    • Restores balance

Balance Tracking

Balance is updated:

  • After login (from uzivatel.konto)
  • After pridejJidloS5 response (from konto)
  • After saveOrders response (from konto)
  • After rollback (from konto)

API Limitations

Known Limitations

  1. No bulk operations: Must order meals one-by-one
  2. No date filtering: Always returns full menu
  3. Soup ordering not supported: Only main dishes can be ordered
  4. No balance top-up: Balance management must be done through web interface
  5. Plaintext passwords: No encryption of credentials in API

Undocumented Fields

Many response fields are present but not documented or used:

  • burza - Exchange/trade related
  • vydejniMisto - Serving location
  • diety - Diet information
  • multipleNazev - Multiple name encoding

These are ignored by the library but preserved in raw_data.

Testing API Calls

Using curl

# Login
curl -X POST https://app.strava.cz/api/login \
  -H "Content-Type: application/json" \
  -d '{
    "cislo": "3753",
    "jmeno": "username",
    "heslo": "password",
    "zustatPrihlasen": false,
    "environment": "W",
    "lang": "EN"
  }'

# Get menu (requires sid from login)
curl -X POST https://app.strava.cz/api/objednavky \
  -H "Content-Type: application/json" \
  -d '{
    "cislo": "3753",
    "sid": "YOUR_SID",
    "s5url": "https://wss5.strava.cz/WSStravne5_15/WSStravne5.svc",
    "lang": "EN",
    "konto": 0,
    "podminka": "",
    "ignoreCert": "false"
  }'

Next Steps

Clone this wiki locally