On this page

Quickstart — Python SDK

The Python SDK is a thin, dependency-free client over the same tools the REST API exposes. It adds three things worth having: it discovers the gateway's base URL for you, it raises a typed exception per failure class instead of handing you a status code, and it refuses some mistakes before a request leaves your process.

Before you start

You need Python 3.9 or newer, a Wexa project, and an administrator role on that project so you can mint a credential.

Step 1 — Install

pip install wexa

The package is wexa and the module is a single file, with no third-party dependencies.

Step 2 — Get a credential

The SDK does not mint credentials; you mint one once and give it to the client. An API key is pinned to exactly one project when it is created, and that scope never widens — which is why the client takes no project argument anywhere.

$FABRIC_USER_TOKEN below is your own Wexa sign-in token, the session token the console holds once you have signed in. The console mints keys from this same endpoint under Simple mode → Generate API key if you would rather not handle it yourself.

curl -sS -X POST https://fabric.wexa.ai/v1/apikeys \
  -H "Authorization: Bearer $FABRIC_USER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"org_id":"org_...","dept_id":"dept_...","project_id":"proj_...","name":"quickstart"}'

The response carries the secret exactly once:

{
  "id": "key_...",
  "name": "quickstart",
  "note": "store this secret now; it is not retrievable again",
  "secret": "fab_sk_..."
}

Minting a key requires an owner, organization-administrator or project-administrator role; any other role is refused with API key creation requires an admin role on this project.

Step 3 — Construct a client

The client needs two things: the workspace it is talking to, and the credential. Pass them explicitly, or leave both out and let it read WEXA_WORKSPACE and WEXA_API_KEY from the environment.

export WEXA_WORKSPACE="https://fabric.wexa.ai"
export WEXA_API_KEY="fab_sk_..."
from wexa import Fabric

fabric = Fabric()

print(fabric.base)
https://fabric.wexa.ai/v1

Constructing the client performs one unauthenticated request to the gateway's connection-info endpoint to discover that base URL, so a client that constructs successfully has already proved the workspace is reachable.

Step 4 — Make your first call

The documentation tool is the best first call: it is registered in every deployment, needs no data in your project, and returns your own scope and limits, so a successful response proves the credential and the scope together.

governance = fabric.docs(topic="governance")

print(governance["mode"])
print(governance["quota"])
auto
{'org_window_max': 600, 'org_window_used': 1, 'project_window_max': 120, 'project_window_used': 1}

The SDK returns the result of the envelope directly, so you get the tool's own output rather than a wrapper to unpack. mode is the project mode — auto is Simple mode — and quota is your rolling call budget at both the project and the organization level.

Step 5 — Write and read the context graph

save_context writes nodes. Each node needs a label, a merge key naming the property that identifies it, and the properties themselves.

result = fabric.save_context(
    nodes=[
        {
            "label": "Customer",
            "key": "name",
            "properties": {"name": "Acme Corp", "tier": "enterprise"},
        }
    ]
)

print(result)
{'nodes_merged': 1, 'relationships_merged': 0, 'ontology_extended': False}

ontology_extended reports whether writing that node taught the project a type it did not have. The first time a Customer is written it is True and new_labels names it; afterwards it is False, because there was nothing new to register.

Reading takes read-only Cypher, and the query must filter on the project:

rows = fabric.query_context(
    query="MATCH (c:Customer) WHERE c.project_id = $project_id RETURN c.name AS name",
)

print(rows["row_count"])

Step 6 — See a refusal

$project_id above is bound by Wexa from your credential. Try to supply it yourself and the SDK stops the call at the call site, before any request is built:

fabric.query_context(
    query="MATCH (n) WHERE n.project_id = $project_id RETURN n",
    project_id="someone_elses",
)
ValidationError: ['project_id'] are bound server-side from your token scope; sending them is rejected

This is a run-time refusal rather than a type error: the argument is accepted by the signature and rejected when the call runs. That is deliberate — the same check has to hold for arguments assembled at run time, which no type system sees. The four arguments treated this way are project_id, projectID, organization_id and executed_by.

Where to go next