Secra API

The Secra API provides cryptographic identity and authentication services for Arkonova Network. It implements a challenge-response authentication flow using Ed25519 signatures, allowing any application to verify user identity without passwords.

Base URL: https://arkonova.network/api/v2/secra

Authentication

Most endpoints require no authentication themselves — they are used to establish authentication. Once authenticated, you receive a JWT token to use in subsequent requests to other APIs.

For endpoints that do require auth, pass the JWT token in the Authorization header:

HTTP Header
Authorization: Bearer <your_jwt_token>

Authentication Flow

Secra uses a 3-step challenge-response flow. No passwords are ever transmitted:

  1. Request a challenge — server returns a unique one-time string
  2. Sign the challenge — user signs it with their Ed25519 private key (via extension or SDK)
  3. Verify the signature — server verifies, returns a JWT token on success
Challenges are single-use and expire after a short window. Never reuse a challenge.

1. Get Challenge

POST /auth/challenge

Request a one-time challenge string for the given address.

ParameterTypeRequiredDescription
addressstringrequiredThe user's Secra address (Ed25519 public key fingerprint)
Request
POST /api/v2/secra/auth/challenge Content-Type: application/json { "address": "arkonova1abc123..." }
Response 200
{ "challenge": "arkonova-auth:1708345123:7f3a9b2c...", "expires_in": 300 }

2. Verify Signature

POST /auth/verify

Submit the signed challenge for server-side verification. Returns a JWT token on success.

