Overview

The SecureLync Partner API allows any authorised partner to integrate encrypted, malware-scanned file sharing directly into their platform — regardless of technology stack or hosting provider.

Partners can create share links, manage tokens, scan files for threats, and embed the SecureLync widget into their UI. All files are AES-256-GCM encrypted client-side before upload. The server never sees plaintext.

Partner API access is invite-only. Contact hello@securelync.com to request credentials. Each partner receives a unique API key and a namespaced user space.

Authentication

All server-side requests must include your partner API key as a Bearer token:

Authorization: Bearer your_partner_api_key_here

Your API key must never be exposed client-side. All calls using the API key must be made from your backend server.

Session Tokens (Widget Auth)

For browser-side widget use, your server calls POST /v1/session to obtain a short-lived session token (15 minutes). This token is safe to include in page HTML — it cannot be used to access the API key and expires automatically.

The widget uses the session token to authenticate API calls from the browser. This is the correct pattern for all widget integrations.

Base URL

https://api.securelync.com/v1

All endpoints are HTTPS only. Every response is JSON with an ok boolean.

Error Handling

{
  "ok": false,
  "error": "X-Partner-User-ID header required."
}
StatusMeaning
200Success
201Resource created
400Bad request — missing or invalid parameters
401Unauthorised — invalid or missing API key
404Resource not found
429Rate limited
500Server error — contact support

Roles

RolePermissions
adminCreate tokens, list ALL organisation tokens, revoke any token, view any token status
vendorCreate tokens, list own tokens, revoke own tokens
clientCreate tokens, list own tokens, revoke own tokens

Health Check

GET/v1/health

No authentication required.

{ "ok": true, "status": "ok", "version": "2.0.0", "service": "SecureLync Partner API" }

Create User

POST/v1/users/create

Creates a SecureLync account for a user on your platform. Idempotent — safe to call on every login.

FieldTypeNotes
user_id requiredstringYour platform's unique user ID
email requiredstringUser's email address
username requiredstringUser's display name
role optionalstringadmin | vendor | client. Default: client
{ "ok": true, "message": "User created.", "securelink_user_id": 42, "username": "yourpartner__user_123", "partner_user_id": "user_123", "partner_role": "vendor" }

Create Session Token

POST/v1/session

Creates a short-lived session token (15 min) for widget authentication. Call from your server on each page load that includes the widget.

FieldTypeNotes
user_id requiredstringYour platform user ID
role optionalstringUser's role. Default: client
{ "ok": true, "session_token": "bXNtfG1z...", "expires_at": "2026-04-11T17:00:00.000Z", "expires_in_seconds": 900 }

Security Scan

POST/v1/scan

Check a file's SHA-256 hash against MalwareBazaar, CIRCL Hashlookup, and VirusTotal before upload. The file itself is never sent — only its hash fingerprint. The widget calls this automatically.

FieldTypeNotes
hash requiredstringSHA-256 hex of the file plaintext (64 chars)
ext optionalstringFile extension e.g. pdf
{ "ok": true, "malicious": 0, "suspicious": 0, "total": 72, "not_found": false, "blocked": false, "sources": ["malwarebazaar", "circl-hashlookup", "virustotal"] }

If blocked is true, the file must not be uploaded. The widget enforces this automatically.

Create Token

POST/v1/tokens/create

Creates a share token for a partner user. Call this before uploading files.

Headers

HeaderNotes
X-Partner-User-ID requiredYour platform user ID
X-Partner-Role optionalUser's role

Body

FieldTypeNotes
label optionalstringMax 64 chars
expires_in_days optionalinteger1–7. Default: 7
max_downloads optionalintegerOmit for unlimited
{ "ok": true, "token_id": 88, "token": "a3f8c2...", "share_url": "https://securelync.com/app?t=a3f8c2...", "expires_at": "2026-04-18T10:00:00.000Z", "expires_in_days": 7, "max_downloads": null, "label": "Contract docs" }

Upload File

POST/v1/tokens/:id/files

Upload an AES-256-GCM encrypted file blob for a token. Accepts multipart/form-data. The widget handles this automatically including client-side encryption.

Headers

HeaderNotes
X-Partner-User-ID requiredYour platform user ID

Form Fields

