Quickstart#

This tutorial will help you get started with the Tonita API through our Python library. We will walk through an example of how listings and corpora can be used to prepare and organize data. We will then go over some of the ways in which search can be performed, as well as how search results can be evaluated.

Before proceeding with the tutorial, make sure that you have an API key (see Authentication) and that the Tonita Python library is installed (see Installation). It would also be helpful to review Key concepts.

Note

In addition to the Tonita Python library, we also provide HTTP endpoints. While this tutorial will focus primarily on our Python library, we also offer examples that make requests to these HTTP endpoints directly using curl. See Making HTTP requests for more information.

Setting a default API key#

We first import the client library and set a default API key for API calls.

import tonita

tonita.api_key = "my_api_key"

This signals that subsequent calls that do not provide an API key will default to this value instead. See API keys and corpus IDs for other ways the API key can be set in the Python library.

Creating a corpus#

We must first create a corpus to populate with listings. To add a corpus, simply make the following call:

tonita.corpora.add(corpus_id="nyc_housing")

# Example return value:
# AddCorpusResponse(corpus_id='nyc_housing')
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -d '{"corpus_id": "nyc_housing"}' \
    https://api.tonita.co/corpora/add

# Example response value:
# {"corpus_id": "nyc_housing"}

AddCorpusResponse is a Python dataclass that contains the response data for your request to add a corpus. Each call to a Tonita API endpoint using the Python library will return a dataclass containing the response data. See Request and response types types for more information.

We can then confirm its existence by listing all corpora associated with this API key:

tonita.corpora.list()

# Example return value:
# ListCorporaResponse(results={"nyc_housing": <State.ACTIVE: 'ACTIVE'>})
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    https://api.tonita.co/corpora/list

# Example response value:
# {"results": {"nyc_housing": "ACTIVE"}}

Or check that, in particular, the corpus we just created exists:

tonita.corpora.get(corpus_id="nyc_housing")

# Example return value:
# GetCorpusResponse(
#     corpus_id='nyc_housing', 
#     exists=True, 
#     state=<State.ACTIVE: 'ACTIVE'>, 
#     seconds_to_expiration=None
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -d '{"corpus_id": "nyc_housing"}' \
    https://api.tonita.co/corpora/get

# Example response value:
# {
#   "corpus_id": "nyc_housing", 
#   "exists": true, 
#   "state": "ACTIVE", 
#   "seconds_to_expiration": null
# }

To create another corpus, simply make another call to tonita.corpora.add. Note that corpus IDs must be unique for a given API key.

tonita.corpora.add(corpus_id="movies")

# Example return value:
# AddCorpusResponse(corpus_id='movies')

tonita.corpora.list()

# Example return value:
# ListCorporaResponse(
#     results={
#         "movies": <State.ACTIVE: 'ACTIVE'>,
#         "nyc_housing": <State.ACTIVE: 'ACTIVE'>
#     }
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -d '{"corpus_id": "movies"}' \
    https://api.tonita.co/corpora/add

# Example response value:
# {"corpus_id": "movies"}

curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    https://api.tonita.co/corpora/list

# Example response value:
# {
#   "results": {
#     "movies": "ACTIVE", 
#     "nyc_housing": "ACTIVE"
#   }
# }

Adding listings#

We can now add listings to our corpora.

As with the API key, we can set a default corpus ID for subsequent calls using the Python library.

tonita.corpus_id = "nyc_housing"
tonita.listings.add(
    data={
        "h388387ds": {
            "data": {
                "bedrooms": 5,
                "bathrooms": 4,
                "in_unit_laundry": True,
                "balcony": True,
                "neighborhood": "Upper East Side",
                "price": 7000,
                "description": [
                    "Peaceful, tree-lined street.", 
                    "Lush green spaces everywhere in the neighborhood."
                ]
            },
            "categories": ["townhouse"]
        }
    }
)

# Expected return value:
# AddListingsResponse(
#     results={
#         "h388387ds": AddSingleListingResult(success=True, error_message="")
#     }
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -H "corpus-id: nyc_housing" \
    -d '{"h388387ds":{"data":{"bedrooms":5,"bathrooms":4,"in_unit_laundry":true,"balcony":true,"neighborhood":"Upper East Side","price":7000,"description":["Peaceful, tree-lined street.","Lush green spaces everywhere in the neighborhood."]},"categories":["townhouse"]}}' \
    https://api.tonita.co/listings/add

# Example response value:
# {"results": {"h388387ds": {"success": true, "error_message": ""}}}

Let’s break this request down. Note that the argument passed to tonita.listings.add() is a dictionary. The keys in this dictionary are the IDs of listings. (Listing IDs must be unique within a corpus.) The sole listing we’re adding to our corpus in the above example has ID "h388387ds".

Each listing ID in turn maps to another dictionary with two keys: "data" and "categories". In the above example, the sole listing "h388387ds" maps to the following dictionary:

{
    "data": {
        "bedrooms": 5,
        "bathrooms": 4,
        "in_unit_laundry": True,
        "balcony": True,
        "neighborhood": "Upper East Side",
        "price": 7000,
        "description": [
                    "Peaceful, tree-lined street.", 
                    "Lush green spaces everywhere in the neighborhood."
                ]
    }
    "categories": ["townhouse"]
}

