> ## 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.

# Open a case

> Opens the case with the id you generate (a UUID v4) and prices the standard non-payment insurance offer for the rental contract (Tarificación).

Returns 201 with no body and a `Location` header. Use GET on that URL to read the offer and the documents the insurer requires. The case is `pending-documentation`, or `rejected` when the insurer will not cover the contract (see `offer.exclusions`).

The required documents depend on each tenant's `workingStatus`, plus the data protection annex signed by the landlord and every tenant.

A case id that was already used answers `409 case-already-exists`, whatever the data. If a call times out, read `GET /non-payment-insurance/cases/{caseId}` to know whether the case was opened: `404` means it was not, and you can send the same id again.




## OpenAPI

````yaml /openapi/arco-partner-api.json post /non-payment-insurance/cases
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:
  /non-payment-insurance/cases:
    post:
      tags:
        - Non-payment insurance
      summary: Open a case
      description: >
        Opens the case with the id you generate (a UUID v4) and prices the
        standard non-payment insurance offer for the rental contract
        (Tarificación).


        Returns 201 with no body and a `Location` header. Use GET on that URL to
        read the offer and the documents the insurer requires. The case is
        `pending-documentation`, or `rejected` when the insurer will not cover
        the contract (see `offer.exclusions`).


        The required documents depend on each tenant's `workingStatus`, plus the
        data protection annex signed by the landlord and every tenant.


        A case id that was already used answers `409 case-already-exists`,
        whatever the data. If a call times out, read `GET
        /non-payment-insurance/cases/{caseId}` to know whether the case was
        opened: `404` means it was not, and you can send the same id again.
      operationId: createCase
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCaseRequest'
            examples:
              createCase:
                $ref: '#/components/examples/CreateCaseRequest'
      responses:
        '201':
          description: Case opened and priced.
          headers:
            Location:
              $ref: '#/components/headers/CaseLocation'
        '400':
          $ref: '#/components/responses/BadRequestError'
        '401':
          $ref: '#/components/responses/UnauthorizedError'
        '403':
          $ref: '#/components/responses/ForbiddenError'
        '409':
          $ref: '#/components/responses/ConflictError'
        '429':
          $ref: '#/components/responses/TooManyRequestsError'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '502':
          $ref: '#/components/responses/InsurerUnavailable'
