Wofino2 Import - JSON Format Documentation
Overview
Wofino2 import is an advanced import format for managing job offers using JSON files. It allows complete lifecycle management of job listings including creation, updating, publishing, unpublishing, and deletion.
Basic Structure
The JSON file must contain a main object with a jobs array:
{
"jobs": [
{
// individual job offers
}
]
}
Individual Job Offer Structure
Required Fields
| Field | Type | Description |
| ------- | ------ | --------------------------------------------- |
| id | string | Unique position identifier (reference number) |
| title | string | Position title |
Optional Fields
| Field | Type | Default Value | Description |
| -------------- | ----------------- | ---------------- | ------------------------------------ |
| action | string | "create" | Action to perform (see below) |
| description | string | "" | Position description (HTML/Markdown) |
| published_at | string (ISO 8601) | current datetime | Publication date |
| valid_to | string (ISO 8601) | +30 days | Expiration date |
Actions
| Value | Description |
| ----------- | ----------------------------------------------------------- |
| create | Creates a new position or updates existing and publishes it |
| update | Updates existing position (remains published) |
| publish | Publishes position (same as create/update) |
| unpublish | Unpublishes position (hides from website) |
| delete | Deletes position completely |
Salary Information
{
"salary": {
"from": 50000,
"to": 80000
}
}
| Field | Type | Description |
| ------------- | ------ | -------------------- |
| salary.from | number | Salary from (in CZK) |
| salary.to | number | Salary to (in CZK) |
Location
{
"location": {
"geoname_id": 3067696,
"city": "Prague",
"region": "Prague",
"country": "CZ",
"address": "Wenceslas Square 1",
"postal_code": "110 00",
"remote": false,
"hybrid": true
}
}
| Field | Type | Description |
| --------------------- | ------ | ------------------------------------------------------------------------- |
| location.geoname_id | number | ID from GeoNames database (preferred method) |
| location.city | string | City (used if geoname_id is not provided) |
Location Processing
- Priority geoname_id: If
geoname_idis provided, the system first searches for an existing location in the database by this ID - Creating new location: If the location doesn't exist, a new record is automatically created using the GeoNames API
- Fallback to city name: If
geoname_idis not provided, the system searches for a location by city name (city) - Automatic linking: Successfully recognized locations are automatically linked to the job offer
Tip: For precise location determination, we recommend using geoname_id, which you can find at geonames.org.
Contact Information
{
"contact": {
"name": "John Doe",
"email": "[email protected]",
"phone": "+420 123 456 789"
}
}
| Field | Type | Required | Description |
| --------------- | ------ | -------- | --------------------------------------------------------------------------- |
| contact.email | string | YES | Contact person's email address (job listing will be unpublished if missing) |
| contact.name | string | NO | Contact person's name |
| contact.phone | string | NO | Phone number |
Contact Information Processing
- Required email: The
emailfield is mandatory - if missing, the job listing will be automatically unpublished - Email normalization: Email is normalized to lowercase for consistent searching
- Finding existing contact: The system searches for an existing contact person by email for the given company
- Creating new contact: If the contact doesn't exist, a new record is created
- Automatic linking: The contact is automatically linked to the job offer
Categories
{
"categories": ["IT", "Backend Development", "PHP"]
}
Complete Example
{
"jobs": [
{
"id": "php-developer-001",
"title": "Senior PHP Developer",
"action": "create",
"description": "<h2>About the Position</h2><p>We are looking for an experienced PHP developer...</p>",
"published_at": "2025-01-15T09:00:00Z",
"valid_to": "2025-03-15T23:59:59Z",
"salary": {
"from": 60000,
"to": 90000
},
"location": {
"geoname_id": 3067696,
"city": "Prague",
"region": "Prague",
"country": "CZ",
"remote": false,
"hybrid": true
},
"contact": {
"name": "John Doe",
"email": "[email protected]",
"phone": "+420 123 456 789"
},
"categories": ["IT", "Backend Development", "PHP"]
},
{
"id": "frontend-developer-002",
"title": "Frontend Developer",
"action": "update",
"description": "<p>Position for a frontend developer with React...</p>",
"salary": {
"from": 45000,
"to": 70000
},
"location": {
"city": "Brno",
"region": "South Moravian",
"country": "CZ",
"remote": false,
"hybrid": true
}
},
{
"id": "old-position-003",
"action": "delete"
},
{
"id": "temporary-hidden-004",
"action": "unpublish"
}
]
}
Response Format
The import responds with a JSON object containing processing results:
{
"success": true,
"processed": 1,
"created": 1,
"updated": 0,
"deleted": 0,
"errors": []
}
Response Fields
| Field | Type | Description |
| ----------- | ------- | ------------------------------ |
| success | boolean | Overall import success |
| processed | number | Total number of processed jobs |
| created | number | Number of created jobs |
| updated | number | Number of updated jobs |
| deleted | number | Number of deleted jobs |
| errors | array | List of error messages |
Error Handling
If errors occur during processing, they are returned in the errors array:
{
"success": false,
"processed": 0,
"created": 0,
"updated": 0,
"deleted": 0,
"errors": [
"Job 'php-developer-001': Missing required field 'title'",
"Job 'js-developer-002': Invalid email format in contact"
]
}
Best Practices
- Use geoname_id: For precise location determination
- Validate email addresses: Ensure contact emails are valid
- Meaningful IDs: Use descriptive and unique job IDs
- Regular updates: Keep job listings current
- Test imports: Always test with a small dataset first
