{"openapi":"3.1.0","info":{"title":"Avertari API","version":"1","description":"Everything the Avertari app does, callable. Browser sessions authenticate with the __Host-avt_session cookie and must send an Origin header on writes; automation uses an organisation API key (Members > API keys) as `Authorization: Bearer avk_...`, which acts as the admin who created it, on that organisation only, and never manages keys or the organisation. Errors are `{ error: { code, message } }`."},"servers":[{"url":"https://app.avertari.io"}],"tags":[{"name":"Service","description":"Health and this document"},{"name":"Auth","description":"Signing in: email link or passkey"},{"name":"Account","description":"The signed-in user"},{"name":"Organisations","description":"Organisations, members, the activity log"},{"name":"Members","description":"Invitations"},{"name":"API keys","description":"Keys for automation"},{"name":"Integrations","description":"Connecting HR systems, identity providers, vaults and log sources"},{"name":"Schema","description":"The person schema and the organisation's own fields"},{"name":"Reports","description":"Workforce and access timing"},{"name":"Journeys","description":"Joiners, movers and leavers, and what should change"},{"name":"Hooks","description":"Endpoints vendors and shippers call"},{"name":"Comms","description":"Lifecycle communication templates"}],"components":{"securitySchemes":{"sessionCookie":{"type":"apiKey","in":"cookie","name":"__Host-avt_session","description":"Set by /api/auth/verify or a passkey sign-in. Writes also need Origin: the app's origin."},"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"avk_...","description":"An organisation API key. Acts as its creator, on its organisation only."},"hookSecret":{"type":"http","scheme":"bearer","description":"The per-integration secret issued on connect (Okta: the raw secret in Authorization; log push: Bearer <secret> or ?token=)."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Integration":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","description":"Catalogue id, e.g. okta, google_workspace, csv_upload"},"kind":{"type":"string","enum":["hris","idp","privilege","comms"]},"displayName":{"type":"string"},"authMethod":{"type":"string","enum":["oauth_consent","api_key","none"]},"status":{"type":"string","enum":["pending","healthy","error","disabled"]},"settings":{"type":"object","properties":{}},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"lastError":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}},"Step":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"integrationId":{"type":"string"},"integrationName":{"type":"string"},"action":{"type":"string","enum":["suspend","remove","add","review"]},"target":{"type":"string"},"reason":{"type":"string"},"privileged":{"type":"boolean"},"state":{"type":"string","enum":["suggested","approved","done","dismissed"]},"at":{"type":"string","format":"date-time"}}},"Entitlement":{"type":"object","properties":{"kind":{"type":"string","enum":["group","role","app","iam_binding","vault"]},"id":{"type":"string"},"name":{"type":"string"},"privileged":{"type":"boolean"},"deprovisions":{"type":"boolean","description":"App assignments from an IdP: the IdP pushes deactivation to the app"}}},"Offboarding":{"type":"object","properties":{"pct":{"type":"number","description":"0-100: how likely this account is shut off without anyone doing it by hand"},"level":{"type":"string","enum":["done","likely","partial","unlikely"]},"reason":{"type":"string"}}},"AccountView":{"type":"object","properties":{"integrationId":{"type":"string"},"integrationName":{"type":"string"},"provider":{"type":"string"},"externalAccountId":{"type":"string"},"status":{"type":"string"},"entitlements":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["group","role","app","iam_binding","vault"]},"id":{"type":"string"},"name":{"type":"string"},"privileged":{"type":"boolean"},"deprovisions":{"type":"boolean","description":"App assignments from an IdP: the IdP pushes deactivation to the app"}}}},"flags":{"type":"array","items":{"type":"string"}},"capturedAt":{"type":"string","format":"date-time"},"offboarding":{"type":"object","properties":{"pct":{"type":"number","description":"0-100: how likely this account is shut off without anyone doing it by hand"},"level":{"type":"string","enum":["done","likely","partial","unlikely"]},"reason":{"type":"string"}}}}},"JourneySummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["joiner","mover","leaver"]},"email":{"type":["string","null"]},"displayName":{"type":["string","null"]},"effectiveAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["open","in_progress","complete","overdue","dismissed"]},"openSteps":{"type":"number"},"overPrivileged":{"type":"number"},"timeToRevokeSeconds":{"type":["number","null"]},"accounts":{"type":"number"},"activeAccounts":{"type":"number"},"offboardingPct":{"type":["number","null"]},"urgent":{"type":"boolean"},"employmentType":{"type":["string","null"]},"dimensions":{"type":"object","properties":{}},"doNotContact":{"type":"boolean"}}},"Person":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"displayName":{"type":["string","null"]},"email":{"type":["string","null"]},"employmentType":{"type":"string"},"title":{"type":["string","null"]},"manager":{"type":["string","null"]},"startDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"endDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"leaveType":{"type":["string","null"]},"gardenLeaveFrom":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"immediateTermination":{"type":"boolean"},"doNotContact":{"type":"boolean"},"dimensions":{"type":"object","properties":{}},"source":{"type":"string","description":"The integration this row came from"},"provider":{"type":"string"},"openJourneys":{"type":"number"}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdBy":{"type":"string","description":"Email of the admin it acts as"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true}}}}},"paths":{"/healthz":{"get":{"summary":"Liveness","tags":["Service"],"security":[],"responses":{"200":{"description":"OK"}}}},"/api/health":{"get":{"summary":"Health and the running revision","description":"The app polls this to offer a reload when a new build is live.","tags":["Service"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"service":{"type":"string"},"revision":{"type":"string"}}}}}}}}},"/api/auth/magic-link":{"post":{"summary":"Request a sign-in link by email","description":"Rate limited per email and per IP. Always answers 200 so addresses can't be probed.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Sent (or silently not, for unknown addresses under invite-only)"}}}},"/api/auth/verify":{"post":{"summary":"Exchange a magic-link token for a session cookie","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"}},"required":["token"]}}}},"responses":{"200":{"description":"Signed in; the __Host-avt_session cookie is set"},"401":{"description":"Token expired or already used"}}}},"/api/auth/sso/start":{"post":{"summary":"Where to send the browser for single sign-on","description":"By email (its domain) or organisation. Always 200; url is null when the domain has no SSO, so nothing leaks.","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"orgId":{"type":"string","format":"uuid"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":["string","null"]}}}}}}}}},"/api/auth/sso/callback":{"get":{"summary":"The identity provider sends the browser back here","description":"Verifies the id_token against the provider's keys, maps groups to a role (and team), creates or updates the membership, starts a session and redirects into the organisation. On failure, redirects to /login?sso_error=<code>.","tags":["Auth"],"security":[],"parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string"}},{"name":"error","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect"}}}},"/api/orgs/{orgId}/sso":{"get":{"summary":"The organisation's single sign-on settings","description":"Owners and admins. The client secret is never returned.","tags":["Organisations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"config":{"type":"object","properties":{"issuer":{"type":"string"},"clientId":{"type":"string"},"hasSecret":{"type":"boolean"},"domains":{"type":"array","items":{"type":"string"}},"scopes":{"type":"string"},"groupsClaim":{"type":"string"},"roleMappings":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":"string","enum":["hr","it_ops","l_and_d","recruitment"]}}}},"defaultRole":{"type":["string","null"]},"enforce":{"type":"boolean"},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}},"redirectUri":{"type":"string","description":"Register this in the provider"},"teams":{"type":"array","items":{"type":"string"}}}}}}}}},"put":{"summary":"Set up or change single sign-on","description":"Owner only, signed in (not an API key). Groups in the token map to roles; the highest wins; a team may ride along. enforce: people from these domains get no email link.","tags":["Organisations"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","description":"https://... the OpenID issuer"},"clientId":{"type":"string"},"clientSecret":{"type":"string","description":"Omit to keep the stored one"},"domains":{"type":"array","items":{"type":"string"}},"scopes":{"type":"string"},"groupsClaim":{"type":"string"},"roleMappings":{"type":"array","items":{"type":"object","properties":{"group":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":"string","enum":["hr","it_ops","l_and_d","recruitment"]}}}},"defaultRole":{"type":["string","null"]},"enforce":{"type":"boolean"},"enabled":{"type":"boolean"}},"required":["issuer","clientId","domains","roleMappings","defaultRole","enforce","enabled"]}}}},"responses":{"200":{"description":"Saved"},"400":{"description":"Bad issuer, domain or mapping; or the domain belongs to another organisation","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}},"403":{"description":"Not the owner"}}},"delete":{"summary":"Remove single sign-on","tags":["Organisations"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Removed"}}}},"/api/auth/passkey/options":{"post":{"summary":"WebAuthn options for signing in with a passkey","tags":["Auth"],"security":[],"responses":{"200":{"description":"PublicKeyCredentialRequestOptions"}}}},"/api/auth/passkey/verify":{"post":{"summary":"Finish a passkey sign-in","tags":["Auth"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"credential":{"type":"object","properties":{}}},"required":["credential"]}}}},"responses":{"200":{"description":"Signed in"},"401":{"description":"Passkey not recognised"}}}},"/api/auth/logout":{"post":{"summary":"End the session","tags":["Auth"],"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"Signed out"}}}},"/api/me":{"get":{"summary":"Who am I","description":"The signed-in user (or the admin an API key acts as), organisations and roles, pending invitations, passkeys.","tags":["Account"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"name":{"type":["string","null"]},"signedInWith":{"type":"string","enum":["email","passkey","sso","api_key"]}}},"organisations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."}}}},"invitations":{"type":"array","items":{"type":"object","properties":{}}},"passkeys":{"type":"array","items":{"type":"object","properties":{}}}}}}}}}},"patch":{"summary":"Change my display name","tags":["Account"],"security":[{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120}}}}}},"responses":{"200":{"description":"Updated"}}}},"/api/passkeys/options":{"post":{"summary":"WebAuthn options for registering a passkey","tags":["Account"],"security":[{"sessionCookie":[]}],"responses":{"200":{"description":"PublicKeyCredentialCreationOptions"}}}},"/api/passkeys":{"post":{"summary":"Register a passkey","tags":["Account"],"security":[{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"credential":{"type":"object","properties":{}},"nickname":{"type":"string"}},"required":["credential"]}}}},"responses":{"201":{"description":"Registered"}}}},"/api/passkeys/{id}":{"delete":{"summary":"Remove a passkey","tags":["Account"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Passkey id","schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"}}}},"/api/orgs":{"post":{"summary":"Create an organisation","description":"The creator becomes its owner. Not available to API keys.","tags":["Organisations"],"security":[{"sessionCookie":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"}}}}}}}}},"/api/orgs/{orgId}":{"get":{"summary":"Organisation detail: members and pending invitations","tags":["Organisations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"organisation":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"slug":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."},"members":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string"},"name":{"type":["string","null"]},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."},"joinedAt":{"type":"string","format":"date-time"}}}},"invitations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"email":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."},"invitedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}}}}}}}}}}},"delete":{"summary":"Delete the organisation and everything in it","description":"Owner only, never an API key. Tenant encryption keys are destroyed.","tags":["Organisations"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Deleted"},"403":{"description":"Not the owner, or called with an API key"}}}},"/api/orgs/{orgId}/invitations":{"post":{"summary":"Invite someone by email","tags":["Members"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."},"message":{"type":"string","description":"Optional personal note, up to 500 characters"}},"required":["email"]}}}},"responses":{"201":{"description":"Invitation sent"},"429":{"description":"Invitation limit for the organisation reached"}}}},"/api/orgs/{orgId}/invitations/{invitationId}/resend":{"post":{"summary":"Send the invitation email again","description":"Three resends an hour per invitation.","tags":["Members"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"invitationId","in":"path","required":true,"description":"Invitation id","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}},"responses":{"200":{"description":"Sent"},"429":{"description":"Resend limit reached"}}}},"/api/orgs/{orgId}/invitations/{invitationId}":{"delete":{"summary":"Revoke an invitation","tags":["Members"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"invitationId","in":"path","required":true,"description":"Invitation id","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Revoked"}}}},"/api/orgs/{orgId}/members/{userId}":{"patch":{"summary":"Change a member's level: role and/or team","description":"Owners and admins. Only an owner makes or unmakes an owner, and the organisation keeps at least one. A team gives the person that team's view of journeys; HR, L&D and Recruitment read, IT Ops (and admins, owners, members with no team) decide access steps.","tags":["Members"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"description":"The member's user id","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."}}}}}},"400":{"description":"That would leave the organisation without an owner"},"403":{"description":"Not allowed to change this member"},"404":{"description":"Not a member"}}},"delete":{"summary":"Remove a member","description":"Owners and admins; an owner can only be removed by an owner, never the last one.","tags":["Members"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"description":"The member's user id","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Removed"},"400":{"description":"Last owner"},"403":{"description":"Not allowed"},"404":{"description":"Not a member"}}}},"/api/invitations/{id}/accept":{"post":{"summary":"Accept an invitation addressed to me","tags":["Members"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Invitation id","schema":{"type":"string"}}],"responses":{"200":{"description":"Joined"}}}},"/api/orgs/{orgId}/activity":{"get":{"summary":"The administrative record","description":"Who connected, changed or removed what, and when. Newest first, paged by id. Owners and admins.","tags":["Organisations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"before","in":"query","required":false,"description":"Page: entries with an id below this","schema":{"type":"string","description":"Page: entries with an id below this"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"action","in":"query","required":false,"description":"Prefix filter, e.g. integration or api_key","schema":{"type":"string","description":"Prefix filter, e.g. integration or api_key"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"at":{"type":"string","format":"date-time"},"action":{"type":"string"},"actor":{"type":"object","properties":{"email":{"type":"string"},"name":{"type":["string","null"]}}},"detail":{"type":"object","properties":{}},"ip":{"type":["string","null"]}}}},"nextBefore":{"type":["string","null"]}}}}}},"403":{"description":"Members can't read it"}}}},"/api/orgs/{orgId}/api-keys":{"get":{"summary":"List API keys","tags":["API keys"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdBy":{"type":"string","description":"Email of the admin it acts as"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true}}}}}}}}},"post":{"summary":"Create an API key","description":"Owners and admins, never another key. The plaintext token is returned once. The key acts as its creator on this organisation only, and stops working if the creator loses their admin role.","tags":["API keys"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":80}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdBy":{"type":"string","description":"Email of the admin it acts as"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"token":{"type":"string","description":"avk_... shown once"}}}}}}}}},"/api/orgs/{orgId}/api-keys/{id}":{"delete":{"summary":"Revoke an API key","tags":["API keys"],"security":[{"sessionCookie":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Key id","schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdBy":{"type":"string","description":"Email of the admin it acts as"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true}}}}}}}}},"/api/connector-identity":{"get":{"summary":"Avertari's public key for private_key_jwt (Okta)","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"pem":{"type":"string"},"kid":{"type":"string"}}}}}}}}},"/.well-known/avertari-jwks.json":{"get":{"summary":"The same key as a JWKS","tags":["Integrations"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"type":"object","properties":{"kty":{"type":"string"},"kid":{"type":"string"},"use":{"type":"string"},"alg":{"type":"string"},"n":{"type":"string"},"e":{"type":"string"}}}}}}}}}}}},"/api/providers":{"get":{"summary":"The integration catalogue","description":"Every system Avertari connects to: what to enter, the credential, the setup guide.","tags":["Integrations"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"kind":{"type":"string"},"auth":{"type":"string"},"settings":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"placeholder":{"type":"string"},"help":{"type":"string"}}}},"credential":{"type":"object","properties":{"label":{"type":"string"},"help":{"type":"string"},"multiline":{"type":"boolean"},"optional":{"type":"boolean"}}},"setup":{"type":"string"},"guide":{"type":"object","properties":{}},"available":{"type":"boolean"}}}}}}}}}},"/api/orgs/{orgId}/integrations":{"get":{"summary":"Connected systems","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","description":"Catalogue id, e.g. okta, google_workspace, csv_upload"},"kind":{"type":"string","enum":["hris","idp","privilege","comms"]},"displayName":{"type":"string"},"authMethod":{"type":"string","enum":["oauth_consent","api_key","none"]},"status":{"type":"string","enum":["pending","healthy","error","disabled"]},"settings":{"type":"object","properties":{}},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"lastError":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}}}}}}}},"post":{"summary":"Connect a system","description":"Owners and admins. settings are the provider's fields from the catalogue; credential is the provider's secret (omit it for Google Workspace to use Avertari's own identity). Providers that receive events (okta, log_push) return a hook URL and a one-time secret.","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"provider":{"type":"string","description":"Catalogue id"},"displayName":{"type":"string"},"settings":{"type":"object","properties":{}},"credential":{"type":"string"}},"required":["provider"]}}}},"responses":{"201":{"description":"Connected","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","description":"Catalogue id, e.g. okta, google_workspace, csv_upload"},"kind":{"type":"string","enum":["hris","idp","privilege","comms"]},"displayName":{"type":"string"},"authMethod":{"type":"string","enum":["oauth_consent","api_key","none"]},"status":{"type":"string","enum":["pending","healthy","error","disabled"]},"settings":{"type":"object","properties":{}},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"lastError":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"},"hook":{"type":"object","properties":{"url":{"type":"string"},"secret":{"type":"string","description":"Shown once"}}}}}}}},"400":{"description":"Missing setting or credential","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]}}}}}}},"/api/orgs/{orgId}/integrations/{id}":{"patch":{"summary":"Change mapping, lifecycle or connection settings","description":"mapping: your field -> their column/attribute (validated against the organisation's schema). lifecycle: whether this source opens journeys. settings: correct the org URL, client ID, host... in place; the row goes back to pending and its manual-sync limit resets.","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mapping":{"type":"object","properties":{}},"dateFormat":{"type":"string","enum":["auto","dmy","mdy"]},"lifecycle":{"type":"boolean"},"settings":{"type":"object","properties":{}}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"provider":{"type":"string","description":"Catalogue id, e.g. okta, google_workspace, csv_upload"},"kind":{"type":"string","enum":["hris","idp","privilege","comms"]},"displayName":{"type":"string"},"authMethod":{"type":"string","enum":["oauth_consent","api_key","none"]},"status":{"type":"string","enum":["pending","healthy","error","disabled"]},"settings":{"type":"object","properties":{}},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"lastError":{"type":["string","null"]},"createdAt":{"type":"string","format":"date-time"}}}}}}}},"delete":{"summary":"Disconnect a system","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"responses":{"200":{"description":"Disconnected"}}}},"/api/orgs/{orgId}/integrations/{id}/preview":{"post":{"summary":"Preview how a CSV's columns map","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"text/csv":{"schema":{"type":"string","description":"The file, or its first rows"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"headers":{"type":"array","items":{"type":"string"}},"sample":{"type":"array","items":{"type":"array","items":{"type":"string"}}},"rows":{"type":"number"},"mapping":{"type":"object","properties":{}}}}}}}}}},"/api/orgs/{orgId}/integrations/{id}/import":{"post":{"summary":"Import a CSV (csv_upload integrations)","description":"Rows become joiner/mover/leaver events and people; journeys open as after a sync.","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"text/csv":{"schema":{"type":"string"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"imported":{"type":"number"},"rows":{"type":"number"},"duplicates":{"type":"number"},"skipped":{"type":"number"},"mapping":{"type":"object","properties":{}}}}}}}}}},"/api/orgs/{orgId}/integrations/{id}/sync":{"post":{"summary":"Sync now (or retry after an error)","description":"Six an hour per integration; correcting the connection resets the count. Not for csv_upload or log_push.","tags":["Integrations"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"responses":{"202":{"description":"Queued","content":{"application/json":{"schema":{"type":"object","properties":{"requested":{"type":"boolean"},"queued":{"type":"boolean"}}}}}},"429":{"description":"Limit reached"}}}},"/api/schema/person":{"get":{"summary":"The standard person schema","tags":["Schema"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"group":{"type":"string"},"type":{"type":"string"},"required":{"type":"boolean"},"help":{"type":"string"},"example":{"type":"string"}}}}}}}}}},"/api/orgs/{orgId}/schema":{"get":{"summary":"The organisation's schema: standard fields plus its own","tags":["Schema"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"fields":{"type":"array","items":{"type":"object","properties":{}}},"customFields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"}}}}}}}}}}}},"/api/orgs/{orgId}/schema/fields":{"post":{"summary":"Add a field of your own","description":"Available across every source and report once added.","tags":["Schema"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string"},"key":{"type":"string","description":"Optional; derived from the label"}},"required":["label"]}}}},"responses":{"201":{"description":"Added"}}}},"/api/orgs/{orgId}/schema/fields/{key}":{"delete":{"summary":"Remove one of your own fields","tags":["Schema"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"key","in":"path","required":true,"description":"Field key","schema":{"type":"string"}}],"responses":{"200":{"description":"Removed"}}}},"/api/csv-templates":{"get":{"summary":"Example CSVs","tags":["Schema"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"columns":{"type":"array","items":{"type":"string"}},"url":{"type":"string"}}}}}}}}}},"/api/csv-templates/{name}":{"get":{"summary":"Download an example CSV","tags":["Schema"],"security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"joiners.csv, leavers.csv or workforce.csv","schema":{"type":"string"}}],"responses":{"200":{"description":"text/csv"}}}},"/api/orgs/{orgId}/reports/workforce":{"get":{"summary":"Workforce: headcount, joiners, leavers, attrition by a dimension","description":"One head per person across sources (the HR record wins). Headcount is as of today; joiners and leavers by start and end date; attrition annualised.","tags":["Reports"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"by","in":"query","required":false,"description":"Dimension key: department, division, location, country, cost_centre, or one of your own","schema":{"type":"string","default":"department","description":"Dimension key: department, division, location, country, cost_centre, or one of your own"}},{"name":"months","in":"query","required":false,"description":"Window in months, ending today","schema":{"type":"integer","minimum":1,"maximum":36,"default":12,"description":"Window in months, ending today"}},{"name":"employmentType","in":"query","required":false,"schema":{"type":"string","enum":["employee","contractor","intern","agency","partner","unknown"]}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"by":{"type":"string"},"months":{"type":"number"},"total":{"type":"object","properties":{"headcount":{"type":"number"},"joiners":{"type":"number"},"leavers":{"type":"number"},"voluntary":{"type":"number"},"involuntary":{"type":"number"},"attritionPct":{"type":["number","null"]}}},"groups":{"type":"array","items":{"type":"object","properties":{"group":{"type":["string","null"]},"headcount":{"type":"number"},"joiners":{"type":"number"},"leavers":{"type":"number"},"attritionPct":{"type":["number","null"]},"byType":{"type":"object","properties":{}}}}},"trend":{"type":"array","items":{"type":"object","properties":{"month":{"type":"string","description":"YYYY-MM"},"headcount":{"type":"number"},"joiners":{"type":"number"},"leavers":{"type":"number"}}}},"dimensions":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"people":{"type":"number"}}}},"employmentTypes":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string"},"headcount":{"type":"number"}}}}}}}}}}}},"/api/orgs/{orgId}/reports/workforce/people":{"get":{"summary":"The people behind one number","tags":["Reports"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"by","in":"query","required":false,"schema":{"type":"string","default":"department"}},{"name":"months","in":"query","required":false,"description":"Window in months, ending today","schema":{"type":"integer","minimum":1,"maximum":36,"default":12,"description":"Window in months, ending today"}},{"name":"employmentType","in":"query","required":false,"schema":{"type":"string","enum":["employee","contractor","intern","agency","partner","unknown"]}},{"name":"kind","in":"query","required":false,"description":"Which number","schema":{"type":"string","enum":["headcount","joiners","leavers"],"description":"Which number"}},{"name":"group","in":"query","required":false,"description":"One group; empty string = people without that dimension","schema":{"type":"string","description":"One group; empty string = people without that dimension"}},{"name":"month","in":"query","required":false,"description":"YYYY-MM: joiners/leavers in that month","schema":{"type":"string","description":"YYYY-MM: joiners/leavers in that month"}},{"name":"day","in":"query","required":false,"description":"YYYY-MM-DD: on that day (wins over month)","schema":{"type":"string","description":"YYYY-MM-DD: on that day (wins over month)"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"kind":{"type":"string"},"by":{"type":"string"},"group":{"type":["string","null"]},"month":{"type":["string","null"]},"day":{"type":["string","null"]},"people":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"displayName":{"type":["string","null"]},"email":{"type":["string","null"]},"employmentType":{"type":"string"},"title":{"type":["string","null"]},"manager":{"type":["string","null"]},"startDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"endDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"leaveType":{"type":["string","null"]},"gardenLeaveFrom":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"immediateTermination":{"type":"boolean"},"doNotContact":{"type":"boolean"},"dimensions":{"type":"object","properties":{}},"source":{"type":"string","description":"The integration this row came from"},"provider":{"type":"string"},"openJourneys":{"type":"number"}}}}}}}}}}}},"/api/orgs/{orgId}/reports/workforce/days":{"get":{"summary":"One month as a calendar of joiners and leavers per day","tags":["Reports"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"by","in":"query","required":false,"schema":{"type":"string","default":"department"}},{"name":"month","in":"query","required":false,"description":"YYYY-MM","schema":{"type":"string","description":"YYYY-MM"}},{"name":"employmentType","in":"query","required":false,"schema":{"type":"string","enum":["employee","contractor","intern","agency","partner","unknown"]}},{"name":"group","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"month":{"type":"string"},"days":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string","format":"date","description":"YYYY-MM-DD"},"joiners":{"type":"number"},"leavers":{"type":"number"},"future":{"type":"boolean"}}}}}}}}}}}},"/api/orgs/{orgId}/reports/access-timing":{"get":{"summary":"Where the systems disagree with HR's dates","description":"active_after_leave, deactivated_late, active_before_start, no_account_by_start, plus unknownToHr: live accounts no HR source can explain.","tags":["Reports"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"months","in":"query","required":false,"description":"Window in months, ending today","schema":{"type":"integer","minimum":1,"maximum":36,"default":12,"description":"Window in months, ending today"}},{"name":"earlyDays","in":"query","required":false,"description":"How many days before the start date an account may be created without being flagged","schema":{"type":"integer","minimum":0,"maximum":90,"default":3,"description":"How many days before the start date an account may be created without being flagged"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"months":{"type":"number"},"earlyDays":{"type":"number"},"hrConnected":{"type":"boolean"},"summary":{"type":"object","properties":{"activeAfterLeave":{"type":"number"},"deactivatedLate":{"type":"number"},"activeBeforeStart":{"type":"number"},"noAccountByStart":{"type":"number"},"unknownToHr":{"type":"number"}}},"findings":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["active_after_leave","deactivated_late","active_before_start","no_account_by_start"]},"personId":{"type":"string","format":"uuid"},"displayName":{"type":["string","null"]},"email":{"type":["string","null"]},"employmentType":{"type":"string"},"department":{"type":["string","null"]},"startDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"endDate":{"type":"string","format":"date","description":"YYYY-MM-DD","nullable":true},"source":{"type":"string"},"system":{"type":["string","null"]},"provider":{"type":["string","null"]},"accountStatus":{"type":["string","null"]},"accountCreatedAt":{"type":["string","null"]},"days":{"type":["number","null"]}}}},"unknownToHr":{"type":"array","items":{"type":"object","properties":{"system":{"type":"string"},"provider":{"type":"string"},"kind":{"type":"string"},"email":{"type":"string"},"externalAccountId":{"type":"string"},"accountCreatedAt":{"type":["string","null"]},"lastLoginAt":{"type":["string","null"]},"privileged":{"type":"number"},"flags":{"type":"array","items":{"type":"string"}}}}}}}}}}}}},"/api/hooks/okta/{orgId}/{id}":{"get":{"summary":"Okta event-hook verification","description":"Answers Okta's one-time challenge (X-Okta-Verification-Challenge).","tags":["Hooks"],"security":[{"hookSecret":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"responses":{"200":{"description":"verification echoed"}}},"post":{"summary":"Okta event hook: user.lifecycle events","description":"Authorization header = the secret issued on connect. Answers 204 within Okta's three seconds; events become journeys.","tags":["Hooks"],"security":[{"hookSecret":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{}}}}}}}}}},"responses":{"204":{"description":"Accepted"},"401":{"description":"Hook not recognised"}}}},"/api/hooks/log_push/{orgId}/{id}":{"post":{"summary":"Push identity logs to Avertari","description":"Bearer <secret> or ?token=<secret>. JSON, JSON lines or gzip; Pub/Sub push, Cloud Logging, EventBridge and Azure Monitor envelopes unwrapped. Okta System Log, Entra directory audits and Google Workspace admin activity are recognised; the rest is counted and dropped.","tags":["Hooks"],"security":[{"hookSecret":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Integration id","schema":{"type":"string"}},{"name":"token","in":"query","required":false,"description":"The secret, for senders that can't set headers","schema":{"type":"string","description":"The secret, for senders that can't set headers"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"string","description":"Records"}},"application/x-ndjson":{"schema":{"type":"string","description":"Records"}},"text/plain":{"schema":{"type":"string","description":"Records"}},"application/gzip":{"schema":{"type":"string","description":"Records"}}}},"responses":{"202":{"description":"Accepted","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"number"},"events":{"type":"number"},"recognised":{"type":"object","properties":{"okta":{"type":"number"},"entra":{"type":"number"},"workspace":{"type":"number"}}},"unknown":{"type":"number"}}}}}},"401":{"description":"Hook not recognised"}}}},"/api/orgs/{orgId}/overview":{"get":{"summary":"Dashboard tiles","tags":["Journeys"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"last30Days":{"type":"object","properties":{"joiners":{"type":"number"},"movers":{"type":"number"},"leavers":{"type":"number"}}},"needsAttention":{"type":"object","properties":{}},"integrations":{"type":"object","properties":{}}}}}}}}}},"/api/orgs/{orgId}/journeys":{"get":{"summary":"Journeys: every joiner, mover and leaver","tags":["Journeys"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["open","in_progress","complete","overdue","dismissed"]}},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["joiner","mover","leaver"]}},{"name":"email","in":"query","required":false,"description":"One person's journeys","schema":{"type":"string","description":"One person's journeys"}}],"responses":{"200":{"description":"OK, newest and most urgent first, up to 200","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["joiner","mover","leaver"]},"email":{"type":["string","null"]},"displayName":{"type":["string","null"]},"effectiveAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["open","in_progress","complete","overdue","dismissed"]},"openSteps":{"type":"number"},"overPrivileged":{"type":"number"},"timeToRevokeSeconds":{"type":["number","null"]},"accounts":{"type":"number"},"activeAccounts":{"type":"number"},"offboardingPct":{"type":["number","null"]},"urgent":{"type":"boolean"},"employmentType":{"type":["string","null"]},"dimensions":{"type":"object","properties":{}},"doNotContact":{"type":"boolean"}}}}}}}}}},"/api/orgs/{orgId}/journeys/{id}":{"get":{"summary":"One journey: accounts across systems, forecast, steps","tags":["Journeys"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Journey id","schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["joiner","mover","leaver"]},"email":{"type":["string","null"]},"displayName":{"type":["string","null"]},"effectiveAt":{"type":"string","format":"date-time"},"status":{"type":"string"},"urgent":{"type":"boolean"},"hr":{"type":"object","properties":{}},"person":{"type":"object","properties":{}},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"integrationId":{"type":"string"},"integrationName":{"type":"string"},"action":{"type":"string","enum":["suspend","remove","add","review"]},"target":{"type":"string"},"reason":{"type":"string"},"privileged":{"type":"boolean"},"state":{"type":"string","enum":["suggested","approved","done","dismissed"]},"at":{"type":"string","format":"date-time"}}}},"report":{"type":"object","properties":{"computedAt":{"type":"string","format":"date-time"},"actual":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string"},"integrationName":{"type":"string"},"provider":{"type":"string"},"externalAccountId":{"type":"string"},"status":{"type":"string"},"entitlements":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string","enum":["group","role","app","iam_binding","vault"]},"id":{"type":"string"},"name":{"type":"string"},"privileged":{"type":"boolean"},"deprovisions":{"type":"boolean","description":"App assignments from an IdP: the IdP pushes deactivation to the app"}}}},"flags":{"type":"array","items":{"type":"string"}},"capturedAt":{"type":"string","format":"date-time"},"offboarding":{"type":"object","properties":{"pct":{"type":"number","description":"0-100: how likely this account is shut off without anyone doing it by hand"},"level":{"type":"string","enum":["done","likely","partial","unlikely"]},"reason":{"type":"string"}}}}}},"overPrivileged":{"type":"array","items":{"type":"object","properties":{}}},"timeToRevokeSeconds":{"type":["number","null"]},"peerCount":{"type":"number"},"summary":{"type":"object","properties":{"openSteps":{"type":"number"},"activeAccounts":{"type":"number"},"privilegedHeld":{"type":"number"},"offboardingPct":{"type":["number","null"]}}}}},"comms":{"type":"object","properties":{}},"openedAt":{"type":"string","format":"date-time"},"closedAt":{"type":"string","format":"date-time","nullable":true},"viewer":{"type":"object","properties":{"role":{"type":"string","enum":["owner","admin","member"]},"team":{"type":["string","null"],"enum":["hr","it_ops","l_and_d","recruitment",null],"description":"The team the person is on: People services (HR), IT Ops, L&D or Recruitment. Decides their view of a journey; only IT Ops, admins, owners and members with no team decide access steps."},"canAct":{"type":"boolean","description":"Whether the caller may decide the access steps"}}}}}}}}}}},"/api/orgs/{orgId}/journeys/{id}/steps/{stepId}":{"post":{"summary":"Decide a step: approve, done or dismiss","description":"Avertari suggests; a person acts in the system itself and records it here. Decisions survive re-reconciliation.","tags":["Journeys"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Journey id","schema":{"type":"string"}},{"name":"stepId","in":"path","required":true,"description":"Step id","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"state":{"type":"string","enum":["approved","done","dismissed"]}},"required":["state"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"steps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"integrationId":{"type":"string"},"integrationName":{"type":"string"},"action":{"type":"string","enum":["suspend","remove","add","review"]},"target":{"type":"string"},"reason":{"type":"string"},"privileged":{"type":"boolean"},"state":{"type":"string","enum":["suggested","approved","done","dismissed"]},"at":{"type":"string","format":"date-time"}}}}}}}}},"403":{"description":"The caller's team (HR, L&D, Recruitment) reads journeys but doesn't decide access steps"}}}},"/api/orgs/{orgId}/comms/templates":{"get":{"summary":"Lifecycle communication templates and the variables they may use","tags":["Comms"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"variables":{"type":"array","items":{"type":"string"}},"templates":{"type":"array","items":{"type":"object","properties":{}}}}}}}}}},"put":{"summary":"Replace the templates","tags":["Comms"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"parameters":[{"name":"orgId","in":"path","required":true,"description":"The organisation (UUID in the app's URL)","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"templates":{"type":"array","items":{"type":"object","properties":{}}}},"required":["templates"]}}}},"responses":{"200":{"description":"Saved"}}}},"/api/openapi.json":{"get":{"summary":"This document","tags":["Service"],"security":[{"sessionCookie":[]},{"apiKey":[]}],"responses":{"200":{"description":"OpenAPI 3.1"}}}}}}