Lumenbase API Reference

    The Lumenbase API is organized around REST. Our API has predictable resource-oriented URLs, accepts JSON request bodies, returns JSON-encoded responses, and uses standard HTTP response codes, authentication, and verbs.

    You use API keys from your workspace to authenticate requests. Create and manage keys in Settings -> Company Settings -> Integrations -> API. The API key determines which workspace the request applies to.

    Full CRUD is available for Contacts, Companies, Deals, Tasks, Invoices, and Activities.

    Base URL & authentication

    https://api.lumenbase.io

    All requests require:

    Authorization: Bearer <YOUR_API_KEY>
    Content-Type: application/json

    Optional: X-Idempotency-Key to prevent duplicate processing on retries; X-Request-Id for tracing.

    Response envelope: Success responses return { success: true, data: { ... }, meta: { request_id, api_version, timestamp } }. Errors return { success: false, error: { code, message, details? }, meta: { ... } }.

    Setup

    1. Go to Settings -> Company Settings -> Integrations -> API. Click "Create API Key" and select the scopes you need.
    2. Copy the key immediately: it won't be shown again.
    3. Optionally create a Connector to map incoming fields to CRM fields and set matching rules (for ingest endpoints).

    Authentication

    Every request carries a workspace API key in the Authorization header. There is no other accepted form.

    Request header

    Authorization: Bearer lmb_0f2a...
    • A key is the prefix lmb_ followed by 64 hexadecimal characters.
    • Keys are stored only as a SHA-256 hash. We cannot recover one for you, so save it when it is created.
    • Revoking a key takes effect immediately. Create a second key before rotating so the changeover has no gap.

    A key carries scopes. Read the Known limitations section before choosing them, because two endpoints do not accept the granular names today.

    API key scopes

    Each API key has one or more scopes that control what it can access. Assign only the scopes you need.

    FieldTypeDescription
    contacts:readscopeRead and list contacts
    contacts:writescopeCreate, update, and delete contacts
    companies:readscopeRead and list companies
    companies:writescopeCreate, update, and delete companies
    deals:readscopeRead and list deals
    deals:writescopeCreate, update, and delete deals
    tasks:readscopeRead and list tasks
    tasks:writescopeCreate, update, and delete tasks
    invoices:readscopeRead and list invoices
    invoices:writescopeCreate, update, and delete invoices
    activities:readscopeRead and list activities
    activities:writescopeCreate and delete activities
    readscopeRead access to all entity types
    adminscopeFull access to all endpoints

    The legacy scopes contact_ingest and activity_ingest still work, and a key holding one is accepted where the matching read or write scope is required. The reverse is not true: a key holding only contacts:write is not accepted where contact_ingest is required. See Known limitations.

    Pagination

    All list endpoints support pagination via query parameters:

    FieldTypeDescription
    pageintegerPage number (default: 1)
    per_pageintegerItems per page, max 100 (default: 25)
    sort_bystringField to sort by (varies per entity)
    sort_orderstring"asc" or "desc" (default: "desc")
    searchstringFree-text search across key fields

    Paginated response shape:

    {
      "success": true,
      "data": {
        "items": [ ... ],
        "pagination": {
          "page": 1,
          "per_page": 25,
          "total": 142,
          "total_pages": 6
        }
      },
      "meta": { "request_id": "...", "api_version": "1", "timestamp": "..." }
    }

    POST: Create / Ingest Contact

    Create or update contacts from forms, landing pages, or third-party systems. Matches by email; optionally creates or links companies.

    POSThttps://api.lumenbase.io/functions/v1/v1-public-contacts

    Scope:

    contacts:write
    or
    contact_ingest

    Request body:

    {
      "first_name": "John",
      "last_name": "Doe",
      "email": "john.doe@example.com",
      "phone": "+1-555-123-4567",
      "title": "Product Manager",
      "company_name": "Acme Inc",
      "company_domain": "acme.com",
      "source": "website_form",
      "signal_strength": 75,
      "message": "Interested in your enterprise plan"
    }
    FieldTypeDescription
    first_namestringContact first name
    last_namestringContact last name
    emailstringEmail (used for matching)
    phonestringPhone number
    titlestringJob title
    company_namestringCompany name (creates if new)
    company_domainstringCompany domain for matching
    sourcestringLead source
    signal_strengthnumberIntent signal 0-100
    messagestringNotes

    201 when new contact created; 200 when existing contact updated.

    POST: Batch Ingest Contacts

    Ingest up to 100 contacts in one request. Same field schema as Contact Ingest.

    POSThttps://api.lumenbase.io/functions/v1/v1-public-contacts-batch

    Scope:

    contacts:write

    {
      "contacts": [
        { "email": "a@example.com", "first_name": "Alice" },
        { "email": "b@example.com", "first_name": "Bob" }
      ],
      "options": { "stop_on_error": false }
    }

    201 all succeed; 207 mixed; 400 all fail. Max 100 contacts, 500 KB payload.

    GET: Retrieve / List Contacts

    GEThttps://api.lumenbase.io/functions/v1/v1-public-contacts-crud?id={uuid}

    Retrieve a single contact by ID.

    GEThttps://api.lumenbase.io/functions/v1/v1-public-contacts-crud?page=1&per_page=25

    List contacts with pagination.

    Scope:

    contacts:read

    Filters:

    FieldTypeDescription
    emailstringFilter by exact email
    company_iduuidFilter by company
    statusstringFilter by status
    searchstringSearch first_name, last_name, email

    Sort by: created_at, updated_at, first_name, last_name, email

    PATCH: Update Contact

    PATCHhttps://api.lumenbase.io/functions/v1/v1-public-contacts-crud?id={uuid}

    Scope:

    contacts:write

    {
      "title": "Senior Product Manager",
      "phone": "+1-555-999-0000"
    }

    Updatable fields: first_name, last_name, email, phone, title, company_id, source, status.

    DELETE: Delete Contact

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-contacts-crud?id={uuid}

    Scope:

    contacts:write

    { "success": true, "data": { "deleted": true, "id": "uuid" } }

    POST: Create Company

    POSThttps://api.lumenbase.io/functions/v1/v1-public-companies

    Scope:

    companies:write

    Upserts by domain if provided. Creates new if no match.

    {
      "name": "Acme Inc",
      "domain": "acme.com",
      "industry": "Technology",
      "size": "51-200",
      "website": "https://acme.com",
      "city": "San Francisco",
      "country": "US"
    }
    FieldTypeDescription
    namestringCompany name
    domainstringCompany domain (used for matching)
    industrystringIndustry
    sizestringCompany size range
    websitestringWebsite URL
    phonestringPhone number
    citystringCity
    statestringState/region
    countrystringCountry code
    statusstringStatus

    GET: Retrieve / List Companies

    GEThttps://api.lumenbase.io/functions/v1/v1-public-companies?id={uuid}
    GEThttps://api.lumenbase.io/functions/v1/v1-public-companies?page=1&per_page=25

    Scope:

    companies:read

    Filters:

    FieldTypeDescription
    domainstringFilter by exact domain
    industrystringFilter by industry
    searchstringSearch name, domain

    Sort by: created_at, updated_at, name, domain

    PATCH: Update Company

    PATCHhttps://api.lumenbase.io/functions/v1/v1-public-companies?id={uuid}

    Scope:

    companies:write

    { "industry": "SaaS", "size": "201-500" }

    DELETE: Delete Company

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-companies?id={uuid}

    Scope:

    companies:write

    POST: Create Deal

    POSThttps://api.lumenbase.io/functions/v1/v1-public-deals

    Scope:

    deals:write

    {
      "title": "Enterprise License: Acme",
      "value": 50000,
      "currency": "USD",
      "stage": "Proposal",
      "expected_close_date": "2026-04-15",
      "company_id": "uuid",
      "contact_id": "uuid"
    }
    FieldTypeDescription
    titlestring (required)Deal title
    valuenumberDeal value
    currencystringCurrency code (default: USD)
    stagestringPipeline stage
    statusstringDeal status
    probabilitynumberWin probability 0-100
    expected_close_datedateExpected close date
    company_iduuidLinked company
    contact_iduuidLinked contact
    pipeline_iduuidPipeline ID
    assigned_touuidAssigned user ID

    GET: Retrieve / List Deals

    GEThttps://api.lumenbase.io/functions/v1/v1-public-deals?id={uuid}
    GEThttps://api.lumenbase.io/functions/v1/v1-public-deals?page=1&per_page=25

    Scope:

    deals:read

    Filters:

    FieldTypeDescription
    stagestringFilter by stage
    statusstringFilter by status
    company_iduuidFilter by company
    pipeline_iduuidFilter by pipeline
    searchstringSearch title

    Sort by: created_at, updated_at, title, value, expected_close_date

    PATCH: Update Deal

    PATCHhttps://api.lumenbase.io/functions/v1/v1-public-deals?id={uuid}

    Scope:

    deals:write

    { "stage": "Negotiation", "probability": 80 }

    DELETE: Delete Deal

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-deals?id={uuid}

    Scope:

    deals:write

    POST: Create Task

    POSThttps://api.lumenbase.io/functions/v1/v1-public-tasks

    Scope:

    tasks:write

    {
      "title": "Follow up with Acme",
      "description": "Send proposal by Friday",
      "priority": "high",
      "due_date": "2026-03-01",
      "assigned_to": "uuid",
      "contact_id": "uuid",
      "deal_id": "uuid"
    }
    FieldTypeDescription
    titlestring (required)Task title
    descriptionstringTask description
    statusstringTask status
    prioritystringPriority: low, medium, high, urgent
    due_datedateDue date
    assigned_touuidAssigned user ID
    contact_iduuidLinked contact
    company_iduuidLinked company
    deal_iduuidLinked deal

    GET: Retrieve / List Tasks

    GEThttps://api.lumenbase.io/functions/v1/v1-public-tasks?id={uuid}
    GEThttps://api.lumenbase.io/functions/v1/v1-public-tasks?page=1&per_page=25

    Scope:

    tasks:read

    Filters:

    FieldTypeDescription
    statusstringFilter by status
    prioritystringFilter by priority
    assigned_touuidFilter by assignee
    contact_iduuidFilter by contact
    company_iduuidFilter by company
    deal_iduuidFilter by deal
    searchstringSearch title

    Sort by: created_at, updated_at, title, due_date, priority

    PATCH: Update Task

    PATCHhttps://api.lumenbase.io/functions/v1/v1-public-tasks?id={uuid}

    Scope:

    tasks:write

    { "status": "completed", "description": "Proposal sent" }

    DELETE: Delete Task

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-tasks?id={uuid}

    Scope:

    tasks:write

    POST: Create Invoice

    POSThttps://api.lumenbase.io/functions/v1/v1-public-invoices

    Scope:

    invoices:write

    {
      "invoice_number": "INV-2026-001",
      "status": "draft",
      "issue_date": "2026-02-19",
      "due_date": "2026-03-19",
      "subtotal": 5000,
      "tax_amount": 500,
      "total": 5500,
      "currency": "USD",
      "company_id": "uuid",
      "contact_id": "uuid",
      "notes": "Net 30"
    }
    FieldTypeDescription
    invoice_numberstringInvoice number
    statusstringdraft, sent, paid, overdue, cancelled
    issue_datedateIssue date
    due_datedateDue date
    subtotalnumberSubtotal amount
    tax_amountnumberTax amount
    totalnumberTotal amount
    currencystringCurrency code
    company_iduuidLinked company
    contact_iduuidLinked contact
    deal_iduuidLinked deal
    notesstringNotes
    line_itemsjsonLine items array

    GET: Retrieve / List Invoices

    GEThttps://api.lumenbase.io/functions/v1/v1-public-invoices?id={uuid}
    GEThttps://api.lumenbase.io/functions/v1/v1-public-invoices?page=1&per_page=25

    Scope:

    invoices:read

    Filters:

    FieldTypeDescription
    statusstringFilter by status
    company_iduuidFilter by company
    contact_iduuidFilter by contact
    searchstringSearch invoice_number

    Sort by: created_at, updated_at, invoice_number, due_date, total, issue_date

    PATCH: Update Invoice

    PATCHhttps://api.lumenbase.io/functions/v1/v1-public-invoices?id={uuid}

    Scope:

    invoices:write

    { "status": "sent", "due_date": "2026-04-01" }

    DELETE: Delete Invoice

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-invoices?id={uuid}

    Scope:

    invoices:write

    POST: Create / Ingest Activity

    POSThttps://api.lumenbase.io/functions/v1/v1-public-activities

    Scope:

    activities:write
    or
    activity_ingest

    Record activities from Jira, support tools, webhooks, or any external source. Links to contacts/companies by email or domain.

    {
      "type": "jira_issue_created",
      "entity_email": "john.doe@example.com",
      "entity_domain": "acme.com",
      "title": "PROJ-123: New Feature Request",
      "description": "Customer requested dashboard export",
      "timestamp": "2026-01-15T10:30:00Z",
      "data": { "issue_key": "PROJ-123", "priority": "high" }
    }

    Activity types:

    jira_issue
    support_ticket
    form_submission
    webhook
    external_activity

    Entity linking:

    • entity_email → Contact by email
    • entity_domain → Company by domain
    • entity_id → Deal by ID

    GET: Retrieve / List Activities

    GEThttps://api.lumenbase.io/functions/v1/v1-public-activities-crud?id={uuid}
    GEThttps://api.lumenbase.io/functions/v1/v1-public-activities-crud?page=1&per_page=25

    Scope:

    activities:read

    Filters:

    FieldTypeDescription
    typestringFilter by activity type
    contact_iduuidFilter by contact
    company_iduuidFilter by company
    deal_iduuidFilter by deal
    searchstringSearch title

    Sort by: created_at, type, title

    DELETE: Delete Activity

    DELETEhttps://api.lumenbase.io/functions/v1/v1-public-activities-crud?id={uuid}

    Scope:

    activities:write

    Field mapping (Connectors)

    Connectors map incoming JSON fields to CRM fields. Use dot notation for nested JSON, e.g. user.profile.email -> Email. Connectors apply to the ingest endpoints (Contact Ingest, Activity Ingest).

    Matching rules

    Contact: email (recommended), phone, or ID. Company: domain (recommended), name, or ID. Deal: ID or title. If no match and required data is provided, a new record is created.

    Error handling

    FieldTypeDescription
    401UNAUTHORIZEDInvalid or missing API key; use Bearer <key>
    403FORBIDDENAPI key lacks required scope
    400VALIDATION_ERRORInvalid request payload or missing required fields
    404NOT_FOUNDResource not found
    405METHOD_NOT_ALLOWEDHTTP method not supported for this endpoint
    413PAYLOAD_TOO_LARGERequest body exceeds max size (50 KB single, 500 KB batch)
    429RATE_LIMIT_EXCEEDEDToo many requests; check X-RateLimit-* and Retry-After
    500INTERNAL_ERRORServer error
    503SERVICE_UNAVAILABLERate-limit counter unavailable; the request was not processed, retry is safe
    207MULTI_STATUSBatch partially succeeded; read results[].success per item rather than the status alone
    410GONEEndpoint retired past its sunset date; the body names its successor

    Branch on error.code, not on the message. Messages are written for people and can change; codes are part of the contract.

    Error response body:

    {
      "success": false,
      "error": {
        "code": "VALIDATION_ERROR",
        "message": "Human-readable message",
        "details": { }
      },
      "meta": { "request_id": "...", "api_version": "1", "timestamp": "..." }
    }

    Rate limits

    Limits are per workspace, in a fixed one-minute window, counted per bucket rather than per endpoint.

    • Contact reads and writes: 100 per minute, 10,000 per day.
    • Activity reads and writes: 100 per minute, 50,000 per day.
    • Batch contact ingest: 5 per minute. Each call carries up to 100 contacts.

    Every response carries

    • X-RateLimit-Limit: requests allowed in the current window.
    • X-RateLimit-Remaining: requests left in it.
    • X-RateLimit-Reset: when the window resets.
    • X-DailyLimit-Remaining: present on buckets with a daily cap.
    • Retry-After: on a 429 only, the wait in seconds.

    A 503 with code SERVICE_UNAVAILABLE means the limit counter itself could not be read. Your request was not processed, so retrying is safe and will not double-write.

    Idempotency

    Send X-Idempotency-Key so a retry after a timeout cannot create a duplicate. Replaying the same key inside 24 hours returns the original result instead of writing again.

    This is implemented on two endpoints only: POST /v1-public-contacts and POST /v1-public-activities. The other endpoints ignore the header. On those, make a retry safe by reading the record first, or by using an update rather than a create.

    X-Idempotency-Key: 7d3f9c1e-2b84-4a17-9f0d-6c5e8a2b1d34

    Use a value unique to the operation you are retrying, 8 to 128 characters. A UUID per logical write works well.

    Keys are scoped to your workspace and the endpoint, and expire after 24 hours.

    Versioning

    The version is in the path and echoed in every response as meta.api_version and the X-API-Version header.

    New fields can appear in a response at any time and are not treated as a breaking change. Parse defensively and ignore fields you do not recognise, rather than validating against an exact shape.

    A breaking change means a new path prefix. The existing one keeps working through the deprecation process below.

    The application version shown elsewhere in the product is a release date, not an API version. The two move independently.

    Deprecation policy

    When an endpoint is retiring, it says so in its own responses before it stops working.

    A retiring endpoint returns

    • Deprecation: true
    • Sunset: the date it stops answering, as an HTTP date.
    • Link: the replacement, with rel pointing at the successor version.

    The sunset date is at least six months after the deprecation is announced. After it passes the endpoint returns 410 Gone, naming its successor.

    Currently deprecated

    POST /public-contacts, superseded by POST /v1-public-contacts. Sunset 26 November 2026.

    Log these headers. They are the earliest warning you will get, and they arrive on responses that are otherwise succeeding.

    OpenAPI description

    The full contract is published as an OpenAPI 3.1 document. Import it into Postman or Insomnia, generate a client, or diff it between releases to see exactly what changed.

    Document URL

    https://lumenbase.io/api/openapi.json

    Fetch it

    curl -s https://lumenbase.io/api/openapi.json -o lumenbase-openapi.json

    It is generated from the same source the endpoints are checked against, so it describes what the API actually does rather than what was intended.

    Known limitations

    Behaviour that does not match what the rest of this reference would lead you to expect. These are being fixed. They are listed here because discovering them at runtime is worse.

    • Deal endpoints return 429 on every request, whatever your volume. Contacts, companies, tasks, invoices and activities are unaffected.
    • The company, task and invoice endpoints check contacts scopes rather than their own. A key needs contacts:read or contacts:write to use them.
    • POST /v1-public-contacts, the batch endpoint and POST /v1-public-activities accept only the legacy scope names contact_ingest and activity_ingest, or admin. A key issued with contacts:write alone is refused with 403.

    Until these are fixed

    Give integration keys the admin scope, or the legacy contact_ingest and activity_ingest scopes, and avoid the deal endpoints. We would rather tell you this than have you debug it.

    Best practices

    • Use separate connectors per source to track origin and customize mapping.
    • Include email for contact matching (most reliable).
    • Send X-Idempotency-Key when retrying a contact or activity ingest. The other endpoints ignore it; see Idempotency.
    • Rate limit: 100 requests/minute per workspace; daily caps 10K contacts and 50K activities. Check X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and Retry-After on 429.
    • Read Known limitations before choosing scopes. Granular scopes are the right default everywhere except the ingest endpoints, which currently require the legacy names or admin.
    • For bulk operations, use the batch endpoint to reduce API calls.
    • Log meta.request_id from every response. It identifies the request in support.

    Not a developer?

    Use Zapier to connect Lumenbase to 6,000+ apps, or browse the Help Center.

    Need an API key? Sign in and go to Settings -> Integrations -> API.