openapi: 3.1.0
info:
    title: Nova Credit Account Monitoring API (Beta)
    description: |
        The Account Monitoring API allows you to periodically refresh a consumer's bank data. Once a consumer grants long-term consent through the NovaConnect widget, use these endpoints to trigger report refreshes and revoke access on their behalf.

        Quick Notes Before Getting Started:

        1. Select the appropriate server for your environment.

        2. Authenticate using a Bearer access token obtained via `GET /connect/accesstoken`.

        3. After a successful refresh, retrieve the updated report using `GET /connect/cash-atlas/v2/json` with the returned `publicToken`.

        4. Account Monitoring must be enabled for your account by a Nova Credit representative before use.

        This feature is currently in Beta.
    termsOfService: https://novacredit.com/terms/
    version: 0.2.0

servers:
    - url: https://api.novacredit.com/connect
      description: 'Production server'
    - url: https://api.sandbox.novacredit.com/connect
      description: 'Sandbox server'

tags:
    - name: Endpoints

paths:
    /cash-atlas/v2/refresh:
        post:
            tags:
                - Endpoints
            summary: Refresh a consumer report
            description: |
                Initiates a report refresh for a consumer. Returns a publicToken that can be used to track and retrieve the report.

                **Prerequisites:**
                - Account Monitoring must be enabled for your account
                - The consumer must have completed the widget flow at least once while Account Monitoring was enabled, to establish consent
                - The consumer's consent must not have expired or been revoked

                If the consumer's access has expired, a RECREDENTIAL_REQUIRED webhook will be sent rather than a synchronous error.
            operationId: refreshConsumerReport
            security:
                - BearerAuth: []
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/RefreshRequest'
                        example:
                            consumerId: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                            productId: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
            responses:
                202:
                    description: 'Refresh initiated.'
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/RefreshSuccess'
                            example:
                                publicToken: '7a3f1c84-92b4-4d7e-a903-1c8e5b6f2d01'
                400:
                    description: 'Bad Request'
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ErrorResponse'
                            example:
                                error: 'MALFORMED_BODY'
                                description: 'Missing, malformed, or unsupported value in the JSON body: consumerId'
                403:
                    description: 'Forbidden'
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/AuthErrorResponse'
                                    - $ref: '#/components/schemas/ErrorResponse'
                            examples:
                                UNAUTHORIZED:
                                    description: 'Invalid or missing access token'
                                    value:
                                        error: 'UNAUTHORIZED'
                                        terminated: 'true'
                                CONSENT_NOT_PROVIDED:
                                    description: 'The consumer did not consent to Account Monitoring functionality'
                                    value:
                                        error: 'CONSENT_NOT_PROVIDED'
                                FEATURE_NOT_ENABLED:
                                    value:
                                        error: 'FEATURE_NOT_ENABLED'
                                        description: 'Account Monitoring is not enabled for this account'
                404:
                    description: 'Not Found'
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/AuthErrorResponse'
                                    - $ref: '#/components/schemas/ErrorResponse'
                            examples:
                                INVALID_CONSUMER_ID:
                                    value:
                                        error: 'INVALID_CONSUMER_ID'
                                        description: 'The consumerId provided is invalid'
                                INVALID_PRODUCT:
                                    description: 'No product found for the provided `productId`, or it does not reference a Cash Atlas v2 product'
                                    value:
                                        error: 'INVALID_PRODUCT'
                                INVALID_TOKEN:
                                    description: 'Malformed access token'
                                    value:
                                        error: 'INVALID_TOKEN'
                                        terminated: 'true'
                500:
                    description: 'Internal Server Error'
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ErrorResponse'
                            example:
                                error: 'INTERNAL_ERROR'

    /consumers/{consumerId}/revoke:
        post:
            tags:
                - Endpoints
            summary: Revoke consumer bank connections
            description: "Revokes access to a consumer's bank connections. A REVOCATION_SUCCEEDED webhook will be sent once revocation completes."
            operationId: revokeConsumerConnections
            security:
                - BasicAuth: []
            parameters:
                - name: consumerId
                  in: path
                  required: true
                  description: "Nova Credit's unique identifier for the consumer."
                  schema:
                      type: string
                      format: uuid
                      minLength: 36
                      maxLength: 36
                      example: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
            responses:
                202:
                    description: 'Revocation initiated successfully.'
                400:
                    description: 'Bad Request'
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ErrorResponse'
                            example:
                                error: 'BAD_REQUEST'
                                description: 'Missing, malformed, or unsupported value in the route parameters: consumerId'
                403:
                    description: 'Forbidden'
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/AuthErrorResponse'
                                    - $ref: '#/components/schemas/ErrorResponse'
                            examples:
                                UNKNOWN_CUSTOMER:
                                    description: 'Invalid or missing credentials'
                                    value:
                                        error: 'UNKNOWN_CUSTOMER'
                                        terminated: 'true'
                                FEATURE_NOT_ENABLED:
                                    value:
                                        error: 'FEATURE_NOT_ENABLED'
                                        description: 'Account Monitoring is not enabled for this account'
                404:
                    description: 'Not Found'
                    content:
                        application/json:
                            schema:
                                oneOf:
                                    - $ref: '#/components/schemas/AuthErrorResponse'
                                    - $ref: '#/components/schemas/ErrorResponse'
                            examples:
                                INVALID_CONSUMER_ID:
                                    value:
                                        error: 'INVALID_CONSUMER_ID'
                                        description: 'The consumerId provided is invalid'
                500:
                    description: 'Internal Server Error'
                    content:
                        application/json:
                            schema:
                                $ref: '#/components/schemas/ErrorResponse'
                            example:
                                error: 'INTERNAL_ERROR'

