R· API
DEVELOPER DOCUMENTATION

RonNiri API: authentication and accounts

The Copy to agent button at /docs copies the complete Markdown reference: shared guidance and every service section. On /docs/:service, it copies that service's reference and its shared authentication guidance only. The full export is also available at /docs/index.md; individual exports use /docs/:service.md.

Base URL: https://api.ronniri.com. Local default: http://localhost:3000.

Two ways to supply service credentials

Every service request needs gateway authorization: X-API-Key: rni_... or Authorization: Bearer rni_.... A browser signed in to the console can also call APIs with its HttpOnly session cookie and CSRF token for writes. Registration alone cannot access the service. Keys belong to approved users, including the admin. An optional deployment-wide API_KEY enables direct requests without creating a user account; treat it as a root secret. It cannot access any user's saved credentials or management endpoints.

  1. Inline credentials: send provider credentials in a JSON POST body over HTTPS. They are used for the upstream operation and are not saved in MongoDB. Never put passwords or keys in query strings. No extra client-side encoding replaces HTTPS. Configure proxies and clients not to log request bodies or authorization headers.
  2. Saved credentials: sign in, save credentials in the console, then send useSavedCredentials: true with a user API key. The server decrypts only the caller's service credentials. Passwords are never returned by the credential-list endpoint. Credentials are encrypted with AES-256-GCM, bound to the user and service. Back up the encryption key separately from the database.

Inline PADI request

POST /padi/certifications
X-API-Key: YOUR_GATEWAY_KEY
Content-Type: application/json

{"email":"[email protected]","password":"YOUR_PADI_PASSWORD","raw":false}

PADI uses email as the username field. Stateless calls clear their in-memory provider client after the response. To reuse login, POST the same email/password to /padi/sessions, then use its sessionId in X-Session-Id on GET /padi/certifications, GET /padi/credentials, GET /padi/session, POST /padi/sessions/refresh, and DELETE /padi/sessions.

Saved PADI request

Save {"email":"[email protected]","password":"..."} with PUT /auth/credentials/padi, then:

POST /padi/certifications
X-API-Key: YOUR_USER_KEY
Content-Type: application/json

{"useSavedCredentials":true,"raw":false}

The same flag works on POST /padi/sessions, POST /padi/credentials, POST /lifesavingSociety/lookup and POST /piitel/login. Do not mix saved and inline credential fields. Piitel login requires an existing Piitel X-Session-Id; create it with POST /piitel/sessions first.

One-request wrapper

POST /:service/request accepts method (default GET), path (service-relative, no query string), query object, body object, and either credentials or useSavedCredentials:true. It dispatches only an existing service endpoint and enforces that endpoint's key permission. It cannot invoke account/admin routes or session/login routes. Query values follow the target endpoint's rules. Responses are wrapped in { "data": ... }.

{
  "method": "GET",
  "path": "/orders",
  "useSavedCredentials": true
}

Send this to /piitel/request with a key containing piitel:account:login and piitel:orders:read. For inline Piitel login replace the flag with "credentials":{"username":"[email protected]","password":"..."}. For PADI, POST /padi/request with method:"POST", path:"/certifications", credentials {email,password}, and optional body:{raw:true}. Lifesaving credentials are {identifier}; AliExpress buyer credentials are {accessToken}. KSP/Amazon account login is unsupported.

Provider sessions created by the wrapper are discarded after the operation by default. Set keepSession:true to return sessionId and expiresAt for follow-up cart/session operations; this additionally requires that service's sessions:manage permission. Set sessionId instead of credentials to reuse a session. Piitel supports cartMode:"classic" for bundles. Discarding a local session does not undo an upstream action: a Piitel account cart change persists at the store. Check state before retrying an uncertain mutation.

Account lifecycle

On the first successful database initialization, the server creates admin username admin, generates a random password and prints it once to server logs. Sign in and change it before using APIs or creating keys. This is an ordinary user account with an additional admin role; its saved provider credentials are private to it. Startup does not reset an existing admin or reprint its password.

POST /auth/register with {username,password} creates a pending registration request, not an active user. Passwords must be 8–256 characters. Usernames are normalized to lowercase, 3–64 characters, using letters, digits, dots, dashes and underscores. The admin approves/rejects requests in the console. Pending and rejected applicants cannot sign in, save credentials, or create keys. There is no automatic approval. Admin can disable approved users; disabling invalidates access immediately. Re-enabling requires new login and keys.

POST /auth/login accepts {username,password} and sets an 8-hour HttpOnly, SameSite=Strict cookie (Secure in production). Response includes user and csrfToken. GET /auth/me returns the current user and CSRF token. All authenticated browser writes require X-CSRF-Token. Account management accepts browser sessions only; even a root API key cannot approve users or manage accounts.

PATCH /auth/profile accepts currentPassword, optional username and optional password. Changing profile requires the current password and invalidates existing browser sessions and API keys. Initial admin login requires a new password. POST /auth/logout invalidates the current browser session.

API keys and permissions

POST /auth/keys: {name,scopes,expiresAt?} creates a key and returns the plaintext key exactly once. MongoDB stores only its SHA-256 hash and display prefix. GET /auth/keys lists metadata; DELETE /auth/keys/:id revokes one. Optional expiresAt is an ISO future timestamp. Maximum 50 unrevoked keys per user. Revocation, user disablement and password/profile changes are checked on every request.

GET /auth/permissions lists the current service permissions. Scope syntax is service:resource:action, for example piitel:catalog:read, piitel:cart:write, padi:certifications:read. A key may include several services and permissions. root grants all current and future service API permissions, not administrator account-management access. No scopes are granted by omission. A write permission does not imply read; select both if needed. Session creation/refresh/deletion requires sessions:manage. Checkout submission has its own checkout:submit permission. The wrapper checks its target and any login/session permission it needs. Each service documentation page lists the exact permission for every registered route.

GET /capabilities reports adapter support and verification state. Provider session IDs are random, scoped by service and owned by the authenticated user (or the legacy direct key). They cannot be reused across users. Users may use their own session across their own keys only if each key has the requested permission. Local provider sessions expire after 30 minutes idle and are lost on restart. Account data, keys and saved credentials persist in MongoDB.

Saved credential management

GET /auth/credentials returns configured services and update timestamps, never plaintext secrets. PUT /auth/credentials/:service replaces credentials; DELETE removes them. Supported schemas:

Service JSON
padi { "email": "...", "password": "..." }
piitel { "username": "...", "password": "..." }
lifesavingSociety { "identifier": "ABC123" }
aliexpress { "accessToken": "..." }

Administrator endpoints

All require an admin browser session, completed initial password change, and CSRF on writes.

Method Endpoint Effect
GET /auth/admin/registrations Pending requests without password hashes
POST /auth/admin/registrations/:id/approve Explicitly approve; body {}
DELETE /auth/admin/registrations/:id Reject pending registration
GET /auth/admin/users Users without password hashes
PATCH /auth/admin/users/:id {status:"disabled"} or {status:"approved"}; cannot disable admin

Request security and errors

Production requires HTTPS, a configured PUBLIC_URL and the trusted Coolify reverse proxy. Do not expose the Node port directly to the internet. The app never logs request bodies, keys or saved provider passwords. The initial admin password is intentionally printed once as requested; rotate it immediately and restrict log access. Account passwords use salted scrypt (N=131072,r=8,p=1). Login/registration attempts are rate-limited, and concurrent password hashing is bounded.

Common errors: 400 INVALID_INPUT/JSON_REQUIRED, 401 UNAUTHORIZED/SESSION_EXPIRED, 403 FORBIDDEN/ADMIN_REQUIRED/CSRF_REQUIRED/SESSION_FORBIDDEN/PASSWORD_CHANGE_REQUIRED, 409 USERNAME_UNAVAILABLE/SESSION_BUSY, 429 RATE_LIMITED, 503 BUSY. Errors have {code,error,details?}. Provider errors preserve their existing codes. Keys and credentials belong in headers/JSON bodies, not URL query parameters. No live payment validation has been performed.

Docker and Coolify deployment

Deploy one application from the server directory, using its Dockerfile. If the repository contains the whole Api project, set base directory /server; if it contains just server's contents, use /. Dockerfile /Dockerfile is relative to that base. Expose container port 3000, health path /health, domain https://api.ronniri.com. The Docker build runs deterministic tests. Node runs as a non-root user with system CA certificates.

Create a MongoDB resource in Coolify with persistent storage, or use an external MongoDB deployment. Set its internal connection URI in this application's environment. Do not use localhost for a separate MongoDB container. Restrict database access to the application/private network. Back up MongoDB and the encryption key separately.

Required production runtime variables:

NODE_ENV=production
PORT=3000
PUBLIC_URL=https://api.ronniri.com
MONGODB_URI=mongodb://USER:PASSWORD@YOUR_MONGODB_HOST:27017/ronniri_api?authSource=admin
CREDENTIAL_ENCRYPTION_KEY=BASE64_ENCODED_32_RANDOM_BYTES

Generate the encryption key with node -e "console.log(require('node:crypto').randomBytes(32).toString('base64'))". Preserve it across deployments; changing/losing it makes existing saved service credentials unreadable. API_KEY is optional: setting a random secret of at least 24 characters enables the legacy direct root gateway key. User-issued keys do not require it. Never commit .env, .env.live, or .local-credential-key.

On local development, .env is loaded automatically without overriding existing environment variables. MONGODB_URI defaults to mongodb://127.0.0.1:27017/ronniri_api. Start MongoDB locally, run npm ci and npm start on Node 24+, and open http://localhost:3000. Without CREDENTIAL_ENCRYPTION_KEY, development generates a persistent ignored .local-credential-key file. MongoDB must be available before the server starts. Production requires an explicit encryption key and HTTPS PUBLIC_URL.

Open the console, sign in as admin using the password printed on first initialization, then change it. Approve users in Administration, save each account's own provider credentials and generate scoped keys. Docs and Markdown exports are public at /docs and /docs/:service; every documentation page has a Copy to agent button.

Use one application replica: live provider sessions/carts and provider concurrency limits are in memory. MongoDB persists accounts, approvals, key hashes, browser sessions and encrypted credentials. Restarting loses live provider sessions but does not erase accounts or keys. A database failure fails authentication closed. The Coolify proxy must strip/replace untrusted forwarded headers; this app trusts one proxy hop. The container port should remain private. The deployed HTTP API was verified on 2026-10-20; see live results. Local Docker build verification and inspection of the deployment's build logs remain outside that check.

Service guides

Common errors and limitations

Support and verification

All providers run in the same Node.js process. This matrix distinguishes implemented code from verified upstream behavior. A route appearing in /capabilities does not mean every manual feature of that site is supported.

The deployed API at https://api.ronniri.com was tested on 2026-10-20: saved-credential PADI/Lifesaving/Piitel reads, complete Piitel search pagination, selected bundle pricing/cart CRUD/isolation, and documentation succeeded. KSP returned KSP_ACCESS_BLOCKED from the deployment server. Test carts and sessions were cleaned up; see live verification.

Provider Implemented Live verification Still required
PADI Login, consumer/pro certifications, pro credentials, raw fields, refresh/re-login, reusable sessions, local logout Consumer login, both certification endpoints, renewal; shared HTTP session/raw-certifications/refresh/logout and consumer credential status Live professional-account checks; interactive verification remains upstream
Lifesaving Society Hidden-field/cookie flow, identifier/scopes, dynamic award columns, name/code/date parsing, shared throttle Authorized real lookup in Current, Concise and Complete; metadata/date parsing; shared HTTP lookup No remaining known feature gap in the specified member-lookup flow; upstream changes can still break it
Piitel Catalog, structured filters, collection counts, taxonomy details, variants, reviews, stock, guest cart CRUD, wishlist read/add/remove, coupons, addresses/shipping; WooCommerce account login/readers and checkout prepare/update/submit Catalog/detail/by-slug/stock, review filters, collection counts, category detail, attribute terms, isolated carts, variation add/remove, shipping selection, invalid coupon rejection, isolated guest wishlists; shared HTTP account login/cart/dashboard/orders/order detail/saved-address/wishlist reads and local session deletion Account wishlist pagination, valid coupon redemption, address changes/draft checks; real checkout/payment validation, GoCredit data/tokenization, returns
KSP Search/autocomplete, details, per-branch availability, branches/promotions, cart read/add/clear/update/remove, branch selection, coupon add, shipping options Browser UI/frontend protocol inspection; native HTTP blocked by explicit bot protection Access from deployment server and validation of all native flows; account/OTP, orders, shipping selection, coupon removal, checkout/payment
Amazon.com Search/details/stock, variants, guest cart read/add using fresh forms Rendered product/search/cart inspected; a native product read succeeded, other native requests returned challenges/failures Stable native access and live cart cycle; cart edit/remove, other marketplaces, account/MFA, orders, checkout/payment
AliExpress Official TOP affiliate search/details, DS SKU inventory and order detail, private buyer-token sessions Signing/transport/schema tests; no approved app keys/token supplied Approved app credentials and API permissions; affiliate coverage is limited; consumer-cart/account automation, full marketplace coverage and checkout/payment are missing

AliExpress consumer browsing was denied by the browser's site-safety policy. No alternate surface was used to retrieve that blocked consumer page. The separate official Alibaba developer documentation was accessible and used for the TOP adapter.

Piitel bundle details, selected-option pricing and native cart add/read/update/remove are live verified, including two configurations with different case colours. See bundle API examples. Native bundle carts explicitly reject Store API checkout, coupons and shipping/customer updates; native checkout is unfinished.

Piitel's Store API POST /checkout/prepare can create an upstream draft. Its separate /checkout/submit route can submit an order and charge payment, but has only contract tests so far; GoCredit-specific payment data still needs validation. No live order or payment was attempted. A browser opened independently does not inherit this server's cart context.

Dockerfile configuration includes tests, a non-root runtime, OS CA certificates, health check and graceful shutdown. On Node 24.22.0, 62 deterministic tests pass, plus the opt-in real MongoDB account integration test. MongoDB persists the account system; deployment requires MONGODB_URI, PUBLIC_URL and CREDENTIAL_ENCRYPTION_KEY. See deployment. Docker Desktop startup failed in inference-manager initialization with a local socket-path error; local image build checks remain pending. The remote HTTP deployment was verified without changing Coolify or DNS settings. Private provider checks can be run with npm run test:accounts after local configuration; missing credentials fail preflight without network calls. Production loads .env but never automatically loads .env.live.