API Docs
Home Dashboard

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.

  1. Go to the Dashboard and upload any file to create your session
  2. Click Generate Key in the API Keys section to get an API key
  3. Use it in the X-API-Key header:
cURL
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.

Response
{
  "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)

Header
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)

Header
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

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
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
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).

FieldTypeDescription
idstringShort unique ID for this verification
hashstringSHA-256 hash of the uploaded file
filenamestringOriginal filename
file_sizeintegerFile size in bytes
verification_urlstringPublic proof page URL
hedera_txstringHedera transaction ID
hashscan_urlstringLink to transaction on HashScan explorer
networkstringtestnet or mainnet (determined by your plan)
sequence_numberintegerHCS topic sequence number
topic_idstringHedera topic ID used for this verification
already_verifiedbooleantrue if file was previously verified (dedup)
existing_proofbooleantrue if returning a previously verified record
first_verifiedstringISO 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

GET /api/v1/verify/:id

Retrieve a verification record by its short ID. No authentication required.

cURL
curl https://aluchin.com/api/v1/verify/a1b2c3d4e5

GET /api/v1/verify/hash/:hash

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
curl https://aluchin.com/api/v1/verify/hash/e3b0c44298fc1c149afbf4c8996fb924...

POST /api/v1/check

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
curl -X POST https://aluchin.com/api/v1/check \
  -F "file=@invoice.pdf"

Response

Match Found
{ "verified": true, "hash": "e3b0...", "verification_url": "...", "hedera_tx": "..." }
No Match
{ "verified": false, "hash": "a1b2...", "message": "This document has not been verified through Aluchin." }

GET /api/v1/verifications

GET /api/v1/verifications

List all verifications for your session, paginated. Requires authentication.

ParameterDefaultDescription
page1Page number
limit20Items per page (max 100)
sortnewestnewest or oldest
searchFilter by filename
cURL
curl https://aluchin.com/api/v1/verifications?page=1&limit=10 \
  -H "X-API-Key: ak_YOUR_KEY"

GET /api/v1/verifications/stats

GET /api/v1/verifications/stats

Get summary statistics for your session: total verifications, monthly usage, current plan, and network.

Response
{
  "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

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
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

GET /api/v1/keys

List all API keys for your session (masked). Requires authentication.

DELETE /api/v1/keys/:keyPreview

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
curl -X DELETE https://aluchin.com/api/v1/keys/ak_AbCdE...xYzW \
  -H "X-Session-Token: YOUR_SESSION"
Response
{ "message": "API key deactivated" }

POST /api/v1/webhooks

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
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)

Response
{
  "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

GET /api/v1/webhooks

List all registered webhooks. Secrets are not included in the response.

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 /api/v1/webhooks/:id

Delete a webhook. Returns 404 if not found or not owned by your account.

Response
{ "message": "Webhook deleted." }

POST /api/v1/webhooks/test

POST /api/v1/webhooks/test

Send a test payload to all your registered webhooks. Useful for verifying your webhook handler is working correctly.

Response
{
  "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

HeaderDescription
X-Aluchin-SignatureHMAC-SHA256 hex digest of the request body, signed with your webhook secret
X-Aluchin-EventEvent type: verification.created or test
Content-Typeapplication/json

Payload

verification.created
{
  "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

Node.js
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);
});
Python
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

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
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}'
Response
{
  "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

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

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)

Bash
# 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.

Workflow
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.

Workflow
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.

Workflow
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:

NetworkPlansUse
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

PlanPriceVerifications / MonthNetwork
Free$010Testnet
Starter$9/mo500Mainnet
Business$29/mo2,000Mainnet
API Pro$79/mo10,000Mainnet

When your monthly quota is reached, the API returns 429 Too Many Requests:

429 Response
{
  "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:

StatusMeaning
400Bad request — missing file or invalid input
401Authentication required or invalid API key
403Forbidden — plan restriction (e.g., free user creating API key, non-API Pro user creating webhook) or API key trying to create another API key
404Verification not found
429Monthly quota exceeded or rate limited
500Server error — try again
503Mainnet not configured (contact support)
Error Response Example
{
  "error": "No file provided. Send as multipart/form-data or JSON { file: \"<base64>\" }"
}