Agents

List, update, and delete real estate agents. Manage avatars and list public agent profiles.

Manage real estate agent profiles for your organization.

The Identity Model

An agent is a per-organization roster row. Every member of a Clerk organization has exactly one agent row in that organization, created automatically the moment the membership exists. A user who belongs to three organizations has three independent rows, one per organization, and each carries that organization's own role fields.

Clerk is canonical for the person. firstName, lastName, and the avatar come from the member's Fondaro (Clerk) account. When the account profile changes, every one of that user's agent rows is updated. When you change one of those fields through PUT /agents/:id on a Clerk-linked row, the API writes the change through to the Clerk account first and then persists the canonical result, so the change is visible in every organization that person belongs to. Those write-through actions are restricted to organization admins and to the member themselves.

The organization is canonical for the role. title, displayEmail, phoneNumber, whatsappNumber, description, and isActive are owned by the organization, stored per row, and never synced anywhere.

Membership changes flow automatically: joining creates the row (or reactivates an existing one), leaving deactivates it while keeping the data, and rejoining reactivates it with the organization's fields intact.

Standalone agents (POST /agents/standalone) are the escape hatch for a public-facing face who has no Fondaro account, for example an external collaborator. They live in the same table, are owned entirely by the organization, and are never linked to a Clerk user.

Every agent reference is a UUID. agents.id is the only identifier any endpoint accepts or returns for an agent, including property_listings.agent_id and brochure agent fields. Clerk user IDs (user_...) are never stored in an agent reference column.

Removed Endpoints

These endpoints no longer exist. The behaviour they provided is now automatic.

RemovedReplacement
POST /agents (create a Clerk-linked agent)Rows are created automatically from Clerk membership. Use POST /agents/standalone for a non-member face
POST /agents/syncThe membership webhook keeps the roster converged; operators can re-run the reconciler if needed
GET /agents/:id/account-profileThere is nothing to reconcile: Clerk values are written to the row unconditionally
POST /agents/:id/adopt-account-fieldSame as above

Create a Standalone Agent

POST /agents/standalone

Authentication: Required (JWT)

Creates an agent profile that is not linked to a Clerk user account. Use this for external agents or collaborators who don't have a Fondaro login.

Request Body

FieldTypeRequiredDescriptionConstraints
firstNamestringYesFirst nameMax 100 chars, non-empty
lastNamestringNoLast nameMax 100 chars
displayEmailstringNoPublic emailValid email format
phoneNumberstringNoPhone number
whatsappNumberstringNoWhatsApp number
descriptionstringNoAgent bio
titlestringNoJob title
isActivebooleanNoActive statusDefault: true
additionalInfoobjectNoCustom data

Example

curl -X POST https://api.fondaro.com/agents/standalone \
  -H "Authorization: Bearer <jwt-session-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "Miguel",
    "lastName": "Fernández",
    "displayEmail": "miguel@example.com",
    "phoneNumber": "+34698765432",
    "title": "Independent Agent"
  }'

List Agents

GET /agents

Authentication: Required (JWT)

Returns all agents for your organization.

Query Parameters

ParameterTypeDefaultDescription
isActivebooleanFilter by active status
searchstringSearch by name

Example

curl "https://api.fondaro.com/agents?isActive=true&search=sarah" \
  -H "Authorization: Bearer <jwt-session-token>"

Get an Agent

GET /agents/:id

Authentication: Required (JWT)

The :id is the agent's UUID. Agents are scoped to your organization: an ID belonging to another organization returns 404.

Example

curl https://api.fondaro.com/agents/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer <jwt-session-token>"

Errors

StatusCondition
404Agent not found

Update an Agent

PUT /agents/:id

Authentication: Required (JWT)

All fields are optional: include only what you want to change.

On a Clerk-linked agent, firstName, lastName, and avatarUrl are written through to the member's Fondaro account and therefore change everywhere that person appears. Those fields may only be changed by an organization admin or by the member themselves. The remaining fields are owned by your organization and stay local to this row.

Request Body

FieldTypeDescriptionConstraints
firstNamestringFirst nameMax 100 chars
lastNamestringLast nameMax 100 chars
avatarUrlstringAvatar URLMax 500 chars
avatarThumbnailUrlstringThumbnail URLMax 500 chars
displayEmailstringPublic emailValid email
phoneNumberstringPhone number
whatsappNumberstringWhatsApp number
descriptionstringBio / description
titlestringJob title
isActivebooleanActive status
additionalInfoobjectCustom data

Example

curl -X PUT https://api.fondaro.com/agents/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer <jwt-session-token>" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Director of Sales",
    "description": "Specializing in luxury beachfront properties on the Costa del Sol."
  }'

Delete an Agent

DELETE /agents/:id

Authentication: Required (JWT)

Example

curl -X DELETE https://api.fondaro.com/agents/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d \
  -H "Authorization: Bearer <jwt-session-token>"

Response

{
  "success": true
}

Upload Agent Avatar

POST /agents/:id/avatar

Authentication: Required (JWT)

Upload a profile photo for an agent. On a Clerk-linked agent the photo becomes the member's account photo and appears in every organization they belong to (organization admins and the member themselves only). On a standalone agent the image is resized, stored, and written to the row.

Request

Send the file as multipart/form-data with the field name avatar.

ConstraintValue
Max file size5 MB
Accepted formatsJPEG, JPG, PNG, WebP, GIF

Example

curl -X POST https://api.fondaro.com/agents/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/avatar \
  -H "Authorization: Bearer <jwt-session-token>" \
  -F "avatar=@photo.jpg"

Response

Returns the updated agent object with new avatarUrl and avatarThumbnailUrl fields.

Errors

StatusCondition
404Agent not found
422File too large or invalid format

Delete Agent Avatar

DELETE /agents/:id/avatar

Authentication: Required (JWT)

Removes the agent's avatar photo.

Example

curl -X DELETE https://api.fondaro.com/agents/a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d/avatar \
  -H "Authorization: Bearer <jwt-session-token>"

Public: Active Agents with Listings

GET /properties/agents?organizationId=<uuid>

Authentication: None required (public endpoint)

Returns active agents that have at least one active property listing. This is intended for public-facing websites to display agent directories.

Query Parameters

ParameterTypeRequiredDescription
organizationIdUUIDYesOrganization ID to list agents for

Example

curl "https://api.fondaro.com/properties/agents?organizationId=a1b2c3d4-5e6f-7a8b-9c0d-1e2f3a4b5c6d"

Response

Returns an array of public agent profiles (no internal IDs or timestamps):

[
  {
    "id": "f1e2d3c4-...",
    "firstName": "Sarah",
    "lastName": "Johnson",
    "avatarUrl": "https://cdn.fondaro.com/avatars/...",
    "avatarThumbnailUrl": "https://cdn.fondaro.com/avatars/...",
    "displayEmail": "sarah@luxuryestates.com",
    "phoneNumber": "+34612345678",
    "whatsappNumber": "+34612345678",
    "description": "Specializing in luxury beachfront properties.",
    "title": "Senior Property Consultant"
  }
]

Response Format Note

Agent responses include both snake_case and camelCase field names for backwards compatibility:

  • first_name / firstName
  • last_name / lastName
  • image_url / avatarUrl

Prefer the camelCase versions in new integrations. The public endpoint only returns camelCase fields.