← Back to Home

Workways Public API

REST API Documentation for Public Sites and Rooms

Overview

The Workways Public API provides access to information about public coworking sites and meeting rooms. This API is designed for developers who want to integrate Workways public spaces data into their applications.

Base URL: https://api.workways.com

Authentication

Authentication Policy:
  • GET endpoints (reading data): Public, no authentication required
  • POST endpoints (creating/modifying data): Require API token authentication

Obtaining API Tokens

To access POST endpoints, you need an API token. Here's how to get one:

  1. Contact Workways: Request API access by emailing appsupport@workways.com
  2. Account Setup: Your account will be configured with the api-developer or app-admin role
  3. Generate Token: Log in to your Workways account and navigate to Settings → API Developer Settings
  4. Create Token: Click "Create Token", give it a descriptive name, and copy the generated token
  5. Store Securely: Save the token in a secure location (e.g., environment variables). The token is only shown once and cannot be retrieved later.
API Token Features:
  • Format: ww_dev_<64-character-hex-string>
  • Security: Tokens are stored as SHA-256 hashes and never exposed in plain text after creation
  • Management: Create multiple tokens, track last usage, revoke tokens anytime
  • Optional Quotas: Daily and monthly API usage limits can be configured per user

Token Management

Token Regeneration

If your token is compromised or lost, you can regenerate it while keeping the same token ID and tracking history:

  1. Log in to your Workways account
  2. Navigate to Settings → API Developer Settings
  3. Click the refresh icon next to the token you want to regenerate
  4. Confirm the regeneration (the old token will become immediately invalid)
  5. Copy and securely store the new token (shown only once)
Token Regeneration Behavior:
  • Keeps the same token ID for tracking purposes
  • Preserves the original creation date
  • Generates a new token hash and prefix
  • Old token becomes invalid immediately
  • New token is shown once and cannot be retrieved later
Token Deletion and Invalidation

Tokens can be removed in two ways depending on who performs the action:

Deletion Behavior:
  • User deletes their own token: The token is permanently deleted from the database
  • Admin deletes another user's token: The token is invalidated (isActive=false) but remains in the database for tracking purposes

Using API Tokens

Include your API token in the Authorization header of your requests using the Bearer authentication scheme:

curl -X POST "https://api.workways.com/api/register" \
  -H "Authorization: Bearer ww_dev_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{...}'

Endpoints Requiring Authentication

Endpoint Method Authentication Required
/api/sites GET ⚡ Optional
/api/rooms GET ⚡ Optional
/api/countries GET ❌ No
/api/icsfeed GET ❌ No
/api/register POST ✅ Yes
/api/meeting-request POST ✅ Yes
/api/check-email POST ✅ Yes
/api/room-price GET ✅ Yes
/api/contract-options GET ✅ Yes
/api/user-info GET ✅ Yes
/api/organization-info GET ✅ Yes
/api/merge-contract POST ✅ Yes

Authentication Error Responses

Missing Authorization Header
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer <your_token>"
}
Invalid Authorization Format
{
  "retcode": -1,
  "message": "Unauthorized: Invalid authorization format. Use: Authorization: Bearer <your_token>"
}
Invalid or Revoked Token
{
  "retcode": -1,
  "message": "Unauthorized: Invalid or revoked token"
}
Inactive/Invalidated Token
{
  "retcode": -1,
  "message": "Votre token est expiré, connectez-vous à votre compte pour le renouveler"
}
Archived Account
{
  "retcode": -1,
  "message": "Votre compte est désactivé, contactez Workways"
}
Archived User Account
{
  "retcode": -1,
  "message": "Unauthorized: User account is archived"
}
Security Best Practices:
  • Never commit API tokens to version control
  • Use environment variables to store tokens
  • Rotate tokens periodically
  • Revoke tokens immediately if compromised
  • Use different tokens for different applications/environments
  • Monitor token usage via the "Last Used" timestamp in your account settings

Response Format

All responses follow a standard JSON format:

{
  "retcode": 1,          // 1 for success, -1 for error
  "message": "OK",       // Status message
  "data": [...]          // Response data (array)
}

Country Input Flexibility

Country parameters accept multiple formats:
  • ISO codes (case-insensitive): "FR", "fr", "BE", "ie"
  • English names (case-insensitive): "France", "belgium", "IRELAND"
  • French names (case-insensitive): "France", "belgique", "IRLANDE"

All formats are normalized internally to ISO codes for database queries.

Country Output Format

All responses return English country names (e.g., "Ireland", "Belgium", "France") for user-friendly display, even though ISO codes are stored internally.

Endpoints

GET /api/sites
Get a list of all public Workways sites with their available rooms.
⚡ Authentication Optional: This endpoint can be called with or without an API key.
  • Without API key: Returns only public rooms (publicOffice, publicMeeting)
  • With API key: Returns all rooms including private ones, with additional fields (actualState, otherRooms array)

Query Parameters

Parameter Type Required Description
country string Optional Filter sites by country. Accepts ISO codes ("IE", "BE", "FR"), English names ("Ireland", "Belgium"), or French names ("Irlande", "Belgique"). Case-insensitive.
type string Optional Filter by room type. Values: publicOffice, publicMeeting (without auth), or all plus any room type when authenticated. Use type=all with API key to get all room types.

Response Fields

Field Type Description
_id string Unique site identifier
name string Site name
country string Country where the site is located (English name, e.g., "Ireland", "Belgium")
publicRooms array Array of public rooms available at this site
publicRooms[]._id string Room unique identifier
publicRooms[].name string Room internal name
publicRooms[].publicName string Room display name (falls back to name if not set)
publicRooms[].type string Room type: "publicOffice" or "publicMeeting"
publicRooms[].surface number Room surface in m² (commercial or computed), or -1 if unknown
publicRooms[].actualState string (Auth only) Current room state: "bookable", "rented", etc.
otherRooms array (Auth only) Array of non-public rooms (same structure as publicRooms)

Example Requests

# Using English name
curl -X GET "https://apidev.workways.com/api/sites?country=Ireland"

# Using ISO code
curl -X GET "https://apidev.workways.com/api/sites?country=IE"

