API reference

iF Chile API

Capture campaign leads, schedule site visits, read live space pricing to build your own quotations, and manage onboardings for won deals — all through a single, versioned REST API.

Agency

Lead intake for marketing partners. Push leads from campaigns, landing pages, and paid channels straight into the sales pipeline.

CRM

Everything an external CRM needs to operate: visit availability and lifecycle, the location & space catalog with effective pricing, and onboarding management. Quotations are generated on your side — the API never creates them.

  • All requests and responses are JSON.
  • Timestamps are ISO 8601 in UTC, e.g. 2026-07-01T13:00:00+00:00.
  • Identifiers are opaque strings issued by the platform.
  • The API is versioned in the path: /api/v1.
Base URL
https://api-crm.ifchile.app/api/v1
Your first request
curl https://api-crm.ifchile.app/api/v1/crm/locations \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Accept: application/json"

Authentication

The API uses bearer tokens with the iftkn- prefix. Tokens are issued by the iF Chile team and are shown exactly once — store them in a secret manager, never in source control.

Every token is scoped to a single module. An agency token only reaches /agency endpoints and a crm token only reaches /crm endpoints. Requests with a valid token but the wrong scope return 403; requests without a token return 401.

Send the token on every request in the Authorization header.

Authenticated request
# Module-scoped bearer token
curl https://api-crm.ifchile.app/api/v1/crm/visits?lead_id=ld_8m2 \
  -H "Authorization: Bearer iftkn-FZ2vQn81xKpd…" \
  -H "Accept: application/json"
Wrong module · 403
{
  "message": "Invalid ability provided."
}

Errors

The API uses conventional HTTP status codes. Every error body carries a human-readable message; validation failures additionally include an errors map keyed by field.

401

Unauthenticated. Missing or invalid token.

403

Forbidden. Wrong module scope, or the API client was disabled.

404

Not found. The resource does not exist upstream.

422

Unprocessable. Validation failed, or the platform rejected the operation (e.g. a visit slot was just taken).

429

Too many requests. Rate limit exceeded — retry after the indicated delay.

502

Bad gateway. The upstream platform is temporarily unreachable. Safe to retry reads.

Validation error · 422
{
  "message": "The first name field is required. (and 1 more error)",
  "errors": {
    "first_name": ["The first name field is required."],
    "source": ["The selected source is invalid."]
  }
}
Upstream outage · 502
{
  "message": "The upstream service is currently unavailable. Please try again later."
}

Rate limits

Each API client may issue up to 120 requests per minute. The current window is exposed via the X-RateLimit-Limit and X-RateLimit-Remaining response headers. When the limit is exceeded the API responds with 429 and a Retry-After header — back off and retry after that many seconds.

Rate limited · 429
{
  "message": "Too Many Attempts."
}

Agency module

Campaign leads

Push prospects captured by campaigns into the sales pipeline. The platform deduplicates people by email or phone and reuses a recent open lead when one exists, so retried submissions never create duplicates.

post /api/v1/agency/leads

Create a lead

Creates (or upserts) a person and an associated lead. Provide at least an email or a phone number so the platform can identify the contact. Returns the lead and person identifiers, plus a created flag — false means an existing open lead was reused.

Body parameters

first_name string required
The contact's first name.
last_name string
The contact's last name.
email string
Contact email. Required when phone is absent.
phone string
Contact phone in E.164 format. Required when email is absent.
company string
Company the contact represents.
source enum required
Acquisition channel. One of organic_web, paid_web, instagram, facebook, referral, event, outbound, whatsapp, website_agent, other.
campaign_id string
Identifier of the campaign that produced this lead.
location_id string
Preferred location, when the prospect expressed one.
business_line string
Business line code the lead belongs to.
engagement_type enum
One of new_opportunity, follow_up, reactivation, upsell, cross_sell.
priority enum
One of low, medium, high, urgent.
message string
Free-form message left by the prospect. Max 2,000 characters.
estimated_team_size integer
Number of people the prospect needs space for.
desired_start_date datetime
When the prospect would like to start, ISO 8601.
marketing_consent boolean
Whether the prospect opted into marketing communications.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/agency/leads \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane@acme.cl",
    "company": "Acme SpA",
    "source": "paid_web",
    "campaign_id": "cmp_7f2k1",
    "location_id": "loc_9a8b7",
    "estimated_team_size": 8,
    "desired_start_date": "2026-08-01T00:00:00+00:00",
    "marketing_consent": true
  }'
