v1.4.0

API Reference

VixFlow is a local-first application. There is no external REST API — all data operations are performed directly in the browser using JavaScript functions that read and write to localStorage. This page documents those internal functions for developers who want to extend or integrate with VixFlow.

Local-first architecture: All functions listed here operate on localStorage. Data never leaves your browser. The only external API calls are to api.anthropic.com for AI features, using your personal API key.

Architecture Overview

VixFlow's data layer is built around a simple pattern: each entity type (clients, proposals, invoices, etc.) has its own localStorage key that stores a JSON array. CRUD operations are performed by reading the array, modifying it, and writing it back.

javascript — core pattern
// Generic read pattern
function getEntity(key) {
  try {
    return JSON.parse(localStorage.getItem(key) || '[]');
  } catch {
    return [];
  }
}

// Generic write pattern
function saveEntity(key, item) {
  const items = getEntity(key);
  const idx = items.findIndex(i => i.id === item.id);
  if (idx >= 0) items[idx] = item;   // update
  else items.push(item);                 // insert
  localStorage.setItem(key, JSON.stringify(items));
}

Clients API

GET getClients()
Returns all clients as an array

Returns all stored clients sorted by creation date (newest first).

javascript
function getClients() {
  const data = JSON.parse(
    localStorage.getItem('vixflow_clients') || '[]'
  );
  return data.sort((a, b) =>
    new Date(b.createdAt) - new Date(a.createdAt)
  );
}

// Example usage
const clients = getClients();
console.log(clients); // [{id, name, email, ...}, ...]

Returns: Client[]

SET saveClient(client)
Create or update a client record

Parameters

ParameterTypeRequiredDescription
idstringRequiredUUID. If matching ID exists, updates. Otherwise inserts.
namestringRequiredClient full name
emailstringRequiredEmail address
companystringOptionalCompany name
currencystringOptionalISO 4217 currency code (default: "USD")
createdAtstringRequiredISO 8601 date string
javascript
saveClient({
  id: crypto.randomUUID(),
  name: 'Rahim Ahmed',
  email: 'rahim@example.com',
  company: 'TechBD Ltd',
  currency: 'USD',
  createdAt: new Date().toISOString()
});
DEL deleteClient(id)
Permanently delete a client by ID
Warning: Deletion is permanent. The client record is removed from localStorage immediately with no undo.
javascript
function deleteClient(id) {
  const clients = getClients().filter(c => c.id !== id);
  localStorage.setItem('vixflow_clients', JSON.stringify(clients));
}

Proposals API

GETgetProposals()
Returns all proposals sorted by date
javascript
function getProposals() {
  return JSON.parse(
    localStorage.getItem('vixflow_proposals') || '[]'
  ).sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
}
FieldTypeDescription
idstringUUID
clientIdstringLinked client ID
titlestringProposal title
statusstring"draft" | "sent" | "accepted" | "rejected"
valuenumberProposed project value
SETsaveProposal(proposal)
Create or update a proposal
javascript
saveProposal({ id: crypto.randomUUID(), clientId: '...', title: 'Website Redesign', content: '## Summary...', status: 'draft', value: 1500, currency: 'USD', createdAt: new Date().toISOString() });

Invoices API

GETgetInvoices()
Returns all invoices sorted by date
javascript
function getInvoices() {
  return JSON.parse(localStorage.getItem('vixflow_invoices') || '[]')
    .sort((a, b) => new Date(b.createdAt) - new Date(a.createdAt));
}
// Filter by status
const overdue = getInvoices().filter(i => i.status === 'overdue');
FieldTypeDescription
invoiceNumberstringe.g. "INV-0042"
itemsLineItem[]{description, qty, unitPrice, total}
totalnumberFinal amount due
statusstring"draft" | "sent" | "paid" | "overdue"
dueDatestringISO 8601 date
SETsaveInvoice(invoice)
Create or update an invoice
javascript
saveInvoice({ id: crypto.randomUUID(), invoiceNumber: 'INV-0042', clientId: '...',
  items: [{ description: 'Design work', qty: 1, unitPrice: 800, total: 800 }],
  subtotal: 800, taxRate: 0, total: 800, currency: 'USD', status: 'draft',
  dueDate: '2026-04-15', createdAt: new Date().toISOString() });

Settings API

GETgetSettings()
Returns user settings object
javascript
function getSettings() {
  return JSON.parse(localStorage.getItem('vixflow_settings') || '{}');
}
// { claudeApiKey, businessName, email, currency, theme, language, ... }

AI API

AI generateAIContent(prompt, options)
Call Claude API with user's key

Core AI generation function. Uses the user's stored Claude API key. Throws an error if no key is set.

javascript
async function generateAIContent(prompt, options = {}) {
  const apiKey = getStoredAPIKey();
  if (!apiKey) throw new Error('No API key configured');

  const {
    model = 'claude-haiku-20240307',
    maxTokens = 1024,
    system = ''
  } = options;

  const res = await fetch('https://api.anthropic.com/v1/messages', {
    method: 'POST',
    headers: {
      'x-api-key': apiKey,
      'anthropic-version': '2023-06-01',
      'content-type': 'application/json'
    },
    body: JSON.stringify({
      model,
      max_tokens: maxTokens,
      system,
      messages: [{ role: 'user', content: prompt }]
    })
  });

  if (!res.ok) throw new Error(`API error: ${res.status}`);
  const data = await res.json();
  return data.content[0].text;
}

// Usage example
const proposal = await generateAIContent(
  `Write a proposal for web design project for TechBD Ltd`,
  { maxTokens: 2048 }
);

Options

OptionTypeDefaultDescription
modelstringclaude-haiku-20240307Claude model to use
maxTokensnumber1024Maximum tokens to generate
systemstring""System prompt for context
GET getStoredAPIKey()
Retrieve the user's Claude API key
javascript
function getStoredAPIKey() {
  const settings = JSON.parse(
    localStorage.getItem('vixflow_settings') || '{}'
  );
  return settings.claudeApiKey || null;
}
// Returns: string (the API key) or null

Export API

GET exportAllData()
Export all data as a JSON file download
javascript
function exportAllData() {
  const exportData = {
    version: '1.4.0',
    exportedAt: new Date().toISOString(),
    clients:   getClients(),
    proposals: getProposals(),
    invoices:  getInvoices(),
    projects:  getProjects(),
    expenses:  getExpenses()
  };

  const blob = new Blob(
    [JSON.stringify(exportData, null, 2)],
    { type: 'application/json' }
  );
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = `vixflow-backup-${Date.now()}.json`;
  a.click();
}