openapi: 3.0.0 info: title: Nectar Public API version: 0.1.0 description: > Welcome to the Nectar Public API. Here you can view and test the provided endpoints before integrating them into your automated systems/tools. After requesting access to the API through support, you can generate your API key from the integrations tab in Nectar. You can access the [Swagger Definition here](/swagger.yaml). ### Authentication All endpoints require an API Key. Be sure to set the `Authorization` header key to `Bearer ` contact: name: Nectar Support url: https://nectarhr.com/contact-us servers: - url: https://api.nectarhr.com description: Nectar API Documentation components: schemas: BaseUser: allOf: - type: object properties: id: type: string email: type: string format: email employee_id: type: string nullable: true first_name: type: string last_name: type: string username: type: string phone_number: type: string example: 123-456-7890 nullable: true department: type: string nullable: true office_location: type: string nullable: true job_title: type: string nullable: true language: type: string nullable: true active: type: boolean invite_email_sent: type: boolean description: >- Indicates whether an invite email was sent for this user during this request. Only present in PUT responses. Returns true when the send_invites query parameter is present and user_invited is true in the request body for this user. - $ref: '#/components/schemas/Links' CompanyRedemptions: type: object properties: data: type: object properties: meta: type: object properties: startDate: type: string format: date endDate: type: string format: date total: type: string financialRedemptionReport: type: array items: type: object properties: gift_card_redemptions: type: string swag_redemptions: type: string amazon_redemptions: type: object properties: US: type: string UK: type: string CA: type: string user: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' CustomAwardsBody: type: object description: >- Request body for sending custom awards. Either `recipientUuids`, `recipientEmails`, or both must be provided. required: - awardUuid properties: awardUuid: type: string description: UUID of the custom award template to send (required) recipientUuids: type: array description: >- Array of recipient user UUIDs. Required if `recipientEmails` is not provided. items: type: string recipientEmails: type: array description: >- Array of recipient user emails. Required if `recipientUuids` is not provided. items: type: string message: type: string description: Optional personal message to include with the award. points: type: number description: Optional point value to include with the award (must be positive). anyOf: - required: - recipientEmails - required: - recipientUuids CustomAwardsResponse: type: object properties: data: type: object properties: awards: type: array items: type: object properties: uuid: type: string name: type: string points: type: number nullable: true message: type: string fixed_points: type: boolean Expand: type: string enum: - user - shoutout ExpandedUser: allOf: - $ref: '#/components/schemas/BaseUser' - type: object properties: user_role: type: string enum: - Administrator - Manager - Employee preferred_name: type: string nullable: true birth_date: type: string nullable: true hire_date: type: string format: date nullable: true inactive_date: type: string format: date nullable: true user_invited: type: boolean user_onboarded: type: boolean manager_email: type: string format: email nullable: true workspaces: type: array items: type: string giveable_points: type: number redeemable_points: type: number logged_in_once: type: boolean custom_properties: type: object additionalProperties: true example: custom_property_1: string FailedResponse: allOf: - $ref: '#/components/schemas/Response' - type: object properties: status: type: string default: failure error: type: object properties: message: type: string code: type: string enum: - N0001 - N0002 - N0003 - N1001 - N1002 - N1003 FlowsTriggerBody: type: object description: Request body for triggering a Flow. Provide either emails or userIds. properties: emails: type: array items: type: string format: email description: List of user emails to enroll in the Flow userIds: type: array items: type: string description: List of user IDs to enroll in the Flow anyOf: - required: - emails - required: - userIds FlowsTriggerResponse: type: object properties: data: type: object properties: flowId: type: string triggerId: type: string enrolledCount: type: number description: Number of users successfully enrolled in the flow enrolledUserIds: type: array items: type: string description: UUIDs of users successfully enrolled skippedCount: type: number description: >- Number of users skipped because they are already enrolled in this flow Links: type: object properties: self: type: string format: uri related: type: array items: type: object properties: type: type: string href: type: string format: uri NectarErrorCodes: oneOf: - type: object properties: N0001: type: string description: Unknown Error - type: object properties: N0002: type: string description: Invalid API Key - type: object properties: N1003: type: string description: Invalid Query Parameters - type: object properties: N1004: type: string description: Invalid Body PageInfo: type: object properties: data: type: object properties: pageInfo: type: object properties: page: type: number pageSize: type: number total: type: number Response: type: object properties: status: type: string enum: - success - failure Shoutout: type: object properties: id: type: string user: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' receivers: type: array items: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' message: type: string amount: type: number core_values: type: array items: type: string created_at: type: string comments: type: array items: type: object properties: id: type: string sender: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' - type: string message: type: string reactions: type: string private: type: boolean image_url: type: string reactions: type: array items: type: object properties: reaction: type: string user: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' scoring_type: type: string enum: - openAI - simple score: type: number action: type: array items: type: string enum: - Admin Added Giveable Points - Admin Added Redeemable Points - Admin Added Swag Points - Anniversary Bonus - Approved Claimable Award - Birthday Bonus - Redeemable to Giveable Point Conversion - Challenge Approved - Community Recognition - Custom Award Redemption - Employee Giveable Point Reset - Employee Giveable Point Top Off - Gave Points - Manager Giveable Point Reset - Manager Giveable Point Top Off - Initial Redeemable Points - Nomination Post - Nomination Response Post - Setup Bonus - Welcome Bonus type: type: string enum: - nomination_post - nomination_response - birthday - anniversary - award - challenge - welcome - setup - shoutout - community_recognition ShoutoutsResponse: type: object properties: data: type: object properties: meta: type: object properties: total: type: integer start_date: type: string format: date-time end_date: type: string format: date-time cursor: type: number nullable: true feed: type: array items: $ref: '#/components/schemas/Shoutout' SuccessfulResponse: allOf: - $ref: '#/components/schemas/Response' - type: object properties: status: type: string enum: - success links: $ref: '#/components/schemas/Links' UserDetailsResponse: type: object properties: data: type: object properties: user: allOf: - anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' UserUpsertBody: type: object properties: email: type: string format: email nectar_id: type: string first_name: type: string last_name: type: string employee_id: type: string department: type: string nullable: true office_location: type: string nullable: true job_title: type: string nullable: true active: type: boolean phone_number: type: string example: 123-456-7890 nullable: true inactive_date: type: string format: date nullable: true hire_date: type: string format: date nullable: true birth_date: type: string format: date nullable: true preferred_name: type: string nullable: true manager_email: type: string format: email nullable: true language: type: string nullable: true role: type: string enum: - Administrator - Manager - Employee description: >- Nectar platform permission role. This controls access permissions within Nectar, not the user's company or HRIS role. Administrator: full admin access (also grants Manager permissions). Manager: receives a manager-level point allowance and can access analytics for direct reports. Employee: standard user with an employee-level point allowance. Warning: sending this field on an update will overwrite the user's existing role. Omit this field to preserve the current role. custom_properties: type: object additionalProperties: true example: custom_property_1: string custom_property_2: 1 custom_property_3: true custom_property_4: null user_invited: type: boolean description: >- Set to true to mark the user as invited. Can only be set to true (setting to false will return an error). When combined with the send_invites query parameter, an invite email will be sent to the user. Without send_invites, the user will be marked as invited in the database but no email will be sent. UserUpsertRequestBody: type: array items: $ref: '#/components/schemas/UserUpsertBody' UsersResponse: type: object properties: data: type: object properties: total: type: integer users: type: array items: anyOf: - $ref: '#/components/schemas/BaseUser' - $ref: '#/components/schemas/ExpandedUser' warnings: type: array description: >- Non-fatal issues detected while processing the request (e.g., duplicate email, employee_id, or phone_number values within the batch). The request still succeeds, but affected users may have been skipped or had fields stripped. Review these to reconcile your source data. items: type: string responses: BadRequest: description: >- `BAD REQUEST`: Body or Query Params are malformed (missing, extra, or invalid values) content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: Bad Request code: N0003 Unauthorized: description: '`UNAUTHORIZED`: Request was sent with an expired or missing API Key' content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: UNAUTHORIZED code: N0002 Forbidden: description: >- `FORBIDDEN`: Request was authenticated but the resource requested is missing or not accessible with that key content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: UNAUTHORIZED code: N0002 NotFound: description: '`NOT FOUND`: The requested resource was not found' content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: Not Found code: N0005 TooManyRequests: description: '`TOO MANY REQUESTS`: Company is being rate limited' content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: TOO MANY REQUESTS code: N0000 InternalServerError: description: >- `INTERNAL SERVER ERROR`: Request was unable to be processed due to a server error. Contact our support team. content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: Bad Request code: N0001 NotImplemented: description: '`NOT IMPLEMENTED`: Method is not implemented on that endpoint.' content: application/json: schema: $ref: '#/components/schemas/FailedResponse' examples: body: value: status: failure error: message: Bad Request code: N0000 securitySchemes: BearerAuth: type: http scheme: bearer bearerFormat: JWT security: - BearerAuth: [] paths: /v1/analytics/financial/redemptions: get: summary: Generates a summary of redemptions made by all users. description: |- Date rules: All requests will include the applied start and end date. security: - BearerAuth: [] responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/CompanyRedemptions' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' parameters: - name: expand in: query schema: type: array items: type: string enum: - user explode: false style: form description: Return each users' expanded data - name: sort in: query schema: type: string enum: - gift_card_redemptions - swag_redemptions - amazon_us - amazon_uk - amazon_ca description: Sorts output by specified value in descending order. - name: start-date in: query schema: type: string format: date description: |- Start Date of range to get data from as defined by RFC 3339, section 5.6, for example, 2017-07-21. - name: end-date in: query schema: type: string format: date description: |- End Date of range to get data from as defined by RFC 3339, section 5.6, for example, 2017-07-21. If defined, start-date is required. /v1/custom-awards: get: summary: Gets custom awards description: Returns a page (default 25) of custom awards security: - BearerAuth: [] parameters: - name: page in: query description: The page number schema: type: number default: 1 - name: automationEnabled in: query description: Only fetch awards that are enabled for automation schema: type: boolean default: false - name: allTime in: query description: >- Gets all time data with no pagination. Only keys with the `INTEGRATION` scope can use this. schema: type: boolean default: false responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/CustomAwardsResponse' - $ref: '#/components/schemas/PageInfo' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' /v1/custom-awards/send: post: summary: Sends a custom award to recipients description: | Sends a custom award to one or more recipients within the company. Awards can include optional messages and point values. All recipients must be valid user UUIDs within the organization. security: - BearerAuth: [] requestBody: description: >- The request body requires `awardUuid` and either `recipientUuids` or `recipientEmails` to be provided, but not both. required: true content: application/json: schema: $ref: '#/components/schemas/CustomAwardsBody' responses: '200': description: Custom award sent successfully content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' /v1/flows/trigger/{triggerId}: post: summary: Trigger a Flow for specified users description: | Enrolls users in a Flow via an API trigger. Users can be identified by email or userId. All specified users must be valid members of the company associated with the API key. If any users are not found, the request will fail without enrolling any users. tags: - Flows security: - BearerAuth: [] parameters: - name: triggerId in: path required: true description: The ID of the API trigger to invoke schema: type: string requestBody: description: | Provide either `emails` or `userIds` (not both). The trigger must be a PAPI or INTEGRATION trigger type. INTEGRATION triggers require an API key with the INTEGRATION permission. The Flow is resolved automatically from the trigger. required: true content: application/json: schema: $ref: '#/components/schemas/FlowsTriggerBody' responses: '200': description: Users enrolled successfully content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/FlowsTriggerResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' /health: get: summary: Health security: [] responses: '200': description: OK /v1/recognition/feed: get: summary: Gets the companies recognition feed security: - BearerAuth: [] responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/ShoutoutsResponse' text/csv: schema: type: string '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' parameters: - name: type in: query schema: type: array items: type: string enum: - nomination_post - nomination_response - birthday - anniversary - award - challenge - welcome - setup - shoutout explode: false style: form description: Type of post - name: private in: query schema: type: boolean - name: hidden_from_leaderboard in: query schema: type: boolean - name: deleted in: query schema: type: boolean default: false - name: minify in: query schema: type: boolean default: false description: Get only minified user data. Only for 'text/csv' format - name: expand in: query schema: type: array items: type: string enum: - user explode: false style: form description: Return each users' expanded data - name: cursor in: query schema: type: number description: Unix timestamp for next date range of feed entries - name: start-date in: query schema: type: string format: date description: |- Start Date of range to get data from as defined by RFC 3339, section 5.6, for example, 2017-07-21. - name: end-date in: query schema: type: string format: date description: |- End Date of range to get data from as defined by RFC 3339, section 5.6, for example, 2017-07-21. If defined, start-date is required. - name: all_time in: query schema: type: boolean description: >- Gets all time data with no pagination. Only keys with the `AI_INSIGHT` scope can use this. /v1/users/{userId}: get: summary: Gets general information about a specific user security: - BearerAuth: [] responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/UserDetailsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' parameters: - name: expand in: query schema: type: array items: type: string enum: - user explode: false style: form description: Return each users' expanded data - name: userId in: path required: true schema: type: string description: The id of the user to fetch data for /v1/users: get: summary: Gets a paginated list of users within the company security: - BearerAuth: [] responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/UsersResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' parameters: - name: expand in: query schema: type: array items: type: string enum: - user explode: false style: form description: Return each users' expanded data - name: active in: query schema: type: boolean - name: invited in: query schema: type: boolean - name: email in: query schema: type: string - name: employee_id in: query schema: type: string - name: cursor in: query schema: type: string - name: limit in: query schema: type: number put: summary: >- Upsert up to 50 users at a time based on nectar_id (recommended), email, or employee_id description: > Creates or updates users. Supports inviting users via the `user_invited` field and `send_invites` query parameter. **Invite behavior:** - Setting `user_invited: true` on a user in the request body will mark that user as invited in the database. - Invite emails are **only sent** when `send_invites=true` is passed as a query parameter. - When `send_invites=true`, invite emails are sent to all users that have `user_invited: true` **in the current request body**, including users that were already invited previously. - When `send_invites=false` or omitted, `user_invited: true` still updates the database, but no emails are sent. - `user_invited` can only be set to `true`. Setting it to `false` is not allowed and will return an error. - The response includes an `invite_email_sent` field for each user indicating whether an invite email was sent during this request. **Duplicate identifiers:** - When multiple users in the request share the same `email`, `employee_id`, or `phone_number`, the request still returns 200 but the response `warnings` array describes which duplicates were detected and how they were handled. - Duplicate `email` or `employee_id`: all users sharing that value are skipped (not created or updated). - Duplicate `phone_number`: if the user has another identifier (email, employee_id, nectar_id), the phone number is stripped and the user is still processed; otherwise the user is skipped. - Callers should inspect `warnings` after every upsert to reconcile their source data. security: - BearerAuth: [] responses: '200': description: OK content: application/json: schema: allOf: - $ref: '#/components/schemas/SuccessfulResponse' - $ref: '#/components/schemas/UsersResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '429': $ref: '#/components/responses/TooManyRequests' '500': $ref: '#/components/responses/InternalServerError' '501': $ref: '#/components/responses/NotImplemented' parameters: - name: expand in: query schema: type: array items: type: string enum: - user explode: false style: form description: Returns the created/updated users base or expanded data - name: lookup_keys in: query schema: type: array items: type: string enum: - nectar_id - email - employee_id explode: false style: form description: >- The keys to use to lookup users. If none are provided, defaults to the behavior below. - name: send_invites in: query schema: type: boolean description: > When set to `true`, invite emails will be sent to all users with `user_invited: true` in the request body, including users that were already invited previously. When set to `false` or omitted, `user_invited: true` will still update the user in the database but no invite emails will be sent. requestBody: description: >- Specifying `nectar_id` allows a request to update both `employee_id` and `email` in the same request. If `nectar_id` is not provided, matches on `employee_id`, then `email`, if neither are found, creates a new user.

Passing `null` for a custom property will remove the user from that property. required: true content: application/json: schema: $ref: '#/components/schemas/UserUpsertRequestBody' tags: []