# Using French name
curl -X GET "https://apidev.workways.com/api/sites?country=Irlande"

# Case insensitive
curl -X GET "https://apidev.workways.com/api/sites?country=ireland"

Example Response

{
  "retcode": 1,
  "message": "OK",
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "name": "Dublin Coworking Center",
      "country": "Ireland",
      "roomCount": 1,
      "meetingRoomCount": 1,
      "publicRooms": [
        {
          "_id": "507f191e810c19729de860ea",
          "name": "Meeting Room A",
          "publicName": "Meeting Room A",
          "type": "publicMeeting",
          "surface": 25
        },
        {
          "_id": "507f191e810c19729de860eb",
          "name": "Hot Desk 1",
          "publicName": "Hot Desk Area",
          "type": "publicOffice",
          "surface": -1
        }
      ]
    }
  ]
}

Example Response (Authenticated with type=all)

{
  "retcode": 1,
  "message": "OK",
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "name": "Dublin Coworking Center",
      "country": "Ireland",
      "roomCount": 1,
      "meetingRoomCount": 1,
      "publicRooms": [
        {
          "_id": "507f191e810c19729de860ea",
          "name": "Meeting Room A",
          "publicName": "Meeting Room A",
          "type": "publicMeeting",
          "surface": 25,
          "actualState": "bookable"
        }
      ],
      "otherRooms": [
        {
          "_id": "507f191e810c19729de860ec",
          "name": "Private Office 101",
          "publicName": "Executive Suite",
          "type": "privateOffice",
          "surface": 45,
          "actualState": "rented"
        }
      ]
    }
  ]
}
🚀 Try it now!
Leave empty for all countries
Response:

            
GET /api/rooms
Get a detailed list of all public rooms with pricing, capacity, and availability information.
⚡ Authentication Optional: This endpoint can be called with or without an API key.
  • Without API key: Returns only public rooms (publicOffice, publicMeeting)
  • With API key: Returns all room types, plus organization info when applicable (organizationId, organizationName, contractEndDate)

Query Parameters

Parameter Type Required Description
country string Optional Filter rooms by country. Accepts ISO codes ("IE", "BE"), English names ("Ireland", "Belgium"), or French names ("Irlande", "Belgique"). Case-insensitive.
site string Optional Filter rooms by site ID (ObjectId)

Response Fields

Field Type Description
_id string Unique room identifier
name string Room internal name
publicName string Room display name (falls back to name if not set)
type string Room type: "publicOffice", "publicMeeting", or other types when authenticated
surface number Room surface in m² (commercial or computed), or -1 if unknown
description string Room description
actualState string Current state: "bookable", "rented", "forrent", etc.
siteId string ID of the site where this room is located
siteName string Name of the site
country string Country of the site (English name, e.g., "Ireland", "Belgium")
minPerson number Minimum number of persons
maxPerson number Maximum number of persons
nbSeat number Number of seats
configuration string Room configuration type
otherConfiguration string Additional configuration details
minDurationBooking number Minimum booking duration (minutes)
maxDurationBooking number Maximum booking duration (minutes)
stepDurationBooking number Booking duration increment (minutes)
slotWeek string Weekly availability schedule
slotSaturday string Saturday availability schedule
slotSunday string Sunday availability schedule
pricePerHour number Price per hour (€). Returns 0 if no API key provided.
pricePerHalfDay number Price per half day (€). Returns 0 if no API key provided.
pricePerDay number Price per day (€). Returns 0 if no API key provided.
pricePerMonth string Monthly rental price
image string (URL) Room image URL (via /imageroom endpoint)
organizationId string (Auth only) Organization ID if room is rented
organizationName string (Auth only) Organization name if room is rented
contractEndDate string (Auth only) Contract end date in YYYY-MM-DD format (from room or organization), or empty string if not set

Example Requests

# Filter by English country name
curl -X GET "https://apidev.workways.com/api/rooms?country=Ireland"

# Filter by ISO code
curl -X GET "https://apidev.workways.com/api/rooms?country=FR"

# Filter by specific site
curl -X GET "https://apidev.workways.com/api/rooms?site=507f1f77bcf86cd799439011"

# Combine filters (French name + site)
curl -X GET "https://apidev.workways.com/api/rooms?country=belgique&site=507f1f77bcf86cd799439011"

Example Response

{
  "retcode": 1,
  "message": "OK",
  "data": [
    {
      "_id": "507f191e810c19729de860ea",
      "name": "Meeting Room A",
      "publicName": "Meeting Room A",
      "type": "publicMeeting",
      "description": "Modern meeting room with video conferencing",
      "actualState": "bookable",
      "surface": 25,
      "siteId": "507f1f77bcf86cd799439011",
      "siteName": "Dublin Coworking Center",
      "country": "Ireland",
      "minPerson": 2,
      "maxPerson": 8,
      "nbSeat": 8,
      "configuration": "boardroom",
      "otherConfiguration": "Video conferencing, whiteboard",
      "minDurationBooking": 60,
      "maxDurationBooking": 480,
      "stepDurationBooking": 30,
      "slotWeek": "09:00-18:00",
      "slotSaturday": "",
      "slotSunday": "",
      "pricePerHour": 0,
      "pricePerHalfDay": 0,
      "pricePerDay": 0,
      "pricePerMonth": "500",
      "image": "https://apidev.workways.com/imageroom?id=imageId123"
    }
  ]
}

Example Response (Authenticated - Private Room with Organization)

