Developer Guide: Programmatic Access to Pintheon Node β
This guide will walk you through the process of programmatically interacting with a Pintheon node, including generating access tokens and uploading files.
Prerequisites β
- Python 3.8 or higher installed
- A running Pintheon node on your local machine (default port: 3000)
requests
library for HTTP requests
Installation β
First, install the required package:
pip install requests
Step 1: Get an Access Token β
To interact with the Pintheon node's API, you'll need an access token. This token is used to authenticate your requests.
Get Your Access Token β
- Open the Pintheon web interface in your browser
- Navigate to Settings > Access Tokens
- Click Generate New Token
- Copy the generated token - you'll use this in your API requests
For detailed instructions with screenshots, see the Access Tokens documentation.
Security Notes β
- Keep your access token secure and never commit it to version control
- Use environment variables to store your token in production
- Rotate your tokens regularly for security
- The access token provides full access to your Pintheon node's API, so treat it like a password
Step 2: Using the Access Token β
Once you have your access token, you can use it to authenticate your API requests to the Pintheon node. The token should be included in the access_token
parameter of your requests.
Step 4: Upload a File Programmatically β
Now you can use the access token to upload files to your Pintheon node. The Pintheon node provides an API endpoint for file uploads that requires a valid access token.
import requests
import os
# Pintheon node configuration
PINTHEON_API_URL = "https://localhost:9999/api_upload" # Default API endpoint
# File to upload
file_path = "path/to/your/file.txt"
# Your access token from the Pintheon web interface
# Go to Settings > Access Tokens to generate one
access_token = "your_access_token_here" # Replace with your actual access token
# 2. Prepare the file upload
try:
# Open the file in binary mode
with open(file_path, 'rb') as f:
# Prepare the multipart form data
files = {
'file': (os.path.basename(file_path), f, 'application/octet-stream')
}
# Required form data
data = {
'access_token': access_token,
'encrypted': 'false' # Set to 'true' for encrypted uploads
}
# 3. Make the upload request
response = requests.post(
PINTHEON_API_URL,
files=files,
data=data,
verify=False, # Only for local development with self-signed certs
timeout=30 # 30 second timeout
)
# 4. Handle the response
if response.status_code == 200:
result = response.json()
cid = result.get('Hash') or result.get('IpfsHash')
if cid:
# Construct the gateway URL
gateway_url = f"https://your-pintheon-gateway/ipfs/{cid}"
print(f"File uploaded successfully!")
print(f"IPFS CID: {cid}")
print(f"Gateway URL: {gateway_url}")
# The file is now available at the gateway URL
# You can use this URL to access the file from any IPFS gateway
else:
print("Upload successful but no CID returned in response")
print(f"Response: {response.text}")
else:
print(f"Upload failed with status {response.status_code}")
print(f"Response: {response.text}")
except FileNotFoundError:
print(f"Error: File not found at {file_path}")
except requests.exceptions.RequestException as e:
print(f"Network error during upload: {e}")
except Exception as e:
print(f"An unexpected error occurred: {e}")
Important Notes: β
Access Token: The access token is generated fresh for each upload with a short expiration time (5 minutes in this example).
HTTPS: The example uses HTTPS with certificate verification disabled (
verify=False
), which is only suitable for local development. For production, use proper SSL certificates.Gateway URL: Replace
your-pintheon-gateway
with your actual Pintheon node's gateway address.Error Handling: The example includes basic error handling, but you may want to enhance it based on your application's needs.
File Size: For large files, consider implementing progress tracking and chunked uploads.
Security: Never expose your private key in client-side code. This example is for server-side use only.
Step 5: Retrieve File Information β
You can retrieve information about uploaded files using the Pintheon node's API. Here's how to get file information and access your uploaded files:
def get_file_info(ipfs_cid, pintheon_gateway="your-pintheon-gateway"):
"""
Retrieve information about an uploaded file using its IPFS CID.
:param ipfs_cid: The IPFS Content Identifier (CID) of the file
:param pintheon_gateway: The base URL of your Pintheon gateway
:return: Dictionary containing file information or None on error
"""
try:
# Construct the URL to the file on the Pintheon gateway
file_url = f"https://{pintheon_gateway}/ipfs/{ipfs_cid}"
# Make a HEAD request to get file metadata
response = requests.head(file_url, allow_redirects=True, timeout=10)
if response.status_code == 200:
# Extract relevant headers
file_info = {
'cid': ipfs_cid,
'url': file_url,
'content_type': response.headers.get('Content-Type'),
'content_length': response.headers.get('Content-Length'),
'last_modified': response.headers.get('Last-Modified'),
'etag': response.headers.get('ETag')
}
return file_info
else:
print(f"Error retrieving file info: {response.status_code}")
return None
except requests.exceptions.RequestException as e:
print(f"Network error retrieving file info: {e}")
return None
# Example usage
if __name__ == "__main__":
# Replace with an actual CID from your upload
cid = "QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco"
file_info = get_file_info(cid, "your-pintheon-gateway")
if file_info:
print("File Information:")
for key, value in file_info.items():
print(f"{key}: {value}")
Accessing Your Files β
Once uploaded, your files are accessible through any IPFS gateway using the CID returned during upload. The URL format is:
https://<pintheon-gateway>/ipfs/<cid>
For example, if your Pintheon gateway is gateway.pintheon.example.com
and your file's CID is QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco
, the URL would be:
https://gateway.pintheon.example.com/ipfs/QmXoypizjW3WknFiJnKLwHCnL72vedxjQkDDP1mXWo6uco
Important Notes: β
Persistence: Files are only available as long as they are pinned by your Pintheon node. Make sure to pin important files through the Pintheon web interface or API.
Caching: The Pintheon gateway may cache files for performance. Changes to a file with the same CID will not be reflected until the cache expires.
Performance: For large files, consider using a dedicated IPFS client for better performance when retrieving files.
Error Handling β
When working with the Pintheon API, it's important to handle errors gracefully. Here's how to handle common error scenarios:
def upload_file(api_url, file_path, access_token, encrypted=False, timeout=30):
"""
Upload a file to a Pintheon node with proper error handling.
:param api_url: URL of the Pintheon API endpoint (e.g., 'https://localhost:9999/api_upload')
:param file_path: Path to the file to upload
:param access_token: Valid access token for authentication
:param encrypted: Whether to encrypt the file (True/False)
:param timeout: Request timeout in seconds
:return: Tuple of (success: bool, result: dict or str)
"""
try:
# Verify file exists and is readable
if not os.path.isfile(file_path):
return False, f"File not found: {file_path}"
if not os.access(file_path, os.R_OK):
return False, f"Permission denied reading file: {file_path}"
# Prepare the request
with open(file_path, 'rb') as f:
files = {'file': (os.path.basename(file_path), f, 'application/octet-stream')}
data = {
'access_token': access_token,
'encrypted': str(encrypted).lower()
}
# Make the request
response = requests.post(
api_url,
files=files,
data=data,
verify=False, # Disable SSL verification for local development
timeout=timeout
)
# Handle the response
if response.status_code == 200:
try:
result = response.json()
if 'Hash' in result or 'IpfsHash' in result:
return True, result
else:
return False, f"Unexpected response format: {result}"
except ValueError:
return False, f"Invalid JSON response: {response.text}"
elif response.status_code == 400:
return False, f"Bad request: {response.text}"
elif response.status_code == 401:
return False, "Authentication failed: Invalid or expired access token"
elif response.status_code == 403:
return False, "Forbidden: Check your token permissions"
elif response.status_code == 413:
return False, "File too large: Exceeds maximum allowed size"
elif response.status_code == 500:
return False, f"Server error: {response.text}"
else:
return False, f"Unexpected status code {response.status_code}: {response.text}
except requests.exceptions.Timeout:
return False, "Request timed out. The server took too long to respond."
except requests.exceptions.SSLError:
return False, "SSL certificate verification failed. For development, you can disable verification (not recommended for production)."
except requests.exceptions.ConnectionError:
return False, "Connection failed. Check if the Pintheon node is running and accessible."
except requests.exceptions.RequestException as e:
return False, f"Request failed: {str(e)}"
except IOError as e:
return False, f"File operation failed: {str(e)}"
except Exception as e:
return False, f"An unexpected error occurred: {str(e)}"
Example Usage with Error Handling β
# Example usage of the upload_file function
api_url = "https://localhost:9999/api_upload"
file_path = "path/to/your/file.txt"
access_token = "your_access_token_here"
success, result = upload_file(api_url, file_path, access_token)
if success:
cid = result.get('Hash') or result.get('IpfsHash')
print(f"File uploaded successfully! CID: {cid}")
# You can now access the file at:
gateway_url = f"https://your-pintheon-gateway/ipfs/{cid}"
print(f"Access your file at: {gateway_url}")
else:
print(f"Upload failed: {result}")
# Handle specific error cases
if "Authentication failed" in result:
print("Please check your access token and try again.")
elif "Connection failed" in result:
print("Please ensure the Pintheon node is running and accessible.")
Common Error Scenarios β
Authentication Errors (401/403)
- Token has expired (generate a new one)
- Invalid token format
- Missing required permissions
- Public key not registered with the node
File Upload Errors
- File too large (413)
- Invalid file format
- Insufficient disk space on node
- Network issues during upload
Server Errors (5xx)
- Pintheon node service down
- Database connection issues
- Internal server errors
Best Practices β
1. Token Management β
- Short-Lived Tokens: Generate tokens with short expiration times (5-15 minutes)
- Token Storage: Store tokens securely using environment variables or a secrets management system
- Token Rotation: Implement token rotation to automatically refresh tokens before they expire
- Least Privilege: Only request the minimum permissions needed for your application
2. File Handling β
File Validation:
- Verify file types and sizes before upload
- Implement virus scanning for user-uploaded content
- Set reasonable file size limits
Large Files:
- For files > 100MB, consider chunked uploads
- Implement progress tracking for better user feedback
- Handle network interruptions gracefully with resume capabilities
3. Performance Optimization β
- Connection Pooling: Reuse HTTP connections for multiple requests
- Timeouts: Set appropriate timeouts for all API calls
- Concurrent Uploads: For multiple files, use concurrent uploads with thread pools
- Caching: Cache frequently accessed files locally when possible
4. Security β
- HTTPS: Always use HTTPS in production
- Input Validation: Sanitize all user inputs
- Error Messages: Don't expose sensitive information in error messages
- Rate Limiting: Implement client-side rate limiting to avoid being throttled
5. Monitoring and Logging β
- Request Logging: Log all API requests and responses (redacting sensitive data)
- Error Tracking: Implement comprehensive error tracking
- Performance Metrics: Monitor upload/download speeds and failure rates
- Alerting: Set up alerts for abnormal conditions (e.g., high error rates)
Troubleshooting β
1. Authentication Issues β
Symptoms:
- HTTP 401 (Unauthorized) or 403 (Forbidden) errors
- "Invalid token" or "Token expired" messages
- "Public key not registered" errors
Solutions:
Token Expired: Generate a new access token with
hvym_stellar
pythonfrom hvym_stellar import StellarSharedKeyTokenBuilder from stellar_sdk import Keypair # Generate a new token sender = Keypair.from_secret("your_secret_key") token = StellarSharedKeyTokenBuilder( sender=sender, receiver_public_key="pintheon_node_public_key", token_type="access", expires_in=300 # 5 minutes ) new_token = token.serialize()
Public Key Not Registered:
- Get your public key:
print(sender.public_key)
- Register it in the Pintheon web interface under Settings > Access Tokens
- Get your public key:
Insufficient Permissions:
- Verify the token was created with the required permissions
- Check the token's caveats for any restrictions
2. Connection Problems β
Symptoms:
- Connection timeouts
- "Connection refused" errors
- SSL certificate verification failures
Solutions:
Verify Node Status:
bash# Check if the Pintheon service is running docker ps | grep pintheon # Check service logs docker logs pintheon-node
Check Network Connectivity:
bash# Test basic connectivity ping your-pintheon-host # Test port accessibility telnet your-pintheon-host 9999 # Test HTTPS connectivity curl -v https://your-pintheon-host:9999/api_upload
SSL Certificate Issues:
- For development, you can disable SSL verification (not recommended for production):python
import requests requests.packages.urllib3.disable_warnings() # Suppress SSL warnings response = requests.get( "https://your-pintheon-host:9999/api_endpoint", verify=False # Disable SSL verification )
- For production, ensure you have valid SSL certificates configured
- For development, you can disable SSL verification (not recommended for production):
3. File Upload Problems β
Symptoms:
- Slow uploads
- Timeout errors
- "File too large" errors
- Corrupted files
Solutions:
Large Files:
- For files > 100MB, implement chunked uploads
- Increase timeout values:python
response = requests.post( "https://your-pintheon-host:9999/api_upload", files=files, data=data, timeout=300 # 5 minute timeout )
File Size Limits:
- Check available disk space on the Pintheon node:bash
df -h /path/to/ipfs/storage
- Check IPFS repo size and quota:bash
ipfs repo stat
- Check available disk space on the Pintheon node:
Corrupted Files:
- Verify file integrity after upload using checksums
- Implement retry logic for failed uploads
4. Performance Issues β
Symptoms:
- Slow response times
- High CPU/memory usage
- Timeout errors
Optimizations:
Connection Pooling:
pythonimport requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry session = requests.Session() retry_strategy = Retry( total=3, backoff_factor=1, status_forcelist=[500, 502, 503, 504] ) adapter = HTTPAdapter(max_retries=retry_strategy) session.mount("https://", adapter) # Use this session for all requests response = session.post("https://your-pintheon-host:9999/api_upload", files=files, data=data)
Concurrent Uploads:
pythonfrom concurrent.futures import ThreadPoolExecutor, as_completed def upload_file_wrapper(file_path): return upload_file(API_URL, file_path, ACCESS_TOKEN) # Upload up to 5 files concurrently with ThreadPoolExecutor(max_workers=5) as executor: future_to_file = { executor.submit(upload_file_wrapper, file_path): file_path for file_path in file_paths } for future in as_completed(future_to_file): file_path = future_to_file[future] try: success, result = future.result() if success: print(f"Uploaded {file_path}: {result.get('Hash')}") else: print(f"Failed to upload {file_path}: {result}") except Exception as e: print(f"Error uploading {file_path}: {str(e)}")
5. Common Error Messages β
"Invalid access token":
- Generate a new token
- Ensure the token hasn't expired
- Verify the token format is correct
"Connection refused":
- Check if the Pintheon node is running
- Verify the host and port are correct
- Check for firewall rules blocking the connection
"Request timed out":
- Increase the timeout value
- Check network connectivity
- Verify the node isn't under heavy load
"File too large":
- Check the file size limit on the Pintheon node
- Consider using chunked uploads for large files
- Verify available disk space on the node
Next Steps β
- Explore the full API documentation for additional endpoints
- Implement file encryption for sensitive data
- Set up automatic token refresh
- Build a client library for your preferred programming language