Skip to main content

Python SDK for the DataDID developer platform — Data API and DID API clients

Project description

Getting Started with datadid-sdk-python

DataDID is a developer platform that combines decentralized identity (DID) with user authentication and action records. The SDK provides two clients:

  • DataClient — authentication, user info, and action records (data-api.memolabs.net)
  • DIDClient — DID creation/deletion and file operations (prodidapi.memolabs.org)

Installation

pip install datadid-sdk-python

Requirements: Python 3.10+


Quick Start

import asyncio
from datadid import DataClient

async def main():
    client = DataClient.production()

    # Log in — the client stores the access token automatically
    tokens = await client.login_with_email_password("you@example.com", "yourpassword")

    # Fetch your profile
    me = await client.get_me()
    print(me.uid, me.role)

asyncio.run(main())

Servers

Client Purpose Production URL Test URL
DataClient Auth, user info, action records https://data-api.memolabs.net https://testdata-api.memolabs.net
DIDClient DID creation, file operations https://prodidapi.memolabs.org https://testdidapi.memolabs.org

Part 1 — DataClient

Create a client

from datadid import DataClient
from datadid.data.types import DataClientOptions

client = DataClient.production()
# or: client = DataClient.testnet()
# or: client = DataClient(DataClientOptions(base_url="https://data-api.memolabs.net"))

Login with email (verification code)

# Step 1: send a code to the user's inbox
await client.send_email_code("alice@example.com")

# Step 2: log in with the code
tokens = await client.login_with_email(
    "alice@example.com",
    "123456",  # code from inbox
    "Web",     # source: a string identifying your app — e.g. "Web", "App", "Mobile"
)

print(tokens.access_token)
print(tokens.refresh_token)

After a successful login the client stores the access token automatically. All subsequent calls that need authentication will use it.


Register a new account

await client.send_email_code("bob@example.com")

tokens = await client.register_with_email(
    "bob@example.com",
    "123456",     # code from inbox
    "mypassword", # choose a password
    "Web",
)

Login with email + password

tokens = await client.login_with_email_password(
    "alice@example.com",
    "mypassword",
)

Reset password

await client.send_email_code("alice@example.com")

await client.reset_password(
    "alice@example.com",
    "123456",      # code from inbox
    "newpassword",
)

Login with Telegram

tokens = await client.login_with_telegram(
    telegram_init_data,  # string from Telegram WebApp.initData
    "App",
)

Login with Pi Browser

tokens = await client.login_with_pi(
    pi_access_token,  # access token from Pi Browser SDK
    "App",
)

Login with EVM wallet (MetaMask, etc.)

# Step 1: request a challenge message from the server
# origin is required — use your app's own domain
message = await client.get_evm_challenge(
    "0xYourWalletAddress",
    chain_id=985,                  # optional, defaults to 985
    origin="https://myapp.com",    # required for login_with_evm to succeed
)

# Step 2: sign the message with the user's wallet
# (using eth_account or any signing library)
from eth_account.messages import encode_defunct
from eth_account import Account
signed = Account.sign_message(encode_defunct(text=message), private_key=private_key)
signature = signed.signature.hex()

# Step 3: submit the signature to log in
result = await client.login_with_evm(message, signature, "Web")

print(result.access_token)
print(result.did)     # the user's DID string (e.g. "did:memo:...")
print(result.number)  # the user's numeric platform ID

Refresh an access token

new_access_token = await client.refresh_token(tokens.refresh_token)

Get current user info

# Basic info (uid, email, username, role)
me = await client.get_me()
print(me.uid, me.role)

# Full profile (avatar, DID, linked social accounts, etc.)
info = await client.get_user_info()
print(info.name)
print(info.address)        # numeric platform ID (e.g. "2018955010523533312")
print(info.did)
print(info.email)
print(info.telegram_info)  # if linked
print(info.twitter_info)   # if linked
print(info.discord_info)   # if linked
print(info.pi_info)        # if linked

Action records

Action records are the platform's points/achievement system. Each action has a numeric ID. When a user completes an action, a record is stored with the points earned and a Unix timestamp.

# Check if the user has completed action #61
record = await client.get_action_record(61)
if record:
    print(f"Completed at {record.time}, earned {record.points} points")
else:
    print("Not completed yet")

# Mark action #61 as completed
await client.add_action_record(61)

# With extra options (some actions require additional data)
await client.add_action_record(61, {"some_option": "value"})