{
  "retcode": 1,
  "message": "OK",
  "data": [
    {
      "_id": "507f191e810c19729de860ec",
      "name": "Private Office 101",
      "publicName": "Executive Suite",
      "type": "privateOffice",
      "description": "Fully equipped private office",
      "actualState": "rented",
      "surface": 45,
      "siteId": "507f1f77bcf86cd799439011",
      "siteName": "Dublin Coworking Center",
      "country": "Ireland",
      "minPerson": 1,
      "maxPerson": 4,
      "nbSeat": 4,
      "configuration": "office",
      "otherConfiguration": "",
      "minDurationBooking": 0,
      "maxDurationBooking": 0,
      "stepDurationBooking": 0,
      "slotWeek": "",
      "slotSaturday": "",
      "slotSunday": "",
      "pricePerHour": 0,
      "pricePerHalfDay": 0,
      "pricePerDay": 0,
      "pricePerMonth": "1500",
      "image": "https://apidev.workways.com/imageroom?id=imageId456",
      "organizationId": "507f1f77bcf86cd799439099",
      "organizationName": "Acme Corp",
      "contractEndDate": "2025-11-30"
    }
  ]
}
🚀 Try it now!
Leave empty for all countries Leave empty for all sites
Response:

            
GET /api/countries
Get a list of all countries where Workways has public sites. This endpoint is useful for populating country dropdowns and filters.

Query Parameters

This endpoint does not accept any query parameters.

Response Fields

Field Type Description
retcode number 1 for success, -1 for error
message string Response message ("OK" or error message)
data array of strings Alphabetically sorted list of country names (English)

Example Request

curl -X GET "https://apidev.workways.com/api/countries"

Example Response

{
  "retcode": 1,
  "message": "OK",
  "data": [
    "Belgium",
    "France",
    "Ireland"
  ]
}
🚀 Try it now!
Response:

            
GET /api/icsfeed
Get an ICS calendar feed for one or more meeting rooms. This endpoint returns an iCalendar file (.ics) that can be imported into Google Calendar, Outlook, Apple Calendar, and other calendar applications.

Query Parameters

Parameter Type Required Description
rooms string Required Comma-separated list of room IDs (MongoDB ObjectId format). Example: "507f191e810c19729de860ea,507f1f77bcf86cd799439011"

Response Format

Returns an .ics file (iCalendar format) containing all meetings for the specified rooms.

Example Requests

# Single room
curl -X GET "https://apidev.workways.com/api/icsfeed?rooms=507f191e810c19729de860ea"

# Multiple rooms
curl -X GET "https://apidev.workways.com/api/icsfeed?rooms=507f191e810c19729de860ea,507f1f77bcf86cd799439011"

# Download to file
curl -X GET "https://apidev.workways.com/api/icsfeed?rooms=507f191e810c19729de860ea" -o calendar.ics

Example Response

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Workways//Meeting Calendar//EN
CALSCALE:GREGORIAN
BEGIN:VEVENT
UID:meeting123@workways.com
DTSTART:20251030T140000Z
DTEND:20251030T150000Z
SUMMARY:Team Meeting
LOCATION:Meeting Room A
DESCRIPTION:Weekly team sync
END:VEVENT
END:VCALENDAR

Calendar Integration

How to use with calendar applications:
  • Google Calendar: Go to Settings → Add calendar → From URL → Paste the ICS feed URL
  • Outlook: File → Account Settings → Internet Calendars → New → Paste URL
  • Apple Calendar: File → New Calendar Subscription → Paste URL
  • Direct download: Open the URL in a browser to download the .ics file

Error Response

{
  "retcode": -1,
  "message": "Bad request: \"rooms\" query parameter is missing, empty, or contains invalid IDs."
}
POST /api/register
Register a new organization (company) for access to Workways spaces. This is the first step for companies wanting to book meeting rooms or offices.

Request Body

Field Type Required Description
name string Required Company name
firstName string Required Contact first name
lastName string Optional Contact last name
email string Required Contact email (used for billing and notifications)
phone string Required Contact phone number (with country code, e.g., +33612345678)
country string Optional Country code: "fr" (France), "be" (Belgium), or "ie" (Ireland). If not provided, derived from the site.
maxResidentUsers number Required Number of users with site access (minimum: 1)
companyNumber string Optional SIRET (France), KBO (Belgium), or VAT number (Ireland)
address string Optional Company billing address
vatNumber string Optional VAT number (if applicable)
language string Optional Preferred language: "fr" or "en" (default: "en", or "fr" if site country is France)
siteId string Optional ID of the site to link with this registration (MongoDB ObjectId). Highest priority for site determination.
roomId string Optional ID of a room of interest (MongoDB ObjectId). Used to determine the site if siteId is not provided.
meetingId string Optional ID of a pending meeting request to link with this registration (MongoDB ObjectId). Used to determine the site if neither siteId nor roomId are provided.
Site Determination Priority:
  • At least one of siteId, roomId, or meetingId must be provided
  • Priority order: siteIdroomIdmeetingId
  • If multiple parameters point to different sites, all sites are added to the organization's memberOf array in priority order
  • The country is derived from the highest priority site if not explicitly provided

Example Request

curl -X POST "https://apidev.workways.com/api/register" \
  -H "Authorization: Bearer ww_dev_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp",
    "firstName": "Jean",
    "lastName": "Dupont",
    "email": "jean.dupont@acme.com",
    "phone": "+33612345678",
    "maxResidentUsers": 5,
    "companyNumber": "12345678901234",
    "address": "123 rue de la Paix, 75001 Paris, France",
    "vatNumber": "FR12345678901",
    "language": "fr",
    "siteId": "507f1f77bcf86cd799439011",
    "roomId": "507f191e810c19729de860ea"
  }'

Response Scenarios

The response depends on whether the user/organization already exists:

Scenario 1: New Organization Created (CREATED)
{
  "retcode": 200,
  "status": "CREATED",
  "message": "Organization registered successfully. A verification email has been sent.",
  "data": {
    "userId": "507f1f77bcf86cd799439011",
    "userEmail": "jean.dupont@acme.com",
    "userRole": "principal-admin",
    "userCreated": true,
    "organizationId": "507f191e810c19729de860ea",
    "organizationName": "Acme Corp",
    "organizationCreated": true,
    "meetingsUpdated": 1,
    "roomOfInterest": {
      "_id": "507f1f77bcf86cd799439022",
      "name": "Office Premium",
      "siteName": "Workways Paris",
      "siteId": "507f1f77bcf86cd799439033"
    },
    "identityVerification": {
      "source": "insee_siret",
      "confidence": 100,
      "verifiedName": "ACME CORPORATION",
      "verifiedNumber": "12345678901234"
    }
  }
}
Scenario 2: Existing Organization Updated (UPDATED)
{
  "retcode": 200,
  "status": "UPDATED",
  "message": "Registration successful. Your organization has been updated.",
  "data": {
    "userId": "507f1f77bcf86cd799439011",
    "userEmail": "jean.dupont@acme.com",
    "userRole": "principal-admin",
    "userCreated": false,
    "organizationId": "507f191e810c19729de860ea",
    "organizationName": "Acme Corp",
    "organizationCreated": false,
    "meetingsUpdated": 0,
    "roomOfInterest": null,
    "identityVerification": null
  }
}
Scenario 3: User Already Exists with Organization (USER_EXISTS)
{
  "retcode": 200,
  "status": "USER_EXISTS",
  "message": "User already registered with an organization.",
  "data": {
    "userId": "507f1f77bcf86cd799439011",
    "organizationId": "507f191e810c19729de860ea"
  }
}

