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

# Get a scoring

> Returns the saved scoring: property context, status and candidatures.

**Property context.** `postalCode` and `monthlyPaymentAmountInEuros` are fixed at creation.

**Members.** Each member echoes the declaration from create or update. `personalId` and `workingStatus` are always present in the response and are `null` when omitted or explicitly set to `null` in the request. Employed and retired members include `netAnnualIncomeAmountInEuros`. Self-employed members include `form100` and `form130`. Annualized self-employed income contributes to `totalNetAnnualIncomeAmountInEuros` and `effortRate` but does not replace the member declaration.

**Saved evaluation.** Does not run delinquency checks again or recalculate income.

**In this release.** `status` is `completed`. Candidatures are ranked for visit prioritization.

Each candidature is `assessed` (solvency, delinquency, discard reasons, annual income, effort rate and confidence tier) or `failed` (`failureReasons`).

**Errors.** `404` when the scoring does not exist or belongs to another client.




## OpenAPI

````yaml /openapi/arco-partner-api.json get /scorings/{scoringId}
openapi: 3.1.0
info:
  title: Vivara Partner API
  version: 1.0.0
  description: >
    Vivara's external API for tenant scoring and non-payment insurance.


    ## Authentication


    Every request must include the `X-API-Key` header with the API key issued to
    the integration. Keys are scoped per API client: scorings and cases created
    with one key are not visible to other clients.


    ## Conventions


    - Money is always a number in euros with up to two decimals (`1250.5` =
    1,250.50 €).

    - Dates are `YYYY-MM-DD`; timestamps are ISO 8601 in UTC.

    - Every answer that carries a resource wraps it in `data`.

    - Every error has the same body: `status`, `statusCode`, `code` and
    `message`. Use `code`, which is stable, to decide what to do. The catalog of
    codes is in the guides.


    ## Processing model


    **Scorings.** Creating or updating a scoring evaluates every candidature
    synchronously and returns no body. Read the results with `GET
    /scorings/{scoringId}`.


    In this release, evaluation finishes during create or update and `status` is
    `completed`. Document upload and asynchronous evaluation will arrive in a
    later release (`processing` and candidature status `pending`).


    **Non-payment insurance.** You generate the id of the case (a UUID v4) and
    open it with `POST /non-payment-insurance/cases`, which prices the offer
    synchronously and answers `201` with a `Location` header and no body. A case
    id that was already used answers `409`, whatever the data. Read the case,
    with its offer and the documents it requires, with `GET
    /non-payment-insurance/cases/{caseId}`. Upload the documents, issue the
    policy with `POST /non-payment-insurance/cases/{caseId}/policy`, and poll
    the case with exponential backoff (at least 30 s between calls) until it is
    `policy-issued` or `rejected`.


    ## Edge, routing and rate limiting


    Traffic is served through Azure Front Door, which terminates TLS at
    `https://api.vivara.io/v1/*` and forwards requests to the partner API.

    The Front Door web application firewall enforces rate limits per client IP.
    When a limit is exceeded it returns `429 Too Many Requests`; requests
    blocked by firewall rules return `403 Forbidden`. Those two answers come
    from the firewall and have no `code`. A `403` with `code: forbidden` comes
    from the API, when the API client has no access to it. Rate limit values are
    shared during onboarding.


    ## Data protection


    Requests contain personal data (DNI or NIE, income, and the documents of the
    people on a rental contract). Delete a scoring with `DELETE
    /scorings/{scoringId}` once it is no longer needed. Remove a document
    uploaded by mistake with `DELETE
    /non-payment-insurance/cases/{caseId}/documents/{documentId}` while the case
    is `pending-documentation` or `ready-to-issue`. Cases cannot be deleted.
servers:
  - url: https://api.vivara.io/v1
    description: Production
  - url: https://api-stg.vivara.io/v1
    description: Staging
security:
  - apiKeyAuth: []
tags:
  - name: Scorings
    description: >-
      Score candidates for a property and prioritize who to offer a visit to
      first
  - name: Non-payment insurance
    description: >-
      Quote, document upload and policy issuance for rental non-payment
      insurance cases