This dictionary has the following keys:

  1. The value for the "data" key (required) will be a dictionary that contains the data for the listing. Here, we have the size of the home, its neighborhood, its price, amenity information, and some strings desribing the listing. You may provided whatever keys and data you like. Note that the more informative the data that you provide, the better the search experience will be.

  2. The value for the "categories" key (optional) will be a list of one or more category strings that can be attached to each listing, and can be used to restrict searches within a corpus by specifying the list of categories allowed during search. What constitutes a category is entirely up to you; a product search engine may use categories to represent different types of products (e.g., household appliances, furniture, clothing, etc.), while a vacation rental company may use categories to represent different cities, or even neighborhoods within a city.

Now that we’ve added a listing to the corpus, we can confirm that this listing exists by viewing all of the listings in this corpus…

tonita.listings.list()

# Example return value:
# ListListingsResponse(
#     results={"h388387ds": <State.ACTIVE: 'ACTIVE'>}, next_listing_id=None
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -H "corpus-id: nyc_housing" \
    https://api.tonita.co/listings/list

# Example response value:
# {"results": {"h388387ds": "ACTIVE"}, "next_listing_id": null}

…and view its data.

tonita.listings.get(listing_ids=["h388387ds"])

# Example return value:
# GetListingsResponse(
#     results={
#         "h388387ds": GetSingleListingResult(
#             success=True,
#             data={
#                 "data": {
#                     "bedrooms": 5,
#                     "bathrooms": 4,
#                     "in_unit_laundry": True,
#                     "balcony": True,
#                     "neighborhood": "Upper East Side",
#                     "price": 7000,
#                     "description": [
#                         "Peaceful, tree-lined street.", 
#                         "Lush green spaces everywhere in the neighborhood."
#                     ]
#                 },
#                 "categories": ["townhouse"]
#             },
#             state=<State.ACTIVE: 'ACTIVE'>,
#             seconds_to_expiration=None,
#             error_message=""
#         )
#     }
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -H "corpus-id: nyc_housing" \
    -d '{"listing_id": "h388387ds"}' \
    https://api.tonita.co/listings/get

# Example response value:
# {
#   "results": {
#     "h388387ds": {
#       "success": true,
#       "data": {
#         "data": {
#           "bedrooms": 5,
#           "bathrooms": 4,
#           "in_unit_laundry": true,
#           "balcony": true,
#           "neighborhood": "Upper East Side",
#           "price": 7000,
#           "description": [
#             "Peaceful, tree-lined street.", 
#             "Lush green spaces everywhere in the neighborhood."
#           ]
#         },
#         "categories": [
#           "townhouse"
#         ],
#       },
#       "state": "ACTIVE",
#       "seconds_to_expiration": null,
#       "error_message": ""
#     }
#   }
# }

Multiple listings can be added at the same time:

tonita.listings.add(
    data={
        "h197233sm": {
            "data": {
                "bedrooms": 1,
                "bathrooms": 1,
                "in_unit_laundry": False,
                "neighborhood": "Hell's Kitchen",
                "price": 400,
                "description": [
                    "Oversized one-bedroom.",
                    "Plenty of train lines in the area.", 
                    "Bustling nightlife scene."
                ]
            },
            "categories": ["apartment", "co-op"]
        },
        "h298921md": {
            "data": {
                "bedrooms": 1,
                "bathrooms": 1,
                "in_unit_laundry": True,
                "neighborhood": "Williamsburg",
                "price": 800,
                "description": [
                    "South and east exposures.", 
                    "Great restaurants nearby.",
                    "Steps from McCarren Park."
                ]
            },
            "categories": ["apartment", "condo"]
        }
    }
)

# Example return value:
# AddListingsResponse(
#     results={
#         "h197233sm": AddSingleListingResult(success=True, error_message=""),
#         "h298921md": AddSingleListingResult(success=True, error_message="")
#     }
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -H "corpus-id: nyc_housing" \
    -d '{"h197233sm":{"data":{"bedrooms":0,"bathrooms":1,"in_unit_laundry":false,"neighborhood":"Hell's Kitchen","price":400,"description":["Very big studio apartment in the back of building.","Plenty of train lines in the area.","Bustling nightlife scene."]},"categories":["apartment","co-op"]},"h298921md":{"data":{"bedrooms":2,"bathrooms":2,"in_unit_laundry":true,"neighborhood":"Williamsburg","price":800,"description":["South and east exposures.","Great restaurants nearby.","Steps from McCarren Park."]},"categories":["apartment","condo"]}}' \
    https://api.tonita.co/listings/add

# Example response value:
# {
#   "results": {
#     "h197233sm": {
#       "success": true,
#       "error_message": ""
#     },
#     "h298921md": {
#       "success": true,
#       "error_message": ""
#     }
#   }
# }

Here, we’re adding two listings: "h197233sm" and "h298921md".

Tip

Listings can also be added by reading listings data from a file. See Managing listings for more details.

Let’s confirm that our "nyc_housing" corpus now has three listings:

tonita.listings.list()

# Example return value:
# ListListingsResponse(
#     results={
#         "h197233sm": <State.ACTIVE: 'ACTIVE'>,
#         "h298921md": <State.ACTIVE: 'ACTIVE'>,
#         "h388387ds": <State.ACTIVE: 'ACTIVE'>
#     },
#     next_listing_id=None
# )
curl -X POST -H "content-type: application/json" \
    -H "x-api-key: my_api_key" \
    -H "corpus-id: nyc_housing" \
    https://api.tonita.co/listings/list

# Example response value:
# {
#   "results": {
#     "h197233sm": "ACTIVE",
#     "h298921md": "ACTIVE",
#     "h388387ds": "ACTIVE"
#   }
#   "next_listing_id": null
# }

Listings can, of course, be deleted and updated. See Managing listings for more details.