Response Fields

Field Type Description
retcode number 200 = success, -1 = error
status string CREATED, UPDATED, or USER_EXISTS
message string Human-readable status message
data.organizationId string Always present. The organization ID (existing or newly created). Use this to link further operations.
data.userId string The user ID (existing or newly created)
data.userEmail string The user's email address (CREATED/UPDATED only)
data.userRole string The user's role (typically "principal-admin") (CREATED/UPDATED only)
data.userCreated boolean True if a new user was created, false if existing user was updated (CREATED/UPDATED only)
data.organizationName string The organization's name (CREATED/UPDATED only)
data.organizationCreated boolean True if a new organization was created, false if existing one was used (CREATED/UPDATED only)
data.meetingsUpdated number Number of pending meeting requests linked to the organization (CREATED/UPDATED only)
data.roomOfInterest object|null Information about the room if roomId was provided (CREATED/UPDATED only)
data.identityVerification object|null Company identity verification result if companyNumber was provided (CREATED/UPDATED only)
Important: The organizationId field is always returned in all success scenarios (CREATED, UPDATED, USER_EXISTS). You should store this ID to reference the organization in subsequent API calls or for your own records.

Process Flow

What happens after registration:
  1. You receive a confirmation email with a validation link
  2. Click the link to verify your email and set your password
  3. Your company number (SIRET/KBO/VAT) is verified automatically (if provided)
  4. Once validated, you can access the Workways platform
  5. Your access cards are activated
POST /api/meeting-request
Request a meeting room booking. The behavior depends on whether your email is already registered in the system.

Important Notes

  • Existing users: Bookings are confirmed immediately (status: ACCEPTED)
  • New users: Must complete registration first (status: REQUEST_ACCEPTED)
  • Minimum advance for new users: Bookings must be at least 2 days in advance
  • Existing users: Can book same-day (but not in the past)
  • Archived accounts: Cannot book (status: ARCHIVED)
  • Public rooms only: Only rooms with type "publicOffice" or "publicMeeting" can be booked

Request Body

Field Type Required Description
contactEmail string Required Contact email for this booking
contactName string Optional Contact name
bookedRoom string Required Room ID (MongoDB ObjectId)
bookedAt string Required Start date/time (ISO 8601 format)
duration number Required Duration in minutes (minimum: 30)
bookedUser number Optional Number of attendees (default: 1)
name string Optional Meeting subject/title
description string Optional Meeting description or notes
language string Optional Preferred language for user: "fr" or "en" (default: "en", or "fr" if site country is France). Only used when creating a new temp user.

Example Request

curl -X POST "https://apidev.workways.com/api/meeting-request" \
  -H "Authorization: Bearer ww_dev_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "contactEmail": "jean.dupont@acme.com",
    "contactName": "Jean Dupont",
    "bookedRoom": "507f191e810c19729de860ea",
    "bookedAt": "2025-11-05T14:00:00Z",
    "duration": 60,
    "bookedUser": 4,
    "name": "Quarterly Review",
    "description": "Q4 2025 team meeting"
  }'

Response Scenarios

Scenario 1: Existing User - Booking Accepted
{
  "retcode": 200,
  "status": "ACCEPTED",
  "message": "Your booking has been confirmed.",
  "data": {
    "meetingId": "507f191e810c19729de860ea",
    "roomName": "Meeting Room A",
    "bookedDate": "2025-11-05",
    "bookedTime": "14:00-15:00",
    "duration": 60
  }
}
Scenario 2: New User - Registration Required
{
  "retcode": 200,
  "status": "REQUEST_ACCEPTED",
  "message": "Your meeting request has been received. Please complete your registration to confirm the booking.",
  "data": {
    "meetingRequestId": "507f191e810c19729de860ea",
    "userId": "507f191e810c19729de860eb",
    "roomName": "Meeting Room A",
    "requestedDate": "2025-11-05",
    "requestedTime": "14:00-15:00",
    "duration": 60
  }
}
Linking Meeting to Registration: When you receive a REQUEST_ACCEPTED response, save the meetingRequestId. You can then pass it as the meetingId parameter when calling /api/register to automatically link the meeting to the new organization once registration is complete.
Scenario 3: Archived User Account
{
  "retcode": 200,
  "status": "ARCHIVED",
  "message": "Your account is no longer valid. Please contact an administrator to restore it.",
  "data": null
}

Error Response Examples

// New user: same-day or past date booking attempt
{
  "retcode": -1,
  "message": "Cannot book meetings for today or past dates"
}

// New user: insufficient advance notice
{
  "retcode": -1,
  "message": "Meetings must be booked at least 2 days in advance"
}

// Existing user: past date booking attempt
{
  "retcode": -1,
  "message": "Cannot book meetings for past dates"
}

// Room not public
{
  "retcode": -1,
  "message": "This room is not available for public booking"
}

// Invalid room ID
{
  "retcode": -1,
  "message": "Room not found"
}
GET /api/room-price

Description: Calculate the booking price for a room based on room type, booking parameters, and room state.

🔒 Authentication Required: This endpoint requires an API token. Include it in the Authorization header:
Authorization: Bearer ww_dev_your_token_here

Supported Room Types

Meeting Rooms (hourly/daily pricing):
  • publicMeeting - No state restrictions
  • meeting, privateMeeting, sharedMeeting, conference - Requires defaultState to be bookable or occupied