Response · 201
{
  "data": {
    "lead_id": "ld_3kq9x",
    "person_id": "pe_8m2v1",
    "created": true
  }
}

CRM module

Catalog & pricing

Read-only access to locations, their spaces, and effective pricing. Use it to build quotations in your own system — pricing resolves through the platform's cascade (global → location → space), so you always read the rate that actually applies.

get /api/v1/crm/locations

List locations

Returns every published location, including its IANA timezone and weekly business hours — both required to interpret visit availability correctly.

Parameters

No parameters.
Request
curl https://api-crm.ifchile.app/api/v1/crm/locations \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": [
    {
      "id": "loc_9a8b7",
      "name": "iF Italia",
      "slug": "if-italia",
      "address": "Av. Italia 850, Providencia",
      "phone": "+56 2 2840 1100",
      "email": "italia@ifchile.com",
      "whatsapp": "+56 9 7777 1100",
      "capacity": 320,
      "timezone": "America/Santiago",
      "business_hours": {
        "monday": { "open": "09:00", "close": "19:00" },
        "tuesday": { "open": "09:00", "close": "19:00" }
      },
      "status": "active"
    }
  ]
}
get /api/v1/crm/locations/{location}

Retrieve a location

Returns a single location by identifier. Responds with 404 when it does not exist.

Path parameters

location string required
The location identifier.
Request
curl https://api-crm.ifchile.app/api/v1/crm/locations/loc_9a8b7 \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": {
    "id": "loc_9a8b7",
    "name": "iF Italia",
    "slug": "if-italia",
    "timezone": "America/Santiago",
    "business_hours": {
      "monday": { "open": "09:00", "close": "19:00" }
    },
    "status": "active"
  }
}
get /api/v1/crm/locations/{location}/spaces

List spaces

Returns the bookable spaces of a location with their type, status, and capacity.

Path parameters

location string required
The location identifier.
Request
curl https://api-crm.ifchile.app/api/v1/crm/locations/loc_9a8b7/spaces \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": [
    {
      "id": "spc_4t7y2",
      "location_id": "loc_9a8b7",
      "floor_id": "flr_2",
      "name": "Office A-203",
      "code": "ITA-203",
      "type": "private_office",
      "status": "available",
      "capacity": 6,
      "square_meters": 24.5,
      "description": "Corner office with natural light."
    }
  ]
}
get /api/v1/crm/spaces/{space}

Retrieve a space

Returns a single space by identifier. Responds with 404 when it does not exist.

Path parameters

space string required
The space identifier.
Request
curl https://api-crm.ifchile.app/api/v1/crm/spaces/spc_4t7y2 \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": {
    "id": "spc_4t7y2",
    "location_id": "loc_9a8b7",
    "name": "Office A-203",
    "type": "private_office",
    "status": "available",
    "capacity": 6,
    "square_meters": 24.5
  }
}
get /api/v1/crm/spaces/{space}/pricing

Retrieve space pricing

Resolves the effective tariff for a space. Rates omitted by the platform are returned as null. The applied_at_scope field tells you which level of the cascade produced the price: global, location, or space.

Responds with 404 when no tariff is configured for the space.

Path parameters

space string required
The space identifier.
Request
curl https://api-crm.ifchile.app/api/v1/crm/spaces/spc_4t7y2/pricing \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": {
    "rates": {
      "hourly": null,
      "half_day": null,
      "daily": 45000,
      "weekly": null,
      "monthly": 850000,
      "yearly": null
    },
    "currency": "CLP",
    "allowed_discounts": [5, 10, 15],
    "guarantee": { "mode": "months_rent", "months": 2 },
    "applied_at_scope": "location"
  }
}

CRM module

Visits

The full visit lifecycle: query open slots, schedule against a lead, then move the visit through confirmed, visited, no_show, or cancelled. Rescheduling replaces the visit and links both records.

get /api/v1/crm/visits/availability

List availability

Returns open slots in 30-minute steps that fit the requested duration, excluding times already blocked by scheduled or confirmed visits. Bound from / to to the location's business hours — the platform does not clip the window for you.