components:
  schemas:
    CreateCaseRequest:
      type: object
      description: >-
        The data the insurer needs to price the policy: the case id, the
        contract, the insured property, the landlord and every tenant.
      required:
        - id
        - effectiveDate
        - contractDurationMonths
        - rentalAmountInEuros
        - insuredProperty
        - landlord
        - tenants
      properties:
        id:
          type: string
          format: uuid
          description: >-
            The case id. You generate it (a UUID v4); it is the id of the case
            in every other call and the correlation id towards the insurer.
          example: 3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42
        externalReference:
          type: string
          maxLength: 100
          description: >-
            Your own identifier for this rental contract. Returned on every case
            response.
          example: CONTRACT-2026-004521
        effectiveDate:
          type: string
          format: date
          description: Requested start date of the policy. Today or later.
          example: '2026-11-01'
        contractDurationMonths:
          type: integer
          enum:
            - 12
            - 18
            - 24
          description: Duration of the rental contract covered by the policy.
          example: 12
        rentalAmountInEuros:
          type: number
          minimum: 0.01
          description: >-
            Monthly rental amount in euros (rent plus monthly expenses), with up
            to two decimals.
          example: 1250
        insuredProperty:
          $ref: '#/components/schemas/Address'
        landlord:
          $ref: '#/components/schemas/LandlordForQuote'
        tenants:
          type: array
          minItems: 1
          maxItems: 4
          description: Every tenant and guarantor on the contract.
          items:
            $ref: '#/components/schemas/TenantForQuote'
    Address:
      type: object
      description: A postal address in Spain.
      required:
        - streetType
        - street
        - postalCode
        - city
        - province
      properties:
        streetType:
          $ref: '#/components/schemas/StreetType'
        street:
          type: string
          description: Street name without its type ("Velázquez", not "Calle Velázquez").
          example: Velázquez
        number:
          type: integer
          description: Omit it when the street has no number.
          example: 42
        floor:
          type: string
          description: Floor of the building.
          example: '3'
        door:
          type: string
          description: Door of the floor.
          example: B
        postalCode:
          type: string
          description: Five-digit postal code.
          pattern: ^\d{5}$
          example: '28001'
        city:
          type: string
          description: City or town.
          example: Madrid
        province:
          type: string
          description: Province.
          example: Madrid
    LandlordForQuote:
      type: object
      description: The landlord, who is the policyholder and the insured.
      required:
        - personalId
      properties:
        personalId:
          type: string
          description: >-
            DNI, NIE, CIF or passport number. Vivara detects which one it is
            from its format; a CIF means the landlord is a company.
          example: 12345678Z
    TenantForQuote:
      type: object
      required:
        - role
        - personalId
        - birthDate
        - postalCode
        - annualIncomeInEuros
        - workingStatus
        - employmentStartDate
      properties:
        externalReference:
          type: string
          maxLength: 100
          description: >-
            Your own identifier for this person. Returned with the tenant's
            `id`.
          example: TENANT-88412
        role:
          $ref: '#/components/schemas/TenantRole'
        personalId:
          type: string
          description: >-
            DNI, NIE or passport number. Vivara detects which one it is from its
            format.
          example: 87654321X
        birthDate:
          type: string
          description: Date of birth, `YYYY-MM-DD`.
          format: date
          example: '1991-04-17'
        postalCode:
          type: string
          pattern: ^\d{5}$
          description: Postal code of the tenant's current address.
          example: '28010'
        annualIncomeInEuros:
          type: number
          minimum: 0
          description: Gross annual income in euros. Up to two decimals.
          example: 42000
        workingStatus:
          $ref: '#/components/schemas/WorkingStatus'
        employmentStartDate:
          type: string
          format: date
          description: Start date of the tenant's current employment or activity.
          example: '2021-09-01'
    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.
    StreetType:
      type: string
      description: The type of street, as the insurer names it.
      enum:
        - street
        - avenue
        - square
        - promenade
        - road
        - way
        - path
        - passage
        - boulevard
        - roundabout
        - ring-road
        - tree-lined-avenue
        - transverse-road
        - cross-street
        - alley
        - slope
        - uphill
        - downhill
        - place
        - park
        - neighbourhood
        - colony
        - development
        - extension
        - group
        - block
        - city-block
        - building
        - tower
        - chalet
        - industrial-estate
        - plot
        - hamlet
        - settlement
        - village
        - stream
      example: street
    TenantRole:
      type: string
      description: Whether the person is a tenant or a guarantor.
      enum:
        - tenant
        - guarantor
      example: tenant
    WorkingStatus:
      type: string
      description: >-
        The working status of a tenant. It decides which income documents the
        insurer asks for. Where a value means the same as in Scorings it uses
        the same literal.
      enum:
        - permanent-employee
        - temporary-employee
        - civil-servant
        - self-employed
        - company
        - retired
        - student
        - unemployed
      example: permanent-employee
  examples:
    CreateCaseRequest:
      summary: Two tenants renting for 12 months
      value:
        id: 3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42
        externalReference: CONTRACT-2026-004521
        effectiveDate: '2026-11-01'
        contractDurationMonths: 12
        rentalAmountInEuros: 1250
        insuredProperty:
          streetType: street
          street: Velázquez
          number: 12
          floor: '3'
          door: B
          postalCode: '28001'
          city: Madrid
          province: Madrid
        landlord:
          personalId: 12345678Z
        tenants:
          - externalReference: TENANT-88412
            role: tenant
            personalId: 87654321X
            birthDate: '1990-05-14'
            postalCode: '28010'
            annualIncomeInEuros: 36000
            workingStatus: permanent-employee
            employmentStartDate: '2021-03-01'
          - externalReference: TENANT-88413
            role: tenant
            personalId: X1234567L
            birthDate: '1992-09-02'
            postalCode: '28010'
            annualIncomeInEuros: 24000
            workingStatus: temporary-employee
            employmentStartDate: '2025-01-15'
  headers:
    CaseLocation:
      description: URL of the created case.
      schema:
        type: string
      example: /v1/non-payment-insurance/cases/3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42
  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
    ConflictError:
      description: >-
        Conflict. The id is already in use with other data, or the status of the
        resource does not allow the operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          examples:
            scoringAlreadyExists:
              summary: Scoring id already in use
              value:
                status: Conflict
                statusCode: 409
                code: scoring-already-exists
                message: Scoring 6d1f0c3e-5b8a-4c1e-9f2a-3b7e8d4a1c90 already exists
            caseAlreadyExists:
              summary: Case id already used with different data
              value:
                status: Conflict
                statusCode: 409
                code: case-already-exists
                message: Case 3f9c2a7e-58b1-4d0a-9a51-0c6e2f1b7d42 already exists.
            invalidCaseStatus:
              summary: The case status does not allow the action
              value:
                status: Conflict
                statusCode: 409
                code: invalid-case-status
                message: >-
                  The policy can only be issued for a ready-to-issue case; this
                  case is rejected.
    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
    InsurerUnavailable:
      description: The insurer did not answer. Safe to retry with the same case id.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            status: Bad Gateway
            statusCode: 502
            code: insurer-unavailable
            message: The insurer is temporarily unavailable. Retry in a few minutes.
  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.