Integration guide · v1.1 · October 2026

MiVida ↔ In4Suite Integration API

Everything the In4Suite team needs to push leads and opportunities into MiVida, keep them up to date, and receive changes back.

Base URL https://<mivida-host>/api Format JSON over HTTPS Auth OAuth2 client credentials Interactive reference /api-doc (staging), tag In4Suite

01Terminology

The two systems use the same words for different things. In this guide, “lead” and “opportunity” always mean In4Suite’s terms unless stated otherwise.

In4Suite
Lead
key: lead_id
MiVida
Customer
a customer profile
In4Suite
Opportunity
key: opportunity_id
MiVida
Opportunity→ agent assigned →Lead
the MiVida lead is what agents work

02Quick start

Three calls: get a token, push the customer, push their opportunity.

bash
# 1. Get an access token (valid 24 hours)
curl -X POST https://<mivida-host>/api/auth/token \
  -H 'Content-Type: application/json' \
  -d '{"client_id": "<your client id>", "client_secret": "<your client secret>"}'
# → {"token": "eyJ0eXAiOiJKV1Qi..."}

# 2. Push a lead (customer profile)
curl -X POST https://<mivida-host>/api/in4suite/leads \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1Qi...' \
  -H 'Content-Type: application/json' \
  -d '{
        "lead_id": "LD-000123",
        "customer_name": "Aisha Rahman",
        "customer_phone": "+971501234567",
        "customer_country_code": "AE",
        "customer_email": "aisha.rahman@example.com",
        "created_at": "2024-03-14T10:22:00+04:00"
      }'

# 3. Push an opportunity for that lead
curl -X POST https://<mivida-host>/api/in4suite/opportunities \
  -H 'Authorization: Bearer eyJ0eXAiOiJKV1Qi...' \
  -H 'Content-Type: application/json' \
  -d '{
        "opportunity_id": "OP-004567",
        "lead_id": "LD-000123",
        "customer_name": "Aisha Rahman",
        "customer_phone": "+971501234567",
        "customer_country_code": "AE",
        "project_id": "PRJ-104",
        "area": "0192a1b2-55aa-7b31-8c12-44ab77cd1200",
        "unit_type": "2 BHK Type B",
        "budget": "1500000-1800000",
        "source_category": "Digital",
        "source": "Facebook",
        "assigned_agent_id": "USR-0042",
        "created_at": "2024-03-14T10:25:00+04:00"
      }'

03Authentication

MiVida uses the OAuth2 client-credentials grant. MiVida issues you a client_id and client_secret through a secure channel, never in plain-text email.

