The unofficial command-line interface for willhaben.at
Manage your marketplace listings directly from the terminal. Built with TypeScript, powered by Bun.
Features β’ Installation β’ Quick Start β’ Commands β’ Configuration β’ Contributing
Caution
Legal Disclaimer / Rechtlicher Hinweis
This is an unofficial tool and is not affiliated with willhaben.at. Using this program may violate willhaben's terms of service. You are solely responsible for ensuring your use complies with applicable terms and laws. The developers accept no liability for any damages or legal consequences arising from its use. Use at your own risk.
Dies ist ein inoffizielles Tool und steht in keiner Verbindung zu willhaben.at. Die Verwendung dieses Programms kann gegen die Nutzungsbedingungen von willhaben verstoΓen. Sie sind selbst dafΓΌr verantwortlich, die RechtmΓ€Γigkeit Ihrer Nutzung sicherzustellen. Die Entwickler ΓΌbernehmen keine Haftung fΓΌr SchΓ€den oder rechtliche Konsequenzen. Die Nutzung erfolgt auf eigenes Risiko.
Listing Management
- Create listings from JSON templates
- Update prices, titles, and descriptions
- Reserve, unreserve, and mark items as sold
- Republish expired listings
- Bulk operations support
Image Support
- Upload single or multiple images
- View listing images
- Delete individual or all images
- Automatic image ordering
Authentication
- Secure OAuth 2.0 PKCE flow
- Automatic token refresh
- Persistent sessions
Developer Experience
- JSON output for scripting
- Caching for faster responses
- Beautiful terminal UI with spinners
- Cross-platform compatibility
- Bun v1.0 or higher
# Clone the repository
git clone https://github.com/willhaben/willhaben-cli.git
cd willhaben-cli
# Install dependencies
bun install
# Build the standalone executable
bun run build
# Move to your PATH (optional)
mv willhaben /usr/local/bin/# Run directly without building
bun run dev -- --helpwillhaben loginA browser window will open for authentication.
willhaben whoamiwillhaben listCreate a template file my-item.json:
{
"title": "iPhone 14 Pro - Excellent Condition",
"description": "Selling my iPhone 14 Pro 256GB in excellent condition...",
"price": 799,
"postCode": "1010",
"locationId": 900,
"location": "Wien",
"categoryPath": ["MOBILE_ELECTRONICS", "MOBILE_PHONES", "IPHONE"],
"condition": "gebraucht",
"delivery": ["PICKUP", "Versand"]
}Then publish:
willhaben publish my-item.json| Command | Description |
|---|---|
willhaben login |
Authenticate with willhaben |
willhaben logout |
Clear stored credentials |
willhaben whoami |
Display current user info |
| Command | Description |
|---|---|
willhaben list |
List all your listings |
willhaben get <id> |
Get details of a listing |
willhaben publish <file> |
Create a new listing from JSON |
willhaben update <id> |
Update listing properties |
willhaben delete <id> |
Delete a listing |
willhaben republish <id> |
Republish an expired listing |
willhaben deactivate <id> |
Take a listing offline |
willhaben reserve <id> |
Mark as reserved |
willhaben unreserve <id> |
Remove reservation |
willhaben sold <id> |
Mark as sold |
| Command | Description |
|---|---|
willhaben images <id> |
List images for a listing |
willhaben upload-image <id> <file...> |
Upload one or more images |
willhaben delete-image <id> <imageId> |
Delete a specific image |
willhaben clear-images <id> |
Delete all images |
| Command | Description |
|---|---|
willhaben config get |
Show all settings |
willhaben config set <key> <value> |
Set a configuration value |
willhaben config reset |
Reset to defaults |
willhaben config path |
Show config file location |
# Basic listing
willhaben list
# With pagination
willhaben list --page 2 --size 50
# Output as JSON (for scripting)
willhaben list --json# Fetch from API
willhaben get 123456789
# Use cached data if available
willhaben get 123456789 --cached
# Output as JSON
willhaben get 123456789 --json# Update price
willhaben update 123456789 --price 99.99
# Update title
willhaben update 123456789 --title "New Title"
# Update multiple fields
willhaben update 123456789 --title "New Title" --price 149# With confirmation prompt
willhaben delete 123456789
# Skip confirmation
willhaben delete 123456789 --force# Upload single image
willhaben upload-image 123456789 photo.jpg
# Upload multiple images
willhaben upload-image 123456789 photo1.jpg photo2.jpg photo3.jpg| Field | Type | Description |
|---|---|---|
title |
string | Listing title (max 100 chars) |
description |
string | Detailed description |
price |
number | Price in EUR |
postCode |
string | Postal code (e.g., "8010") |
locationId |
number | Willhaben location ID |
location |
string | District/city name |
categoryPath |
string[] | Category path from root to leaf |
| Field | Type | Description |
|---|---|---|
street |
string | Street address |
condition |
string | "neu", "gebraucht", or "defekt" |
delivery |
string[] | ["PICKUP"], ["Versand"], or both |
attributes |
object | Category-specific attributes |
contactInfo |
object | Contact information override |
skipValidation |
boolean | Skip attribute validation |
Electronics - Printer
{
"title": "HP LaserJet Pro - wie neu",
"description": "Verkaufe meinen HP LaserJet Pro Drucker...",
"price": 120,
"postCode": "8010",
"locationId": 117458,
"location": "Jakomini",
"categoryPath": [
"COMPUTER_SOFTWARE",
"PRINTER_MONITORS_SPEAKER",
"PRINTER",
"LASER_PRINTER"
],
"condition": "gebraucht",
"delivery": ["PICKUP", "Versand"],
"attributes": {
"BRAND_PRINTER": "HP"
}
}Hobby - Drone
{
"title": "DJI Mini 3 Pro - Fly More Combo",
"description": "DJI Mini 3 Pro mit allem ZubehΓΆr...",
"price": 750,
"postCode": "1010",
"locationId": 900,
"location": "Wien",
"categoryPath": [
"LEISURE_INSTRUMENTS_CULINARY",
"MODEL_MAKING",
"RC_MODEL_MAKING",
"DRONES_MULTICOPTER",
"OUTDOOR"
],
"condition": "gebraucht",
"delivery": ["PICKUP", "Versand"],
"attributes": {
"ENGINE_TYPE": "ELECTRIC_DRIVE"
}
}Books
{
"title": "Clean Code - Robert C. Martin",
"description": "Buch in sehr gutem Zustand...",
"price": 15,
"postCode": "5020",
"locationId": 30501,
"location": "Salzburg",
"categoryPath": [
"BOOKSFILMANDMUSIC",
"NON_FICTION_BOOKS"
],
"condition": "gebraucht",
"delivery": ["Versand"]
}Category codes follow the willhaben category tree structure:
| Top-Level Code | Category |
|---|---|
LIVING_HOUSEHOLD_GASTRONOMY |
Wohnen / Haushalt |
BOOKSFILMANDMUSIC |
BΓΌcher / Filme / Musik |
COMPUTER_SOFTWARE |
Computer / Software |
MOBILE_ELECTRONICS |
Handy / Telefon |
LEISURE_INSTRUMENTS_CULINARY |
Freizeit / Instrumente |
SPORTS_LEISURE |
Sport / Freizeit |
FASHION_ACCESSORIES |
Mode / Accessoires |
Use willhaben categories to explore the full category tree.
Configuration is stored in ~/.willhaben/:
| File | Description |
|---|---|
config.json |
Settings and authentication tokens |
listings.json |
Local listing cache |
| Key | Values | Default | Description |
|---|---|---|---|
outputFormat |
text, json |
text |
Default output format |
All commands support --json for machine-readable output:
# Get listing IDs
willhaben list --json | jq '.[].id'
# Check if listing exists
willhaben get 123456789 --json 2>/dev/null && echo "exists"# Reserve all listings
for id in $(willhaben list --json | jq -r '.[].id'); do
willhaben reserve "$id"
done
# Bulk price update
willhaben list --json | jq -r '.[] | select(.price < 10) | .id' | \
xargs -I {} willhaben update {} --price 10src/
βββ index.ts # CLI entry point
βββ api/
β βββ client.ts # HTTP client with auth
β βββ listings.ts # Listing operations
β βββ categories.ts # Category tree
β βββ auth.ts # OAuth 2.0 PKCE flow
βββ cli/
β βββ commands/ # Command implementations
βββ store/
β βββ config.ts # Configuration management
β βββ listings.ts # Listing cache
βββ types/
βββ index.ts # TypeScript interfaces
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
# Clone and install
git clone https://github.com/willhaben/willhaben-cli.git
cd willhaben-cli
bun install
# Run in development mode
bun run dev -- --help
# Type checking
bun run typecheckThe API was reverse-engineered from the willhaben mobile app using mitmproxy. If you find new endpoints or changes:
- Capture traffic with mitmproxy
- Document the endpoint in an issue
- Submit a PR with the implementation
- Use TypeScript strict mode
- Follow existing patterns
- Keep functions small and focused
- Add types for all API responses
- Categories browser command
- Bulk import from CSV
- Watch mode for listing changes
- Message inbox support
- Statistics and analytics
- Multiple account support
How do I find my locationId?
Location IDs can be found in the category tree response or by inspecting the willhaben app traffic. Common IDs:
- Vienna (Wien): 900
- Graz: 117458
- Salzburg: 30501
- Linz: 40101
Why do I get "validation error" when publishing?
Some categories require specific attributes. Check the category's attributeReferences in the category tree, or use "skipValidation": true in your template to bypass validation (not recommended).
Can I use this for commercial purposes?
This tool is provided for personal use. Commercial use may have additional legal implications regarding willhaben's terms of service. Consult legal advice if needed.
- Built with Bun - The fast JavaScript runtime
- CLI powered by Commander.js
- Beautiful output with Chalk and Ora
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ in Austria