FieldTypeNotes
file requiredbinaryEncrypted blob: IV[12] + tag[16] + ciphertext
enc_key requiredstringAES-256 key as 64-char hex
enc_iv requiredstringIV as 24-char hex
original_name requiredstringOriginal filename
file_size optionalintegerOriginal file size in bytes
mime_type optionalstringMIME type
{ "ok": true, "file_key": "a1b2c3d4e5f6", "share_url": "https://securelync.com/app?t=a3f8c2...", "original_name": "contract.pdf", "file_size": 245760 }
Important: Encrypt files client-side before uploading. Never send plaintext files to this endpoint. Use the widget for automatic encryption, or implement AES-256-GCM client-side following the encryption spec below.

List Tokens

GET/v1/tokens

Headers

HeaderNotes
X-Partner-User-ID requiredPass admin role to see all org tokens
X-Partner-Role optionalUser's role

Token Status

GET/v1/tokens/:id/status
{ "ok": true, "token_id": 88, "active": true, "expired": false, "download_capped": false, "download_count": 1, "max_downloads": null, "expires_at": "2026-04-18T10:00:00.000Z" }

Revoke Token

DELETE/v1/tokens/:id

Permanently revokes a token and deletes associated files. Cannot be undone.

{ "ok": true, "message": "Token revoked." }

Widget Overview

The SecureLync widget is a self-contained JavaScript modal that embeds encrypted file sharing into any web page. It handles the full flow: security scanning, client-side AES-256-GCM encryption, upload, and share link generation.

The widget calls the Partner API via your server-side proxy — so it works on any hosting provider including those with strict CSP policies like InfinityFree.

Widget Installation

On standard hosting (cPanel, Xneelo, VPS, cloud), the widget script loads directly:

<script>
window.SecureLyncConfig = {
  session_token: '<?= $session_token ?>',  // from PHP: sl_get_session_token()
  user_id:       '<?= $user_id ?>',
  role:          '<?= $role ?>',            // 'admin' | 'vendor' | 'client'
  trigger_id:    'my-share-btn',             // ID of button that opens widget
  api_base:      '/sl-proxy.php?path=/v1',   // your proxy path
};
</script>
<script src="https://api.securelync.com/widget.js" defer></script>

On InfinityFree (which blocks external scripts via CSP), download widget.js and serve it locally — see the proxy setup section below.

Proxy Setup

The proxy is a thin server-side file that forwards widget API calls to api.securelync.com. It adds your API key server-side so it never reaches the browser. This is required on any host with a restrictive connect-src CSP (such as InfinityFree), and recommended everywhere for security.

Save sl-proxy.php to your web root and point the widget's api_base at it. No other configuration is needed — it reads your API key from your existing config file.

PHP Integration

Add these functions to your integration file (e.g. includes/securelync.php). Define SL_API_KEY in your config before including this file.

<?php
// ── Core request helper ───────────────────────────────────────────────────
function sl_request(string $method, string $endpoint, array $extra_headers = [], ?array $body = null): array {
    $ch = curl_init('https://api.securelync.com/v1' . $endpoint);
    $headers = [
        'Authorization: Bearer ' . SL_API_KEY,
        'Content-Type: application/json',
        'Accept: application/json',
    ];
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CUSTOMREQUEST  => $method,
        CURLOPT_HTTPHEADER     => array_merge($headers, $extra_headers),
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    if ($body !== null) curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body));
    $response = curl_exec($ch);
    $err = curl_error($ch);
    curl_close($ch);
    if ($err) return ['ok' => false, 'error' => 'Connection error: ' . $err];
    return json_decode($response, true) ?? ['ok' => false, 'error' => 'Invalid response'];
}

// ── Ensure user exists (call on every login — idempotent) ─────────────────
function sl_ensure_user(int $uid, string $email, string $name, string $role = 'client'): array {
    return sl_request('POST', '/users/create', [], [
        'user_id'  => (string)$uid,
        'email'    => $email,
        'username' => $name,
        'role'     => $role,
    ]);
}

// ── Map your roles to SecureLync roles ────────────────────────────────────
// Customise this for your platform's role system
function sl_role_for_user(): string {
    if (function_exists('isAdmin') && isAdmin()) return 'admin';
    $mode = $_SESSION['role'] ?? $_SESSION['active_mode'] ?? 'client';
    return in_array($mode, ['vendor', 'agent', 'staff']) ? 'vendor' : 'client';
}

// ── Get session token for widget (call on each page load) ─────────────────
function sl_get_session_token(int $uid, string $role): string {
    $res = sl_request('POST', '/session', [], [
        'user_id' => (string)$uid,
        'role'    => $role,
    ]);
    return $res['session_token'] ?? '';
}