Query parameters

location_id string required
Location to check.
space_id string
Narrow availability to one space.
from datetime required
Window start, ISO 8601.
to datetime required
Window end. Must be after from.
duration_minutes integer required
Desired visit length, 15–480 minutes.
Request
curl "https://api-crm.ifchile.app/api/v1/crm/visits/availability?location_id=loc_9a8b7&from=2026-07-01T12:00:00Z&to=2026-07-01T22:00:00Z&duration_minutes=45" \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": [
    { "starts_at": "2026-07-01T13:00:00+00:00", "ends_at": "2026-07-01T13:45:00+00:00" },
    { "starts_at": "2026-07-01T13:30:00+00:00", "ends_at": "2026-07-01T14:15:00+00:00" },
    { "starts_at": "2026-07-01T15:00:00+00:00", "ends_at": "2026-07-01T15:45:00+00:00" }
  ]
}
get /api/v1/crm/visits

List visits

Returns the visits of a lead, most recent first.

Query parameters

lead_id string required
The lead whose visits to list.
Request
curl "https://api-crm.ifchile.app/api/v1/crm/visits?lead_id=ld_3kq9x" \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": [
    {
      "id": "vs_6p1d4",
      "lead_id": "ld_3kq9x",
      "person_id": null,
      "location_id": "loc_9a8b7",
      "space_id": "spc_4t7y2",
      "responsible_user_id": "usr_2c5n8",
      "status": "confirmed",
      "source": "manual",
      "title": "Tour — Office A-203",
      "notes": "Interested in a 6-person office.",
      "time_zone": "America/Santiago",
      "starts_at": "2026-07-01T13:00:00+00:00",
      "ends_at": "2026-07-01T13:45:00+00:00",
      "cancellation_reason": null,
      "rescheduled_from_id": null,
      "rescheduled_to_id": null,
      "created_at": "2026-06-09T18:21:07+00:00"
    }
  ]
}
post /api/v1/crm/visits

Schedule a visit

Books a visit slot for a lead (or a walk-in person) at a location. If the slot was taken between your availability check and this call, the API responds 422 with the platform's conflict message — re-query availability and retry.

Body parameters

lead_id string
Lead being visited. Required when person_id is absent.
person_id string
Walk-in contact. Required when lead_id is absent.
location_id string required
Location of the visit.
space_id string
Specific space of interest.
responsible_user_id string required
Sales executive responsible for the tour.
starts_at datetime required
Visit start, ISO 8601.
ends_at datetime required
Visit end. Must be after starts_at.
time_zone string
IANA timezone for display purposes. Defaults to America/Santiago.
title string
Short label for calendars.
notes string
Internal notes. Max 2,000 characters.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/visits \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": "ld_3kq9x",
    "location_id": "loc_9a8b7",
    "space_id": "spc_4t7y2",
    "responsible_user_id": "usr_2c5n8",
    "starts_at": "2026-07-01T13:00:00+00:00",
    "ends_at": "2026-07-01T13:45:00+00:00",
    "time_zone": "America/Santiago",
    "notes": "Interested in a 6-person office."
  }'
Response · 201
{
  "data": {
    "id": "vs_6p1d4",
    "status": "scheduled"
  }
}
patch /api/v1/crm/visits/{visit}

Reschedule a visit

Moves a visit to a new slot. The platform marks the original visit as rescheduled and creates a replacement that inherits the lead and space — the response returns the new visit identifier alongside the original.

Body parameters

starts_at datetime required
New start time, ISO 8601.
ends_at datetime required
New end time. Must be after starts_at.
responsible_user_id string
Reassign the visit to another executive.
notes string
Updated notes.
Request
curl -X PATCH https://api-crm.ifchile.app/api/v1/crm/visits/vs_6p1d4 \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{
    "starts_at": "2026-07-02T14:00:00+00:00",
    "ends_at": "2026-07-02T14:45:00+00:00"
  }'
Response · 200
{
  "data": {
    "id": "vs_9w3k7",
    "status": "scheduled",
    "rescheduled_from_id": "vs_6p1d4"
  }
}
post /api/v1/crm/visits/{visit}/confirm

Confirm a visit

Marks a scheduled visit as confirmed by the prospect. No body is required.

Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/visits/vs_6p1d4/confirm \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": {
    "id": "vs_6p1d4",
    "status": "confirmed"
  }
}
post /api/v1/crm/visits/{visit}/cancel

