Factorial Core Employees API

List, read, create, and update employees in the Factorial HR directory. The Core Employees v2 API exposes a clean, non-data-intensive employee record (replacing the legacy v1 shape) plus the /v1/me endpoint for identifying the current OAuth2 token holder. Supports both OAuth2 and x-api-key authentication.

Factorial Core Employees API is one of 22 APIs that Factorial publishes on the APIs.io network, described by a machine-readable OpenAPI specification.

This API exposes 3 machine-runnable capabilities that can be deployed as REST, MCP, or Agent Skill surfaces via Naftiko and 1 JSON Schema definition.

Tagged areas include HR, Employees, and Core. The published artifact set on APIs.io includes API documentation, an OpenAPI specification, a JSON-LD context, sample payloads, 3 Naftiko capability specs, and 1 JSON Schema.

Documentation

Specifications

Examples

Schemas & Data

Other Resources

OpenAPI Specification

factorial-openapi.yml Raw ↑
openapi: 3.0.0
info:
  title: Factorial API
  description: >-
    Open Api Specifications available at
    [https://github.com/factorialco/oas](https://github.com/factorialco/oasLooking)


    Guides and support available at
    [https://help.factorialhr.com/integrations](https://help.factorialhr.com/integrations)


    # Authentication


    The public API provides two methods of authentication, ApiKeys and OAuth2.
    The following sections provide information regarding each one and their
    intent.


    ## OAuth2


    > OAuth2 is used to identify individual users, not applicatins or platforms.


    OAuth2 is available for authenticating to the public API and making requests
    via third parties **on behalf of a user**. All actions are authored on
    behalf of the user that creates the token. This means the intent is to be
    used mainly to do submit actions the actual user is performing on an
    alternative interface.


    To generate a token you will require opening an authorization dialog that
    returns a code, this code can then be exchanged for a token.


    ### Configuration


    In order to create an OAuth application, you must be an admin, head over to
    your [personal repository of OAuth
    applications](https://api.factorialhr.com/oauth/applications), click on `New
    application` and follow the creation process.


    The Factorial API enforces the same permissions at the user level than the
    Factorial web application. This means that Factorial API users will only be
    able to perform the same actions they are allowed to do in the Factorial
    platform.


    Next step will be to generate the Authorization Code you will need in order
    to generate an OAuth2 Token.


    ### OAuth2 Code Generation


    Should be generated via browser by opening the following url. The user
    should be already logged in to Factorial beforehand.


    `https://api.factorialhr.com/oauth/authorize?client_id=&redirect_uri=&response_type=code&scope=`


    YOUR_CLIENT_ID: OAuth2 Application Id

    REDIRECT_URI: OAuth2 Redirect URL


    #### State Parameter


    An optional query parameter called `state` can be added to the code
    generation url. Any string can be used and will be sent on the callback url.


    > Authorization protocols provide a `state` parameter that allows you to
    restore the previous state of your application. The `state` parameter
    preserves some state objects set by the client in the Authorization request
    and makes it available to the client in the response.


    ### OAuth2 Token Generation


    Once you have the authorization code, you can request their access token to
    Factorial.


    `curl -X POST 'https://api.factorialhr.com/oauth/token' -d
    'client_id=&client_secret=&code=&grant_type=authorization_code&redirect_uri='`


    YOUR_CLIENT_ID: OAuth2 Application Id

    YOUR_CLIENT_SECRET: OAuth2 Application Secret

    AUTHORIZATION_CODE: OAuth2 CODE

    REDIRECT_URI: OAuth2 Redirect URL


    > You can generate only one OAuth2 token per Code, that means that if you
    want to generate a new token for a Code that already have one you should
    refresh your token.


    Every time a new token is generated a refresh token is generated as well, so
    that you can use it on the OAuth2 Refresh Token, and an expire date is also
    provided.


    ### OAuth2 Refresh Token


    You can generate a new token under the same Code with a new expire date (you
    can do it as many times as you need). A refresh token is also returned here
    so that you can use it on the OAuth2 Refresh Token again.


    `curl -X POST 'https://api.factorialhr.com/oauth/token' -d
    'client_id=&client_secret=&refresh_token=&grant_type=refresh_token'`


    YOUR_CLIENT_ID: OAuth2 Application Id

    YOUR_CLIENT_SECRET: OAuth2 Application Secret

    REFRESH_TOKEN: OAuth2 Refresh Token


    ### OAuth2 Token Usage


    The generated token is the credential for performing authenticated requests
    to Factorial. This token should be included in the Authorization header
    prefixed with the word Bearer and a separating space.

    As an example, if your token is `12345` then the header content should be
    `Bearer 12345`.


    ### Maintaining a persistent connection


    To maintain a persistent connection, you should not let the token expire.
    You can avoid this by simply refreshing your token before the expiration
    date. This will give you another token with a new expiration date, before
    that token expires you should refresh it again, and so on...

    If you want to do this automatically, you should provide something in your
    code that will help you perform the update every time the token expires.
    Otherwise, you would have to do the update manually and make sure you
    refresh your token before the expiration date to maintain the connection.


    ## ApiKeys


    > API keys are used to identify systems, not the individual users that
    access.


    ApiKeys have **TOTAL ACCESS** to everything and never expire. Its the
    creators responsability to generate them and store them securely.


    ### Generation


    In the `Core>Keys` section of this documentation you can access the apis for
    managing this resource.


    ### Usage


    ApiKeys are a single string of symbols that must be added as a custom header
    on the request. The header name must be `x-api-key` and the key must be the
    value without any prefixes.


    ### Disclaimer


    ApiKey management require full admin permissions as the resource itself
    allows for full admin access to the entire platform on behalf of the company
    and not of a user, therefore any operations are not linked to any user in
    particular.


    # Development


    ## SDKs


    Coming soon


    ## Sandbox


    A sandbox/demo environment is available for testing integrations via public
    API calls. Developers can request provisioning with full access to a demo
    company where to test code before actually interacting with a production
    environment.


    Contact your account manager or account executive to request this
    environment and get OAuth2 credentials for generating tokens.


    Note: the domain for sandbox is different than that from production. Sandbox
    base domain is `http://api.demo.factorialhr.com`


    ## Postman


    Click the "Run in Postman" button to open the full list of endpoints on your
    Postman workspace as a Postman Collection.

    Inside the collection lookout for the Collection's Variables, configure your
    variables accordingly.


    ### Delegating Token Generation To Postman


    Coming soon


    # Changelog


    Coming soon


    # How to...


    ## Custom Fields


    Custom fields are useful when you want to add some fields that are not the
    default ones, to every employee of the company.


    For that, you have to create via Factorial App the base custom field in
    order to have all the employees with it. That option is available in
    customization, inside the company menu


    Once you have that, via API, you can [Create a value for a custom
    field](https://apidoc.factorialhr.com/#72f3f786-e37d-4e80-ada2-0beedd03b171)
    to each employee. You should know the custom field id in order to make that,
    you can check it by [getting a collection of custom
    fields](https://apidoc.factorialhr.com/#f98dae5a-a8d0-474e-a181-7e9603409b42)
  version: 1.0.0
servers:
  - url: "https://api.factorialhr.com/api"
  - url: "https://api.demo.factorialhr.com/api"

security:
  - oauth2: []
  - apikey: []
tags:
  - name: Core
  - name: Core > Employees
    description: "Used for managing employees' information. Only\_`admins`\_can see all the employees' information,\_`regular users`\_will get a restricted version of the payload as a response based on the permission set by the admin"
  - name: Core > Employees > V1
    description: >-
      This version contains employees information and also those that are
      related to the employee such as contracts. So it is data intensive, hard
      to maintain and not very efficient. This is addressed in version
      [V2](https://apidoc.factorialhr.com/#575b6e00-1014-42df-809d-85a683aa4d54)
  - name: Core > Employees > V2
    description: >-
      This version contains strictly employees information. Hence it is not data
      intensive and easy to work with. We recommend using this version as V1
      will be deprecated with time.
  - name: Core > Webhooks
    description: >-
      > ### 📘

      >

      > "Knock knock on X outside Factorial when Y happens inside Factorial"


      > ### 🚧 Usage

      >

      > Webhooks can be used directly or via intermediary platforms or services.
      Using them directly requires technical knowledge.


      ## Factorial Webhooks


      > ### 🚧 URL

      >

      > The same URL can be used to get notifications for all events or
      different ones per event. Notice that if the same url for receiving
      notifications is used for all events, then distinguishing an event from
      another might be an issue.


      When an event happens inside Factorial, a POST request will be triggered
      to the associated event URL. If the request fails for any given reason, a
      retry will be performed shortly after.


      ## Payload


      Payloads per hook vary. The common factor will always be the id field for
      the related resource that triggered the webhook. Implementations should
      avoid relying on other fields.


      ## Webhooks Types


      | **Type** | **Information** |

      | --- | --- |

      | employee_invited | When creating a new employee, optionally you can send
      an invitation to create an account in Factorial. If you send an
      invitation, this event gets triggered. |

      | employee_created | When creating a new employee, after submitting the
      form, this event gets triggered. |

      | employee_terminated | When terminating an employee, after submitting the
      form, this event gets triggered |

      | employee_unterminated | When un terminating an employee, after
      submitting the form, this event gets triggered |

      | attendance_clockin | When the user clocks in and starts the timer, this
      event is triggered. |

      | attendance_clockout | When the user clocks out and stops the timer, this
      event is triggered |

      | ats_application_created | When a candidate applies for a posting. |

      | ats_application_updated | When a candidates application for a posting
      suffers changes. |

      | ats_job_posting_created | When a job posting is created. |

      | ats_job_posting_updated | When a job posting is updated. |

      | ats_job_posting_deleted | When a job posting is deleted. |

      | timeoff_leave_created | When a Timeoff Leave is created. |

      | timeoff_leave_updated | When a Timeoff Leave suffers any changes. |

      | timeoff_leave_approved | When a Timeoff Leave is explicitly approved. |

      | document_created | When a document is created. |
  - name: Core > Custom Fields
  - name: Core > Files
  - name: Core > Files > Documents
    description: >-
      ###### **What does it do?**


      This endpoints will allow you to create, update retrieve or delete
      documents for the company or an employee. You are also going to be able to
      request e-signatures from employees


      ###### **Is it related to other entities?**


      Documents are going to be created under you company, but also can be
      assign to an employee.


      ###### **Who can use it?**


      Only admins are able to create documents.
  - name: Core > Files > Folders
    description: >-
      ###### **What does it do?**


      This endpoints will allow you to create, update or retrieve folders


      ###### **Is it related to other entities?**


      Once you create folder you are going to be able to store documents inside
      them.


      ###### **Who can use it?**


      Everyone can create folders
  - name: Core > Location
  - name: Core > Holidays
  - name: Core > Legal Entities
  - name: Core > Keys
    description: "> API keys are used to identify systems, not the individual users that access.\n\nKeys give total access to the Factorial platform and the operations performed with such are not linked/associated to any user in particular. Therefore their management and storage must be done with extreme caution.\n\nUnlike OAuth2 tokens, Keys dont have a TTL and therefore dont require regenerating the key. As long as the key is not deleted, it will keep working indefinitly.\n\nFor security reasons, when creating a key the code that is generated will only be displayed on the response of the creation. Administrators should copy and safely store such Key as it cant be recovered later. Listing keys will only show a hashed version of the key.\n\n### Usage\n\nApiKeys are a single string of symbols that must be added as a custom header on the request. The header name must be\_`x-api-key`\_and the key must be the value without any prefixes.\n\nIf a request is received with both oauth token and apikey, the api key will overrule the oauth as it has broader permissions.\n\n### Disclaimer\n\nApiKey management require full admin permissions as the resource itself allows for full admin access to the entire platform on behalf of the company and not of a user."
paths:
  /v2/core/employees:
    get:
      tags:
        - Core::Employees::V2
      summary: Get Employees From a Company
      operationId: listEmployees
      description: >-
        Only `admins` can see all the employees' information, `regular users`
        will get a restricted version of the payload as a response based on the
        permission set by the admin
      parameters:
        - name: full_text_name
          in: query
          schema:
            type: string
          description: Retrieves the list of employees by full names
          example: "Bob Stone"
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Employee"
        '500':
          description: Internal Server Error
    post:
      tags:
        - Core::Employees::V2
      summary: Create Employee
      operationId: createEmployee
      description: Create employee
      requestBody:
        content:
          application/json:
            schema:
              type: "object"
              properties:
                email:
                  type: "string"
                  example: "[email protected]"
                first_name:
                  type: "string"
                last_name:
                  type: "string"
                birthday_on:
                  type: "string"
                  example: "yyyy-mm-dd"
                role:
                  type: "string"
                  example: "basic"
                  enum: ["basic", "admin"]
                terminated_on:
                  type: "string"
                  example: "yyyy-mm-dd"
                gender:
                  type: "string"
                  example: "female"
                  enum: ["male", "female"]
                nationality:
                  type: "string"
                bank_number:
                  type: "string"
                country:
                  type: "string"
                city:
                  type: "string"
                state:
                  type: "string"
                postal_code:
                  type: "string"
                address_line_1:
                  type: "string"
                address_line_2:
                  type: "string"
                identifier:
                  type: "string"
                swift_bic:
                  type: "string"
                  example: "1234567890"
                company_id:
                  type: "integer"
                  example: 5
                legal_entity_id:
                  type: "integer"
                  example: 5
                manager_id:
                  type: "integer"
                  example: 5
                timeoff_manager_id:
                  type: "integer"
                  example: 5
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Employee"
        '500':
          description: Internal Server Error
  /v2/core/employees/{id}:
    get:
      tags:
        - Core::Employees::V2
      summary: Get Employee
      operationId: getEmployee
      description: >-
        Only admins can see all the employees' information, regular users will
        get a restricted version of the payload as a response based on the
        permission set by the admin
      parameters:
        - name: id
          in: path
          schema:
            type: string
          required: true
          description: '(Required) '
          example: 5
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Employee"
        '500':
          description: Internal Server Error
    put:
      tags:
        - Core::Employees::V2
      summary: Update Employee
      operationId: updateEmployee
      description: Update employee
      requestBody:
        content:
          application/json:
            schema:
              type: "object"
              properties:
                email:
                  type: "string"
                  example: "[email protected]"
                first_name:
                  type: "string"
                last_name:
                  type: "string"
                birthday_on:
                  type: "string"
                  example: "yyyy-mm-dd"
                role:
                  type: "string"
                  example: "basic"
                  enum: ["basic", "admin"]
                terminated_on:
                  type: "string"
                  example: "yyyy-mm-dd"
                gender:
                  type: "string"
                  example: "female"
                  enum: ["male", "female"]
                nationality:
                  type: "string"
                bank_number:
                  type: "string"
                country:
                  type: "string"
                city:
                  type: "string"
                state:
                  type: "string"
                postal_code:
                  type: "string"
                address_line_1:
                  type: "string"
                address_line_2:
                  type: "string"
                identifier:
                  type: "string"
                swift_bic:
                  type: "string"
                  example: "1234567890"
                manager_id:
                  type: "integer"
                  example: 5
                timeoff_manager_id:
                  type: "integer"
                  example: 5
      parameters:
        - name: id
          in: path
          schema:
            type: string
          required: true
          description: '(Required) '
          example: <integer>
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Employee"
        '500':
          description: Internal Server Error
  /v1/me:
    get:
      tags:
        - Core::Me
      summary: Get Information About Current User
      operationId: getCurrentUser
      description: After token grant, get information of the token holder
      responses:
        '200':
          description: OK
components:
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: "/oauth/authorize"
          tokenUrl: "/oauth/token"
          refreshUrl: "/oauth/token"
          scopes:
            read: Required for all operations
            write: Required for write operations
    apikey:
      type: apiKey
      in: header
      name: x-api-key
  schemas:
    Employee:
      type: "object"
      properties:
        email:
          type: "string"
          example: "[email protected]"
        first_name:
          type: "string"
        last_name:
          type: "string"
        birthday_on:
          type: "string"
          example: "yyyy-mm-dd"
        role:
          type: "string"
          example: "basic"
          enum: ["basic", "admin"]
        terminated_on:
          type: "string"
          example: "yyyy-mm-dd"
        gender:
          type: "string"
          example: "female"
          enum: ["male", "female"]
        nationality:
          type: "string"
        bank_number:
          type: "string"
        country:
          type: "string"
        city:
          type: "string"
        state:
          type: "string"
        postal_code:
          type: "string"
        address_line_1:
          type: "string"
        address_line_2:
          type: "string"
        identifier:
          type: "string"
        swift_bic:
          type: "string"
          example: "1234567890"
        company_id:
          type: "integer"
          example: 5
        legal_entity_id:
          type: "integer"
          example: 5
        manager_id:
          type: "integer"
          example: 5
        timeoff_manager_id:
          type: "integer"
          example: 5