Office Rooms (weekly/monthly pricing):
  • publicOffice - No state restrictions
  • office, privateOffice, sharedOffice - Requires defaultState to be rented or forrent

Query Parameters

For Meeting Rooms:
Parameter Type Required Description
roomId string ✅ Yes MongoDB ObjectId of the room
startDate string ⚠️ Optional Start date/time in flexible format (e.g., "2025-01-18T10:00:00")
duration number ❌ No Duration in minutes (default: 60)
nbPersons number ❌ No Number of persons (default: 2)
For Office Rooms:
Parameter Type Required Description
roomId string ✅ Yes MongoDB ObjectId of the room
period string ❌ No Rental period: "week" or "month" (default: "month")

Example Requests

Meeting Room Price
curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/room-price?roomId=507f1f77bcf86cd799439011&startDate=2025-01-18T10:00:00&duration=120&nbPersons=4"
Office Room Price
curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/room-price?roomId=507f1f77bcf86cd799439011&period=month"

Success Response Examples

Meeting Room - Price Available
{
  "retcode": 1,
  "message": "OK",
  "data": {
    "roomId": "507f1f77bcf86cd799439011",
    "roomType": "privateMeeting",
    "defaultState": "bookable",
    "actualState": "free",
    "startDate": "2025-01-18T10:00:00",
    "duration": 120,
    "nbPersons": 4,
    "price": 100
  }
}
Office Room - Price Available
{
  "retcode": 1,
  "message": "OK",
  "data": {
    "roomId": "507f1f77bcf86cd799439011",
    "roomType": "privateOffice",
    "defaultState": "rented",
    "actualState": "rented",
    "period": "month",
    "price": 100
  }
}
Room State Not Supported - Price Unavailable
{
  "retcode": -1,
  "message": "Price calculation not available for this room state/type",
  "data": {
    "roomId": "507f1f77bcf86cd799439011",
    "roomType": "meeting",
    "defaultState": "toclean",
    "actualState": "toclean",
    "price": -1
  }
}
⚠️ Price = -1: When price is -1, the price calculation is not available for the room's current state or type. The endpoint still returns 200 OK to allow graceful handling on the client side.

Error Response Examples

// Missing roomId
{
  "retcode": -1,
  "message": "Missing required parameter: roomId"
}

// Invalid roomId format
{
  "retcode": -1,
  "message": "Invalid roomId format"
}

// Room not found
{
  "retcode": -1,
  "message": "Room not found"
}

// Unsupported room type
{
  "retcode": -1,
  "message": "Price calculation not supported for room type: privateAccess"
}

// Invalid period (for offices)
{
  "retcode": -1,
  "message": "Invalid period: must be \"week\" or \"month\""
}

// Invalid duration (for meetings)
{
  "retcode": -1,
  "message": "Invalid duration: must be a positive number"
}

// Unauthorized (no token)
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer "
}

Response Fields

Field Type Description
retcode number 1 = success, -1 = error or price unavailable
message string Human-readable status message
data.roomId string ID of the room
data.roomType string Type of the room (e.g., "publicMeeting", "privateOffice")
data.defaultState string Room's default state (e.g., "bookable", "rented")
data.actualState string Room's current state (e.g., "free", "occupied")
data.price number Calculated price, or -1 if unavailable
data.startDate string (Meetings only) Start date/time if provided
data.duration number (Meetings only) Duration in minutes
data.nbPersons number (Meetings only) Number of persons
data.period string (Offices only) Rental period ("week" or "month")

GET /api/contract-options 🔐 Auth Required

Returns available contract options (additional services) for a specific site. Options are based on Rate records and can include parking, equipment rentals, monthly services, etc.

Query Parameters

Parameter Type Required Description
site string Yes Site ID to filter available options

Example Request

curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/contract-options?site=507f1f77bcf86cd799439011"

Success Response Example

{
  "retcode": 1,
  "message": "OK",
  "data": [
    {
      "_id": "507f1f77bcf86cd799439011",
      "key": "parking",
      "name": "Parking space",
      "nameFr": "Place de Parking",
      "nameEn": "Parking Space",
      "type": "other",
      "isUnique": true,
      "isGeneric": false,
      "supportsQuantity": false,
      "pricing": {
        "publicBase": 150,
        "memberBase": 135,
        "publicPromo": null,
        "memberPromo": null,
        "promoMonthDuration": null,
        "setupFees": 50
      },
      "vat": {
        "type": "standard",
        "rate": null
      }
    },
    {
      "_id": "507f1f77bcf86cd799439022",
      "key": "tv_rental",
      "name": "TV Rental",
      "nameFr": "Location TV",
      "nameEn": "TV Rental",
      "type": "quantity",
      "isUnique": false,
      "isGeneric": true,
      "supportsQuantity": true,
      "pricing": {
        "publicBase": 30,
        "memberBase": 27,
        "publicPromo": null,
        "memberPromo": null,
        "promoMonthDuration": null,
        "setupFees": 0
      },
      "vat": {
        "type": "standard",
        "rate": null
      }
    },
    {
      "_id": "507f1f77bcf86cd799439033",
      "key": "service_by_month",
      "name": "Monthly Service",
      "nameFr": "Service mensuel",
      "nameEn": "Monthly Service",
      "type": "promo",
      "isUnique": false,
      "isGeneric": true,
      "supportsQuantity": false,
      "pricing": {
        "publicBase": 200,
        "memberBase": 180,
        "publicPromo": 150,
        "memberPromo": 135,
        "promoMonthDuration": 3,
        "setupFees": 100
      },
      "vat": {
        "type": "special",
        "rate": 10
      }
    }
  ]
}

Option Types

Category Keys Description
Unique (one per organization) parking, bike_garage, meeting_room_package, food_service, garbage_service, cleaning_service, private_network, private_wifi Can only be subscribed once per organization
Generic (multiple allowed) tv_rental, fridge_rental, phonebooth_rental, appliance_rental, furniture_rental, service_by_month, service_by_month_prepaid Can be subscribed multiple times per organization