AliveCheck action IDs (AliveCheck is the platform's liveness/subscription service):

  • 5 — first-time AliveCheck subscription
  • 6 — AliveCheck renewal

Error handling

from datadid import DataDIDApiError

try:
    await client.login_with_email_password("alice@example.com", "wrongpassword")
except DataDIDApiError as err:
    print(str(err))          # human-readable message
    print(err.status_code)   # HTTP status code (e.g. 401, 500)
    print(err.response_body) # raw JSON from the server

Manual token management

By default, login methods store the access token on the client automatically. You can disable this:

from datadid import DataClient
from datadid.data.types import DataClientOptions

client = DataClient(DataClientOptions(
    base_url="https://data-api.memolabs.net",
    disable_auto_token=True,
))

tokens = await client.login_with_email("alice@example.com", "123456", "Web")

# Token was NOT stored automatically — set it yourself:
client.set_access_token(tokens.access_token)

# Read the current token at any time:
token = client.get_access_token()

Part 2 — DIDClient

DID operations use a sign-then-submit pattern. You never send your private key to the server — you only sign a message locally, and the server pays the gas fee and submits the transaction on your behalf.

The pattern for every write operation:

  1. Ask the server for a message to sign
  2. Sign that message with your wallet (free, off-chain)
  3. Submit the signature — the server does the rest

Create a client

from datadid import DIDClient

did_client = DIDClient.production()
# or: did_client = DIDClient.testnet()

Create a DID

address = "0xYourWalletAddress"

# Step 1: get the message to sign
message = await did_client.get_create_message(address)

# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
from eth_account.messages import encode_defunct
from eth_account import Account
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
signature = signed.signature.hex()

# Step 3: submit — server creates the DID on-chain
new_did = await did_client.create_did(signature, address)

print(new_did)  # "did:memo:abc123..."

Check if a DID exists

result = await did_client.get_did_exists("0xYourWalletAddress")
print(result)

Get DID info

info = await did_client.get_did_info("0xYourWalletAddress")
print(info.did)     # the DID string (e.g. "did:memo:...")
print(info.number)  # the numeric platform ID

Delete a DID

my_did = "did:memo:abc123..."

# Step 1: get the message to sign
message = await did_client.get_delete_message(my_did)

# Step 2: sign it — the message is a hex-encoded byte string, sign the bytes
signed = Account.sign_message(encode_defunct(primitive=bytes.fromhex(message[2:])), private_key=private_key)
signature = signed.signature.hex()

# Step 3: submit
result = await did_client.delete_did(signature, my_did)
print(result.status)

Upload a file

Files are stored directly by wallet address. For files that need their own on-chain DID, see mfile operations below.

await did_client.upload_file(file_data, "0xYourWalletAddress")

List files

files = await did_client.list_files("0xYourWalletAddress")

Download a file

file = await did_client.download_file("0xYourWalletAddress")

Upload an mfile (file with an on-chain DID)

An mfile is a file that gets its own DID minted on-chain, making it permanently addressable and verifiable on the Memo network. This uses the sign-then-submit pattern.

# Step 1: create the upload request — returns a message to sign
message = await did_client.create_mfile_upload(file_data, "0xYourWalletAddress")

# Step 2: sign it
signature = ...  # sign message with your wallet

# Step 3: confirm the upload
result = await did_client.confirm_mfile_upload(signature, "0xYourWalletAddress")

Download an mfile

file = await did_client.download_mfile(
    "did:mfile:bafkrei...",  # the mfile DID
    "0xYourWalletAddress",
)

Running the tests

python tests/run.py

Tests hit the real production and testnet servers. The ACCESS_TOKEN constant in tests/data_client_test.py needs to be a valid token; replace it if tests fail with a 401 error.


API Reference

DataClient

Method Description
DataClient.production() Client for production
DataClient.testnet() Client for test server
set_access_token(token) Manually set the auth token
get_access_token() Read the current token
send_email_code(email) Send verification code to email
login_with_email(email, code, source) Login with email + code
register_with_email(email, code, password, source) Register new account
login_with_email_password(email, password) Login with email + password
reset_password(email, code, new_password) Reset password
login_with_telegram(initdata, source) Login with Telegram
login_with_pi(pi_access_token, source) Login with Pi Browser
get_evm_challenge(address, chain_id?) Get EVM sign-in challenge
login_with_evm(message, signature, source) Login with EVM wallet signature
refresh_token(refresh_token) Get a new access token
get_me() Basic user info (uid, email, role)
get_user_info() Full user profile
get_action_record(action_id) Get action completion record (or None)
add_action_record(action_id, opts?) Record an action completion

DIDClient

Method Description
DIDClient.production() Client for production (prodidapi.memolabs.org)
DIDClient.testnet() Client for test server (testdidapi.memolabs.org)
get_create_message(address) Get message to sign before creating a DID
create_did(sig, address) Create a DID (submit signature)
create_did_admin(address) Admin: create DID without signature
create_ton_did(address) Create a Ton-network DID
get_did_exists(address) Check if a DID exists
get_did_info(address) Get DID info and chain balances
get_delete_message(did) Get message to sign before deleting a DID
delete_did(sig, did) Delete a DID (submit signature)
upload_file(data, address) Upload a file
list_files(address) List files for an address
download_file(address) Download a file
create_mfile_upload(data, address) Start an mfile upload (returns message to sign)
confirm_mfile_upload(sig, address) Confirm mfile upload (submit signature)
download_mfile(mdid, address) Download a file by its mfile DID

Error class

Attribute Type Description
str(err) str Human-readable error message
status_code int HTTP status code
response_body Any Raw JSON response from server

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

datadid_sdk_python-1.0.7.tar.gz (15.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

datadid_sdk_python-1.0.7-py3-none-any.whl (13.1 kB view details)

Uploaded Python 3

File details

Details for the file datadid_sdk_python-1.0.7.tar.gz.

File metadata

  • Download URL: datadid_sdk_python-1.0.7.tar.gz
  • Upload date:
  • Size: 15.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for datadid_sdk_python-1.0.7.tar.gz
Algorithm Hash digest
SHA256 f0992aee7d88ee22095d58618ef9b62a9e25a0e2b1ad56caf11492f0ece96858
MD5 54361fe9f63a7fef1095732c630dbdc5
BLAKE2b-256 341486acc782902d9f5f0a2d5f6853da85afa26425aca23f8be184be334c770c

See more details on using hashes here.

File details

Details for the file datadid_sdk_python-1.0.7-py3-none-any.whl.

File metadata

File hashes

Hashes for datadid_sdk_python-1.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 bdfc0e2f1ed346bc37029fdcbaaebba6ab7e50bab98a0603135bd4f23dc93c8d
MD5 b551c8d81388c22389f2896c0226ea2a
BLAKE2b-256 f013cc5ae6eb675d5ede2bdba0d714ba0ffafcb2cbe0f441678a3798a5d050df

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page