Nillion Storage APIs
The Nillion Storage APIs provide a simple HTTP interface for storing and retrieving secrets on the Nillion Network Testnet with built-in management of store IDs and secret names.
The Storage APIs are suitable for quick hackathon projects and proof of concepts. If you need lower-level control or want to handle store ID management yourself, check out our Python Client for backend applications and Javascript Client for frontend applications.
Overview
The Nillion Storage APIs make it easy to quickly bootstrap a hackathon project that securely stores and retrieves secret data from the Nillion Network Testnet. APIs include built-in management of store IDs (locations of your secrets on Nillion) and abstract away Testnet payments. You can use Nillion Storage APIs to:
- Create an app id
- Store 2 types of secrets (numbers and strings/blobs)
- Customize secret permissions: grant retrieve, update, delete, and compute permissions to specific User IDs when storing secrets
- List all store IDs and names of secrets for your app id
- Retrieve secret values from Nillion using their store IDs
Storage APIs Quickstart
This guide shows how to store secrets, list all store IDs and secret names for your app, and retrieve secrets using the Nillion Storage APIs.
Prerequisites
All you need is a way to make HTTP requests. The examples below use curl
and JavaScript. You can explore and test all API endpoints directly from the Nillion Storage API Reference.
0: Register Your App
First run the following command from your terminal to register a new app:
- curl
- JavaScript
- Python
curl -X POST https://nillion-storage-apis-v0.onrender.com/api/apps/register
fetch('https://nillion-storage-apis-v0.onrender.com/api/apps/register', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
})
.then((response) => response.json())
.then((data) => console.log(data))
.catch((error) => console.error('Error:', error));
import requests
response = requests.post('https://nillion-storage-apis-v0.onrender.com/api/apps/register')
print(response.json())
This returns an app_id
to track the store IDs for your secrets. Save the app_id
from the response. This is your app's unique identifier.
1. [Optional] Check Your User ID
Check the deterministic user ID generated by your user seed using POST /api/user
. You can share this user ID with others so they can give you permissions to retrieve their secrets.
- JavaScript
- Python
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// 1. Check your deterministic user ID
console.log('Checking user ID generated by your seed...');
const user = await fetch(`${API_BASE}/api/user`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
nillion_seed: USER_SEED,
}),
}).then((res) => res.json());
console.log('Your User ID:', user.nillion_user_id);
import requests
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
print('Checking user ID generated by your seed...')
response = requests.post(
f'{API_BASE}/api/user',
headers={'Content-Type': 'application/json'},
json={'nillion_seed': USER_SEED}
)
user = response.json()
print('Your User ID:', user['nillion_user_id'])
2. Store a Secret Number
Store a number secret using POST /api/apps/{app_id}/secrets
. The empty permissions arrays mean only the storing user has access.
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// 2. Store first secret (number)
console.log('\nStoring first secret...');
const storeResult1 = await fetch(`${API_BASE}/api/apps/${APP_ID}/secrets`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: {
nillion_seed: USER_SEED,
secret_value: 16,
secret_name: 'my_secret_number',
},
permissions: {
retrieve: [],
update: [],
delete: [],
compute: {},
},
}),
}).then((res) => res.json());
console.log('First secret stored at:', storeResult1);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
print('\nStoring first secret...')
storeResult1 = requests.post(
f'{API_BASE}/api/apps/{APP_ID}/secrets',
headers={'Content-Type': 'application/json'},
json={
'secret': {
'nillion_seed': USER_SEED,
'secret_value': 16,
'secret_name': 'my_secret_number'
},
'permissions': {
'retrieve': [],
'update': [],
'delete': [],
'compute': {}
}
}
).json()
print('First secret stored at:', storeResult1)
3. Store a Secret String
Store a string/blob secret using the same endpoint.
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// 3. Store second secret (string/blob)
console.log('\nStoring second secret...');
const storeResult2 = await fetch(`${API_BASE}/api/apps/${APP_ID}/secrets`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: {
nillion_seed: USER_SEED,
secret_value: 'gm!',
secret_name: 'my_secret_blob',
},
permissions: {
retrieve: [],
update: [],
delete: [],
compute: {},
},
}),
}).then((res) => res.json());
console.log('Second secret stored at:', storeResult2);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
print('\nStoring second secret...')
storeResult2 = requests.post(
f'{API_BASE}/api/apps/{APP_ID}/secrets',
headers={'Content-Type': 'application/json'},
json={
'secret': {
'nillion_seed': USER_SEED,
'secret_value': 'gm!',
'secret_name': 'my_secret_blob'
},
'permissions': {
'retrieve': [],
'update': [],
'delete': [],
'compute': {}
}
}
).json()
print('Second secret stored at:', storeResult2)
4. List Store IDs
Get all store IDs for your app using GET /api/apps/{app_id}/store_ids
to find your secrets.
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// 4. List store IDs
const storeIds = await fetch(`${API_BASE}/api/apps/${APP_ID}/store_ids`)
.then((res) => res.json())
.then((data) => data.store_ids);
console.log('Store IDs:', storeIds);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
response = requests.get(f'{API_BASE}/api/apps/{APP_ID}/store_ids')
storeIds = response.json()['store_ids']
print('Store IDs:', storeIds)
5. Retrieve Secrets
Get each secret's value using GET /api/secret/retrieve/{store_id}
with the correct secret name and user seed.
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
const storeIds = await fetch(`${API_BASE}/api/apps/${APP_ID}/store_ids`)
.then((res) => res.json())
.then((data) => data.store_ids);
// 5. Retrieve both secrets using the store IDs we just created
console.log('\nRetrieving secrets...');
const secret1 = await fetch(
`${API_BASE}/api/secret/retrieve/${storeIds[0].store_id}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=${storeIds[0].secret_name}`
).then((res) => res.json());
console.log('First secret retrieved:', secret1);
const secret2 = await fetch(
`${API_BASE}/api/secret/retrieve/${storeIds[1].store_id}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=${storeIds[1].secret_name}`
).then((res) => res.json());
console.log('Second secret retrieved:', secret2);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
response = requests.get(f'{API_BASE}/api/apps/{APP_ID}/store_ids')
storeIds = response.json()['store_ids']
print('\nRetrieving secrets...')
secret1 = requests.get(
f'{API_BASE}/api/secret/retrieve/{storeIds[0]["store_id"]}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': storeIds[0]['secret_name']
}
).json()
print('First secret retrieved:', secret1)
secret2 = requests.get(
f'{API_BASE}/api/secret/retrieve/{storeIds[1]["store_id"]}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': storeIds[1]['secret_name']
}
).json()
print('Second secret retrieved:', secret2)
6. Update Secret
Update an existing secret's value using PUT /api/apps/{app_id}/secrets/{store_id}
with the secret's store ID and updated value.
Make sure to update the APP_ID
and STORE_ID
below with your values before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const STORE_ID = 'INSERT_YOUR_STORE_ID_HERE'; // use the store_id of the secret you want to update
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// Update the secret with a new value
console.log('\nUpdating secret...');
const updateResponse = await fetch(
`${API_BASE}/api/apps/${APP_ID}/secrets/${STORE_ID}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nillion_seed: USER_SEED,
secret_value: "gm gm gm gm!",
secret_name: "my_secret" // use the original secret name
}),
}
).then((res) => res.json());
console.log('Secret updated:', updateResponse);
// Verify the updated secret
const verifyResponse = await fetch(
`${API_BASE}/api/secret/retrieve/${STORE_ID}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=my_secret`
).then((res) => res.json());
console.log('Updated secret retrieved:', verifyResponse);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
STORE_ID = 'INSERT_YOUR_STORE_ID_HERE' # use the store_id of the secret you want to update
USER_SEED = 'user_123' # generates a deterministic nillion user id; use any string
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
print('\nUpdating secret...')
updateResponse = requests.put(
f'{API_BASE}/api/apps/{APP_ID}/secrets/{STORE_ID}',
headers={'Content-Type': 'application/json'},
json={
'nillion_seed': USER_SEED,
'secret_value': "gm gm gm gm!",
'secret_name': "my_secret" # use the original secret name
}
).json()
print('Secret updated:', updateResponse)
# Verify the updated secret
verifyResponse = requests.get(
f'{API_BASE}/api/secret/retrieve/{STORE_ID}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': 'my_secret'
}
).json()
print('Updated secret retrieved:', verifyResponse)
Quickstart Complete Code
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // your seed generates a deterministic nillion user id - check it in step 1
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
async function runQuickstart() {
try {
// 1. Check your deterministic user ID
console.log('Checking user ID generated by your seed...');
const user = await fetch(`${API_BASE}/api/user`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
nillion_seed: USER_SEED,
}),
}).then((res) => res.json());
console.log('Your User ID:', user.nillion_user_id);
// 2. Store first secret (number)
console.log('\nStoring first secret...');
const storeResult1 = await fetch(`${API_BASE}/api/apps/${APP_ID}/secrets`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: {
nillion_seed: USER_SEED,
secret_value: 16,
secret_name: 'my_secret_number',
},
permissions: {
retrieve: [],
update: [],
delete: [],
compute: {},
},
}),
}).then((res) => res.json());
console.log('First secret stored at:', storeResult1);
// 3. Store second secret (string/blob)
console.log('\nStoring second secret...');
const storeResult2 = await fetch(`${API_BASE}/api/apps/${APP_ID}/secrets`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: {
nillion_seed: USER_SEED,
secret_value: 'gm!',
secret_name: 'my_secret_blob',
},
permissions: {
retrieve: [],
update: [],
delete: [],
compute: {},
},
}),
}).then((res) => res.json());
console.log('Second secret stored at:', storeResult2);
// 4. List store IDs
console.log('\nListing store IDs...');
const storeIds = await fetch(`${API_BASE}/api/apps/${APP_ID}/store_ids`)
.then((res) => res.json())
.then((data) => data.store_ids);
console.log('Store IDs:', storeIds);
// 5. Retrieve both secrets using the store IDs we just created
console.log('\nRetrieving secrets...');
const secret1 = await fetch(
`${API_BASE}/api/secret/retrieve/${storeIds[0].store_id}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=${storeIds[0].secret_name}`
).then((res) => res.json());
console.log('First secret retrieved:', secret1);
const secret2 = await fetch(
`${API_BASE}/api/secret/retrieve/${storeIds[1].store_id}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=${storeIds[1].secret_name}`
).then((res) => res.json());
console.log('Second secret retrieved:', secret2);
// 6. Update first secret
console.log('\nUpdating first secret...');
const updateResponse = await fetch(
`${API_BASE}/api/apps/${APP_ID}/secrets/${storeIds[0].store_id}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
nillion_seed: USER_SEED,
secret_value: "gm gm gm gm!",
secret_name: storeIds[0].secret_name
}),
}
).then((res) => res.json());
console.log('Secret updated:', updateResponse);
// Verify the update
const verifyUpdate = await fetch(
`${API_BASE}/api/secret/retrieve/${storeIds[0].store_id}?retrieve_as_nillion_user_seed=${USER_SEED}&secret_name=${storeIds[0].secret_name}`
).then((res) => res.json());
console.log('Updated secret retrieved:', verifyUpdate);
} catch (error) {
console.error('Error in flow:', error);
}
}
// Run the quickstart
runQuickstart();
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
def run_quickstart():
try:
print('Checking user ID generated by your seed...')
user = requests.post(
f'{API_BASE}/api/user',
headers={'Content-Type': 'application/json'},
json={'nillion_seed': USER_SEED}
).json()
print('Your User ID:', user['nillion_user_id'])
print('\nStoring first secret...')
storeResult1 = requests.post(
f'{API_BASE}/api/apps/{APP_ID}/secrets',
headers={'Content-Type': 'application/json'},
json={
'secret': {
'nillion_seed': USER_SEED,
'secret_value': 16,
'secret_name': 'my_secret_number'
},
'permissions': {
'retrieve': [],
'update': [],
'delete': [],
'compute': {}
}
}
).json()
print('First secret stored at:', storeResult1)
print('\nStoring second secret...')
storeResult2 = requests.post(
f'{API_BASE}/api/apps/{APP_ID}/secrets',
headers={'Content-Type': 'application/json'},
json={
'secret': {
'nillion_seed': USER_SEED,
'secret_value': 'gm!',
'secret_name': 'my_secret_blob'
},
'permissions': {
'retrieve': [],
'update': [],
'delete': [],
'compute': {}
}
}
).json()
print('Second secret stored at:', storeResult2)
print('\nListing store IDs...')
storeIds = requests.get(f'{API_BASE}/api/apps/{APP_ID}/store_ids').json()['store_ids']
print('Store IDs:', storeIds)
print('\nRetrieving secrets...')
secret1 = requests.get(
f'{API_BASE}/api/secret/retrieve/{storeIds[0]["store_id"]}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': storeIds[0]['secret_name']
}
).json()
print('First secret retrieved:', secret1)
secret2 = requests.get(
f'{API_BASE}/api/secret/retrieve/{storeIds[1]["store_id"]}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': storeIds[1]['secret_name']
}
).json()
print('Second secret retrieved:', secret2)
# 6. Update first secret
print('\nUpdating first secret...')
updateResponse = requests.put(
f'{API_BASE}/api/apps/{APP_ID}/secrets/{storeIds[0]["store_id"]}',
headers={'Content-Type': 'application/json'},
json={
'nillion_seed': USER_SEED,
'secret_value': "gm gm gm gm!",
'secret_name': storeIds[0]['secret_name']
}
).json()
print('Secret updated:', updateResponse)
# Verify the update
verifyUpdate = requests.get(
f'{API_BASE}/api/secret/retrieve/{storeIds[0]["store_id"]}',
params={
'retrieve_as_nillion_user_seed': USER_SEED,
'secret_name': storeIds[0]['secret_name']
}
).json()
print('Updated secret retrieved:', verifyUpdate)
except Exception as error:
print('Error in flow:', error)
# Run the quickstart
run_quickstart()
How to Share Secrets with Other Users
Store with Permissions
To give another user access to your secrets, include their user_id in the permissions arrays when storing.
Make sure to update the APP_ID
below with your app_id from step 0 before running the code:
- JavaScript
- Python
const APP_ID = 'INSERT_YOUR_APP_ID_HERE';
const USER_SEED = 'user_123'; // generates a deterministic nillion user id; use any string
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
// Example using a "test" user seed - your friend should use their own unique seed in production
const friend_user_id =
'63P5NjU6a2zkjJqengfuDuwMUF9Yu3ogrrqMPNjidc4ogfcvefDchZgRNNJQg9T3WKiyZ4L7kF4zGwFurpxCo5bP';
const storeResultForFriend = await fetch(
`${API_BASE}/api/apps/${APP_ID}/secrets`,
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
secret: {
nillion_seed: USER_SEED,
secret_value: 'secret message to my friend!',
secret_name: 'message_to_friend',
},
permissions: {
retrieve: [friend_user_id], // give friend retrieve permission
update: [],
delete: [],
compute: {},
},
}),
}
).then((res) => res.json());
console.log('Secret stored for friend:', storeResultForFriend);
import requests
APP_ID = 'INSERT_YOUR_APP_ID_HERE'
USER_SEED = 'user_123'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
# Example using a "test" user seed - your friend should use their own unique seed in production
friend_user_id = '63P5NjU6a2zkjJqengfuDuwMUF9Yu3ogrrqMPNjidc4ogfcvefDchZgRNNJQg9T3WKiyZ4L7kF4zGwFurpxCo5bP'
storeResultForFriend = requests.post(
f'{API_BASE}/api/apps/{APP_ID}/secrets',
headers={'Content-Type': 'application/json'},
json={
'secret': {
'nillion_seed': USER_SEED,
'secret_value': 'secret message to my friend!',
'secret_name': 'message_to_friend'
},
'permissions': {
'retrieve': [friend_user_id], # give friend retrieve permission
'update': [],
'delete': [],
'compute': {}
}
}
).json()
print('Secret stored for friend:', storeResultForFriend)
Retrieve with Permissions
If you tell your friend the store id, that friend can then retrieve the secret using their seed:
Make sure to update the store_id
below before running the code:
- JavaScript
- Python
const store_id = 'store_id_from_above';
const API_BASE = 'https://nillion-storage-apis-v0.onrender.com';
const friend_user_seed = 'test'; // friends should use their own unique seed
const secret = await fetch(
`${API_BASE}/api/secret/retrieve/${store_id}?retrieve_as_nillion_user_seed=${friend_user_seed}&secret_name=message_to_friend`
).then((res) => res.json());
console.log('Secret retrieved by friend:', secret);
import requests
store_id = 'store_id_from_above'
API_BASE = 'https://nillion-storage-apis-v0.onrender.com'
friend_user_seed = 'test' # friends should use their own unique seed
secret = requests.get(
f'{API_BASE}/api/secret/retrieve/{store_id}',
params={
'retrieve_as_nillion_user_seed': friend_user_seed,
'secret_name': 'message_to_friend'
}
).json()
print('Secret retrieved by friend:', secret)