Aluchin API
Verify any document on the blockchain in one API call. Get permanent, tamper-proof proof of existence.
Quick Start
Get your first verification in under 3 minutes.
- Go to the Dashboard and upload any file to create your session
- Click Generate Key in the API Keys section to get an API key
- Use it in the
X-API-Keyheader:
curl -X POST https://aluchin.com/api/v1/verify \ -H "X-API-Key: ak_YOUR_KEY_HERE" \ -F "file=@invoice.pdf"
The response includes a permanent verification_url you can share with anyone to prove the document existed at that exact moment.
{
"id": "a1b2c3d4e5",
"hash": "e3b0c44298fc1c149afb...",
"filename": "invoice.pdf",
"verification_url": "https://aluchin.com/v/a1b2c3d4e5",
"hedera_tx": "0.0.5144666@1706000000.000000000",
"hashscan_url": "https://hashscan.io/testnet/transaction/...",
"network": "testnet",
"sequence_number": 42
}
Authentication
All API requests require authentication via one of two headers:
API Key (recommended for server-to-server)
X-API-Key: ak_YOUR_KEY_HERE
Create API keys in the Dashboard. Keys start with ak_ and are 35 characters long. Store them securely — they cannot be retrieved after creation.
Session Token (for browser apps)
X-Session-Token: YOUR_SESSION_TOKEN
Session tokens are created automatically when you upload your first file. They're stored in localStorage and used by the dashboard and Try It widget.
Both methods link requests to the same account. An API key created from a session will share the same verification history and quota.
The GET /api/v1/auth/me endpoint returns your user info including email_notifications (boolean) indicating whether verification confirmation emails are enabled.
POST /api/v1/verify
Upload a document to create a blockchain verification. The SHA-256 hash of the file is submitted to Hedera Consensus Service, creating a permanent, tamper-proof record.
Request
Two input methods:
Multipart form data (recommended for files):
curl -X POST https://aluchin.com/api/v1/verify \ -H "X-API-Key: ak_YOUR_KEY" \ -F "file=@document.pdf"
JSON with base64 (for programmatic use):
curl -X POST https://aluchin.com/api/v1/verify \
-H "X-API-Key: ak_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"file": "BASE64_ENCODED_FILE", "filename": "invoice.pdf"}'
Response
Returns 201 Created for new verifications, or 200 OK if the file was already verified (deduplication).
| Field | Type | Description |
|---|---|---|
| id | string | Short unique ID for this verification |
| hash | string | SHA-256 hash of the uploaded file |
| filename | string | Original filename |
| file_size | integer | File size in bytes |
| verification_url | string | Public proof page URL |
| hedera_tx | string | Hedera transaction ID |
| hashscan_url | string | Link to transaction on HashScan explorer |
| network | string | testnet or mainnet (determined by your plan) |
| sequence_number | integer | HCS topic sequence number |
| topic_id | string | Hedera topic ID used for this verification |
| already_verified | boolean | true if file was previously verified (dedup) |
| existing_proof | boolean | true if returning a previously verified record |
| first_verified | string | ISO timestamp of when the file was originally verified (dedup only) |
Global Deduplication
If any user has previously verified a file with the same SHA-256 hash, the API returns the original verification record (200 OK) instead of creating a duplicate. This is global across all users — the same document always maps to the same proof. The response includes existing_proof: true and first_verified with the original timestamp. Deduplicated requests do not count against your monthly quota.
GET /api/v1/verify/:id
Retrieve a verification record by its short ID. No authentication required.
curl https://aluchin.com/api/v1/verify/a1b2c3d4e5
GET /api/v1/verify/hash/:hash
Look up a verification by the document's SHA-256 hash. Useful for checking if a specific file has been verified without uploading it.
curl https://aluchin.com/api/v1/verify/hash/e3b0c44298fc1c149afbf4c8996fb924...
POST /api/v1/check
Upload a file to check if it matches any existing verification. Does not create a new record or consume quota. Perfect for re-verification workflows.
curl -X POST https://aluchin.com/api/v1/check \ -F "file=@invoice.pdf"
Response
{ "verified": true, "hash": "e3b0...", "verification_url": "...", "hedera_tx": "..." }
{ "verified": false, "hash": "a1b2...", "message": "This document has not been verified through Aluchin." }
GET /api/v1/verifications
List all verifications for your session, paginated. Requires authentication.
| Parameter | Default | Description |
|---|---|---|
| page | 1 | Page number |
| limit | 20 | Items per page (max 100) |
| sort | newest | newest or oldest |
| search | Filter by filename |
curl https://aluchin.com/api/v1/verifications?page=1&limit=10 \ -H "X-API-Key: ak_YOUR_KEY"
GET /api/v1/verifications/stats
Get summary statistics for your session: total verifications, monthly usage, current plan, and network.
{
"total_verifications": 47,
"total_file_size": 12582912,
"this_month": 7,
"api_key_count": 2,
"plan": "free",
"monthly_limit": 10,
"monthly_usage": 7,
"network": "testnet"
}
POST /api/v1/keys
Generate a new API key. Requires session token authentication (API keys cannot create other API keys). Requires a paid plan (Starter, Business, or API Pro). Free users receive 403.
curl -X POST https://aluchin.com/api/v1/keys \
-H "X-Session-Token: YOUR_SESSION" \
-H "Content-Type: application/json" \
-d '{"label": "Production Server"}'
The full key is returned only once. Store it securely.
GET /api/v1/keys
List all API keys for your session (masked). Requires authentication.
DELETE /api/v1/keys/:keyPreview
Revoke an API key. Requires session token authentication — you cannot use an API key to delete itself. The :keyPreview is the masked key format shown in GET /keys (e.g., ak_AbCdE...xYzW).
curl -X DELETE https://aluchin.com/api/v1/keys/ak_AbCdE...xYzW \ -H "X-Session-Token: YOUR_SESSION"
{ "message": "API key deactivated" }
POST /api/v1/webhooks
Register a webhook URL to receive POST notifications after each successful verification. Requires the API Pro plan ($79/mo). Other plans receive 403.
curl -X POST https://aluchin.com/api/v1/webhooks \
-H "X-Session-Token: YOUR_SESSION" \
-H "Content-Type: application/json" \
-d '{"url": "https://your-server.com/webhook"}'
URL must be HTTPS in production. Maximum 5 webhooks per account.
Response (201 Created)
{
"id": "wh_abc123",
"url": "https://your-server.com/webhook",
"secret": "a1b2c3d4e5f6...64_hex_chars",
"created_at": "2025-01-15T14:30:00.000Z",
"message": "Webhook created. Save the secret — it will not be shown again."
}
Important: The secret is shown only once. Store it securely — you'll need it to verify webhook signatures.
GET /api/v1/webhooks
List all registered webhooks. Secrets are not included in the response.
{
"webhooks": [
{
"id": "wh_abc123",
"url": "https://your-server.com/webhook",
"active": 1,
"created_at": "2025-01-15T14:30:00.000Z"
}
]
}
DELETE /api/v1/webhooks/:id
Delete a webhook. Returns 404 if not found or not owned by your account.
{ "message": "Webhook deleted." }
POST /api/v1/webhooks/test
Send a test payload to all your registered webhooks. Useful for verifying your webhook handler is working correctly.
{
"results": [
{ "url": "https://your-server.com/webhook", "success": true, "status": 200 }
]
}
Webhook Payload & Signatures
Every webhook delivery includes an HMAC-SHA256 signature so you can verify it came from Aluchin.
Headers
| Header | Description |
|---|---|
| X-Aluchin-Signature | HMAC-SHA256 hex digest of the request body, signed with your webhook secret |
| X-Aluchin-Event | Event type: verification.created or test |
| Content-Type | application/json |
Payload
{
"event": "verification.created",
"timestamp": "2025-01-15T14:30:00.000Z",
"data": {
"id": "a1b2c3d4e5",
"hash": "e3b0c44298fc1c149afb...",
"filename": "invoice.pdf",
"file_size": 245760,
"verification_url": "https://aluchin.com/v/a1b2c3d4e5",
"hedera_tx": "0.0.5144666@1706000000.000000000",
"hashscan_url": "https://hashscan.io/mainnet/transaction/...",
"network": "mainnet",
"sequence_number": 42
}
}
Verifying Signatures
const crypto = require('crypto');
function verifyWebhook(body, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return signature === expected;
}
// In your Express handler:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-aluchin-signature'];
if (!verifyWebhook(req.body, sig, WEBHOOK_SECRET)) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(req.body);
console.log('Verified:', payload.data.filename);
res.sendStatus(200);
});
import hmac, hashlib
def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(), body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)
# In your Flask handler:
@app.route('/webhook', methods=['POST'])
def webhook():
sig = request.headers.get('X-Aluchin-Signature')
if not verify_webhook(request.data, sig, WEBHOOK_SECRET):
return 'Invalid signature', 401
data = request.json
print(f"Verified: {data['data']['filename']}")
return '', 200
Delivery: Webhooks have a 10-second timeout. If the first attempt fails, Aluchin retries once automatically after 2 seconds. After that, the delivery is dropped.
PUT /api/v1/auth/me/notifications
Toggle email notifications. When enabled, you receive a confirmation email after each successful verification with document details and a proof link.
curl -X PUT https://aluchin.com/api/v1/auth/me/notifications \
-H "X-Session-Token: YOUR_SESSION" \
-H "Content-Type: application/json" \
-d '{"email_notifications": false}'
{
"email_notifications": false,
"message": "Notification preference updated."
}
Email notifications are enabled by default for all users. You can also toggle this from the Dashboard settings.
Code Examples
Python
import requests
API_KEY = "ak_YOUR_KEY_HERE"
BASE = "https://aluchin.com/api/v1"
# Verify a file
with open("invoice.pdf", "rb") as f:
res = requests.post(
f"{BASE}/verify",
headers={"X-API-Key": API_KEY},
files={"file": f}
)
data = res.json()
print(f"Proof: {data['verification_url']}")
print(f"TX: {data['hedera_tx']}")
# Check a file later
with open("invoice.pdf", "rb") as f:
check = requests.post(f"{BASE}/check", files={"file": f})
if check.json()["verified"]:
print("Document is authentic.")
else:
print("WARNING: Document has been tampered with!")
Node.js
const fs = require('fs');
const API_KEY = 'ak_YOUR_KEY_HERE';
const BASE = 'https://aluchin.com/api/v1';
async function verifyFile(filePath) {
const file = fs.readFileSync(filePath);
const base64 = file.toString('base64');
const res = await fetch(`${BASE}/verify`, {
method: 'POST',
headers: {
'X-API-Key': API_KEY,
'Content-Type': 'application/json'
},
body: JSON.stringify({
file: base64,
filename: filePath.split('/').pop()
})
});
const data = await res.json();
console.log('Proof URL:', data.verification_url);
return data;
}
verifyFile('invoice.pdf');
cURL (one-liner)
# Verify curl -s -X POST https://aluchin.com/api/v1/verify \ -H "X-API-Key: ak_YOUR_KEY" -F "file=@doc.pdf" | jq .verification_url # Check curl -s -X POST https://aluchin.com/api/v1/check -F "file=@doc.pdf" | jq .verified
Integration Patterns
Accounting & Invoicing
After generating an invoice, verify it immediately and store the proof link alongside the record. When an auditor needs to confirm the invoice hasn't been altered, they re-upload the file to the /check endpoint.
1. Generate invoice PDF
2. POST /verify with the PDF → get verification_url
3. Store verification_url in your database alongside the invoice
4. Email client: "Your invoice is verified: {verification_url}"
5. Auditor: re-upload PDF to /check → confirmed authentic
Legal Contracts
After a contract is signed, verify the final version. The proof link provides third-party evidence that the document existed in its exact form at a specific timestamp.
1. Contract finalized and signed 2. POST /verify with signed PDF → get verification_url + hedera_tx 3. Embed proof link in contract metadata or cover letter 4. Years later: re-upload to /check → proves document unchanged
Compliance & Audit Trails
For regulatory compliance, verify each compliance record as it's created. The blockchain timestamp is independent of your systems, providing tamper-proof evidence for regulatory audits.
1. Create compliance record / report 2. POST /verify → permanent blockchain proof 3. Store verification_url in compliance database 4. Auditor verifies via /check or visits proof page directly 5. HashScan link proves the record on Hedera's public ledger
Testnet vs Mainnet
Aluchin uses two Hedera networks based on your plan:
| Network | Plans | Use |
|---|---|---|
| Testnet | Free | Development, testing, demos. Data may be cleared by Hedera at any time. Not permanent. |
| Mainnet | Starter, Business, API Pro | Production. Permanent blockchain record with real HBAR. Data lives forever. |
The network field in API responses tells you which network was used. Proof pages show a "Testnet" or "Mainnet" badge for transparency.
Rate Limits & Quotas
| Plan | Price | Verifications / Month | Network |
|---|---|---|---|
| Free | $0 | 10 | Testnet |
| Starter | $9/mo | 500 | Mainnet |
| Business | $29/mo | 2,000 | Mainnet |
| API Pro | $79/mo | 10,000 | Mainnet |
When your monthly quota is reached, the API returns 429 Too Many Requests:
{
"error": "Monthly verification limit reached",
"usage": 10,
"limit": 10,
"plan": "free",
"upgrade_url": "https://aluchin.com/#pricing"
}
Duplicate uploads don't count against your quota — if anyone has already verified the same file, you get the existing proof for free. Check your usage anytime via GET /verifications/stats.
In addition, the API enforces rate limits of 30 requests per minute and 5 uploads per minute per IP to prevent abuse.
Error Handling
All errors return JSON with an error field:
| Status | Meaning |
|---|---|
400 | Bad request — missing file or invalid input |
401 | Authentication required or invalid API key |
403 | Forbidden — plan restriction (e.g., free user creating API key, non-API Pro user creating webhook) or API key trying to create another API key |
404 | Verification not found |
429 | Monthly quota exceeded or rate limited |
500 | Server error — try again |
503 | Mainnet not configured (contact support) |
{
"error": "No file provided. Send as multipart/form-data or JSON { file: \"<base64>\" }"
}