paths:
  /scorings/{scoringId}:
    parameters:
      - $ref: '#/components/parameters/ScoringId'
    get:
      tags:
        - Scorings
      summary: Get a scoring
      description: >
        Returns the saved scoring: property context, status and candidatures.


        **Property context.** `postalCode` and `monthlyPaymentAmountInEuros` are
        fixed at creation.


        **Members.** Each member echoes the declaration from create or update.
        `personalId` and `workingStatus` are always present in the response and
        are `null` when omitted or explicitly set to `null` in the request.
        Employed and retired members include `netAnnualIncomeAmountInEuros`.
        Self-employed members include `form100` and `form130`. Annualized
        self-employed income contributes to `totalNetAnnualIncomeAmountInEuros`
        and `effortRate` but does not replace the member declaration.


        **Saved evaluation.** Does not run delinquency checks again or
        recalculate income.


        **In this release.** `status` is `completed`. Candidatures are ranked
        for visit prioritization.


        Each candidature is `assessed` (solvency, delinquency, discard reasons,
        annual income, effort rate and confidence tier) or `failed`
        (`failureReasons`).


        **Errors.** `404` when the scoring does not exist or belongs to another
        client.
      operationId: getScoring
      responses:
        '200':
          description: Successful operation
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                properties:
                  data:
                    $ref: '#/components/schemas/Scoring'
              examples:
                completed:
                  $ref: '#/components/examples/CompletedScoring'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '404':
          $ref: '#/components/responses/NotFoundError'
        '429':
          $ref: '#/components/responses/TooManyRequestsError'
        '500':
          $ref: '#/components/responses/InternalServerError'