// ── Server-side token creation (without widget) ───────────────────────────
function sl_create_token(int $uid, string $role, string $label = '', int $expires_days = 7, ?int $max_downloads = null): array {
    return sl_request('POST', '/tokens/create', [
        'X-Partner-User-ID: ' . $uid,
        'X-Partner-Role: '    . $role,
    ], array_filter([
        'label'           => $label ?: null,
        'expires_in_days' => $expires_days,
        'max_downloads'   => $max_downloads,
    ], fn($v) => $v !== null));
}

// ── List tokens ───────────────────────────────────────────────────────────
function sl_list_tokens(int $uid, string $role): array {
    return sl_request('GET', '/tokens', [
        'X-Partner-User-ID: ' . $uid,
        'X-Partner-Role: '    . $role,
    ]);
}

// ── Revoke token ──────────────────────────────────────────────────────────
function sl_revoke_token(int $uid, string $role, int $token_id): array {
    return sl_request('DELETE', '/tokens/' . $token_id, [
        'X-Partner-User-ID: ' . $uid,
        'X-Partner-Role: '    . $role,
    ]);
}

PHP + InfinityFree

InfinityFree enforces a server-level CSP that blocks external scripts and fetch calls. Two steps are required:

Step 1: Download widget.js from https://api.securelync.com/widget.js and upload it to your htdocs root. Reference it locally:

<script src="/widget.js" defer></script>

Step 2: Upload sl-proxy.php to your htdocs root. The proxy forwards API calls server-side, bypassing the CSP restriction. Set your api_base to point to it:

api_base: '/sl-proxy.php?path=/v1'

When you migrate from InfinityFree to paid hosting (cPanel, Xneelo, etc.), no code changes are needed — the proxy works identically on all PHP hosting.

Keep widget.js updated. When SecureLync releases widget updates, re-download and re-upload widget.js. On paid hosting with no CSP restrictions, you can switch to the external script tag and updates are automatic.

Full page example (InfinityFree)

<?php
require_once __DIR__ . '/includes/config.php'; // defines SL_API_KEY
require_once __DIR__ . '/includes/securelync.php';

$uid   = (int)$_SESSION['user_id'];
$role  = sl_role_for_user();

// Ensure SL account exists for this user
sl_ensure_user($uid, $_SESSION['email'], $_SESSION['name'], $role);

// Get widget session token
$token = sl_get_session_token($uid, $role);
?>
<button id="sl-share-btn">🔒 Share File</button>

<script>
window.SecureLyncConfig = {
  session_token: '<?= htmlspecialchars($token, ENT_QUOTES) ?>',
  user_id:       '<?= $uid ?>',
  role:          '<?= htmlspecialchars($role, ENT_QUOTES) ?>',
  trigger_id:    'sl-share-btn',
  api_base:      '/sl-proxy.php?path=/v1',
};
</script>
<script src="/widget.js" defer></script>

PHP + Xneelo / cPanel

On standard cPanel or Xneelo hosting, you control your CSP headers so the external script tag works directly. The proxy is still recommended for security (keeps the API key server-side).

<?php
// Add to your page's HTTP headers (e.g. in .htaccess or at top of PHP)
header("Content-Security-Policy: script-src 'self' 'unsafe-inline' https://api.securelync.com; connect-src 'self'");

require_once __DIR__ . '/includes/securelync.php';
$uid   = (int)$_SESSION['user_id'];
$role  = sl_role_for_user();
sl_ensure_user($uid, $_SESSION['email'], $_SESSION['name'], $role);
$token = sl_get_session_token($uid, $role);
?>
<button id="sl-share-btn">🔒 Share File</button>

<script>
window.SecureLyncConfig = {
  session_token: '<?= htmlspecialchars($token, ENT_QUOTES) ?>',
  user_id:       '<?= $uid ?>',
  role:          '<?= htmlspecialchars($role, ENT_QUOTES) ?>',
  trigger_id:    'sl-share-btn',
  api_base:      '/sl-proxy.php?path=/v1', // keep proxy for API key security
};
</script>
<script src="https://api.securelync.com/widget.js" defer></script>

Node.js Integration

// securelync.js — server-side helper module
const SL_API = 'https://api.securelync.com/v1';
const SL_KEY = process.env.SL_API_KEY;

async function slRequest(method, endpoint, extraHeaders = {}, body = null) {
  const res = await fetch(SL_API + endpoint, {
    method,
    headers: {
      'Authorization': 'Bearer ' + SL_KEY,
      'Content-Type':  'application/json',
      'Accept':        'application/json',
      ...extraHeaders,
    },
    body: body ? JSON.stringify(body) : undefined,
  });
  return res.json();
}

