The Vector Panda SDK has one client class, VP, but four ways to give it credentials. They all produce the same authenticated client object; what differs is where the API key comes from and what side effects the construction has.

This page is the reference for picking the right one.

The four authentication modes at a glance: VP.login() (browser device flow, saves to ~/.veep/credentials.json, best for first-time setup), VP.from_creds() (reads the saved file, best for interactive work after a prior login), VP(api_key="sk_...") (explicit literal, best for one-off scripts), VP() (reads VEEP_API_KEY, best for CI and containers). All four produce the same authenticated client object.

TL;DR

Mode Where the key comes from Use this when
VP.login() Browser device flow; saves to disk First time on a new machine
VP.from_creds() ~/.veep/credentials.json (or VEEP_CREDS) Interactive work after a prior login
VP(api_key="sk_...") Explicit literal One-off scripts, you already have the key
VP() VEEP_API_KEY environment variable CI, containers, anywhere a secret manager hands you the env

Pick whichever matches how the key arrives in this process. The runtime behaviour after construction is identical.

Mode 1: VP.login() (interactive device flow)

Mode 1 in detail: VP.login() opens a browser to start the device flow, the customer approves sign-in via OAuth, and the SDK saves credentials to ~/.veep/credentials.json. Best for first time on a new machine; interactive only and not suitable for unattended scripts.

Opens a browser, walks you through OAuth, and writes the resulting key to ~/.veep/credentials.json (chmod 600). Designed for the first time you sit down at a new machine.

from veep import VP

vp = VP.login()                  # opens a browser; complete the device-flow prompt
# vp is now authenticated AND ~/.veep/credentials.json is written
from veep import VP

vp = VP.login()                  # opens a browser; complete the device-flow prompt
# vp is now authenticated AND ~/.veep/credentials.json is written;
# subsequent processes wrap with VectorPandaStore(client=VP.from_creds(), ...)

The login flow itself is identical — it's the one-time interactive step. From here on you'd construct a VectorPandaStore in code that runs unattended.

After this runs once, every subsequent process on the same machine can use VP.from_creds() without re-prompting. The credentials file is also what the Vector Panda quickstart on /docs writes, so a fresh login from the SDK and a fresh login from the website both land on the same file.

You don't normally call this in code that runs unattended. If you find yourself wanting to, that's a signal to switch to mode 3 or 4.

Mode 2: VP.from_creds() (read the saved file)

The most common interactive mode. Reads ~/.veep/credentials.json (or whatever VEEP_CREDS points to) and constructs a client without any user prompt.

from veep import VP

vp = VP.from_creds()                # reads ~/.veep/credentials.json
print(vp.whoami())                  # {'client_id': '...', 'client_name': '...'}
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_vectorpanda import VectorPandaStore
from veep import VP

vp = VP.from_creds()                # reads ~/.veep/credentials.json
store = VectorPandaStore(
    collection_name="my-collection",
    embedding=HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2"),
    client=vp,
)
print(store.client.whoami())        # {'client_id': '...', 'client_name': '...'}

If the credentials file doesn't exist, this raises AuthError with a hint to run VP.login(). It does not fall back to env vars; that's mode 4's job.

