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

# Add a contact

> A contact added by hand, like the “Add” button in your requests on the portal, with the same rules for name, phone and email. The key's account becomes responsible for it. The firm's owner, an admin or a manager adds it to the firm's requests, and `board` set to `personal` keeps it in their own requests; for anyone else the contact stays in their own requests. Without `status`, the contact starts at the `new` stage. Requires the `leads:read` and `leads:write` abilities. With `Idempotency-Key`, a request repeated within 10 minutes returns the contact added the first time (200), with the same `meta.possible_duplicate`, and adds no other.



## OpenAPI

````yaml en/openapi.json POST /leads
openapi: 3.1.2
info:
  title: Housera API
  version: 1.0.0
  description: >-
    Publish and manage real estate listings on Housera from your CRM or your own
    application, under the same rules as the form on the Housera portal.
servers:
  - url: https://staging.housera.ro/api/v1
    description: 'Sandbox (staging): test data, same rules as production.'
  - url: https://housera.ro/api/v1
    description: 'Production: the real listings on housera.ro.'
security:
  - bearer: []
tags:
  - name: Your listings
  - name: Photos
  - name: Events
  - name: Vocabulary
  - name: Connect with Housera
  - name: Client requests
  - name: The company and its team
  - name: Marketing mandates
  - name: Viewings
  - name: Projects
  - name: Partnerships
  - name: API key
  - name: Statistics
paths:
  /leads:
    post:
      tags:
        - Client requests
      summary: Add a contact
      description: >-
        A contact added by hand, like the “Add” button in your requests on the
        portal, with the same rules for name, phone and email. The key's account
        becomes responsible for it. The firm's owner, an admin or a manager adds
        it to the firm's requests, and `board` set to `personal` keeps it in
        their own requests; for anyone else the contact stays in their own
        requests. Without `status`, the contact starts at the `new` stage.
        Requires the `leads:read` and `leads:write` abilities. With
        `Idempotency-Key`, a request repeated within 10 minutes returns the
        contact added the first time (200), with the same
        `meta.possible_duplicate`, and adds no other.
      operationId: v1.leads.store
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
          description: >-
            A unique value for this creation (for example a UUID). A request
            repeated with the same value within 10 minutes returns what the
            first one created, without creating anything else: the listing for
            `POST /listings`, the contact for `POST /leads`, the message for
            `POST /leads/{lead}/messages`. For listings and messages, only the
            first 64 characters count.
        - name: locale
          in: query
          required: false
          schema:
            type: string
            enum:
              - ro
              - en
            default: en
          example: en
          description: >-
            The response language, `ro` or `en`. It changes error messages
            (`title`, `detail`), labels and, when the listing has an approved
            translation in that language, its title and description. Codes are
            the same in every language. It takes precedence over
            `Accept-Language` and over the account's language.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  maxLength: 60
                  description: Name.
                phone:
                  type:
                    - string
                    - 'null'
                  maxLength: 40
                  description: Phone.
                email:
                  type:
                    - string
                    - 'null'
                  format: email
                  maxLength: 120
                  description: The client's email, if you have it.
                source:
                  anyOf:
                    - $ref: '#/components/schemas/LeadSource'
                    - type: 'null'
                  description: >-
                    How the request came in: `message`, `phone` (call request),
                    `viewing_request`, `referral` or `other`. If you leave it
                    out, the source stays empty, as in the portal.
                status:
                  anyOf:
                    - $ref: '#/components/schemas/LeadStatus'
                    - type: 'null'
                  description: Status.
                note:
                  type:
                    - string
                    - 'null'
                  maxLength: 500
                  description: Note.
                price:
                  type:
                    - integer
                    - 'null'
                  minimum: 0
                  maximum: 100000000
                  description: Price.
                board:
                  type:
                    - string
                    - 'null'
                  enum:
                    - firm
                    - personal
                    - null
                  description: >-
                    Where the contact goes: `firm` (the firm's requests, only
                    for the owner, admins and managers) or `personal` (your own
                    requests). Without it, the contact goes to the firm's
                    requests for whoever runs them and to their own requests for
                    everyone else.
              required:
                - name
      responses:
        '200':
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/LeadApiResource'
                    description: The result of the request.
                  meta:
                    type: object
                    properties:
                      possible_duplicate:
                        anyOf:
                          - type: 'null'
                          - type: object
                            properties:
                              id:
                                type: integer
                                description: >-
                                  The id of the contact that looks like the same
                                  person.
                              matched_on:
                                type: string
                                description: 'What matched: `phone`, `name` or both.'
                            required:
                              - id
                              - matched_on
                          - type: object
                            properties:
                              id:
                                type: integer
                                description: >-
                                  The id of the contact that looks like the same
                                  person.
                              matched_on:
                                type: array
                                items: {}
                                description: 'What matched: `phone`, `name` or both.'
                            required:
                              - id
                              - matched_on
                        description: >-
                          The contact the check in `POST /leads/duplicate-check`
                          finds: the same phone or exactly the same name, in the
                          same requests. The new contact was added anyway.
                          `null` if there is none.
                    required:
                      - possible_duplicate
                    description: >-
                      Data about the response, outside the result, for example a
                      list's pagination.
                required:
                  - data
                  - meta
          description: >-
            The contact had already been added with the same `Idempotency-Key`.
            The response holds it.
        '201':
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    $ref: '#/components/schemas/LeadApiResource'
                    description: The result of the request.
                  meta:
                    type: object
                    properties:
                      possible_duplicate:
                        anyOf:
                          - type: 'null'
                          - type: object
                            properties:
                              id:
                                type: integer
                                description: >-
                                  The id of the contact that looks like the same
                                  person.
                              matched_on:
                                type: string
                                description: 'What matched: `phone`, `name` or both.'
                            required:
                              - id
                              - matched_on
                          - type: object
                            properties:
                              id:
                                type: integer
                                description: >-
                                  The id of the contact that looks like the same
                                  person.
                              matched_on:
                                type: array
                                items: {}
                                description: 'What matched: `phone`, `name` or both.'
                            required:
                              - id
                              - matched_on
                        description: >-
                          The contact the check in `POST /leads/duplicate-check`
                          finds: the same phone or exactly the same name, in the
                          same requests. The new contact was added anyway.
                          `null` if there is none.
                    required:
                      - possible_duplicate
                    description: >-
                      Data about the response, outside the result, for example a
                      list's pagination.
                required:
                  - data
                  - meta
          description: >-
            The contact was added. The response holds the request, with its
            `id`, and `meta.possible_duplicate` the contact that looks like the
            same person, if there is one.
        '400':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: The request body is not valid JSON (`malformed_json`).
        '401':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: The key is missing, revoked or expired (`unauthenticated`).
        '403':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            The key lacks the abilities required (`missing_ability`), or you
            asked for the firm's requests without running them (`forbidden`).
        '409':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            A request with the same `Idempotency-Key` is still in progress
            (`idempotency_key_in_use`). Retry in a few seconds.
        '413':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: The request body is larger than 1 MB (`payload_too_large`).
        '415':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            The request body isn't declared as JSON (`unsupported_media_type`).
            Send it with `Content-Type: application/json`.
        '422':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/ValidationProblem'
          description: >-
            The data fails the rules: one entry per field in `errors[]`, each
            with a stable `code`.
        '429':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            Too many requests. Try again after the number of seconds in
            `Retry-After`.
        '503':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            Housera has temporarily paused writes through the API
            (`api_writes_paused`). Try again after the number of seconds in
            `Retry-After`.
