{
  "openapi": "3.1.0",
  "info": {
    "title": "Workant Open API",
    "version": "1.0.0",
    "contact": {
      "name": "Workant",
      "url": "https://workant.io"
    },
    "description": "A **read-only** API for pulling your own Workant data into your own applications.\n\n## Authentication\nEvery request needs an API key sent as a bearer token:\n`Authorization: Bearer wk_...`. Generate keys in Workant under\n**Company Settings → Developers**. Keys are scoped to your company — every\nresponse only ever contains your own data.\n\n## Pagination\nList endpoints take `?page=` (1-indexed) and `?perPage=` (max 100, default\n50) and return a `{ data, meta }` envelope. Invalid values return `400` —\nthere is no silent clamping.\n\n## Rate limits\nUsage is capped per company across rolling **daily / weekly / monthly**\nwindows (UTC). Every response carries `X-RateLimit-*` headers describing the\nmost-constraining window; exceeding a limit returns `429` with `Retry-After`.\n\n## Versioning\nEach area is versioned independently in its path (`/users/v1`). When a new\nmajor version of an area ships, the previous version stays live during a\npublished deprecation window."
  },
  "servers": [
    {
      "url": "https://api.workant.io/public",
      "description": "Production"
    }
  ],
  "tags": [
    {
      "name": "Users",
      "description": "Company users — basic profile and public custom fields."
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/users/v1": {
      "get": {
        "operationId": "listUsersV1",
        "summary": "List users",
        "tags": [
          "Users"
        ],
        "description": "Returns the company's users (basic profile plus any public custom fields), ordered by creation date and paginated.",
        "parameters": [
          {
            "$ref": "#/components/parameters/PageParam"
          },
          {
            "$ref": "#/components/parameters/PerPageParam"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter by lifecycle. Omit to return all users (including archived). `active` = not archived; `archived` = archived.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "archived"
              ]
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Exact, case-insensitive email match.",
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of users.",
            "headers": {
              "X-RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimitLimit"
              },
              "X-RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimitRemaining"
              },
              "X-RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimitReset"
              },
              "X-RateLimit-Window": {
                "$ref": "#/components/headers/RateLimitWindow"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/PublicUser"
                      }
                    },
                    "meta": {
                      "$ref": "#/components/schemas/PaginationMeta"
                    }
                  },
                  "required": [
                    "data",
                    "meta"
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Pass your API key as a bearer token: `Authorization: Bearer wk_...`. Keys are generated in Workant under Company Settings → Developers. A missing, malformed, or revoked key returns 401."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Standard error envelope returned for every 4xx/5xx response.",
        "properties": {
          "message": {
            "type": "string",
            "example": "Invalid API key"
          }
        },
        "required": [
          "message"
        ]
      },
      "PaginationMeta": {
        "type": "object",
        "description": "Pagination metadata returned alongside every list response.",
        "properties": {
          "total": {
            "type": "integer",
            "description": "Total matching records.",
            "example": 137
          },
          "page": {
            "type": "integer",
            "description": "1-indexed current page.",
            "example": 1
          },
          "perPage": {
            "type": "integer",
            "description": "Records per page.",
            "example": 50
          },
          "totalPages": {
            "type": "integer",
            "example": 3
          },
          "hasMore": {
            "type": "boolean",
            "description": "Whether a further page exists.",
            "example": true
          }
        },
        "required": [
          "total",
          "page",
          "perPage",
          "totalPages",
          "hasMore"
        ]
      },
      "CustomField": {
        "type": "object",
        "description": "A company-defined user field flagged for the public API. The full set of public fields is returned for every user; `value` is null when this user has no value for the field.",
        "properties": {
          "field": {
            "type": "string",
            "example": "Department"
          },
          "value": {
            "type": [
              "string",
              "null"
            ],
            "example": "Engineering"
          }
        },
        "required": [
          "field",
          "value"
        ]
      },
      "PublicUser": {
        "type": "object",
        "description": "A company user's public profile.",
        "properties": {
          "id": {
            "type": "string",
            "example": "aWZ6h2k9q1"
          },
          "firstName": {
            "type": [
              "string",
              "null"
            ],
            "example": "Ada"
          },
          "lastName": {
            "type": [
              "string",
              "null"
            ],
            "example": "Lovelace"
          },
          "email": {
            "type": "string",
            "format": "email",
            "example": "ada@example.com"
          },
          "phone": {
            "type": [
              "string",
              "null"
            ],
            "example": "+358401234567"
          },
          "employeeNumber": {
            "type": [
              "string",
              "null"
            ],
            "example": "EMP-0042"
          },
          "dateBirth": {
            "type": [
              "string",
              "null"
            ],
            "format": "date",
            "example": "1990-05-17"
          },
          "companyUserFields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomField"
            }
          }
        },
        "required": [
          "id",
          "firstName",
          "lastName",
          "email",
          "phone",
          "employeeNumber",
          "dateBirth",
          "companyUserFields"
        ]
      }
    },
    "parameters": {
      "PageParam": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "1-indexed page number.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PerPageParam": {
        "name": "perPage",
        "in": "query",
        "required": false,
        "description": "Records per page (max 100).",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 50
        }
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Request quota for the most-constraining window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitRemaining": {
        "description": "Requests remaining in that window.",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitReset": {
        "description": "Unix epoch seconds at which that window resets (UTC).",
        "schema": {
          "type": "integer"
        }
      },
      "RateLimitWindow": {
        "description": "Which window the headers describe.",
        "schema": {
          "type": "string",
          "enum": [
            "daily",
            "weekly",
            "monthly"
          ]
        }
      },
      "RetryAfter": {
        "description": "Seconds to wait before retrying.",
        "schema": {
          "type": "integer"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "A query parameter was invalid (e.g. out of range or non-numeric).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "\"perPage\" must be between 1 and 100"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The API key is missing, malformed, or revoked.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "Invalid API key"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "A rate limit was exceeded: either the per-minute burst guard or a daily/weekly/monthly usage quota. Retry after the window resets.",
        "headers": {
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          },
          "X-RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimitLimit"
          },
          "X-RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimitRemaining"
          },
          "X-RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimitReset"
          },
          "X-RateLimit-Window": {
            "$ref": "#/components/headers/RateLimitWindow"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "message": "Rate limit exceeded — daily quota of 5000 requests reached."
            }
          }
        }
      }
    }
  }
}