components:
  parameters:
    ScoringId:
      name: scoringId
      in: path
      required: true
      schema:
        type: string
        format: uuid
      description: Scoring identifier provided at creation.
  schemas:
    Scoring:
      type: object
      required:
        - id
        - status
        - postalCode
        - monthlyPaymentAmountInEuros
        - candidatures
        - createdAt
        - updatedAt
      properties:
        id:
          type: string
          format: uuid
          description: Scoring identifier, same as the scoringId path parameter.
        status:
          type: string
          enum:
            - processing
            - completed
          description: >
            `completed` — every candidature is `assessed` or `failed`.

            `processing` — documents are being evaluated (later release). Create
            and update finish with `completed` today.
        postalCode:
          type: string
          description: Property postal code set at creation.
        monthlyPaymentAmountInEuros:
          type: number
          description: Monthly property payment in euros (EUR) set at creation.
        candidatures:
          type: array
          description: >
            Visit-prioritization order when `status` is `completed` (higher
            confidence tier first, then lower effort rate). Request order while
            `processing`.
          items:
            $ref: '#/components/schemas/CandidatureAssessment'
        createdAt:
          type: string
          format: date-time
          description: Creation timestamp (ISO 8601, UTC).
        updatedAt:
          type: string
          format: date-time
          description: Last update timestamp (ISO 8601, UTC).
    CandidatureAssessment:
      description: Candidature result. The status field determines the shape.
      oneOf:
        - $ref: '#/components/schemas/PendingCandidature'
        - $ref: '#/components/schemas/AssessedCandidature'
        - $ref: '#/components/schemas/FailedCandidature'
    Error:
      type: object
      required:
        - status
        - statusCode
        - code
        - message
      properties:
        status:
          type: string
          description: HTTP reason phrase.
        statusCode:
          type: integer
          description: HTTP status code.
        code:
          type: string
          description: >-
            Stable, machine-readable error code in kebab-case. Use it, not the
            message, to decide what to do. The full list is in the error catalog
            of the guides (Key concepts, Errors).
        message:
          type: string
          description: >-
            Human-readable explanation, in English. It names the fields or the
            documents behind the error.
    PendingCandidature:
      type: object
      required:
        - externalReference
        - status
        - members
      properties:
        externalReference:
          type: string
          description: Candidature identifier provided by the API client.
        status:
          type: string
          const: pending
          description: Documents of the candidature are being evaluated asynchronously.
        members:
          type: array
          items: 57a828e0-d543-418a-bc93-e65ec5079aaa
    AssessedCandidature:
      type: object
      required:
        - externalReference
        - status
        - solvencyResult
        - delinquencyResult
        - discardReasons
        - isDelinquent
        - isSolvent
        - totalNetAnnualIncomeAmountInEuros
        - effortRate
        - confidenceTier
        - members
      properties:
        externalReference:
          type: string
          description: Candidature identifier provided by the API client.
        status:
          type: string
          const: assessed
          description: Evaluation completed.
        solvencyResult:
          type:
            - string
            - 'null'
          enum:
            - ok
            - ok-marginal
            - ko
            - null
          description: |
            `ok` — effort rate below 35%.
            `ok-marginal` — from 35% to 40% inclusive.
            `ko` — above 40%.
            `null` — effort rate could not be calculated.
        delinquencyResult:
          type: string
          enum:
            - ok
            - ko
            - not-checked
          description: >
            `ok` — no member appears in the delinquency register.

            `ko` — at least one member appears in the register.

            `not-checked` — not every member has a `personalId`, or the check
            did not run.
        discardReasons:
          type: array
          description: >-
            Reasons this assessed candidature is discarded. Empty when it passes
            both checks.
          uniqueItems: true
          items:
            type: string
            enum:
              - delinquent
              - insolvent
        isDelinquent:
          type: boolean
          description: >-
            True when delinquencyResult is ko. False when it is ok or
            not-checked.
        isSolvent:
          type: boolean
          description: >-
            True when solvencyResult is ok or ok-marginal. False when it is ko
            or null.
        totalNetAnnualIncomeAmountInEuros:
          type:
            - number
            - 'null'
          description: >-
            Total annual net income in euros used in the saved assessment,
            including annualized self-employed income. Null if any member income
            was unavailable. Reading a scoring never recalculates income using
            the current quarter.
        effortRate:
          type:
            - number
            - 'null'
          minimum: 0
          description: >-
            Percentage (0 to 100 scale, two decimals) of the annual property
            payment over the total net annual income of the members. For example
            31.17 means 31.17 percent. Null when it cannot be calculated.
        confidenceTier:
          type: string
          enum:
            - basic
            - declared
            - accredited
          description: >
            `basic` — any member omits `personalId` or `workingStatus`.

            `declared` — every member provides both.

            `accredited` — every value backed by a document (not available in
            this release).
        members:
          type: array
          items: 57a828e0-d543-418a-bc93-e65ec5079aaa
    FailedCandidature:
      type: object
      required:
        - externalReference
        - status
        - failureReasons
        - members
      properties:
        externalReference:
          type: string
          description: Candidature identifier provided by the API client.
        status:
          type: string
          const: failed
          description: The candidature could not be fully evaluated.
        failureReasons:
          type: array
          uniqueItems: true
          minItems: 1
          items:
            type: string
            enum:
              - service-unavailable
              - personal-id-rejected
              - postal-code-rejected
          description: >
            `service-unavailable` — delinquency register check could not be
            completed (retry on `PUT`).

            `personal-id-rejected` — a member ID number was rejected.

            `postal-code-rejected` — the property postal code was rejected.
        members:
          type: array
          items:
            type: object
            additionalProperties: false
            description: >-
              Member data as originally declared, with omitted personalId and
              workingStatus normalized to explicit null values. Self-employed
              annualized income is used only for `effortRate` and is not
              returned as `netAnnualIncomeAmountInEuros`.
            required:
              - personalId
              - workingStatus
            properties:
              personalId:
                type:
                  - string
                  - 'null'
                description: Spanish DNI or NIE, or null when not declared.
              workingStatus:
                type:
                  - string
                  - 'null'
                enum:
                  - employed
                  - retired
                  - null
                  - self-employed
                description: >-
                  Employment situation. In requests, omit `workingStatus` when
                  unknown; explicit `null` is also accepted with the same
                  meaning. In responses, the field is present and `null` when
                  not declared. Self-employed requires `form100` and `form130`.
              netAnnualIncomeAmountInEuros:
                type: number
                description: >-
                  Annual net income in euros for employed and retired members,
                  or when employment is not declared. Self-employed members
                  declare form100 and form130 instead.
              form100:
                type: object
                additionalProperties: false
                description: >-
                  Required for self-employed members. Annual Modelo 100 net
                  income, retained for reference and excluded from the scoring
                  calculation.
                required:
                  - netIncomeAmountInEuros
                properties:
                  netIncomeAmountInEuros:
                    type: number
                    exclusiveMinimum: 0
                    description: Annual net income in euros, up to two decimals.
              form130:
                type: object
                additionalProperties: false
                description: >-
                  Required for self-employed members alongside form100,
                  replacing generic annual income. Scoring uses only cumulative
                  form130 divided by the months covered by the previous calendar
                  quarter at scoring time (Europe/Madrid). Scoring in Q1 divides
                  by 12, Q2 by 3, Q3 by 6 and Q4 by 9.
                required:
                  - netIncomeAmountInEuros
                properties:
                  netIncomeAmountInEuros:
                    type: number
                    exclusiveMinimum: 0
                    description: >-
                      Cumulative net income in euros (EUR), up to two decimals,
                      not the tax payment or a monthly amount.
                    example: 1411
            oneOf:
              - properties:
                  workingStatus:
                    enum:
                      - employed
                      - retired
                      - null
                required:
                  - netAnnualIncomeAmountInEuros
                not:
                  anyOf:
                    - required:
                        - form100
                    - required:
                        - form130
              - properties:
                  workingStatus:
                    enum:
                      - self-employed
                required:
                  - form100
                  - form130
                not:
                  required:
                    - netAnnualIncomeAmountInEuros
  examples:
    CompletedScoring:
      summary: Evaluation completed with assessed and failed candidatures
      value:
        data:
          id: 6d1f0c3e-5b8a-4c1e-9f2a-3b7e8d4a1c90
          status: completed
          postalCode: '08001'
          monthlyPaymentAmountInEuros: 1200
          candidatures:
            - externalReference: cand-001
              status: assessed
              solvencyResult: ok
              delinquencyResult: ok
              discardReasons: []
              isDelinquent: false
              isSolvent: true
              totalNetAnnualIncomeAmountInEuros: 46200
              effortRate: 31.17
              confidenceTier: declared
              members:
                - personalId: 12345678Z
                  workingStatus: employed
                  netAnnualIncomeAmountInEuros: 25200
                - personalId: X1234567L
                  workingStatus: retired
                  netAnnualIncomeAmountInEuros: 21000
            - externalReference: cand-002
              status: assessed
              solvencyResult: ok-marginal
              delinquencyResult: ko
              discardReasons:
                - delinquent
              isDelinquent: true
              isSolvent: true
              totalNetAnnualIncomeAmountInEuros: 38400
              effortRate: 37.5
              confidenceTier: declared
              members:
                - personalId: 87654321X
                  workingStatus: self-employed
                  form100:
                    netIncomeAmountInEuros: 44000
                  form130:
                    netIncomeAmountInEuros: 28800
            - externalReference: cand-004
              status: failed
              failureReasons:
                - service-unavailable
              members:
                - personalId: Z1234567R
                  workingStatus: self-employed
                  form100:
                    netIncomeAmountInEuros: 44000
                  form130:
                    netIncomeAmountInEuros: 28800
          createdAt: '2026-10-26T16:00:00.000Z'
          updatedAt: '2026-10-26T16:00:05.000Z'
  responses:
    BadRequestError:
      description: >-
        Bad request. The body, path or headers do not match the expected shape
        or types.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            invalidScoring:
              summary: Invalid scoring
              value:
                status: Bad Request
                statusCode: 400
                code: validation-error
                message: >-
                  "candidatures[0].members[0].netAnnualIncomeAmountInEuros" must
                  be a number
            invalidQuote:
              summary: Invalid quote
              value:
                status: Bad Request
                statusCode: 400
                code: validation-error
                message: '"insuredProperty" is required'
    UnauthorizedError:
      description: >-
        Unauthorized. The X-API-Key header is missing or the API key is not
        valid.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: Unauthorized
            statusCode: 401
            code: invalid-api-key
            message: Invalid API key
    ForbiddenError:
      description: >-
        Forbidden. The API client has no access to this API, or the request was
        blocked by the edge firewall.
      content:
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/Error'
              - 179b90ba-7311-450d-aaec-7de48cb6a4fb
          examples:
            forbidden:
              summary: The API client has no access to this API
              value:
                status: Forbidden
                statusCode: 403
                code: forbidden
                message: The API client has no access to this API
            firewall:
              summary: Blocked by the edge firewall
              value:
                status: Forbidden
                statusCode: 403
                message: Request blocked by the firewall
    NotFoundError:
      description: >-
        Not found. The scoring, the case or the document does not exist for the
        authenticated API client.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            scoringNotFound:
              summary: Scoring not found
              value:
                status: Not Found
                statusCode: 404
                code: scoring-not-found
                message: Scoring 6d1f0c3e-5b8a-4c1e-9f2a-3b7e8d4a1c90 not found
            caseNotFound:
              summary: Case not found
              value:
                status: Not Found
                statusCode: 404
                code: case-not-found
                message: No case exists with id 3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42.
            documentNotFound:
              summary: Document not found in the case
              value:
                status: Not Found
                statusCode: 404
                code: document-not-found
                message: >-
                  No document exists with id
                  c41a8e93-7d2b-4f6a-b5e1-2a9f0c8d3e17 in case
                  3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42.
            pathNotFound:
              summary: The path does not exist
              value:
                status: Not Found
                statusCode: 404
                code: not-found
                message: Cannot GET /non-payment-insurance/unknown
    TooManyRequestsError:
      description: >-
        Too many requests. The rate limit enforced by Azure Front Door was
        exceeded. Retry with exponential backoff.
      content:
        application/json:
          schema:
            type: object
            description: >-
              Error answered by the edge firewall (Azure Front Door), before the
              request reaches the API. It has no `code`.
            required:
              - status
              - statusCode
              - message
            properties:
              status:
                type: string
                description: HTTP reason phrase.
              statusCode:
                type: integer
                description: HTTP status code.
              message:
                type: string
                description: Human-readable explanation.
          example:
            status: Too Many Requests
            statusCode: 429
            message: Rate limit exceeded
    InternalServerError:
      description: Internal server error.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: Internal Server Error
            statusCode: 500
            code: internal-error
            message: Something went wrong
  securitySchemes:
    apiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key issued per external API client.

````

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