For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
DocsAPI Reference
  • Fundamentals
    • Home
    • Why Skyflow?
    • Get started with Skyflow
    • Explore what Skyflow can do
    • Authenticate
    • Accounts and environments
    • Deployment models
    • Security best practices
    • Compliance and certifications
    • Get data into Skyflow
    • Platform FAQs
  • Governance
    • Overview
  • Tokenization
    • Overview
  • Connections
    • Overview
  • Processing
  • AI and data sanitization
    • Overview
  • SDKs
    • Overview
      • Go: Migrate from V1 to V2
      • Python: Migrate from V1 to V2
      • Node.js: Migrate from V1 to V2
      • Java: Migrate from V1 to V2
  • Elements
    • Collect and reveal data with Skyflow Elements
LogoLogo
Login
Login
On this page
  • Authentication
  • Initialize the client
  • Insert records
  • Other operations at a glance
  • Request options
  • Error handling
  • v2.1+ updates
  • Get help
SDKsOverview

Python SDK: Migrate from V1 to V2

Was this page helpful?
Previous

Node.js SDK: Migrate from V1 to V2

Next
Built with

Skyflow Python SDK v2 introduces a new authentication model, multi-vault support, typed request and response classes, and richer error diagnostics. This guide walks through the key changes with before-and-after code examples, focuses on Insert end-to-end, then shows how the same pattern applies to other operations. A final section covers the smaller v2.1+ changes that are backward compatible.

Authentication

V1 required a token provider function. V2 lets you choose from five credential types.

V1:

1def token_provider():
2 global bearer_token
3 if not is_expired(bearer_token):
4 return bearer_token
5 bearer_token, _ = generate_bearer_token('<YOUR_CREDENTIALS_FILE_PATH>')
6 return bearer_token

V2:

1# Option 1: API key (recommended)
2credentials = {
3 'api_key': '<YOUR_API_KEY>',
4}
5
6# Option 2: Environment variable — set SKYFLOW_CREDENTIALS in your environment
7
8# Option 3: Credentials file
9credentials = {
10 'path': '<PATH_TO_CREDENTIALS_JSON>',
11}
12
13# Option 4: Stringified JSON
14credentials = {
15 'credentials_string': '<YOUR_CREDENTIALS_STRING>',
16}
17
18# Option 5: Bearer token
19credentials = {
20 'token': '<YOUR_BEARER_TOKEN>',
21}

Use only one authentication method per credentials object.

Initialize the client

V2 introduces a builder pattern for client initialization and adds multi-vault support. Log levels are now per-instance instead of global.

V1:

1config = Configuration('<VAULT_ID>', '<VAULT_URL>', token_provider)
2client = Client(config)

V2 (single vault):

1from skyflow import Skyflow, Env, LogLevel
2
3skyflow_client = (
4 Skyflow.builder()
5 .add_vault_config({
6 'vault_id': '<VAULT_ID>',
7 'cluster_id': '<CLUSTER_ID>', # ID from your vault URL, e.g., https://{clusterId}.vault.skyflowapis.com
8 'env': Env.PROD,
9 'credentials': credentials,
10 })
11 .add_skyflow_credentials(credentials) # Used as a fallback if no per-vault credentials are set
12 .set_log_level(LogLevel.INFO)
13 .build()
14)

V2 (multiple vaults):

1skyflow_client = (
2 Skyflow.builder()
3 .add_vault_config({
4 'vault_id': '<PRIMARY_VAULT_ID>',
5 'cluster_id': '<PRIMARY_CLUSTER_ID>',
6 'env': Env.PROD,
7 'credentials': primary_credentials,
8 })
9 .add_vault_config({
10 'vault_id': '<SECONDARY_VAULT_ID>',
11 'cluster_id': '<SECONDARY_CLUSTER_ID>',
12 'env': Env.PROD,
13 'credentials': secondary_credentials,
14 })
15 .set_log_level(LogLevel.INFO)
16 .build()
17)

Key changes:

  • vault_url is replaced by cluster_id (derived from your vault URL).
  • env is now required. Supported values: Env.PROD, Env.SANDBOX.
  • Log level is set per client instance via set_log_level().
  • A single client can manage multiple vault configurations.

Insert records

V2 replaces the dict-based request payload with a typed InsertRequest. Responses are returned as typed InsertResponse objects.

V1:

1client.insert(
2 {
3 "records": [
4 {
5 "table": "cards",
6 "fields": {
7 "cardNumber": "41111111111",
8 "cvv": "123",
9 },
10 }
11 ]
12 },
13 InsertOptions(True),
14)

V2:

1from skyflow.vault.data import InsertRequest
2
3insert_data = [
4 {
5 'card_number': '<VALUE1>',
6 'cvv': '<VALUE2>',
7 },
8]
9
10insert_request = InsertRequest(
11 table='<SENSITIVE_DATA_TABLE>',
12 values=insert_data,
13 return_tokens=True,
14 continue_on_error=True,
15)
16
17response = skyflow_client.vault('<VAULT_ID>').insert(insert_request)

V1 response:

1{
2 "records": [
3 {
4 "table": "cards",
5 "fields": {
6 "cardNumber": "f3907186-e7e2-466f-91e5-48e12c2bcbc1",
7 "cvv": "1989cb56-63da-4482-a2df-1f74cd0dd1a5",
8 "skyflow_id": "d863633c-8c75-44fc-b2ed-2b58162d1117"
9 },
10 "request_index": 0
11 }
12 ]
13}

