> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowpayroll.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Send the pay run to the connected pension providers

> Submits enrolments and the contribution schedule to each connected scheme in the pay run. Completing a pay run produces the export files and stops there, so a submission only happens when you ask for one. Pass schemeId to send a single scheme, and operationType (pension.members.enrol or pension.contributions.submit) to send just that part, which is how a part that did not land is sent again on its own. With both parts, enrolments go first, because a member the provider has never seen cannot appear on a contribution schedule. Read schemes in the response to find out what the send decided, scheme by scheme: Submitted, Skipped (not connected, or nothing outstanding), Blocked (the connection needs finishing or repairing) or Failed, each with a reason token. Do not read an empty submissions list as success. Submission is asynchronous, so submissions carries the ledger as it stands now; read the pay run's submissions to follow them. Sending the same unchanged data twice is deduplicated rather than submitted again. Naming a schemeId the pay run does not hold answers 404. Answers 409 while the pay run is still calculating: the schedule is built from the run's contributions, not from the export files, so sending early would put a schedule short of members in front of the provider. The request is unchanged - retry once the run has finished.



## OpenAPI

````yaml /api-reference/specs/pension-v2.json post /provider-sync/{payrollConfigId}/{year}/{frequency}/{period}/send
openapi: 3.0.4
info:
  title: FlowPayroll Pension API
  version: v2
servers:
  - url: https://api.sandbox.flowpayroll.ai/v2/pension
security: []
tags:
  - name: Pension providers
    description: >-
      Look up the pension providers available to your organisation. Providers
      are set up in the product, so the API exposes them read-only.
  - name: Pension schemes
    description: >-
      Your organisation's arrangements with providers. Scheme endpoints use the
      /pension-schema path.
  - name: Pension groups
    description: >-
      Contribution rule sets within a scheme: pension type, contribution basis,
      and employee and employer factors.
  - name: Employee enrolment
    description: >-
      Associate employees with pension groups, remove associations, and send
      enrolment letters.
  - name: Pension information
    description: >-
      An employee's full pension picture in one call: composition, latest
      assessment, and postponement.
  - name: Auto-enrolment
    description: >-
      Assessment results per pay run, employees with outstanding or no
      auto-enrolment, and a stateless assessment preview.
  - name: Postponement
    description: Defer auto-enrolment per employee, overriding the organisation defaults.
  - name: Organisation defaults
    description: >-
      The organisation's default pension group, postponement definitions, and
      auto-enrolment mode.
  - name: Pension calculations
    description: >-
      Per-period contribution amounts, the contributions CSV, and provider
      export files.
  - name: Provider submissions
    description: >-
      Send a completed pay run to its connected pension provider, approve the
      payment, and read back what the provider reported: opt-outs, stopped
      contributions, refunds and schedules.