Cancel a visit

Cancels a visit. A reason is mandatory and is stored on the visit record.

Body parameters

reason string required
Why the visit was cancelled. Max 500 characters.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/visits/vs_6p1d4/cancel \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Client asked to cancel." }'
Response · 200
{
  "data": {
    "id": "vs_6p1d4",
    "status": "cancelled"
  }
}
post /api/v1/crm/visits/{visit}/visited

Mark as visited

Marks the visit as completed — the prospect showed up and took the tour.

Body parameters

notes string
Outcome notes from the tour. Max 2,000 characters.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/visits/vs_6p1d4/visited \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{ "notes": "Great fit — wants a quote for A-203." }'
Response · 200
{
  "data": {
    "id": "vs_6p1d4",
    "status": "visited"
  }
}
post /api/v1/crm/visits/{visit}/no-show

Mark as no-show

Marks the visit as a no-show — the prospect did not arrive.

Body parameters

notes string
Context for the no-show. Max 2,000 characters.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/visits/vs_6p1d4/no-show \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{ "notes": "Did not answer the phone." }'
Response · 200
{
  "data": {
    "id": "vs_6p1d4",
    "status": "no_show"
  }
}

CRM module

Onboardings

When a lead is won, an onboarding tracks everything needed before move-in. Create one against an existing account or register the account inline, then keep its status in sync as requirements complete on your side.

post /api/v1/crm/onboardings

Create an onboarding

Starts an onboarding for a won lead. Reference an existing account with account_id, or register a new one inline via the account object — exactly one of the two is required.

Body parameters

lead_id string
The won lead this onboarding originates from.
account_id string
Existing account. Required when account is absent.
account object
New account to register. Required when account_id is absent.
account.type enum required
Either company or individual.
account.legal_name string required
Registered legal name.
account.tax_id string required
Chilean RUT, e.g. 76.123.456-7.
account.email string required
Billing / primary contact email.
account.phone string
Contact phone.
status enum
Initial status. One of pending, in_progress, completed, reopened, cancelled. Defaults to the platform's initial state.
notes string
Internal notes. Max 2,000 characters.
Request
curl -X POST https://api-crm.ifchile.app/api/v1/crm/onboardings \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{
    "lead_id": "ld_3kq9x",
    "account": {
      "type": "company",
      "legal_name": "Acme SpA",
      "tax_id": "76.123.456-7",
      "email": "billing@acme.cl"
    }
  }'
Response · 201
{
  "data": {
    "id": "onb_5r8t2",
    "account_id": "acc_1j4h6"
  }
}
get /api/v1/crm/onboardings/{onboarding}

Retrieve an onboarding

Returns an onboarding with its current status and requirement progress.

Path parameters

onboarding string required
The onboarding identifier.
Request
curl https://api-crm.ifchile.app/api/v1/crm/onboardings/onb_5r8t2 \
  -H "Authorization: Bearer iftkn-FZ2v…"
Response · 200
{
  "data": {
    "id": "onb_5r8t2",
    "account_id": "acc_1j4h6",
    "legal_document_id": "doc_7x2p9",
    "status": "in_progress",
    "started_at": "2026-06-01T12:00:00+00:00",
    "completed_at": null,
    "requirements": [
      { "name": "Signed contract", "complete": true },
      { "name": "Guarantee deposit", "complete": false }
    ],
    "notes": null
  }
}
patch /api/v1/crm/onboardings/{onboarding}

Update an onboarding

Updates the status, notes, or completion timestamp. Send at least one field.

Body parameters

status enum
One of pending, in_progress, completed, reopened, cancelled.
notes string
Internal notes. Max 2,000 characters.
completed_at datetime
When the onboarding finished, ISO 8601.
Request
curl -X PATCH https://api-crm.ifchile.app/api/v1/crm/onboardings/onb_5r8t2 \
  -H "Authorization: Bearer iftkn-FZ2v…" \
  -H "Content-Type: application/json" \
  -d '{
    "status": "completed",
    "completed_at": "2026-06-09T15:00:00+00:00"
  }'
Response · 200
{
  "data": {
    "id": "onb_5r8t2",
    "status": "completed"
  }
}