components:
  schemas:
    LeadSource:
      type: string
      enum:
        - phone
        - message
        - viewing_request
        - referral
        - other
      title: LeadSource
    LeadStatus:
      type: string
      enum:
        - new
        - contacted
        - viewing
        - offer
        - closed
      title: LeadStatus
    LeadApiResource:
      type: object
      properties:
        id:
          type: integer
          description: >-
            The request ID. The `lead.created` and `lead.updated` events carry
            the same one.
        source:
          type:
            - string
            - 'null'
          enum:
            - phone
            - message
            - viewing_request
            - referral
            - other
            - null
          description: >-
            How the first request came in: `message`, `phone` (call request),
            `viewing_request`, `referral` or `other` (added by hand in the
            portal). When the same client sends another request on the same
            listing, you get a `lead.updated` event with that request's channel
            in its `source`.
        status:
          type: string
          enum:
            - new
            - contacted
            - viewing
            - offer
            - closed
          description: >-
            The request's stage in the portal: `new`, `contacted`, `viewing`,
            `offer` or `closed`.
        listing:
          type:
            - object
            - 'null'
          properties:
            code:
              type: string
              description: The listing's public code.
            external_ref:
              type:
                - string
                - 'null'
              description: >-
                The listing's ID in your system, if you created it with `PUT
                /listings/ref/{ref}`. Only a key in the space where it was set
                can see it; for every other key it is `null`.
          required:
            - code
            - external_ref
          description: >-
            The listing the request came through; `null` for a request sent from
            the agency's page or added by hand.
        complex:
          type:
            - object
            - 'null'
          properties:
            code:
              type: string
              description: The development's public code.
            title:
              type:
                - string
                - 'null'
              description: The development's title.
            url:
              type: string
              description: The development's address on Housera.
          required:
            - code
            - title
            - url
          description: >-
            At a developer, the request's project: the development it came on,
            or the one the unit is part of, with `code`, `title` and `url`.
            `null` outside a project.
        contact:
          type: object
          properties:
            name:
              type: string
              description: The client's name.
            phone:
              type:
                - string
                - 'null'
              description: The client's phone number (E.164), if there is one.
            email:
              type:
                - string
                - 'null'
              description: The client's email, if there is one.
          required:
            - name
            - phone
            - email
          description: The client's contact details.
        message:
          type:
            - string
            - 'null'
          description: >-
            What the client wrote: their first message on the listing, or the
            text sent from the agency's page. `null` if they wrote nothing, for
            example on a call request.
        erased:
          type: boolean
          description: >-
            `true` when the client deleted their account: the name is
            anonymized, and the phone, email, message and note are `null`.
            Delete the client's data from your copy too.
        note:
          type:
            - string
            - 'null'
          description: >-
            The account's note on the request, as in the portal. For a request
            sent from the agency's page, the note starts with the client's text.
        price:
          type:
            - integer
            - 'null'
          description: >-
            The amount the client offered, in whole euros, as in the portal;
            `null` when none is set.
        agent:
          type:
            - object
            - 'null'
          properties:
            name:
              type: string
              description: >-
                The name of the agent's account. The portal shows the name in
                `display_name`.
            email:
              type:
                - string
                - 'null'
              description: >-
                The agent's email; `null` when we have no real address for them,
                for example a colleague who came from a CRM with no email on
                their team record.
            display_name:
              type: string
              description: >-
                The agent's approved public name, the one the portal shows next
                to the request. It differs from `name` when the agent has a
                different public name approved.
          required:
            - name
            - email
            - display_name
          description: >-
            The agent who holds the request in the portal; `null` while it waits
            in the company's inbox for someone to take it.
        requests:
          type: object
          properties:
            callback_at:
              type:
                - string
                - 'null'
              description: >-
                The client's latest call request (ISO 8601); `null` if they
                never asked to be called.
            viewing_at:
              type:
                - string
                - 'null'
              description: >-
                The client's latest viewing request (ISO 8601); `null` if they
                never asked for a viewing.
          required:
            - callback_at
            - viewing_at
          description: >-
            When the client last asked to be called and to come to a viewing, as
            in the portal. `source` only gives the channel of the first request.
        office:
          type:
            - object
            - 'null'
          properties:
            id:
              type: integer
              description: The office's id. Send it as `office` in `GET /leads`.
            name:
              type: string
              description: >-
                The office's name. The head office is named in the language of
                the response: “Head office” in English, “Sediu” in Romanian.
          required:
            - id
            - name
          description: The request's office; `null` for a request outside a company.
        inbox:
          type:
            - object
            - 'null'
          properties:
            reason:
              type: string
              enum:
                - no_listing
                - left
                - no_agent
              description: >-
                Why it waits: `no_listing` (the client wrote from the company's
                page), `left` (the agent who held the request or the listing
                left the company or was deactivated) or `no_agent` (the listing
                has no active agent).
            since:
              type:
                - string
                - 'null'
              description: When the request came in (ISO 8601), as in the portal.
          required:
            - reason
            - since
          description: >-
            Why the request waits in “To take”, and when it came in; `null`
            while someone holds it.
        created_at:
          type:
            - string
            - 'null'
          description: When the request came in (ISO 8601).
        updated_at:
          type:
            - string
            - 'null'
          description: The request's last change in the portal (ISO 8601).
      required:
        - id
        - source
        - status
        - listing
        - complex
        - contact
        - message
        - erased
        - note
        - price
        - agent
        - requests
        - office
        - inbox
        - created_at
        - updated_at
      title: LeadApiResource
    Problem:
      type: object
      title: Problem
      properties:
        type:
          type: string
          format: uri
          description: The URL of the problem type (RFC 9457).
        title:
          type: string
          description: A short summary of the problem, in the request's language.
        status:
          type: integer
          description: The HTTP status code.
        code:
          type: string
          description: >-
            The stable code of the refusal, the one to handle the error by (the
            list is on the Errors page).
        detail:
          type: string
          description: The explanation, in the request's language.
        existing:
          type: object
          properties:
            code:
              type: string
              description: The existing listing's public code.
            external_ref:
              type:
                - string
                - 'null'
              description: >-
                Your ID for the existing listing, if you set it with `PUT
                /listings/ref/{ref}`. Otherwise `null`.
          required:
            - code
            - external_ref
          description: >-
            Only on `409 duplicate_listing`: the listing you already have for
            the same property.
      required:
        - type
        - title
        - status
        - code
        - detail
    ValidationProblem:
      type: object
      title: ValidationProblem
      properties:
        type:
          type: string
          format: uri
          description: The URL of the problem type (RFC 9457).
        title:
          type: string
          description: A short summary of the problem, in the request's language.
        status:
          type: integer
          description: 'The HTTP status code: `422`.'
        errors:
          type: array
          items:
            type: object
            properties:
              pointer:
                type: string
                description: The field it refers to, as a JSON Pointer (`/features/2`).
              code:
                type: string
                description: >-
                  The rule that failed, as a stable code (the list is on the
                  Errors page).
              detail:
                type: string
                description: >-
                  The explanation, in the request's language. The wording can
                  change, so handle the error by `code`.
            required:
              - pointer
              - code
              - detail
          description: One entry for each field that fails the rules.
      required:
        - type
        - title
        - status
        - errors
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      description: 'Authorization: Bearer <key>'

````

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