paths:
  /provider-sync/{payrollConfigId}/{year}/{frequency}/{period}/send:
    post:
      tags:
        - Provider submissions
      summary: Send the pay run to the connected pension providers
      description: >-
        Submits enrolments and the contribution schedule to each connected
        scheme in the pay run. Completing a pay run produces the export files
        and stops there, so a submission only happens when you ask for one. Pass
        schemeId to send a single scheme, and operationType
        (pension.members.enrol or pension.contributions.submit) to send just
        that part, which is how a part that did not land is sent again on its
        own. With both parts, enrolments go first, because a member the provider
        has never seen cannot appear on a contribution schedule. Read schemes in
        the response to find out what the send decided, scheme by scheme:
        Submitted, Skipped (not connected, or nothing outstanding), Blocked (the
        connection needs finishing or repairing) or Failed, each with a reason
        token. Do not read an empty submissions list as success. Submission is
        asynchronous, so submissions carries the ledger as it stands now; read
        the pay run's submissions to follow them. Sending the same unchanged
        data twice is deduplicated rather than submitted again. Naming a
        schemeId the pay run does not hold answers 404. Answers 409 while the
        pay run is still calculating: the schedule is built from the run's
        contributions, not from the export files, so sending early would put a
        schedule short of members in front of the provider. The request is
        unchanged - retry once the run has finished.
      operationId: PostPayRunSendToProvider
      parameters:
        - name: payrollConfigId
          in: path
          required: true
          schema:
            type: string
        - name: year
          in: path
          required: true
          schema:
            type: integer
            format: int32
        - name: frequency
          in: path
          required: true
          schema:
            type: string
        - name: period
          in: path
          required: true
          schema:
            type: integer
            format: int32
        - name: schemeId
          in: query
          schema:
            type: string
        - name: operationType
          in: query
          schema:
            type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendToProviderResultV2ResponseBody'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '409':
          description: Conflict
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponseBody'
components:
  schemas:
    SendToProviderResultV2ResponseBody:
      required:
        - message
      type: object
      properties:
        message:
          $ref: '#/components/schemas/MessageWithTokenResponse'
        content:
          $ref: '#/components/schemas/SendToProviderResultV2ContentResponse'
        validationIssues:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssue'
          nullable: true
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
          description: >-
            Deprecated: the same issues as `validationIssues` (`reasonText` is
            `reason`, `reasonId` is `reasonToken`, `reasonParameters` is
            `reasonTokenArguments`). Read `validationIssues`; this will be
            removed.
          nullable: true
          readOnly: true
          deprecated: true
        metadata:
          allOf:
            - $ref: '#/components/schemas/ContentMetadataResponse'
          description: >-
            Deprecated: the same values as `content.metadata`. Read that; this
            will be removed.
          deprecated: true
      additionalProperties: false
      description: >-
        The response envelope every FlowPayroll API answers with: a `message`,
        the

        `content`, and any `validationIssues`. `errors` and the top-level

        `metadata` are deprecated copies of `validationIssues` and

        `content.metadata`, and will be removed.
    ObjectResponseBody:
      required:
        - message
      type: object
      properties:
        message:
          $ref: '#/components/schemas/MessageWithTokenResponse'
        content:
          $ref: '#/components/schemas/ObjectContentResponse'
        validationIssues:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssue'
          nullable: true
        errors:
          type: array
          items:
            $ref: '#/components/schemas/Error'
          description: >-
            Deprecated: the same issues as `validationIssues` (`reasonText` is
            `reason`, `reasonId` is `reasonToken`, `reasonParameters` is
            `reasonTokenArguments`). Read `validationIssues`; this will be
            removed.
          nullable: true
          readOnly: true
          deprecated: true
        metadata:
          allOf:
            - $ref: '#/components/schemas/ContentMetadataResponse'
          description: >-
            Deprecated: the same values as `content.metadata`. Read that; this
            will be removed.
          deprecated: true
      additionalProperties: false
      description: >-
        The response envelope every FlowPayroll API answers with: a `message`,
        the

        `content`, and any `validationIssues`. `errors` and the top-level

        `metadata` are deprecated copies of `validationIssues` and

        `content.metadata`, and will be removed.
    MessageWithTokenResponse:
      required:
        - token
      type: object
      properties:
        text:
          type: string
          nullable: true
        token:
          type: string
          description: >-
            Stable snake_case key for the message, for clients that translate
            it.
          nullable: true
        tokenArguments:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssueArgument'
          nullable: true
        textId:
          type: string
          description: >-
            Deprecated: the same value as `token`. Read that; this will be
            removed.
          nullable: true
          readOnly: true
          deprecated: true
        textParameters:
          type: array
          items:
            $ref: '#/components/schemas/Pair'
          description: >-
            Deprecated: the same values as `tokenArguments`. Read that; this
            will be removed.
          nullable: true
          readOnly: true
          deprecated: true
      additionalProperties: false
      description: >-
        What happened, as English `text` and a stable `token` to translate from.

        `textId` and `textParameters` are deprecated copies of `token` and
        `tokenArguments`.
    SendToProviderResultV2ContentResponse:
      type: object
      properties:
        data:
          $ref: '#/components/schemas/SendToProviderResultV2'
        metadata:
          $ref: '#/components/schemas/ContentMetadataResponse'
      additionalProperties: false
    ValidationIssue:
      type: object
      properties:
        field:
          type: string
          nullable: true
        reason:
          type: string
          nullable: true
        reasonToken:
          type: string
          nullable: true
        reasonTokenArguments:
          type: array
          items:
            $ref: '#/components/schemas/ValidationIssueArgument'
          nullable: true
      additionalProperties: false
    Error:
      type: object
      properties:
        field:
          type: string
          nullable: true
        reasonText:
          type: string
          nullable: true
        reasonId:
          type: string
          nullable: true
        reasonParameters:
          type: array
          items:
            $ref: '#/components/schemas/Pair'
          nullable: true
      additionalProperties: false
      description: >-
        Deprecated: an entry of the old `errors` list. Read `validationIssues`
        instead.
      deprecated: true
    ContentMetadataResponse:
      type: object
      properties:
        dateFormat:
          type: string
          nullable: true
        dateTimeFormat:
          type: string
          nullable: true
        paginationToken:
          type: string
          nullable: true
      additionalProperties: false
    ObjectContentResponse:
      type: object
      properties:
        data:
          nullable: true
        metadata:
          $ref: '#/components/schemas/ContentMetadataResponse'
      additionalProperties: false
    ValidationIssueArgument:
      type: object
      properties:
        name:
          type: string
          nullable: true
        value:
          nullable: true
      additionalProperties: false
    Pair:
      type: object
      properties:
        key:
          type: string
          nullable: true
        value:
          type: string
          nullable: true
      additionalProperties: false
      description: >-
        Deprecated: a key and value of the old `textParameters` and
        `reasonParameters`.
      deprecated: true
    SendToProviderResultV2:
      required:
        - schemes
        - submissions
      type: object
      properties:
        schemes:
          type: array
          items:
            $ref: '#/components/schemas/SchemeSendOutcomeV2'
          nullable: true
        submissions:
          type: array
          items:
            $ref: '#/components/schemas/ProviderSyncRecordV2'
          nullable: true
      additionalProperties: false
      description: |-
        The answer to a send: what it decided for every scheme in the pay run,
        and the submissions the ledger now holds.
    SchemeSendOutcomeV2:
      required:
        - schemeId
        - schemeName
        - status
      type: object
      properties:
        schemeId:
          type: string
          nullable: true
        schemeName:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/SchemeSendStatusV2'
        providerSlug:
          type: string
          description: The connected provider, or null when the scheme has no connection.
          nullable: true
        connectionId:
          type: string
          nullable: true
        reasonToken:
          type: string
          description: |-
            Stable, provider-agnostic reason nothing was sent, or null when
            something was. Branch on this; use it as the i18n lookup key, and
            treat an unrecognised value as a generic reason, because the list
            grows.
          nullable: true
        reasonMessage:
          type: string
          description: |-
            Default English for reasonToken, safe to show a user as-is.
            Wording may change between releases; the token will not.
          nullable: true
      additionalProperties: false
      description: What a send did for one scheme in the pay run.
    ProviderSyncRecordV2:
      required:
        - createdBy
        - createdDate
        - operationType
        - providerSlug
        - schemeId
        - status
        - updatedBy
        - updatedDate
      type: object
      properties:
        schemeId:
          type: string
          nullable: true
        operationType:
          type: string
          nullable: true
        operationId:
          type: string
          nullable: true
        providerSlug:
          type: string
          nullable: true
        status:
          $ref: '#/components/schemas/ProviderSyncStatusV2'
        providerReference:
          type: string
          description: |-
            The provider's own reference for what it created, once it has
            one. Use it to reconcile against the provider's records.
          nullable: true
        errorToken:
          type: string
          description: |-
            Stable, provider-agnostic reason code the submission did not land.
            Branch on this, and use it as the i18n lookup key; treat an
            unrecognised value as a generic failure, because the list grows.
          nullable: true
        errorMessage:
          type: string
          description: |-
            Default English for errorToken, safe to show a user as-is.
            Wording may change between releases; the token will not.
          nullable: true
        notResentToken:
          type: string
          description: |-
            Stable reason code saying that the last send did not reach the
            provider because an identical submission was already there. Null
            whenever something was actually sent.
                        

            Not a failure: `status` still describes the submission the
            provider holds. Show it, or a repeated send looks like a dead
            button.
          nullable: true
        notResentMessage:
          type: string
          description: Default English for notResentToken, safe to show a user as-is.
          nullable: true
        issues:
          type: array
          items:
            $ref: '#/components/schemas/ProviderSyncIssueV2'
          description: >-
            What the provider itself said it would not accept, record by record.

            The error token says the submission was refused; this says which

            details to change, so nothing has to be inferred from the file.

            Carries the first page; read issueCount for the total the provider

            reported, and the provider-sync issues endpoint for every one of
            them.
          nullable: true
        issueCount:
          type: integer
          description: |-
            How many issues the provider reported in total. Greater than the
            number in issues when the provider refused more records than this
            record carries.
          format: int32
          nullable: true
        memberCount:
          type: integer
          format: int32
        totalAmount:
          type: number
          format: double
        createdBy:
          type: string
          description: |-
            Who started this submission, and when. Nothing is sent to a pension
            provider on its own, so every record names the person who sent it;
            a submission made before the platform recorded this reads "System".
          nullable: true
        createdDate:
          type: string
          format: date-time
        updatedBy:
          type: string
          description: |-
            Who last changed it. "System" once the provider has answered, since
            that is the provider's own reply rather than somebody's action.
          nullable: true
        updatedDate:
          type: string
          description: |-
            When the provider answered (UTC), on a settled submission — the
            provider's own moment, not when this service recorded it, so it
            is safe to reconcile against the provider's records and does not
            move with our queue timings.
          format: date-time
      additionalProperties: false
    SchemeSendStatusV2:
      enum:
        - Submitted
        - Skipped
        - Blocked
        - Failed
      type: string
      description: What a send did for one scheme.
    ProviderSyncStatusV2:
      enum:
        - Pending
        - AwaitingProvider
        - Succeeded
        - Failed
        - NeedsAttention
        - Cancelled
        - SubmitFailed
      type: string
      description: Where a submission to a pension provider has got to.
    ProviderSyncIssueV2:
      required:
        - message
      type: object
      properties:
        reference:
          type: string
          description: |-
            The identifier the submission sent for the record concerned, so it
            can be matched back to a person. Absent when the provider refused
            the submission as a whole rather than one of its records.
          nullable: true
        referenceLabel:
          type: string
          description: |-
            Who that reference is, resolved from the pay run: show this rather
            than the raw reference. Absent when the reference matches nobody in
            the run, or when the provider refused the submission as a whole.
          nullable: true
        employeeId:
          type: string
          description: >-
            The employee this refusal is about, as their own id. The reference
            is

            whatever identifier the scheme sends the provider (a payroll id,
            say),

            which is not something a caller can look an employee up by, so the

            link to the person is carried rather than inferred from it.
          nullable: true
        code:
          type: string
          description: The provider's own error code, for support and audit.
          nullable: true
        message:
          type: string
          description: The provider's own wording. Safe to show a user as-is.
          nullable: true
        noActionNeeded:
          type: boolean
          description: >-
            True when the provider is confirming this record already holds what

            the submission asked for, rather than refusing it: a worker an

            earlier send already enrolled, which is what a re-sent batch looks

            like from the provider's side.
                        

            Show these, so what is on screen matches the provider's own

            answer, but apart from the ones somebody has to act on and never as

            a reason the submission failed. A record with `Status``Succeeded`
            can still carry them.
      additionalProperties: false
      description: One thing the pension provider refused.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.