Skip to content
CRM · API reference

Flaxxa CRM API and webhooks.

Drive Flaxxa CRM from your own software: a REST API with workspace keys, signed webhooks and idempotency keys.

No credit card
Free plan
Cancel anytime
flaxxa.com / product / crm / docs
cURLREST · JSON
# Flaxxa CRM · first request
curl https://flaxxa.com/api/v1/crm \
  -H "Authorization: Bearer $FLAXXA_KEY" \
  -H "Accept: application/json"

# webhooks: X-Flaxxa-Signature (HMAC-SHA256)
# retries: Idempotency-Key, 24 h
200 OKapplication/json
+ webhooks · HMAC-signed
REST
Requests per key by default
120/min
Idempotency window
24h
Quick start

How do I make my first API call?

Replace $FLAXXA_KEY with a key from your workspace. The first call returns a real id you can use for the next ones.

cURL
curl -X POST https://flaxxa.com/api/v1/crm/leads/bulk-upsert \
  -H "Authorization: Bearer flx_live_YOUR_KEY" \
  -H "Accept: application/json" -H "Content-Type: application/json" \
  -H "Idempotency-Key: sync-2026-11-05-001" \
  -d '{
    "source": "gyaanshala", "pipeline_id": 12, "dedupe_on": "external_id",
    "rows": [
      { "external_id": "EXT-10001", "name": "Asha Verma", "email": "[email protected]", "phone": "+919876543210" },
      { "external_id": "EXT-10002", "name": "Rahul Sen",  "email": "[email protected]" }
    ]
  }'
PHP
Http::withToken(env('FLAXXA_CRM_KEY'))->acceptJson()
    ->put("https://flaxxa.com/api/v1/crm/leads/by-external-id/{$student->id}", [
        'name' => $student->name, 'email' => $student->email, 'phone' => $student->mobile,
        'source' => 'gyaanshala', 'pipeline_id' => 12, 'status' => 'contacted',
    ])->throw();
Python
import requests
r = requests.post("https://flaxxa.com/api/v1/crm/leads/bulk-upsert",
    headers={"Authorization": f"Bearer {KEY}", "Accept": "application/json"},
    json={"source": "gyaanshala", "pipeline_id": 12, "dedupe_on": "external_id", "rows": rows[:300]})
r.raise_for_status()
print(r.json()["data"])  # created / updated / skipped counts and per-row results
Request
PUT /api/v1/crm/leads/by-external-id/EXT-10001 HTTP/1.1
Host: flaxxa.com
Authorization: Bearer flx_live_·············
Content-Type: application/json

{
  "name":        "Asha Verma",
  "email":       "[email protected]",
  "phone":       "+919876543210",
  "source":      "gyaanshala",
  "pipeline_id": 12,
  "status":      "contacted",
  "custom_data": { "course": "NEET 2027" }
}
Response · 201
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": {
    "id": 4812, "external_id": "EXT-10001", "email": "[email protected]",
    "source": "gyaanshala", "channel": "api", "status": "contacted",
    "pipeline_id": 12, "stage_id": 41, "created_at": "2026-10-27T10:00:00+00:00"
  }
}
Authentication

How do I authenticate?

Every call requires Authorization: Bearer <key>. Rotate from workspace settings — old keys are revoked instantly. Server-side only; never ship a live key to the browser.

Base URLhttps://flaxxa.com/api/v1/crm
Leads

Leads API

Create and sync leads into a pipeline of your choosing. `source` is where the lead came from (your platform); `channel` is set to api automatically for API-key callers.

POST/leads/bulk-upsert

Bulk upsert

{ source, pipeline_id, stage_id, dedupe_on: external_id|email|phone, rows[] } — creates or updates each row; returns created, updated, skipped and limit_skipped counts with per-row results. Honours Idempotency-Key.

PUT/leads/by-external-id/{external_id}

Upsert one by your id

