Directory & Contractors

What is the Directory?

On the YunoJuno platform, the directory is your view of the contractors you work with. It is built around the client contact record: a stable entity that represents the long-term relationship between your organisation and a single contractor.

Unlike a contractor’s global profile, the client contact belongs to the relationship itself. Client-contact custom fields and directory-level lifecycle state all sit on this record. As a contractor moves through registration and onboarding with you, the same client_contact_id remains the stable anchor across every lifecycle event.

This matters because the contractor lifecycle and the client-contact lifecycle are related but not identical. A client contact can be created for a brand-new invitee, or it can be created for a contractor who is already registered and onboarded elsewhere on YunoJuno. Directory events describe what is happening for your specific relationship with a contractor, not for the contractor globally.


Actors

ActorWho they areWhat they do
HirerA person or service account at your organisationInvites contractors into your directory, adds existing YunoJuno contractors, and manages client-contact custom fields.
ContractorThe independent worker being added to your directoryAccepts the invite (if new to YunoJuno), completes registration, and works through onboarding until they become bookable.
PlatformAutomated YunoJuno lifecycle logicTracks registration, onboarding, and bookability for each client-contact relationship, and emits webhooks as those states change.

Lifecycle Overview

Each client-contact relationship progresses through a sequence of directory lifecycle events:

Not every relationship passes through every event. A contractor who is already registered and onboarded when you add them will trigger created with a lifecycle snapshot that already shows them as registered and finished onboarding — no separate registered or onboarding_completed event will follow.


Lifecycle Events

client.client_contact.created

Emitted when the client-contact relationship is first established. This covers both of the ways a client contact can come into existence:

  • you invite a new contractor into your directory
  • you add a contractor who already exists on YunoJuno

Because both routes share this event, created does not imply that the contractor is still invited. The webhook snapshot may already show registration_state = REGISTERED and onboarding_state = FINISHED if the contractor was already established on-platform when the relationship began.

client.client_contact.registered

Emitted only for invite-driven flows, once the contractor completes account registration. In platform terms, this is the point at which the contractor leaves the invited state, becomes registered, and begins onboarding for your organisation.

client.client_contact.onboarding_completed

Emitted when an invited contractor finishes onboarding. Consumers should treat status.bookability_state on the payload as the source of truth for bookability, rather than inferring it from the event name alone. In most directory-invite flows this event coincides with the contractor becoming bookable, but the payload remains authoritative.

client.client_contact.custom_fields_updated

Emitted whenever client-contact custom fields are updated. This event shares the same data.object snapshot as the other lifecycle events, and additionally carries data.changes so the exact fields touched in this update are visible.


Status Fields

Every lifecycle webhook carries a status object describing the current state of the client-contact relationship. The shape is intended to be integration-friendly rather than a raw mirror of internal model names.

FieldWhat it means
registration_stateWhether the contractor is still invited or now registered in the context of this client contact.
onboarding_stateThe current onboarding milestone for the relationship.
bookability_stateWhether the contractor can currently be booked by you.

The onboarding states exposed today are:

StateWhat it means
WAITING_EMAIL_CONFIRMATIONThe contractor has registered but has not yet confirmed their email address.
STARTEDThe contractor has begun onboarding but has not yet completed it.
FINISHEDOnboarding is complete for this relationship.

Custom Field Diffs

When client-contact custom fields change, the webhook carries both the full current snapshot and a diff of what changed in this event:

  • data.object.custom_fields is the full current snapshot of all custom fields after the update
  • data.changes.fields lists only the fields touched by this event
  • each entry in data.changes.fields carries old and new value snapshots so the exact before-and-after can be read directly

Change Types

Change typeWhat it means
ADDEDThe field did not have a value before and now does.
UPDATEDThe field had a value before and has a different value now.
CLEAREDThe field had a value before and has been cleared.

In current directory flows these are the common change types. The webhook primitives are intentionally future-friendly so the API can support richer custom-field change semantics over time without changing the outer event shape.

Example

1{
2 "event_type": "client.client_contact.custom_fields_updated",
3 "data": {
4 "object": {
5 "client_contact_id": "clct_c2k8wm3du8fe1fnxg6ch1hbr0",
6 "custom_fields": [
7 { "name": "cost_center", "value": "CC-200", "metadata": null },
8 { "name": "secondary_approver", "value": "", "metadata": null }
9 ]
10 },
11 "changes": {
12 "changed_fields_count": 2,
13 "fields": [
14 {
15 "name": "cost_center",
16 "change_type": "UPDATED",
17 "old": { "value": "CC-100", "metadata": null },
18 "new": { "value": "CC-200", "metadata": null }
19 },
20 {
21 "name": "secondary_approver",
22 "change_type": "CLEARED",
23 "old": { "value": "jane.smith@example.com", "metadata": null },
24 "new": { "value": "", "metadata": null }
25 }
26 ]
27 }
28 }
29}