webhooks:
    CONNECTION_EXPIRING:
        post:
            summary: Connection expiring
            description: |
                Sent proactively when a consumer's consent is approaching expiration. Nova Credit sends this event twice: once 14 days before expiry and once 7 days before expiry. This is driven by Nova Credit's consent window, not by any expirations that might be in place on the financial institution's end.

                Use this event to invite the consumer to complete the NovaConnect widget flow again before the connection lapses, avoiding any interruption to refresh functionality.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/ConnectionExpiringWebhook'
                        example:
                            eventId: 'a7e3b921-5cd8-4f2e-8b03-6d9a0c1e7f45'
                            eventCreatedTime: '2027-03-01T00:00:00.00Z'
                            consumerId: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                            consumerExternalId: '472cbdc9-cf31-4117-a095-e27e2db054e5'
                            eventType: 'CONSUMER_CONNECTION'
                            status: 'CONNECTION_EXPIRING'
                            consentExpiresAt: '2027-04-01T00:00:00.00Z'
            responses:
                '200':
                    description: 'Webhook received successfully.'

    RECREDENTIAL_REQUIRED:
        post:
            summary: Re-credentialing required
            description: |
                Sent when Nova Credit detects that one or more of the consumer's connections are no longer usable — for example, if the consumer revoked access at their financial institution.

                A refreshed report may still be successfully generated if the consumer has additional connections that are still active. The data in the report will be determined based only on the active connections. If there are no active connections, a refreshed report will terminate with a NOT_AUTHENTICATED status.

                The consumer must complete the NovaConnect widget flow again to re-establish their connections.
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/RecredentialRequiredWebhook'
                        example:
                            eventId: '9c4d2a81-1bf3-4e9c-b702-5a6f7c9e0b34'
                            eventCreatedTime: '2026-04-15T09:10:00.00Z'
                            consumerId: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                            consumerExternalId: '472cbdc9-cf31-4117-a095-e27e2db054e5'
                            eventType: 'CONSUMER_CONNECTION'
                            status: 'RECREDENTIAL_REQUIRED'
                            publicToken: '7a3f1c84-92b4-4d7e-a903-1c8e5b6f2d01'
            responses:
                '200':
                    description: 'Webhook received successfully.'

    REVOCATION_FAILED:
        post:
            summary: Revocation failed
            description: "Sent when an attempt to revoke the consumer's connections fails. Nova Credit will retry automatically; this event is sent after each failed attempt."
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/RevocationFailedWebhook'
                        example:
                            eventId: 'c2d4e6f8-1a3b-4c5d-8e9f-0a1b2c3d4e5f'
                            eventCreatedTime: '2026-04-01T15:00:00.00Z'
                            consumerId: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                            consumerExternalId: '472cbdc9-cf31-4117-a095-e27e2db054e5'
                            eventType: 'CONSUMER_CONNECTION'
                            status: 'REVOCATION_FAILED'
                            attemptsRemaining: 2
            responses:
                '200':
                    description: 'Webhook received successfully.'

    REVOCATION_SUCCEEDED:
        post:
            summary: Revocation succeeded
            description: "Sent after the consumer's connections have been successfully revoked."
            requestBody:
                required: true
                content:
                    application/json:
                        schema:
                            $ref: '#/components/schemas/RevocationSucceededWebhook'
                        example:
                            eventId: '3f9a1b72-8de4-4c7a-9f01-2c5e6b8d4a12'
                            eventCreatedTime: '2026-04-01T14:22:00.00Z'
                            consumerId: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                            consumerExternalId: '472cbdc9-cf31-4117-a095-e27e2db054e5'
                            eventType: 'CONSUMER_CONNECTION'
                            status: 'REVOCATION_SUCCEEDED'
            responses:
                '200':
                    description: 'Webhook received successfully.'