Creates the lead if unknown (201), updates it otherwise (200). Body: name, email, phone, title, company_name, source, pipeline_id, stage_id, status, assigned_to, custom_data.

POST/leads

Create lead

{ email or phone, title, company_name, source, pipeline_id, stage_id, assigned_to, custom_data, external_id }. Honours Idempotency-Key.

GET/leads

List leads

Filter: pipeline_id, filters[status][], filters[source][], q, date_from/date_to; paginated {data, meta}.

GET/leads/export

Export leads

The filtered leads as a CSV file.

GET/leads/{id}

Retrieve lead

The lead with its contact, pipeline, stage, score and activities.

PUT/leads/{id}

Update lead

Any lead field, including stage_id (moves it on the board and runs stage automations).

POST/leads/{id}/qualify · /disqualify · /convert · /lose

Lifecycle

Qualify; disqualify or lose with { reason }; convert into a deal with { title, … }. Stamps qualified_at / converted_at.

POST/leads/{id}/assign · /score

Assign and score

Assign to { user_id }, or recompute the lead's score from your scoring rules.

DELETE/leads/{id}

Delete lead

Soft-deletes the lead.

Contacts

Contacts API

The people behind the leads and deals, with lifecycle stage, score and deal totals.

GET/contacts

List contacts

Search, filter by lifecycle stage and sort; paginated.

POST/contacts

Create contact

{ name, email, phone, … }.

GET/contacts/{id}

Retrieve contact

Contact with its leads and deals.

PUT/contacts/{id}

Update contact

Any contact field.

DELETE/contacts/{id}

Delete contact

Removes the contact.

Deals

Deals API

Opportunities on a pipeline, with value, currency, expected close and line items.

GET/deals

List deals

Open and closed deals with stage, value and expected close.

POST/deals

Create deal

{ pipeline_id, title, stage_id, value_cents, currency_code, contact_id, assigned_to, expected_close_date, custom_data }.

GET/deals/{id}

Retrieve deal

Deal with contact, activities and history.

PUT/deals/{id}

Update deal

title, value_cents, probability, expected_close_date, assigned_to, custom_data.

POST/deals/{id}/stage

Move stage

{ stage_id } — records the move and runs stage automations and sequences.

POST/deals/{id}/win · /lose

Close

Mark the deal won or lost.

POST/deals/{id}/clone

Clone deal

Copies the deal into a new open deal.

GET/deals/{id}/products

Line items

List, add (POST), update (PUT /{line}) or remove (DELETE /{line}) products on the deal.

DELETE/deals/{id}

Delete deal

Removes the deal.

Pipelines

Pipelines API

Every lead and deal sits on one pipeline. Create pipelines in the app or over the API, then use the ids. Scope crm.pipeline.manage.

GET/pipelines

List pipelines

Pipelines with lead and deal counts.

POST/pipelines

Create pipeline

{ name, description, stages[] }.

GET/pipelines/{id}/stages

List stages

Stage ids you pass as stage_id, with their probabilities.

POST/pipelines/{id}/stages

Add stage

Adds a stage; PUT /stages/{stage} updates and DELETE removes one.

PUT/pipelines/{id}/stages/order

Reorder stages

Sets the stage order.

Activities & sequences

Activities & sequences API

GET/activities

List activities

Calls, emails, meetings, notes, tasks and messages on your records.

POST/activities

Log activity

{ type: call|email|meeting|task|note|whatsapp|sms, subject, body, entity_type: Lead|Deal|Contact, entity_id }.

POST/activities/{id}/complete

Complete activity

Marks a task or activity done, with an optional outcome.

GET/sequences

List sequences

Your sequences and their steps.

POST/sequences/{id}/enroll

Enrol

{ lead_id or contact_id } — starts the sequence for that record.

Webhooks

Webhooks API