Rate Types

Type Description Features
other Standard service Fixed pricing
quote Quote-based service Price determined on request
quantity Quantity-based service Price multiplied by quantity
promo Promotional pricing Discounted price for initial period
promoWithQuantity Promotional + quantity Both promotional pricing and quantity support

Error Response Examples

// Missing site parameter
{
  "retcode": -1,
  "message": "Missing required parameter: site"
}

// Invalid site ID format
{
  "retcode": -1,
  "message": "Invalid site ID format"
}

// Site not found
{
  "retcode": -1,
  "message": "Site not found"
}

// Unauthorized (no token)
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer <your_token>"
}

Response Fields

Field Type Description
_id string Unique rate ID
key string Option identifier key
name string Technical name
nameFr string Translated name in French
nameEn string Translated name in English
type string Rate type (other, quote, quantity, promo, promoWithQuantity)
isUnique boolean True if only one subscription allowed per organization
isGeneric boolean True if multiple subscriptions allowed
supportsQuantity boolean True if the option supports quantity (type = quantity or promoWithQuantity)
pricing.publicBase number Public base price (monthly)
pricing.memberBase number Member base price (monthly)
pricing.publicPromo number|null Public promotional price (if applicable)
pricing.memberPromo number|null Member promotional price (if applicable)
pricing.promoMonthDuration number|null Promotional period duration in months
pricing.setupFees number One-time setup/installation fees
vat.type string VAT type: "standard", "none", or "special"
vat.rate number|null Custom VAT rate (only if type = "special")
💡 Pricing Logic:
  • Member vs Public: Organizations with member status use memberBase/memberPromo prices; others use publicBase/publicPromo
  • Promotional Period: For promo types, the promo price applies for the first N months (defined by promoMonthDuration), then switches to base price
  • Quantity: For quantity-based options, the total price = unit price × quantity

GET /api/user-info 🔐 Auth Required

Returns user information by ID or email address. Useful for retrieving user details and their associated organization.

Query Parameters

Parameter Type Required Description
id string One of id/email required User ID (MongoDB ObjectId). Takes priority if both parameters are provided.
email string One of id/email required User email address (case insensitive)

Example Requests

By User ID
curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/user-info?id=507f1f77bcf86cd799439011"
By Email
curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/user-info?email=jean.dupont@acme.com"

Success Response Example

{
  "retcode": 1,
  "message": "OK",
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "firstName": "Jean",
    "lastName": "Dupont",
    "email": "jean.dupont@acme.com",
    "role": "principal-admin",
    "isUserArchived": false,
    "organizationId": "507f191e810c19729de860ea",
    "organizationName": "Acme Corp",
    "isOrganizationArchived": false
  }
}
User Without Organization
{
  "retcode": 1,
  "message": "OK",
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "firstName": "Marie",
    "lastName": "Martin",
    "email": "marie.martin@example.com",
    "role": "temp",
    "isUserArchived": false,
    "organizationId": null,
    "organizationName": null,
    "isOrganizationArchived": null
  }
}

Error Response Examples

// Missing parameter
{
  "retcode": -1,
  "message": "Missing required parameter: id or email"
}

// Invalid user ID format
{
  "retcode": -1,
  "message": "Invalid user ID format"
}

// Invalid email format
{
  "retcode": -1,
  "message": "Invalid email format"
}

// User not found
{
  "retcode": -1,
  "message": "User not found"
}

// Unauthorized (no token)
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer <your_token>"
}

Response Fields

Field Type Description
_id string Unique user ID
firstName string User's first name
lastName string User's last name (may be empty)
email string User's email address
role string User's role (e.g., "principal-admin", "admin", "user", "temp")
isUserArchived boolean True if the user account is archived
organizationId string|null ID of the user's organization (null if not associated)
organizationName string|null Name of the user's organization (null if not associated)
isOrganizationArchived boolean|null True if the organization is archived (null if no organization)

User Roles

Role Description
principal-admin Primary administrator of an organization (billing contact)
admin Administrator with management privileges
user Standard user with access privileges
temp Temporary user (pending registration completion)

GET /api/organization-info 🔐 Auth Required

Returns detailed organization information including contract details, allocated rooms, accessible sites, contract options, and monthly billing amount.

Query Parameters

Parameter Type Required Description
id string Yes Organization ID (MongoDB ObjectId)

Example Request

curl -H "Authorization: Bearer ww_dev_your_token_here" \
  "https://api.workways.com/api/organization-info?id=507f1f77bcf86cd799439011"

Success Response Example

{
  "retcode": 1,
  "message": "OK",
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "name": "Acme Corp",
    "isArchived": false,
    "contractEndDate": "2025-12-31",
    "renewalMonths": 12,
    "allocatedRooms": [
      {
        "_id": "507f191e810c19729de860ea",
        "name": "Bureau Premium A12",
        "contractEndDate": "2025-12-31",
        "price": 850,
        "siteId": "507f1f77bcf86cd799439022"
      },
      {
        "_id": "507f191e810c19729de860eb",
        "name": "Bureau Standard B05",
        "contractEndDate": "",
        "price": 450,
        "siteId": "507f1f77bcf86cd799439022"
      }
    ],
    "accessibleSites": [
      {
        "_id": "507f1f77bcf86cd799439022",
        "name": "Workways Paris",
        "country": "fr"
      },
      {
        "_id": "507f1f77bcf86cd799439033",
        "name": "Workways Lyon",
        "country": "fr"
      }
    ],
    "basePrice": 1300,
    "contractOptions": [
      {
        "id": 1,
        "name": "Place de parking",
        "key": "parking",
        "quantity": 2,
        "price": 150,
        "pricePromo": null,
        "startDate": "2024-01-01",
        "endDate": ""
      },
      {
        "id": 2,
        "name": "Location TV",
        "key": "tv_rental",
        "quantity": 1,
        "price": 30,
        "pricePromo": null,
        "startDate": "",
        "endDate": ""
      }
    ]
  }
}

Error Response Examples

// Missing parameter
{
  "retcode": -1,
  "message": "Missing required parameter: id"
}