components:
    securitySchemes:
        BearerAuth:
            type: http
            scheme: bearer
            description: 'Access token obtained via GET /connect/accesstoken using your API credentials.'
        BasicAuth:
            type: http
            scheme: basic
            description: 'Basic Auth, containing the base-64 encoded string of your client_id:secret_key.'

    schemas:
        RefreshRequest:
            type: object
            properties:
                consumerId:
                    type: string
                    format: uuid
                    minLength: 36
                    maxLength: 36
                    description: "Nova Credit's unique identifier for the consumer (UUID)."
                    example: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                productId:
                    type: string
                    format: uuid
                    minLength: 36
                    maxLength: 36
                    description: 'The Cash Atlas v2 product to generate the report for.'
                    example: 'f47ac10b-58cc-4372-a567-0e02b2c3d479'
            required:
                - consumerId
                - productId

        RefreshSuccess:
            type: object
            properties:
                publicToken:
                    type: string
                    format: uuid
                    minLength: 36
                    maxLength: 36
                    description: 'Public token for this new report, can be used to retrieve the report once completed'
                    example: '7a3f1c84-92b4-4d7e-a903-1c8e5b6f2d01'
            required:
                - publicToken

        WebhookBase:
            type: object
            properties:
                eventId:
                    type: string
                    format: uuid
                    minLength: 36
                    maxLength: 36
                    description: 'Unique ID for this webhook event.'
                    example: '3f9a1b72-8de4-4c7a-9f01-2c5e6b8d4a12'
                eventCreatedTime:
                    type: string
                    format: date-time
                    minLength: 20
                    maxLength: 30
                    description: 'ISO 8601 timestamp of when the event was created.'
                    example: '2026-04-01T14:22:00.00Z'
                consumerId:
                    type: string
                    format: uuid
                    minLength: 36
                    maxLength: 36
                    description: "Nova Credit's unique identifier for the consumer."
                    example: 'b281e335-9d19-4aa7-b559-e74d08a05cf4'
                consumerExternalId:
                    type: string
                    minLength: 1
                    maxLength: 64
                    description: "Your system's identifier for the consumer. Omitted if not set."
                    example: '472cbdc9-cf31-4117-a095-e27e2db054e5'
                eventType:
                    type: string
                    minLength: 1
                    maxLength: 64
                    enum:
                        - CONSUMER_CONNECTION
            required:
                - eventId
                - eventCreatedTime
                - consumerId
                - eventType

        ConnectionExpiringWebhook:
            allOf:
                - $ref: '#/components/schemas/WebhookBase'
                - type: object
                  properties:
                      status:
                          type: string
                          minLength: 1
                          maxLength: 64
                          enum:
                              - CONNECTION_EXPIRING
                  required:
                      - status
                - type: object
                  properties:
                      consentExpiresAt:
                          type: string
                          format: date-time
                          minLength: 20
                          maxLength: 30
                          description: "ISO 8601 timestamp indicating when the consumer's consent will expire."
                          example: '2027-04-01T00:00:00.00Z'
                  required:
                      - consentExpiresAt

        RecredentialRequiredWebhook:
            allOf:
                - $ref: '#/components/schemas/WebhookBase'
                - type: object
                  properties:
                      status:
                          type: string
                          minLength: 1
                          maxLength: 64
                          enum:
                              - RECREDENTIAL_REQUIRED
                  required:
                      - status
                - type: object
                  properties:
                      publicToken:
                          type: string
                          format: uuid
                          minLength: 36
                          maxLength: 36
                          description: 'The public token for the refresh that encountered the authentication failure, if applicable.'
                          example: '7a3f1c84-92b4-4d7e-a903-1c8e5b6f2d01'

        RevocationFailedWebhook:
            allOf:
                - $ref: '#/components/schemas/WebhookBase'
                - type: object
                  properties:
                      status:
                          type: string
                          minLength: 1
                          maxLength: 64
                          enum:
                              - REVOCATION_FAILED
                  required:
                      - status
                - type: object
                  properties:
                      attemptsRemaining:
                          type: integer
                          description: 'Number of retry attempts remaining before revocation gives up.'
                          example: 2
                  required:
                      - attemptsRemaining

        RevocationSucceededWebhook:
            allOf:
                - $ref: '#/components/schemas/WebhookBase'
                - type: object
                  properties:
                      status:
                          type: string
                          minLength: 1
                          maxLength: 64
                          enum:
                              - REVOCATION_SUCCEEDED
                  required:
                      - status

        ErrorResponse:
            title: ErrorResponse
            type: object
            description: 'Returned by route-level errors.'
            properties:
                error:
                    type: string
                    minLength: 1
                    maxLength: 64
                    description: 'A concise code representing the type of error.'
                    example: 'MALFORMED_BODY'
                description:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: 'A detailed description of the error.'
                    example: 'Missing, malformed, or unsupported value in the JSON body: consumerId'
            required:
                - error

        AuthErrorResponse:
            title: AuthErrorResponse
            type: object
            description: 'Returned by authentication errors.'
            properties:
                error:
                    type: string
                    minLength: 1
                    maxLength: 64
                    description: 'A concise code representing the type of error.'
                    example: 'UNAUTHORIZED'
                errorDisplay:
                    type: string
                    minLength: 1
                    maxLength: 255
                    description: 'A detailed description of the error.'
                terminated:
                    type: string
                    enum:
                        - 'true'
                        - 'false'
                    minLength: 4
                    maxLength: 5
                    description: 'Whether the flow was terminated by this error.'
                    example: 'true'
            required:
                - error
                - terminated