V2 response:

1InsertResponse(
2 inserted_fields=[
3 {
4 'skyflow_id': 'a8f3ed5d-55eb-4f32-bf7e-2dbf4b9d9097',
5 'card_number': '5479-4229-4622-1393',
6 }
7 ],
8 errors=[],
9)

Other operations at a glance

Every vault operation in v2 follows the same pattern: build a typed request, then pass it to a method on the vault client. The snippets below show v2 request construction; the v1 patterns mirrored the dict-based shape used by client.insert() in v1.

Get:

1from skyflow.vault.data import GetRequest
2
3get_request = GetRequest(
4 table='<TABLE_NAME>',
5 ids=['<SKYFLOW_ID_1>', '<SKYFLOW_ID_2>'],
6 return_tokens=True,
7)
8response = skyflow_client.vault('<VAULT_ID>').get(get_request)

Update:

1from skyflow.vault.data import UpdateRequest
2
3update_request = UpdateRequest(
4 table='<TABLE_NAME>',
5 data={
6 'skyflow_id': '<SKYFLOW_ID>',
7 'card_number': '<NEW_VALUE>',
8 },
9 return_tokens=True,
10)
11response = skyflow_client.vault('<VAULT_ID>').update(update_request)

Delete:

1from skyflow.vault.data import DeleteRequest
2
3delete_request = DeleteRequest(
4 table='<TABLE_NAME>',
5 ids=['<SKYFLOW_ID_1>', '<SKYFLOW_ID_2>'],
6)
7response = skyflow_client.vault('<VAULT_ID>').delete(delete_request)

Detokenize:

1from skyflow.vault.tokens import DetokenizeRequest
2
3detokenize_request = DetokenizeRequest(
4 tokens=['<TOKEN_1>', '<TOKEN_2>'],
5)
6response = skyflow_client.vault('<VAULT_ID>').detokenize(detokenize_request)

Query:

1from skyflow.vault.data import QueryRequest
2
3query_request = QueryRequest(
4 query='SELECT * FROM <TABLE_NAME> WHERE skyflow_id = "<SKYFLOW_ID>"',
5)
6response = skyflow_client.vault('<VAULT_ID>').query(query_request)

Request options

V2 moves request options onto the request constructor itself instead of a separate InsertOptions object.

V1:

1options = InsertOptions(
2 tokens=True,
3)

V2:

1from skyflow.utils.enums import TokenMode
2
3insert_request = InsertRequest(
4 table='<TABLE_NAME>',
5 values=insert_data,
6 return_tokens=False, # Do not return tokens
7 continue_on_error=False, # Stop inserting if any record fails
8 upsert='<UPSERT_COLUMN>', # Column used for upsert logic, if any
9 token_mode=TokenMode.ENABLE,
10 tokens='<TOKENS>', # Required when token_mode is ENABLE
11)

The same pattern applies to the other request classes: UpsertRequest, UpdateRequest, DeleteRequest, and GetRequest all accept their options directly as constructor parameters.

Error handling

V2 errors carry more context to help with debugging.

V1:

1{
2 "code": "<http_code>",
3 "message": "<message>"
4}

V2:

1{
2 "http_status": "<http_status>",
3 "grpc_code": "<grpc_code>",
4 "http_code": "<http_code>",
5 "message": "<message>",
6 "request_id": "<request_id>",
7 "details": ["<details>"]
8}

Use the request_id field when contacting Skyflow Support — it uniquely identifies the request for faster diagnosis.

v2.1+ updates

v2.1.0 introduces a small set of backward-compatible changes. Existing v2.0 code continues to work; deprecated forms emit a deprecation warning.

Method renames:

DeprecatedPreferred
skyflow_client.update_log_level(level)skyflow_client.set_log_level(level)

Detokenize redaction parameter:

The redaction key in detokenize requests is deprecated in favor of redaction_type. Both keys are accepted; if both are provided, redaction_type takes precedence.

1from skyflow.vault.tokens import DetokenizeRequest
2from skyflow.utils.enums import RedactionType
3
4# Preferred (v2.1+)
5detokenize_request = DetokenizeRequest(
6 tokens=['<TOKEN>'],
7 redaction_type=RedactionType.PLAIN_TEXT,
8)

FileUploadRequest positional arguments:

Positional arguments on FileUploadRequest(table, skyflow_id, column_name) are deprecated. Use keyword arguments instead.

1from skyflow.vault.data import FileUploadRequest
2
3# Preferred (v2.1+)
4file_upload_request = FileUploadRequest(
5 table='<TABLE_NAME>',
6 skyflow_id='<SKYFLOW_ID>',
7 column_name='<COLUMN_NAME>',
8 file_path='<PATH_TO_FILE>',
9)

Credential field aliases:

Credential JSON files now accept both legacy and new field names. Existing files continue to work unchanged.

Legacy (still accepted)Preferred
clientIDclientId
keyIDkeyId
tokenURItokenUri

New errors field on Detect responses:

DeidentifyFileResponse, DeidentifyTextResponse, and ReidentifyTextResponse now include an errors field alongside their existing response data.

For the full list of changes, see the Python SDK releases on GitHub.

Get help

If you hit issues during migration, contact Skyflow Support and include the request_id from any failed call.