// Invalid organization ID format
{
  "retcode": -1,
  "message": "Invalid organization ID format"
}

// Organization not found
{
  "retcode": -1,
  "message": "Organization not found"
}

// Unauthorized (no token)
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer <your_token>"
}

Response Fields

Field Type Description
_id string Unique organization ID
name string Organization name
isArchived boolean True if the organization is archived
contractEndDate string Contract end date (YYYY-MM-DD format, empty if no end date)
renewalMonths number|null Number of months for automatic contract renewal (null if no auto-renewal)
basePrice number|null Base monthly rental price extracted from rentalPrice field (null if not set)
allocatedRooms array List of rooms allocated to this organization
allocatedRooms[]._id string Room ID
allocatedRooms[].name string Room name
allocatedRooms[].contractEndDate string Room-specific contract end date (YYYY-MM-DD, empty if inherits from organization)
allocatedRooms[].price number|null Monthly rental price for this room
allocatedRooms[].siteId string|null ID of the site where the room is located
accessibleSites array List of sites the organization has access to
accessibleSites[]._id string Site ID
accessibleSites[].name string Site name
accessibleSites[].country string Country code (e.g., "fr", "be", "ie")
contractOptions array List of subscribed contract options
contractOptions[].id number Option ID (unique within the organization)
contractOptions[].name string Option display name
contractOptions[].key string Option key (e.g., "parking", "tv_rental")
contractOptions[].quantity number Quantity subscribed
contractOptions[].price number|null Custom price (null = uses default rate price)
contractOptions[].pricePromo number|null Custom promotional price (null = uses default rate promo)
contractOptions[].startDate string Option start date (YYYY-MM-DD, empty = inherits from organization)
contractOptions[].endDate string Option end date (YYYY-MM-DD, empty = inherits from organization)

POST /api/merge-contract 🔐 Auth Required

Merge/update contract information for an organization. Allows updating rental details, contract options, and room allocations.

Body Parameters (JSON)

Parameter Type Required Description
organizationId string Yes Organization ID (MongoDB ObjectId)
rentalPrice string No Rental price (e.g., "1500€")
rentalComment string No Comment about the rental contract
rentalStartAt string No Contract start date (YYYY-MM-DD format)
rentalEndAt string No Contract end date (YYYY-MM-DD format)
rentalUrl string No URL to Google Drive folder containing client documents
rentalRenewal number No Number of months for automatic renewal
contractOptionsToAdd array No List of contract options to add (see format below)
contractOptionsToRemove array No List of contract option IDs to remove
contractOptions array No Replace all contract options with this list
rooms array No Replace all room allocations with this list of room IDs
roomsToAdd array No List of room IDs to add to the organization
roomsToRemove array No List of room IDs to remove from the organization

Contract Option Format

When adding contract options via contractOptionsToAdd or contractOptions, each option should have:

{
  "optionModelId": "507f1f77bcf86cd799439099", // Required - Option ID from /api/contract-options response
  "key": "parking",           // Option key (e.g., "parking", "tv_rental")
  "name": "Place de parking", // Display name
  "quantity": 2,              // Quantity subscribed
  "price": 150,               // Custom price (optional, -1 = use default rate)
  "pricePromo": -1,           // Custom promo price (optional, -1 = use default)
  "promoMonthDuration": 3,    // Number of months for promo price (optional)
  "startAt": "2024-01-01",    // Option start date (YYYY-MM-DD, optional)
  "endAt": ""                 // Option end date (YYYY-MM-DD, optional, empty = inherits from org)
}

Example Request

curl -X POST \
  -H "Authorization: Bearer ww_dev_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "organizationId": "507f1f77bcf86cd799439011",
    "rentalPrice": "1500€",
    "rentalEndAt": "2025-12-31",
    "rentalRenewal": 12,
    "contractOptionsToAdd": [
      {
        "optionModelId": "507f1f77bcf86cd799439099",
        "key": "parking",
        "name": "Place de parking",
        "quantity": 2,
        "price": 150
      }
    ],
    "roomsToAdd": ["507f191e810c19729de860ea"]
  }' \
  "https://api.workways.com/api/merge-contract"

Success Response Example

{
  "retcode": 1,
  "message": "OK",
  "data": {
    "organizationId": "507f1f77bcf86cd799439011",
    "organizationName": "Acme Corp"
  }
}

Error Response Examples

// Missing required parameter
{
  "retcode": -1,
  "message": "Missing required parameter: organizationId"
}

// Invalid organization ID format
{
  "retcode": -1,
  "message": "Invalid organizationId format"
}

// Organization not found
{
  "retcode": -1,
  "message": "Organization not found"
}

// Unauthorized (no token)
{
  "retcode": -1,
  "message": "Unauthorized: Authorization header is required. Use: Authorization: Bearer <your_token>"
}

Notes

  • Incremental updates: Use contractOptionsToAdd/contractOptionsToRemove and roomsToAdd/roomsToRemove to modify existing lists incrementally.
  • Full replacement: Use contractOptions or rooms to completely replace the existing lists.
  • Dates: All date parameters use YYYY-MM-DD format (e.g., "2025-12-31").

Interactive Demo Application

Try the Workways Public API Demo

Experience the full booking workflow with our interactive demo application. Test all API endpoints in a user-friendly interface.

🚀 Launch Demo App (English) 🚀 Lancer la démo (Français)

Features: Browse sites and rooms, view availability calendars, submit booking requests, register organizations

Booking Workflows

The Workways Public API supports two main booking workflows, with different behavior based on room type and user registration status.

Workflow 1: Meeting Room Booking (publicMeeting)

For rooms with type "publicMeeting"

Step 1: Select a Room and Time Slot

Use the /api/rooms endpoint to find available meeting rooms, then check availability using the /api/icsfeed endpoint to view occupied time slots.

Step 2: Submit Booking Request

POST to /api/meeting-request with room ID, date/time, and contact email.

Step 3: Response Depends on User Status

Scenario A: Existing User (Email Found)
  • Response Status: ACCEPTED
  • Booking State: Confirmed immediately
  • Advance Notice: Can book same-day (but not in the past)
  • Next Step: Booking is confirmed, user receives notification
  • Calendar: Immediately visible in ICS feed