ParameterTypeRequiredDescription
addressstringrequiredThe user's Secra address
challengestringrequiredThe challenge string received from /auth/challenge
signaturestringrequiredHex-encoded Ed25519 signature of the challenge
publicKeystringrequiredHex-encoded Ed25519 public key
Request
POST /api/v2/secra/auth/verify Content-Type: application/json { "address": "arkonova1abc123...", "challenge": "arkonova-auth:1708345123:7f3a9b2c...", "signature": "a4f3e9...", "publicKey": "b2c8d1..." }
Response 200 — Success
{ "success": true, "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "address": "arkonova1abc123..." }
Response 404 — User not registered
{ "error": "user_not_found" }
A 404 means the address has never registered with Arkonova. The user must register via the Secra extension first.

3. Set Flask Session

POST /auth/session

Persist the JWT token as a server-side session cookie. Call this after a successful verify to enable session-based authentication across page loads.

ParameterTypeRequiredDescription
tokenstringrequiredJWT token received from /auth/verify
Response 200
{ "ok": true }

Signing Data (Client-Side)

The Secra extension handles signing via postMessage. Here's the full client-side flow:

JavaScript — Extension Sign Request
// Request signing via the Secra browser extension function signWithSecra(message) { return new Promise((resolve, reject) => { const handler = (event) => { if (event.data?.type === 'SECRA_SIGN_RESPONSE') { window.removeEventListener('message', handler); resolve(event.data.signature); } else if (event.data?.type === 'SECRA_SIGN_REJECTED') { window.removeEventListener('message', handler); reject(new Error('rejected')); } }; window.addEventListener('message', handler); window.postMessage({ type: 'SECRA_SIGN_REQUEST', source: 'your-app', message: message }, '*'); setTimeout(() => { window.removeEventListener('message', handler); reject(new Error('timeout')); }, 60000); }); } // Full auth flow example async function loginWithSecra(address) { // Step 1: Get challenge const { challenge } = await fetch('/api/v2/secra/auth/challenge', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address }) }).then(r => r.json()); // Step 2: Sign with extension const signature = await signWithSecra(challenge); // Step 3: Verify const { token } = await fetch('/api/v2/secra/auth/verify', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ address, challenge, signature, publicKey }) }).then(r => r.json()); return token; // JWT }

About Ed25519 Keys

Secra uses Ed25519 (Edwards-curve Digital Signature Algorithm) for all cryptographic operations. Ed25519 provides:

Python — Verify an Ed25519 Signature
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat import binascii def verify_secra_signature(public_key_hex: str, message: str, signature_hex: str) -> bool: public_key_bytes = binascii.unhexlify(public_key_hex) signature_bytes = binascii.unhexlify(signature_hex) message_bytes = message.encode('utf-8') public_key = Ed25519PublicKey.from_public_bytes(public_key_bytes) try: public_key.verify(signature_bytes, message_bytes) return True except Exception: return False

Get User Info

GET /user/<address>

Retrieve public information about a registered Secra user. No authentication required.

Response 200
{ "address": "arkonova1abc123...", "username": "alice", "registered_at": "2025-01-15T10:00:00", "public_key": "b2c8d1..." }

Profile API

The Profile API lets you read and update authenticated user profiles. All profile endpoints require a JWT token.

Get My Profile

GET /profile/me

Returns the full profile of the currently authenticated user, including private fields (balance, privacy settings).

Requires Authorization: Bearer <token>
Response 200
{ "address": "arkonova1abc123...", "username": "alice", "name": "Alice", "about_me": "Developer at Arkonova", "avatar": "https://...", "banner": "https://...", "frame": "frame:neon", "badge": null, "theme": "theme:cosmos", "emoji_status": "🚀", "gift_status_id": null, "vdarko_balance": "1250", "flame": 7, "createdAt": "2025-06-01T12:00:00", "privacy": { "can_receive_messages": true, "show_online": true, "show_balance": false, "allow_dm_from_strangers": true } }

Get Profile by Address

GET /profile/<address>

Returns a user's profile by their Secra address. The caller only sees their own balance; other private fields are hidden per the target's privacy settings.

Requires authentication

Update Profile

PUT /profile/update

Update one or more profile fields. All fields are optional — send only what you want to change.

Requires authentication
FieldTypeDescription
usernamestring3–64 chars, letters/digits/_/-, globally unique
displayNamestringDisplay name (shown in chats)
avatarstringURL or base64 image (pass null to remove)
bannerstringProfile banner URL or base64
biostringAbout me text
framestringItem key, e.g. "frame:neon"
themestringItem key, e.g. "theme:cosmos" or "c:<uuid>" for community themes
decostringChat background deco key, e.g. "deco:aurora"
emoji_statusstringSingle emoji shown next to username
gift_status_idstringID of an owned mythic gift to display as status
privacyobjectPrivacy flags — see table below

Privacy fields (all booleans):

FieldDefaultDescription
can_receive_messagestrueAllow others to message you
show_onlinetrueShow online presence indicator
show_balancefalseShow vDARKO balance on public profile
show_avatartrueShow avatar publicly
show_bannertrueShow banner publicly
show_biotrueShow bio publicly
allow_profile_viewtrueAllow anyone to view your profile page
allow_dm_from_strangerstrueAllow DMs from people not in your chats
show_badgetrueShow role/verified badge
Request — Update username and equip theme
PUT /api/v2/secra/profile/update Authorization: Bearer <token> Content-Type: application/json { "username": "alice_dev", "displayName": "Alice (Dev)", "theme": "theme:cosmos", "frame": "frame:neon", "emoji_status": "🚀", "privacy": { "show_online": false, "allow_dm_from_strangers": false } }
Response 200
{ "success": true }

Check Username Availability

POST /profile/check-username

Check if a username is available before attempting to change it.

ParameterTypeRequiredDescription
usernamestringrequiredUsername to check
Response 200
{ "available": true }

Cosmetics & Nova Store

The cosmetics system powers the Nova Store — frames, themes, chat decorations, and community-created themes. Purchases use vDARKO, the in-app currency.

Get All Decorations

GET /decorations

Public endpoint. Returns all enabled decoration items grouped by kind, plus approved community themes and gifts.

No authentication required — safe to call from any client.
Response 200
{ "frames": [ { "id": "neon", "label": "Neon Frame", "name_en": "Neon", "name_ru": "Неон", "price": "500", "free": false, "css_vars": { "cos-frame-bg": "..." }, "isPremium": true } ], "themes": [ { "id": "cosmos", "label": "Cosmos", "price": "0", "free": true, "css_vars": { "cos-theme-bg": "#020407", "cos-theme-accent": "#3b82f6" } } ], "decos": [ { "id": "aurora", "label": "Aurora", "price": "300", "free": false, "css_vars": { "cos-deco-bg": "radial-gradient(...)" } } ], "community_themes": [ { "id": "a1b2c3d4-...", "name": "Midnight Blue", "price": "0", "free": true, "downloads": 142, "css_vars": { "bg": "#0a0c10", "accent": "#3b82f6" }, "creator": { "username": "bob", "avatar": "https://..." } } ], "gifts": [] }
To apply a community theme, set theme to "c:<uuid>" via PUT /profile/update.

My Cosmetics Inventory

GET /shop/cosmetics/me

Returns owned item keys, current vDARKO balance, and equipped items. Add ?include_catalog=true to also return full catalog with prices.

Requires authentication
Response 200
{ "owned": ["frame:neon", "theme:cosmos", "deco:aurora"], "balance": "750", "equipped": { "theme": "theme:cosmos", "frame": "frame:neon", "deco": "deco:aurora" } }

Cosmetics Catalog

GET /shop/cosmetics/catalog

Public catalog of all items with prices and availability status. No auth required.

Response 200
{ "items": [ { "item_key": "deco:aurora", "price": "300", "enabled": true }, { "item_key": "frame:neon", "price": "500", "enabled": true }, { "item_key": "theme:cosmos","price": "0", "enabled": true } ] }

Buy an Item

POST /shop/cosmetics/buy

Purchase a cosmetic item using vDARKO balance. The item is added to your inventory. You can optionally equip it immediately.

Requires authentication
ParameterTypeRequiredDescription
item_keystringrequiredItem key, e.g. "frame:neon" or "theme:c:<uuid>"
equipbooleanoptionalIf true, equips the item immediately after purchase (default: false)
Request
POST /api/v2/secra/shop/cosmetics/buy Authorization: Bearer <token> Content-Type: application/json { "item_key": "frame:neon", "equip": true }
Response 200 — Success
{ "success": true, "balance": "250", "item_key": "frame:neon" }
Response 400 — Already owned or insufficient balance
{ "error": "already_owned" } // or { "error": "insufficient_balance", "balance": "100", "price": "500" }
vDARKO balance is non-refundable. Purchases are final.
Python — Browse catalog and buy a theme
import requests BASE = "https://arkonova.network/api/v2/secra" HEADERS = {"Authorization": "Bearer <your_token>"} # Browse available items catalog = requests.get(f"{BASE}/decorations").json() for theme in catalog["themes"]: print(f"{theme['id']}: {theme['name_en']} — {theme['price']} vDARKO") # Buy and equip a theme resp = requests.post(f"{BASE}/shop/cosmetics/buy", headers=HEADERS, json={ "item_key": "theme:cosmos", "equip": True }) print(resp.json()) # {"success": true, "balance": "750", "item_key": "theme:cosmos"}

Error Codes

All errors return JSON with an error field and an appropriate HTTP status:

StatusErrorMeaning
400missing_fieldsRequired parameters are absent
400invalid_challengeChallenge is expired or already used
400invalid_signatureEd25519 signature verification failed
400Invalid usernameUsername format invalid or too short/long
400Username already takenUsername is in use by another account
400Invalid avatar URL/dataAvatar URL rejected (unsafe or malformed)
400already_ownedCosmetic item is already in your inventory
400insufficient_balanceNot enough vDARKO to purchase the item
400item_not_foundCosmetic item key does not exist in catalog
401unauthorizedInvalid or missing JWT token
404user_not_foundAddress is not registered in the system
429rate_limitedToo many requests — slow down
500server_errorInternal server error

Need help integrating Secra? Join our developer community in Quanta.

Open Quanta Messenger Back to Wiki
Domain migration

Primary domain: arkonova.network

We are migrating away from arkonova.ru. Please update bookmarks and links.

Open primary domain