This is what every example on /docs/projects/* and /docs/tutorials/* uses, because the .150 test runner has the credentials file already populated. In your own laptop session the same call works the same way.

Mode 3: VP(api_key="...") (explicit literal)

Hands the key directly, ignoring both the credentials file and the env var. Useful when you have the key in some other store (Vault, Secrets Manager, password manager) and want to avoid intermediate state on disk.

from veep import VP

vp = VP(api_key="veep_live_yourrealkeyhere")
from langchain_vectorpanda import VectorPandaStore

# Shortcut: the store builds VP for you when you pass api_key=.
store = VectorPandaStore(
    collection_name="my-collection",
    embedding=embeddings,                       # any LangChain Embeddings
    api_key="veep_live_yourrealkeyhere",
)

The SDK refuses obvious placeholder strings (veep_live_REPLACE_ME, your-key-here, anything with XXXX) before it makes a network call, so a copy-paste mistake fails with a useful error instead of "401 unauthorized."

Don't commit literal keys to source control. If you find yourself reaching for this mode in a script that lives in a repo, switch to mode 4.

Mode 4: VP() (read from VEEP_API_KEY)

The CI mode. With no arguments, the constructor falls back to the VEEP_API_KEY environment variable.

# In your shell or container env:
export VEEP_API_KEY=veep_live_yourrealkeyhere
from veep import VP

vp = VP()                            # reads VEEP_API_KEY from the environment
from langchain_vectorpanda import VectorPandaStore
from veep import VP

# VectorPandaStore has no direct env-var fallback; construct VP() and pass it.
store = VectorPandaStore(
    collection_name="my-collection",
    embedding=embeddings,
    client=VP(),                     # VP() reads VEEP_API_KEY
)

Pair this with whatever your platform uses for secret injection (Kubernetes Secrets, Docker --env-file, GitHub Actions secrets, Forgejo Actions secrets, AWS Secrets Manager via env, etc.). The SDK never logs the key value and never writes it to disk.

VEEP_HOST is the matching env var for the API base URL, useful when you're running against a non-default cluster. Default is the public Vector Panda cloud.

Where credentials come from

Where credentials come from: side-by-side comparison of the three non-interactive modes. VP.from_creds() reads ~/.veep/credentials.json or VEEP_CREDS, no user prompt. VP(api_key="sk_...") uses the explicit key you pass, ignoring file and env. VP() reads VEEP_API_KEY, best for CI and containers. Choose the mode that matches how the key arrives in this process.

Verify the client is authenticated

Whichever mode you used, the same probe works:

from veep import VP

vp = VP.from_creds()
me = vp.whoami()
print(f"signed in as client_id={me['client_id']}, client_name={me['client_name']}")
from langchain_huggingface import HuggingFaceEmbeddings
from langchain_vectorpanda import VectorPandaStore
from veep import VP

store = VectorPandaStore(
    collection_name="my-collection",
    embedding=HuggingFaceEmbeddings(model_name="sentence-transformers/all-MiniLM-L6-v2"),
    client=VP.from_creds(),
)
me = store.client.whoami()
print(f"signed in as client_id={me['client_id']}, client_name={me['client_name']}")

whoami() makes an authenticated round-trip and returns the client's identity. If it succeeds, the credentials are valid; if it raises AuthError, they aren't.

How the modes interact

How the modes interact: each constructor and helper method is a separate path with deliberate behaviour. (1) VP(api_key=X) uses X. (2) VP() reads VEEP_API_KEY, no fallback to credentials.json. (3) VP.from_creds() reads credentials.json or VEEP_CREDS, no fallback to environment. (4) VP.login() runs the browser flow and writes credentials.json. Common gotchas: from_creds does not read env vars, VP() does not read credentials.json, VP.login() is not for automation.

The four modes don't overlap, but they fall through in a specific order if you use mode 3 or 4 with no arguments:

VP(api_key=X) → uses X
VP()          → reads VEEP_API_KEY from environment
                (no fallback to ~/.veep/credentials.json)

VP.from_creds() → reads ~/.veep/credentials.json (or VEEP_CREDS path)
                  (no fallback to environment)

VP.login() → ignores everything, runs the browser flow, writes credentials.json

The two static methods (login, from_creds) and the constructor are deliberately separate paths; the SDK doesn't try to guess which you meant. If you want "use the credentials file or the env var, whichever exists," that's a one-liner you write yourself:

import os
from veep import VP

vp = VP.from_creds() if os.path.exists(os.path.expanduser("~/.veep/credentials.json")) else VP()

But most production code knows which mode it's in and shouldn't need that branch.

Common gotchas

Related