export async function slEnsureUser(userId, email, username, role = 'client') {
  return slRequest('POST', '/users/create', {}, { user_id: userId, email, username, role });
}

export async function slGetSessionToken(userId, role = 'client') {
  const res = await slRequest('POST', '/session', {}, { user_id: userId, role });
  return res.session_token ?? null;
}

export async function slCreateToken(userId, role, label = '', expiresInDays = 7) {
  return slRequest('POST', '/tokens/create',
    { 'X-Partner-User-ID': userId, 'X-Partner-Role': role },
    { label, expires_in_days: expiresInDays }
  );
}

// Express.js route example
// app.get('/chat', async (req, res) => {
//   const token = await slGetSessionToken(req.user.id, req.user.role);
//   res.render('chat', { slToken: token, slUserId: req.user.id });
// });

For the proxy in Node.js, use a simple route that forwards requests:

// Express proxy route
app.all('/sl-proxy', async (req, res) => {
  const path = req.query.path || '';
  if (!path.startsWith('/v1/')) return res.status(404).json({ ok: false, error: 'Invalid path' });

  const upstream = await fetch('https://api.securelync.com' + path, {
    method: req.method,
    headers: {
      'Authorization': 'Bearer ' + process.env.SL_API_KEY,
      'Content-Type':  req.headers['content-type'] || 'application/json',
      'X-Partner-User-ID': req.headers['x-partner-user-id'] || '',
      'X-Partner-Role':    req.headers['x-partner-role']    || '',
    },
    body: ['POST','PUT','PATCH'].includes(req.method) ? req : undefined,
    duplex: 'half',
  });

  res.status(upstream.status);
  upstream.body.pipeTo(new WritableStream({
    write(chunk) { res.write(chunk); },
    close()      { res.end(); },
  }));
});

Python Integration

import os, requests

SL_API = 'https://api.securelync.com/v1'
SL_KEY = os.environ['SL_API_KEY']

def sl_request(method, endpoint, extra_headers=None, body=None):
    headers = {
        'Authorization': f'Bearer {SL_KEY}',
        'Content-Type':  'application/json',
        'Accept':        'application/json',
        **(extra_headers or {}),
    }
    r = requests.request(method, SL_API + endpoint, headers=headers,
                         json=body, timeout=15)
    return r.json()

def sl_ensure_user(user_id, email, username, role='client'):
    return sl_request('POST', '/users/create', body={
        'user_id': str(user_id), 'email': email,
        'username': username, 'role': role,
    })

def sl_get_session_token(user_id, role='client'):
    res = sl_request('POST', '/session', body={'user_id': str(user_id), 'role': role})
    return res.get('session_token')

def sl_create_token(user_id, role, label='', expires_in_days=7):
    return sl_request('POST', '/tokens/create',
        extra_headers={'X-Partner-User-ID': str(user_id), 'X-Partner-Role': role},
        body={'label': label, 'expires_in_days': expires_in_days})

# Django/Flask view example:
# def chat_view(request):
#     token = sl_get_session_token(request.user.id, request.user.role)
#     return render(request, 'chat.html', {'sl_token': token})

For the Python proxy (Django/Flask), forward requests similarly to the Node.js example, injecting the API key server-side.

Security Notes

Never expose your API key client-side. All calls using the API key must be server-side. The session token is the only credential safe to include in page HTML.

File encryption: All files are AES-256-GCM encrypted in the browser before upload. The server stores only encrypted blobs. Decryption keys are never stored server-side unencrypted.

Security scanning: Every file is hash-checked against MalwareBazaar, CIRCL Hashlookup, and VirusTotal before encryption. Only the SHA-256 fingerprint is sent — never the file itself.

Data isolation: Partner users are namespaced to your partner ID and are invisible to direct SecureLync users and other partners.

Expiry: All tokens expire within 7 days maximum. Encrypted file bytes are deleted automatically on expiry.

Hosting Compatibility

HostingExternal script tagProxy requiredNotes
InfinityFree❌ CSP blocked✅ RequiredServe widget.js locally; keep updated manually
cPanel / Xneelo✅ WorksRecommendedAdd CSP header to allow api.securelync.com
VPS / Dedicated✅ WorksRecommendedFull control over headers and config
Vercel / Netlify✅ WorksRecommendedUse serverless function as proxy
Node.js / Python✅ WorksRecommendedUse middleware route as proxy
© 2026 SecureLync. All rights reserved. Partner API v2.0.0 hello@securelync.com