Base URL: https://limebat.com/api/v1. This standalone API is owned by
website/limebat (Manage-Tasks/limebatweb.git). It does not use or proxy through
ERP/Gateway. SSH traffic still goes directly from the apps to the user's servers.
Send Accept: application/json; requests with a body use
Content-Type: application/json. Authenticated routes require
Authorization: Bearer TOKEN. HTTPS is mandatory in production. Responses are
private/non-cacheable. No route accepts an SSH password, private key, or vault
recovery key in plaintext.
| Method/path | Request | Response / permission |
|---|---|---|
POST /auth/login |
email (valid, ≤254 chars), password (nonempty, ≤72 chars), device_name (nonempty, ≤120 chars) |
200 with token, ISO expires_at, and user; creates a device token valid for 30 days |
GET /me |
— | 200 {"user": {"id":"UUID","name":"Name","email":"[email protected]","sync_enabled":true}}; authenticated active account |
POST /auth/logout |
— | 204; revokes the current device token |
GET /devices |
— | 200 {"devices":[{"id":"123","name":"LimeBat · ios","current":true,"last_used_at":null,"expires_at":"ISO timestamp"}]}; only this account's unexpired tokens |
DELETE /devices/{id} |
Numeric token ID | 204; revoke only an owned device; another account's ID returns 404 |
GET /vault |
— | 200 {"revision":0,"envelope":null} initially; authenticated active account with sync_enabled=true |
PUT /vault |
expected_revision and envelope, below |
200 {"revision":N+1} only if current revision equals N; same sync entitlement required |
IDs in user responses are opaque UUIDs, not internal database IDs. Token values
are returned only at login; the database stores Sanctum's token hashes. There
can be at most 20 unexpired device tokens per account. Revoke an old device before
adding more. Disabling an account blocks every token. Resetting its password using
the administrator command revokes all device tokens and retains encrypted data.
There is no public signup, billing or password-recovery endpoint in this phase.
An administrator provisions accounts and sync entitlements with limebat:user.
Applications must never grant their own entitlement or treat a local flag as
server authorization. Disabling sync returns 403 for both vault routes; it does
not delete the vault, local profiles or access to account/device management.
Login is limited to 5 attempts/minute per normalized email and 10/minute per IP.
Authenticated API routes are limited to 120 requests/minute per account. Generic
validation failures use 422 {"message":"…","errors":{"field":["…"]}}.
Login failures do not distinguish an unknown, disabled, or wrong-password account.
Missing, expired, revoked or disabled-account tokens return 401.
No sync entitlement returns 403; missing/foreign devices return 404.
Rate/device limits return 429. Retry after the indicated rate limit or revoke a
device as appropriate. Requests larger than 1,500,000 bytes return 413 (a proxy
may reject them earlier). Production plaintext HTTP receives 400 rather than
a redirect that could forward credentials. Temporary service failures return 5xx.
Example PUT request shape (base64 placeholders must be replaced by valid bytes):
{
"expected_revision": 0,
"envelope": {
"algorithm": "AES-256-GCM",
"nonce": "BASE64_OF_12_RANDOM_BYTES",
"ciphertext": "BASE64_OF_ENCRYPTED_VAULT",
"tag": "BASE64_OF_16_AUTHENTICATION_BYTES"
}
}
expected_revision is an integer 0–1,000,000,000. Envelope keys are exactly the
four above. Encoding is canonical padded standard base64. Ciphertext decodes to
1–1,048,576 bytes; the nonce is 12 bytes and tag 16 bytes. The server validates the
envelope structure and size, but cannot decrypt or inspect its contents. It stores
one account-owned snapshot, never shares it between users, and atomically compares
and increments the revision. Stale writes return
409 {"message":"…","code":"revision_conflict"} without changing stored data.
Clients must fetch, decrypt and merge before retrying. A lost success response is
reconciled by fetching the current snapshot rather than blindly overwriting it.
The apps generate a random 256-bit recovery key, represented as unpadded URL-safe
base64 (43 characters). It is not derived from the account password. AES-256-GCM
uses a fresh random nonce per encryption and the UTF-8 additional authenticated
data limebat:v1:ACCOUNT_UUID:NEW_REVISION. The decrypted JSON is:
{
"version": 1,
"hosts": [{
"id": "CLIENT_GENERATED_ID", "name": "Example", "address": "192.0.2.10",
"username": "alice", "port": 22, "group": "Work", "authMethod": "password",
"password": "", "privateKey": "", "passphrase": ""
}],
"pins": {"[192.0.2.10]:22": "ssh-ed25519 SHA256:VERIFIED_FINGERPRINT"}
}
This plaintext example describes the client contract; it is never the API request
body. IDs are unique per snapshot, ports are 1–65535, and there are at most 10,000
profiles within the encrypted byte limit. authMethod is password or
privateKey. SSH passwords, private keys and passphrases remain inside the
ciphertext. Terminal output and running sessions are never synchronized.
Clients save a local base snapshot and revision atomically with their working vault in platform secure storage. Independent changes merge automatically by profile ID; deletion versus edit and simultaneous conflicting edits require explicit review. Any differing locally trusted host fingerprint also requires review, even when the local profile was otherwise unchanged. A remote deletion never silently clears an existing local trusted identity. Explicit user choices apply only to the reviewed cloud revision. Lower-than-known cloud revisions, wrong keys, modified ciphertext and unsupported formats stop sync without replacing the local vault. This protocol does not hide account metadata or payload sizes and cannot detect a malicious server replaying history to an entirely new device without a previously known revision.
Sign-in is required initially. First sync setup displays a recovery key and requires acknowledgment that it was saved. A new device signs in, supplies this key, and downloads/decrypts the configurations. Existing signed-in devices retain an account-scoped secure copy and can work offline; edits sync on foreground resume, after edits, or during a 30-second foreground poll. There is no promise of background execution on iOS/Android. A revoked/expired token locks the app at its next authenticated response. Reauthentication to the same account preserves unsynced local work. A different account never inherits that work or its key.
Explicit logout closes SSH sessions and deletes that account's local vault and recovery key. Unsynced work must either sync first or be explicitly discarded. If offline logout cannot revoke the server token, it still clears local access and tells the user to revoke the device elsewhere. Remote revocation cannot erase already-downloaded data from an offline device. Losing every recovery-key copy means encrypted data is unrecoverable, even after an account password reset. There is no silent recovery-key reset or destructive vault reset route. Back up the recovery key separately; administrator account recovery cannot decrypt it.
Existing pre-account profiles stay in their original secure device vault until the user explicitly imports them into the signed-in account. That import is recorded once and retains the original as a local backup. Payment collection, self-service registration, account deletion/export, key rotation and a complete lost-device recovery UI remain release work; do not sell subscriptions yet.