Scenario B: New User (Email Not Found)
  • Response Status: REQUEST_ACCEPTED
  • Booking State: Pending registration
  • Advance Notice: Minimum 2 days in advance
  • Next Step: User must complete registration via /api/register
  • Registration: Includes email validation and password setup
  • Final Confirmation: Booking confirmed after account validation
Scenario C: Archived Account
  • Response Status: ARCHIVED
  • Action Required: Contact administrator to restore account
  • Booking: Not allowed until account is restored

Workflow 2: Office Space Rental (publicOffice)

For rooms with type "publicOffice"

Step 1: Browse Office Spaces

Use the /api/rooms endpoint with type=publicOffice filter to find available office spaces.

Step 2: Direct Registration

Office spaces require a rental contract and cannot be booked via the booking endpoint. Users are directed to the registration form immediately.

Step 3: Submit Organization Registration

POST to /api/register with company details. Include the office space context in the request (optional field or comments).

Step 4: Manual Processing

  • Registration request creates a pending organization
  • User receives email validation link
  • Company number (SIRET/KBO/VAT) is verified if provided
  • Workways team prepares rental contract
  • Once validated, access cards are activated

Note: Office rentals are monthly contracts and require manual approval, unlike meeting rooms which can be instantly booked.

User States and Permissions

User State Same-Day Booking Advance Booking Registration Required
Existing User (Active) ✅ Allowed ✅ No minimum ❌ Not required
New User ❌ Not allowed ✅ Minimum 2 days ✅ Required
Archived User ❌ Not allowed ❌ Not allowed ⚠️ Contact admin

Integration Best Practices

Recommended Implementation Flow:
  1. Room Discovery: Use /api/sites and /api/rooms to list available spaces
  2. Differentiate Room Types: Show different UI for publicMeeting vs publicOffice
    • Meeting rooms → Calendar booking interface
    • Office spaces → Registration/contact form
  3. Check Availability: Use /api/icsfeed to display occupied time slots in your calendar UI
  4. Handle Response Status: Check the status field in responses:
    • ACCEPTED → Booking confirmed, reload calendar
    • REQUEST_ACCEPTED → Redirect to registration form
    • ARCHIVED → Show error message with admin contact
  5. Reload Calendar Feed: After successful booking (ACCEPTED), refresh the ICS feed to show the new occupied slot
  6. Email Validation: Always validate email format before submission
  7. Date Validation: Implement client-side date validation based on user type (if known)

Error Handling

When an error occurs, the API returns a response with retcode: -1 and an appropriate error message.

Error Response Examples

Invalid Country
{
  "retcode": -1,
  "message": "Invalid country: \"XYZ\". Use ISO code (e.g., \"FR\", \"BE\") or country name (e.g., \"France\", \"Belgium\")",
  "data": []
}
Invalid Site ID
{
  "retcode": -1,
  "message": "Invalid site ID format."
}
Internal Server Error
{
  "retcode": -1,
  "message": "Internal server error"
}

Common HTTP Status Codes

HTTP Status Description
200 Success - Request completed successfully
400 Bad Request - Invalid parameters (e.g., invalid country name, invalid site ID format)
401 Unauthorized - Missing, invalid, or revoked API token (POST endpoints only)
500 Internal Server Error - Something went wrong on the server

Integration with Make.com

Make.com (formerly Integromat) allows you to create powerful automation workflows with Workways API without writing code.

Getting Started with Make.com

  1. Create a free account at Make.com
  2. Create a new scenario
  3. Use the HTTP module to call Workways API endpoints

Configuration for Public Endpoints (GET)

For public endpoints (sites, rooms, countries, icsfeed), no authentication is required:

HTTP Module Configuration:
  • Method: GET
  • URL: https://api.workways.com/api/sites
  • Headers: None required

Configuration for Authenticated Endpoints (POST)

For POST endpoints (register, meeting-request, check-email), you must authenticate with your API token:

HTTP Module Configuration:
  • Method: POST
  • URL: https://api.workways.com/api/register
  • Headers:
    • Authorization: Bearer ww_dev_your_token_here
    • Content-Type: application/json
  • Body type: Raw (JSON)
  • Request content: Your JSON data

Example: Register Organization Automation

Scenario: New form submission → Register in Workways → Send confirmation email

1. Trigger: Webhook (receives form data)
2. HTTP Module:
   - Method: POST
   - URL: https://api.workways.com/api/register
   - Headers:
     * Authorization: Bearer ww_dev_xxxxxxxxxx
     * Content-Type: application/json
   - Body:
     {
       "name": "{{trigger.companyName}}",
       "firstName": "{{trigger.firstName}}",
       "lastName": "{{trigger.lastName}}",
       "email": "{{trigger.email}}",
       "phone": "{{trigger.phone}}",
       "country": "{{trigger.country}}",
       "maxResidentUsers": {{trigger.users}}
     }
3. Email Module: Send confirmation with {{response.data.requestId}}

Example: Check Room Availability

Scenario: Daily report of available rooms

1. Schedule: Every day at 8:00 AM
2. HTTP Module (Get Sites):
   - Method: GET
   - URL: https://api.workways.com/api/sites?country=France
3. HTTP Module (Get Rooms):
   - Method: GET
   - URL: https://api.workways.com/api/rooms?site={{site._id}}
4. Google Sheets: Update availability report
💡 Pro Tips for Make.com:
  • Store your API token in Make.com's Data Store for security
  • Use Error Handler to catch 401 errors (invalid/expired tokens)
  • Add Sleep modules between requests to avoid rate limits
  • Use Iterator to process multiple sites/rooms in parallel
  • Enable Data Store to cache API responses and reduce API calls

Use Cases

Integration Examples:
  • Build a public website showing available coworking spaces
  • Create a mobile app for finding meeting rooms
  • Integrate with Make.com or Zapier for automation
  • Export data to Google Sheets or Airtable
  • Build analytics dashboards for space availability

Rate Limits

Currently, there are no enforced rate limits on these public endpoints. However, please be respectful and avoid excessive requests.

Support

If you have questions or need support, please contact: