Skip to main content

easyvista-python-client

CI Coverage License Python Docs

Typed Python client for the EasyVista Service Manager REST API. Sync + async, Pydantic models, Bearer or Basic auth.

While the package is preparing for 1.0, breaking changes may land between minor versions; a deprecation policy will follow the 1.0 release.

Documentation

Full documentation: https://easyvista-python-client.readthedocs.io/

Build it locally with pip install -e ".[docs]" then sphinx-build -b html -W docs docs/_build/html.

Install

pip install easyvista-python-client

Usage (sync)

from easyvista_python_client import (
    EasyvistaClient,
    EasyvistaConfig,
    PostRequest,
    ev_equals_filter,
)

# `account` is the instance id in the API root (https://host/api/v1/12345), not a username.
config = EasyvistaConfig(server="https://my.easyvista.com", account="12345", token="...")
with EasyvistaClient(config) as client:
    # catalog_code, the *_id values and the close status_guid are
    # instance-specific -- `client.describe_instance()` finds them for you.
    # `external_reference` is your own marker, and it is what lets you
    # reconcile a create that failed: see the note below this block.
    ticket = client.create_ticket(
        PostRequest(
            catalog_code="INC_STANDARD",
            title="Printer down",
            description="The 3rd-floor printer is offline",
            # The vendor documents `origin` as a channel NAME, not an id --
            # the one create field with a portable form. An int is also
            # accepted (measured on one instance) and passes through as sent.
            origin="Phone",
            department_id=9,
            urgency_id=8,
            impact_id=28,
            external_reference="MYAPP-0001",  # your own marker; set it always
        )
    )
    fetched = client.get_ticket(ticket.rfc_number)
    open_status = ev_equals_filter("STATUS_ID", 3)
    results = client.search_tickets(search=open_status, max_rows=50)

    # page through everything with the iterator (follows the API's offset paging)
    for t in client.iter_tickets(search=open_status, page_size=100, max_records=1000):
        ...  # async: `async for t in client.iter_tickets(...)`

    # close it with your instance's "closed" status GUID. Every argument is
    # optional -- `client.close_ticket(ticket.rfc_number)` sends the close with
    # no status of its own, but where that lands the ticket is not established
    # by this package; see the user guide before relying on it.
    client.close_ticket(
        ticket.rfc_number,
        status_guid="{00000000-0000-0000-0000-000000000000}",
        delete_actions=1,
        comment="Resolved",
    )

A create needs a subject: catalog_guid (the vendor's preferred identifier) or catalog_code. Anything beyond that is catalog-specific and enforced server-side, so a field a given catalog insists on raises EasyvistaValidationError (HTTP 590, code 2013) — it is not retried, and the message names no field.

Do not retry that 590 blindly. Measured on one instance (2026-08-25), a rejected create may still have created the ticket: 12 attempts returned 3 RFC_NUMBERs and afterwards all 12 tickets existed. A 590 means possibly created, never not created. Set external_reference on every create and reconcile by that marker — it survives the failed insert and is searchable.

Comments and actions

An action is a unit of work, and it is born open — an open action shows in the UI as a pending row with its text not displayed, which reads as though the note was lost. A comment is an action that has been ended.

from easyvista_python_client import PostAction, PostTask

# A COMMENT: `create_task` posts the same record already ended, in one call.
# Put the text in `description` -- the UI renders one field per action and
# `description` shadows `comment`, so text in `comment` beside a populated
# `description` is stored, readable through the API, and displayed to nobody.
client.create_task(
    rfc,
    PostTask(action_type_id=94, group_id=3, description="Investigating now."),
)

# WORK SOMEONE MUST STILL DO: create it open, then end it when it is done.
client.create_action(
    rfc,
    PostAction(action_type_id=94, group_id=3, description="Chase the supplier."),
)
client.end_action(
    rfc,
    action_id=1234,                    # not recoverable from the create response
    start_date="01/09/2026 17:00:00",  # your instance's format, not ISO 8601
    end_date="01/09/2026 17:15:00",
    elapsed_time=15,                   # MINUTES
)

There is no private-comment flag. Visibility is carried by the action type, which is per-deployment — read the ids off existing actions with client.discover("ACTION_TYPE") rather than hardcoding one.

end_action on a workflow action changes the ticket. Ending your own action only ends it; ending the ticket's open workflow step advances the workflow and moves the ticket's status. Naming action_id is therefore required — the vendor's id-less "end every open action" form is behind an explicit end_all=True.

Assets and documents

from pathlib import Path
from easyvista_python_client import (
    EasyvistaClient,
    EasyvistaConfig,
    PostAsset,
    ev_contains_filter,
    ev_equals_filter,
)

with EasyvistaClient(EasyvistaConfig.from_env()) as client:
    asset = client.create_asset(PostAsset(catalog_id=3153, asset_tag="LAPTOP-001"))
    tag_filter = ev_equals_filter("ASSET_TAG", "LAPTOP-001")
    found = client.search_assets(search=tag_filter, max_rows=50)

    # On the instance this package was characterized against, `~` needs an
    # explicit wildcard to mean "contains" -- a bare value is exact match,
    # identical to `:`. ev_contains_filter appends it for you; the vendor
    # documents `~` as plain Contains, so pass wildcard=None if that is your
    # deployment. It raises ValueError if the value carries `_` or `[` (both
    # are metacharacters to `~` itself, with no escape) or `*`/`%` while a
    # wildcard is being appended. For an exact match on a tag like
    # "LAPTOP_01", use ev_equals_filter: `:` does not expand a wildcard.
    partial = client.search_assets(search=ev_contains_filter("ASSET_TAG", "LAPTOP"))

    # attach a file to a ticket (uploaded as base64 inside the JSON body)
    pdf = Path("report.pdf")
    client.add_document("I240101_0001", filename=pdf.name, content=pdf.read_bytes())
    attachments = client.list_documents("I240101_0001")

Usage (async)

import asyncio

from easyvista_python_client import AsyncEasyvistaClient, EasyvistaConfig


async def main():
    async with AsyncEasyvistaClient(EasyvistaConfig.from_env()) as client:
        ticket = await client.get_ticket("I240101_0001")
        print(ticket.rfc_number)


asyncio.run(main())

Configuration via environment

Set EASYVISTA_URL (or EASYVISTA_SERVER), EASYVISTA_ACCOUNT, and either EASYVISTA_TOKEN / EASYVISTA_TOKEN_FILE or EASYVISTA_LOGIN + EASYVISTA_PASSWORD, then call EasyvistaConfig.from_env().

Agent skills

skills/ holds Agent Skills for driving this client from an AI agent — one per domain (client setup, search syntax, tickets, actions, documents, assets, directory, reporting and context). Each is a directory with a SKILL.md following the Agent Skills specification; see skills/README.md for the index.

They are source-tree material: present in the git repository and the source distribution, absent from the installed wheel.

Contributing

See CONTRIBUTING.md for development setup and quality checks.

License

MIT — see LICENSE.

Sponsoring

The development of this package is indirectly supported by Novahé & Constellation.

Metadata

Release files for easyvista-python-client 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for easyvista-python-client 0.2.0
File Size Uploaded
easyvista_python_client-0.2.0.tar.gz 253.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for easyvista-python-client 0.2.0
File Interpreter ABI Platform
easyvista_python_client-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 430.3 kB

Release files / easyvista_python_client-0.2.0.tar.gz

Download URL easyvista_python_client-0.2.0.tar.gz
Size 253.6 kB
Tags Source
SHA-256 checksum
How to use checksums
dcb340d6b1862bebd96fe9abab0879137a54af1d71f44abf866b0ceb8117800f
BLAKE2b-256 checksum
How to use checksums
ae7008040ff7e5c2b42cdf58cb820d0892290225f2d6abaf3fd1d7f0c1803344
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release files / easyvista_python_client-0.2.0-py3-none-any.whl

Download URL easyvista_python_client-0.2.0-py3-none-any.whl
Size 176.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
098738bf85bb8c190e80e2ae7cdbe921b5c6535153ee6e636bdaceac210c84e2
BLAKE2b-256 checksum
How to use checksums
9de6cb2f8f9bea07441ee4284c593b07756002ae16b145f6d7fd5be85717833d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 2, 2026.

Transparency log

Release history Release notifications | RSS feed

0.4.1

2 release files

0.4.0

2 release files

0.3.0

2 release files

This release

0.2.0 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page