StepRequest
Get a tokenPOST /api/auth/token with {"client_id": "...", "client_secret": "..."}
Use itHeader Authorization: Bearer <token> on every /api/in4suite/* call
  • Tokens are valid for 24 hours. Request a new one before expiry, or when a call returns 401.
  • The /api/in4suite/* endpoints accept only tokens issued to the In4Suite client. Any other token, including a MiVida user’s login token, gets 403.
  • Invalid credentials on /auth/token return 403 Invalid client credentials.

04Conventions

Your IDs are the keys

Every record is addressed by your ID (lead_id, opportunity_id). You never need to store MiVida’s IDs, though responses include them (mivida_customer_id, mivida_opportunity_id, mivida_lead_id, mivida_project_id) for support conversations. IDs are strings of up to 64 characters and may contain anything except /.

Projects and agents are addressed by your IDs too: MiVida stores your project id and agent id on its own project and employee records (fields, agent assignment).

Create-or-update with POST is safe to retry

POST creates the record if MiVida doesn’t know the ID yet, and updates it if it does. Re-sending the same payload never creates duplicates, so retrying after a timeout or network error is always safe.

resultHTTPMeaning
created201New record created.
updated200Existing record updated.
linked200Leads only. MiVida already had this customer (same email, else same phone) and linked it to your lead_id instead of creating a duplicate.

PUT and PATCH on /…/{id} only update. They return 404 if MiVida doesn’t know the ID.

Partial updates

On update, only the fields you send change. Fields you omit keep their current value.

  • “Required” fields are required to create. On update you may omit them, but you can’t blank them: "" or null gives 422.
  • created_at is used on create only and ignored on update.
  • Unknown fields are ignored, so extra fields won’t break a call.

Dates and times

  • Send ISO 8601 with a UTC offset, e.g. 2024-03-14T10:22:00+04:00 or 2024-03-14T06:22:00Z. A value without an offset is read in MiVida’s business timezone.
  • Received timestamps are always UTC, e.g. 2024-03-14T06:22:00Z.
  • created_at may not be in the future. Five minutes of clock skew are tolerated.

Response shapes

Single write (POST, PUT, PATCH). warnings lists non-fatal notes. The record was saved (example).

json
{ "result": "created", "warnings": [], "data": { ...record... } }

Lookup (GET):

json
{ "data": { ...record... } }

Validation failure (HTTP 422). Every problem is listed, by field name:

json
{
  "errors": [
    { "field": "customer_country_code", "message": "customer_country_code \"ZZ\" is not a known ISO2 country code or dial code." },
    { "field": "created_at", "message": "created_at cannot be in the future." }
  ],
  "code": 422
}

Other errors (400, 401, 403, 404, 500):

json
{ "errors": { "name": "Not Found", "message": "No record with lead_id \"LD-9\" exists in MiVida.", "status": 404 }, "code": 404 }

HTTP status summary

StatusWhenWhat to do
200 / 201Success—
400Body isn’t valid JSON or not the expected shape, or a batch has more than 100 itemsFix the request
401Missing, invalid or expired tokenGet a new token and retry
403Token isn’t the In4Suite client’sUse the In4Suite credentials
404GET, PUT or PATCH for an ID MiVida doesn’t knowCreate it with POST
422Validation failedFix the listed fields; don’t retry unchanged
5xxMiVida-side failureRetry with backoff; contact MiVida if it persists

05Endpoints

Base URL: https://<mivida-host>/api

MethodPathPurpose
POST/in4suite/leadsCreate or update a lead
PUT PATCH/in4suite/leads/{lead_id}Update a lead
GET/in4suite/leads/{lead_id}Fetch a lead as MiVida holds it
POST/in4suite/leads/batchCreate or update up to 100 leads
POST/in4suite/opportunitiesCreate or update an opportunity
PUT PATCH/in4suite/opportunities/{opportunity_id}Update an opportunity
GET/in4suite/opportunities/{opportunity_id}Fetch an opportunity, with MiVida’s lead status and current agent
POST/in4suite/opportunities/batchCreate or update up to 100 opportunities

06Leads (customer profiles)

Fields

FieldTo createType / limitNotes
lead_idrequiredstring ≤ 64Your Lead ID.
customer_namerequiredstring ≤ 128
customer_phonerequiredstring ≤ 15Unique across MiVida customers. Spaces, dashes, dots and brackets are removed; a leading + is kept.
customer_country_coderequiredstringISO 3166-1 alpha-2 (AE) is preferred. Dial codes (971, +971, 00971) are accepted too. Shared dial codes resolve to the main country (1 → US, 7 → RU, 44 → GB, 61 → AU), so send ISO2 for the others.
customer_emailrequiredemail ≤ 128Unique across MiVida customers.
created_atrequiredISO 8601Original creation time in In4Suite. Kept as the customer’s creation date.
salutationoptionalstringmaster data your In4Suite salutation, e.g. Mr., M/s., Bishop. Matched ignoring case, spaces and dots (Dr. = Dr); M/s. and Ms. are distinct. One MiVida doesn’t know is stored as sent, not rejected.
customer_categoryoptionalstring ≤ 128master data customer category
customer_locationoptionalstring ≤ 255Free text
preferred_contact_methodoptionalstring ≤ 128master data contact method
preferred_contact_timeoptionalstring ≤ 128master data contact time

Behaviour

  • Matching existing customers. If MiVida doesn’t know your lead_id yet but already has a customer with the same email (checked first) or phone, that customer is linked to your lead_id (result: "linked") and updated with your fields. No duplicate is created.
  • Conflict. If that email or phone belongs to a customer already linked to a different lead_id, you get 422 naming the other lead. Two In4Suite leads can’t share an email or phone in MiVida.
  • Copies stay in sync. MiVida keeps a copy of the customer’s name, phone, email and country on each of their opportunities and leads. Updating the lead updates those copies too.

Example: update one field

http
PATCH /api/in4suite/leads/LD-000123
Content-Type: application/json

{ "customer_phone": "+971509999999" }
response · 200
{
  "result": "updated",
  "warnings": [],
  "data": {
    "lead_id": "LD-000123",
    "mivida_customer_id": "0192a1b2-7c44-7e9a-bf21-2b1c9d4e5f60",
    "customer_name": "Aisha Rahman",
    "customer_phone": "+971509999999",
    "customer_country_code": "AE",
    "customer_email": "aisha.rahman@example.com",
    "salutation": null,
    "customer_category": null,
    "customer_location": null,
    "preferred_contact_method": null,
    "preferred_contact_time": null,
    "created_at": "2024-03-14T06:22:00Z",
    "updated_at": "2026-10-07T08:15:31Z"
  }
}

07Opportunities

Fields

Fields marked master data are sent as your In4Suite names (e.g. 2 BHK Type B, Walk-In). MiVida keeps its lists in sync with In4Suite’s and matches names ignoring case, spaces and separators. area is the exception: a MiVida unit size id from the MiVida Master Data sheet. The customer’s email isn’t sent with the opportunity; MiVida takes it from the lead.

FieldTo createType / limitNotes
opportunity_idrequiredstring ≤ 64Your Opportunity ID.
lead_idrequiredstring ≤ 64The customer’s lead_id. Push that lead first. Can’t be changed after the opportunity is created.
customer_namerequiredstring ≤ 128
customer_phonerequiredstring ≤ 15
customer_country_coderequiredstringSame rules as for leads.
project_idrequiredstringYour In4Suite project id (e.g. PRJ-104), matched against the In4Suite Project ID set on each MiVida project. MiVida project codes and ids are not accepted.
source_categoryrequiredstringmaster data your In4Suite source category, e.g. Walk-In. MiVida’s value (walk_in) is accepted too.
unit_typerequiredstringmaster data your In4Suite unit type, e.g. 2 BHK Type B. 2BHK, 2 BHK and 2_bhk are the same type. MiVida’s value (2_bhk_type_b) is accepted too.
created_atrequiredISO 8601Original creation time in In4Suite. Decides whether the record is historical.
areaoptionalstring (id)master data MiVida unit size id. Must belong to project_id. MiVida fills in the phase, block and unit type from it.
sourceoptionalstringmaster data your In4Suite source, e.g. Signages. Must belong to source_category. The same name may exist under several categories; the one under source_category is used.
budgetoptionalstring ≤ 40One amount (1500000) or a range (1500000-1800000).
assigned_agent_idoptionalstringYour In4Suite id of the agent. See agent assignment.
customer_categoryoptionalstringmaster data
customer_locationoptionalstring ≤ 255Free text
buying_horizonoptionalstringmaster data
preferred_contact_methodoptionalstringmaster data
preferred_contact_timeoptionalstringmaster data
remarksoptionalstring ≤ 255Note for the assigning manager

Agent assignment

Agents are identified by your In4Suite id for them, matched exactly against the In4Suite ID set on each MiVida employee. Employee codes are not accepted.

SituationOutcome
Id matches an employee with a MiVida user accountAssigned. MiVida creates its lead for that agent.
Id matches an employee without a user accountSaved unassigned, with your id kept. warnings says so. Status 201/200, not an error. A MiVida admin can assign it once the account exists.
Id not mapped to any MiVida employee422 on assigned_agent_id
Not sent, live recordMiVida assigns automatically, round-robin among the project cluster’s agents
Not sent, historical recordLeft unassigned
Update with a different idMiVida’s lead is reassigned: recorded in its history, and the new agent is notified (not for historical records).
Update with an empty valueIgnored. Agents can’t be removed through the API.
response · 201 with a warning
{
  "result": "created",
  "warnings": ["Employee USR-0222 has no MiVida user account; the opportunity is left unassigned. It can be assigned once the account exists."],
  "data": { "opportunity_id": "OP-004568", "status": "unassigned", "is_agent_assigned": false, "assigned_agent_id": "USR-0222", "...": "..." }
}

Response fields

FieldMeaning
opportunity_id, lead_idYour IDs
mivida_opportunity_idMiVida’s opportunity id
mivida_lead_idMiVida’s lead id once an agent is assigned; null before
statusunassigned or assigned
lead_statusStage in MiVida’s sales pipeline (e.g. opportunity, site_visited, booked, sold); null while unassigned
is_historicalWhether MiVida archived it on arrival
assigned_agent_idYour In4Suite id of the current agent. If that agent has no MiVida account, or MiVida reassigned it to someone not mapped to In4Suite, the last id you sent (null if you never sent one).
is_agent_assignedWhether a MiVida agent actually holds it
project_id, mivida_project_id, project_code, areaYour In4Suite project id (as you send it), MiVida’s project id, MiVida’s project code and the unit size id
other fieldsAs sent, after normalization

Rules to know

  • One customer, many opportunities. A lead may have any number of opportunities. MiVida doesn’t treat them as duplicates.
  • Changing project_id without area is rejected if the stored area belongs to the old project. Send the new project’s area with it.
  • Changing source_category without source is rejected if the stored source belongs to the old category. Send a source from the new category, or "source": "" to clear it.
  • A lead deleted in MiVida. If a MiVida user deletes the lead, In4Suite updates still apply to the opportunity, and the response carries a warning saying so.
  • An opportunity deleted in MiVida can’t be re-created with the same opportunity_id (422). Contact MiVida if this happens.

08Historical records

An opportunity whose created_at falls before today, in MiVida’s business timezone, is historical. MiVida decides this once, when the record is created; updates never change it.

Historical records:

  • keep their original dates (created, assigned, stage), so reports place them in the right period;
  • are archived: kept out of agents’ work lists, dashboards, funnel reports, automatic lead scoring and reminders;
  • trigger no notifications to agents or customers, and are not synced back to In4Suite;
  • are never auto-assigned;
  • stay searchable in MiVida (filter “Historical: Yes”). A MiVida admin can un-archive one, for example when the customer comes back.
Late live pushes are archived too

An opportunity created yesterday but delivered today, say after an outage, counts as historical. Deliver live opportunities on the day they’re created. A MiVida admin can un-archive any that arrive late.

09Batches and the initial load

Batch endpoints

http
POST /api/in4suite/opportunities/batch
Content-Type: application/json

{ "items": [ { ...opportunity... }, { ...opportunity... } ] }
  • Up to 100 items per request. More returns 400.
  • Each item has the same fields as the single endpoint and is created or updated independently. A failing item doesn’t affect the others, even when MiVida hits an internal error on it: that item is reported as failed with an “internal error” message and the rest of the batch still runs.
  • The response is 200 whenever the body is well formed. Check each item’s result. index is the item’s position in your items array.
response · 200
{
  "summary": { "total": 2, "created": 0, "updated": 1, "linked": 0, "failed": 1 },
  "results": [
    { "index": 0, "opportunity_id": "OP-1", "result": "updated", "warnings": [],
      "mivida_opportunity_id": "...", "mivida_lead_id": "...", "is_historical": true },
    { "index": 1, "opportunity_id": "OP-3", "result": "failed",
      "errors": [ { "field": "lead_id", "message": "In4Suite lead \"LD-404\" has not been pushed to MiVida yet. Push the lead first, then retry this opportunity." } ] }
  ]
}

Loading about 200,000 historical records

  1. All leads first, through POST /in4suite/leads/batch. An opportunity is rejected if its lead hasn’t arrived yet.
  2. Then all opportunities, through POST /in4suite/opportunities/batch.
  3. Send 100 items per request, with at most 4 requests in parallel.
  4. Collect the failed items, fix them and re-send only those. Re-sending items that already succeeded is harmless.
  5. A failure reading “This record was being written by another request at the same time” means two parallel requests raced for the same ID. Retry it.
  6. Start with a dry run on MiVida’s staging environment using a few thousand records, to check the master-data mapping and throughput.

After the initial load, push changes as they happen through the single endpoints or batches.

10Changes sent back to In4Suite

MiVida notifies In4Suite when a MiVida user changes a record that came from In4Suite. Changes In4Suite sent itself are not echoed back, and historical records aren’t synced.

We need your input

MiVida needs the URL and credentials of the In4Suite endpoint that will receive these events. Sync-back stays switched off until then. The format below is MiVida’s proposal; if In4Suite already has an inbound API, send us its specification and we’ll adapt.

Delivery

  • POST <your URL> with a JSON body.
  • Headers: Content-Type: application/json, Authorization: Bearer <token you give us>, Idempotency-Key: <event_id>.
  • Any 2xx response counts as delivered. Anything else, or a 15-second timeout, is retried up to 8 times, about a minute apart.
  • Delivery is at-least-once: use event_id to discard duplicates. Order isn’t guaranteed; compare occurred_at if order matters.

Envelope

json
{
  "event_id": "0192a1c0-1d2e-7f30-8a41-5b6c7d8e9f00",
  "event": "opportunity.assigned",
  "occurred_at": "2026-10-07T08:15:31Z",
  "data": { ... }
}

Events

eventSent whendata
opportunity.assignedA MiVida user assigns or reassigns the opportunity’s agentopportunity_id, assigned_agent_id (your In4Suite id of the agent; null when the opportunity was unassigned; omitted when the agent isn’t mapped to In4Suite, so keep your current value), assigned_at
opportunity.status_changedThe MiVida lead moves along the pipelineopportunity_id, status, status_label, status_remarks, status_updated_at
lead.updatedA MiVida user changes the customer’s contact detailslead_id plus only the changed fields among customer_name, customer_phone, customer_email, customer_country_code

MiVida pipeline statuses, in order

  1. opportunity
  2. site_visited
  3. booked
  4. sold
  5. loo_executed
  6. min_deposit_paid
  7. afl_requested
  8. afl_issued
  9. afl_executed

LOO is the Letter of Offer; AFL is the Agreement for Lease.

11Error messages

FieldMessage (abridged)Fix
any required field<field> cannot be blank.Send a value
customer_emailcustomer_email is not a valid email address.
customer_email / customer_phoneEmail already exists. / Phone already exists.Another MiVida customer holds it
customer_email / customer_phone… already belongs to In4Suite lead "X".Two of your leads share this value
customer_country_code… is not a known ISO2 country code or dial code.Use ISO2
created_at… must be an ISO 8601 date-time … / … cannot be in the future.
lead_idIn4Suite lead "X" has not been pushed to MiVida yet …Push the lead, then retry
lead_idAn opportunity cannot be moved to another lead …Not supported
project_id… is not mapped to any MiVida project (In4Suite Project ID).Ask MiVida to set the In4Suite Project ID on the project
area… does not match any MiVida unit size id. / … belongs to a different project …Check the master data sheet
unit_type / source_category / source… is not a MiVida unit type / source category / source.Check the master data sheet
source… does not belong to source category "X".
sourcesource_category changed: the stored source "X" does not belong to "Y" …Send a source from the new category, or ""
assigned_agent_idNo MiVida employee is mapped to In4Suite id "X".Ask MiVida to set the In4Suite ID on the employee
budgetbudget format message1500000 or 1500000-1800000
opportunity_idThis opportunity was deleted in MiVida …Contact MiVida
opportunity_id / lead_id (batch)MiVida could not process this item because of an internal error …Retry later; contact MiVida if it persists

12Go-live checklist

  • MiVida provides client_id / client_secret for each environment (staging, production).
  • MiVida sets the In4Suite Project ID on every project In4Suite will send opportunities for.
  • MiVida sets the In4Suite ID on every employee In4Suite assigns opportunities to.
  • In4Suite verifies the master data mapping (unit sizes, unit types, source categories and sources) against the MiVida Master Data sheet.
  • Dry run of the historical load on staging; review the failed items.
  • In4Suite provides the sync-back URL and token.
  • Production historical load: leads, then opportunities.
  • Switch to live pushes.

Coming next

  • Bookings (next phase): In4Suite bookings will update MiVida pipeline stages, including for historical records.
  • Activity history (calls, notes, site visits) is out of scope for this phase.

13Changes in 1.1

What changed since version 1.0. The first three rows change what you send or receive.

Area1.01.1
project_id (request)MiVida project code or idYour In4Suite project id, mapped on the MiVida project. Codes and MiVida ids are no longer accepted.
project_id (response)MiVida project idYour In4Suite project id, as you send it. MiVida’s id moves to mivida_project_id.
assigned_agent_idEmployee codeYour In4Suite agent id, mapped on the MiVida employee. Employee codes are no longer accepted. Also used in responses and in opportunity.assigned.
opportunity.assignedassigned_agent_id always presentOmitted when MiVida’s agent isn’t mapped to In4Suite; null only when the opportunity was unassigned.
unit_type, source_category, sourceMiVida value or label, case-insensitiveYour In4Suite names, ignoring case, spaces and separators. MiVida’s lists now include In4Suite’s. The same source may exist under several categories.
salutationStored as sentYour In4Suite salutation, matched to MiVida’s (Dr. → Dr). Unknown ones are still stored as sent.