Subscribe a URL to CRM events. Deliveries carry X-Flaxxa-Event and X-Flaxxa-Signature (HMAC-SHA256 of the body with the endpoint's signing secret). Here you name lead.* and deal.* events; activity, sequence and forecast events are subscribed through the workspace webhooks endpoint, POST /api/v1/webhooks.

POST/webhooks

Subscribe

{ url, events: ["deal.won", "lead.*"] } — empty events means every CRM event. The signing_secret is returned once. Honours Idempotency-Key.

GET/webhooks

List

Your endpoints with their events and failure counts.

GET/webhooks/{id}/deliveries

Deliveries

The delivery log for one endpoint.

DELETE/webhooks/{id}

Unsubscribe

Stops delivery.

Webhook events

Which webhook events can I subscribe to?

Subscribe via POST /webhooks. Verify X-Flaxxa-Signature on every payload.

  • app.crm.lead.created

    A lead was created.

  • app.crm.lead.updated

    A lead's fields changed.

  • app.crm.lead.stage_changed

    A lead moved to another stage on its pipeline.

  • app.crm.lead.qualified

    A lead was qualified.

  • app.crm.lead.unqualified

    A lead was disqualified.

  • app.crm.lead.scored

    Lead scoring produced a new score.

  • app.crm.lead.assigned

    A lead was given an owner.

  • app.crm.lead.converted

    A lead was converted into a deal.

  • app.crm.lead.lost

    A lead was marked lost.

  • app.crm.deal.created

    A deal was created.

  • app.crm.deal.stage_changed

    A deal moved to another stage.

  • app.crm.deal.won

    A deal was won.

  • app.crm.deal.lost

    A deal was lost.

  • app.crm.deal.rotting

    An open deal passed the workspace's idle threshold.

  • app.crm.activity.logged

    An activity (call, email, meeting, note, task) was logged.

  • app.crm.activity.completed

    An activity was marked complete.

  • app.crm.sequence.enrolled

    A record was enrolled in a sequence.

  • app.crm.sequence.step_executed

    A sequence step ran (sent, skipped or failed).

  • app.crm.sequence.completed

    A record finished a sequence.

  • app.crm.forecast.generated

    A forecast was generated.

Errors

What errors can the API return?

All errors return a JSON envelope: { error: { code, message, details } }. Retry idempotent calls on 5xx with exponential backoff.

CodeNameWhen it fires
401unauthenticatedAPI key missing, expired or revoked.
402feature_disabledYour plan doesn't include CRM API access, or the feature (forecasting, assistants) isn't on your plan.
403insufficient_scopeKey valid but lacks the scope — crm.lead.create to create, crm.lead.edit to update, crm.lead.view to read.
404not_foundNo lead, deal or pipeline with that id in this workspace.
422validation_failed{ message, errors } — for example, an invalid email, or a pipeline_id that doesn't belong to the workspace.
429plan_rate_limitedPast your plan's CRM API requests per minute. Retry after the Retry-After seconds.
Conventions

Which rules apply to every request?

Every Flaxxa app's API follows the same authentication, rate limits, idempotency and webhook signing.

Bearer auth

Every API call uses a Bearer token. Keys belong to a workspace and are scoped per app. Create and revoke them from workspace API settings.

Rate limits

Each key can make 120 requests a minute unless the app sets its own limit. Going over returns 429 with a Retry-After header.

Idempotency

Send an Idempotency-Key header on a POST and a retry with the same key within 24 hours returns the first response instead of running again.

Signed webhooks

Every webhook payload carries an X-Flaxxa-Signature HMAC-SHA256 header made with the secret you get when you subscribe. Verify it before processing.

API FAQ

Flaxxa CRM API: common questions

Frequently asked questions

Call PUT /leads/by-external-id/{your_id} with an API key that has the crm.lead.edit scope. Flaxxa CRM creates the lead the first time and updates it after that, so repeated syncs never make duplicates. For batches, POST /leads/bulk-upsert.

Get started in minutes

Ship faster with Flaxxa CRM.

Create a workspace, make an API key in its settings, and send your first request.

Free plan · No credit card · Cancel anytime