Developers · Resources

Resources

9 resources, 39 endpoints — every one documented straight from the route code, with a curl example you can copy, paste and run.

Resource

Entities

Legal-entity records (the Alethia entity register). Reads are workspace-scoped passthroughs of the stored documents; mutations run through a dedicated idempotent, revision-fenced command layer rather than the generic CRUD helpers. Restricted entities are hidden from keys without the restricted_records capability.

GET/api/v1/entitiesList entities

Lists the workspace's entities ordered by document id, with cursor paging. Records with restricted: true are filtered out unless the key has the restricted_records capability; stale registryCheck evidence is stripped from each record.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Entity[], nextCursor: string | null }. Each element: The stored entity document: id plus every persisted field (the create/patch fields above, plus server-stamped slug, revision, workspaceId, createdAt, updatedAt and provenance fields). registryCheck (Companies House evidence) is included only while the evidence is current — stale evidence is stripped by stripNonCurrentEntityRegistryCheck.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid pagination cursor.The cursor is malformed or was tampered with.
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/entities" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/entitiesCreate an entity

Creates an entity through the idempotent entity-mutation command. Requires an Idempotency-Key header; replays of the same key + body return the original result with Idempotency-Replayed: true. displayName defaults to legalName; jurisdiction defaults to "Other", entityType to "OTHER", status to "active". Unknown keys and server-owned fields are rejected (422). Emits an entity.created webhook via the durable outbox.

scope: writemodule: tithe

Request headers

Idempotency-Keyrequired
Client-chosen idempotency token, 8–200 chars, no control characters. Missing → 400.

Request body

Strict object (unknown keys rejected). Validated by PublicApiEntityCreateDataSchema.

FieldTypeRequiredDescription
legalNamestringRequiredLegal name, 1–300 chars. The route pre-checks presence and returns 422 with fields.legalName when missing/blank.
displayNamestringOptionalDisplay name, 1–200 chars. Defaults to legalName when omitted or blank.
jurisdictionstringOptionalJurisdiction. Defaults to "Other".Allowed: "UK", "Luxembourg", "Jersey", "Guernsey", "Isle of Man", "Ireland", "Netherlands", "Belgium", "France", "Germany", "Austria", "Switzerland", "Liechtenstein", "Spain", "Portugal", "Italy", "Malta", "Cyprus", "Greece", "Poland", "Czechia", "Slovakia", "Hungary", "Romania", "Bulgaria", "Croatia", "Slovenia", "Estonia", "Latvia", "Lithuania", "Denmark", "Sweden", "Finland", "Norway", "Iceland", "Cayman Islands", "British Virgin Islands", "Bermuda", "Gibraltar", "Mauritius", "Other"
jurisdictionCodestringOptionalStable ISO 3166-1 alpha-2 country scope; required for structured ISO 20275 legal forms.
entityTypestringOptionalEntity type. Defaults to "OTHER".Allowed: "UK_LTD", "UK_PLC", "UK_LLP", "UK_LP", "LU_SCSP", "LU_SCS", "LU_SARL", "LU_SA", "LU_RAIF", "LU_SECURITISATION", "JE_COMPANY", "JE_LP", "JE_UNIT_TRUST", "OTHER"
statusstringOptionalLifecycle status. Defaults to "active".Allowed: "active", "dormant", "in_liquidation", "sold", "dissolved", "proposed", "historic", "advisory", "archived"
legalFormstringOptionalLegal form label (max 160 chars).
legalFormElfCodestringOptionalCountry-scoped four-character ISO 20275 ELF code.
legalFormJurisdictionCodestringOptionalGLEIF accepted legal jurisdiction (country or ISO 3166-2 subdivision) for the ELF identity.
legalFormVariantCodestringOptionalJurisdiction-qualified convenience variant key; never implies cross-country equivalence.
legalFormNameOriginalstringOptionalExact native/source or Custom/Other text (max 3000 chars).
legalFormFamilystringOptionalBroad product behaviour family; unclassified is retained when no reviewed mapping exists.Allowed: "company", "partnership", "cooperative", "association", "foundation", "trust", "fund", "public-law-body", "sole-trader", "branch", "supranational-eu", "other", "unclassified"
legalFormSourcestringOptionalStructured legal-form provenance; product overlays are never represented as raw ISO labels.Allowed: "ISO_20275", "product_overlay", "custom"
legalFormSourceVersionstringOptionalPinned provenance version: ISO 20275 1.6 or the versioned product-overlay mapping.
registrationNumberstringOptionalRegistry number (max 100 chars).
registryTypestringOptionalRegister family/code, distinct from the registration number (max 50 chars).
registryAuthoritystringOptionalRegister court or authority (max 300 chars).
registeredSeatstringOptionalLegal/statutory seat, distinct from postal address (max 300 chars).
headOfficeSiretstringOptionalFrench head-office SIRET; distinct from SIREN and tax reference (max 50 chars).
rneRegistrationstringOptionalFrench RNE registration/evidence reference (max 300 chars).
rcsRegistrationstringOptionalFrench conditional RCS registration/city text (max 300 chars).
apeNafCodestringOptionalFrench APE/NAF activity code (max 50 chars).
eoristringOptionalOptional EORI identifier (max 50 chars).
economicIdentificationNumberstringOptionalOptional German W-IdNr. (max 100 chars).
incorporationDatestringOptionalISO date (YYYY-MM-DD).
registeredOfficeobjectOptionalAddress object: line1 (required), line2, city, county, region, postalCode, optional ISO countryCode, and exact country text (required). Full-object replace.
taxReferencestringOptionalTax reference (max 100 chars).
vatNumberstringOptionalVAT number (max 100 chars).
leistringOptionalLegal Entity Identifier — exactly 20 letters/digits.
yearEndstringOptionalAccounting year end (max 100 chars).
regionstringOptionalRegion label (max 120 chars).
businessPurposestringOptionalBusiness purpose (max 5,000 chars).
agmDatestringOptionalAGM date text (max 200 chars).
fiscalYearEndstringOptionalFiscal year end (max 32 chars).
internationalLocalCounselstringOptionalLocal counsel (max 300 chars).
significantSubsidiarybooleanOptionalSignificant-subsidiary flag.
taxTypestringOptionalTax type label (max 120 chars).
dbaNamesarray<string>OptionalTrading names (max 50, unique case-insensitively).
auditorsstringOptionalAuditors (max 500 chars).
administratorsstringOptionalAdministrators (max 500 chars).
lawyersstringOptionalLawyers (max 500 chars).
registeredAgentstringOptionalRegistered agent (max 500 chars).
serviceProviderIdsarray<string>OptionalPerson/entity ids of service providers (max 100, unique).
colourstringOptionalSix-digit hex colour, e.g. #4A6741.
fundNavobjectOptionalLatest NAV snapshot: { value: number ≥ 0, currency: ISO-4217 code, asOf: ISO date }. Full-object replace.
fatcaCrsobjectOptionalFATCA/CRS classification: fatcaStatus, giin, crsStatus, crsClassification, selfCertifiedAt (ISO date), notes — at least one field. Full-object replace.
tagsarray<string>OptionalTag ids (max 100, unique).
previousNamesarray<object>OptionalPrevious names: { name (required), from?: ISO date, to?: ISO date } (max 100).
customFieldsobjectOptionalWorkspace-defined custom fields: string values (max 2,000 chars), at most 100 keys.
restrictedbooleanOptionalRecord-level ACL flag. Changing it requires the restricted_records capability.
viewerIdsarray<string>OptionalExplicit viewer ids for restricted records (max 500). Changing it requires the restricted_records capability.
notesstringOptionalFree notes (max 10,000 chars).

Response

201The created entity record when the key also has read scope; otherwise only { id, revision? }. The stored entity document: id plus every persisted field (the create/patch fields above, plus server-stamped slug, revision, workspaceId, createdAt, updatedAt and provenance fields). registryCheck (Companies House evidence) is included only while the evidence is current — stale evidence is stripped by stripNonCurrentEntityRegistryCheck.

Headers: Idempotency-Replayed, ETag

Errors (11)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Idempotency-Key header is required.The Idempotency-Key header is absent.
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
409Entity conflict | Entity limit reached. | Idempotency key conflicts with an earlier request.A conflicting entity exists, the free-tier entity cap is reached, or the Idempotency-Key was already used with a different request body.
503Entity mutations are temporarily unavailable.The workspace's entity-mutation mode is transitioning (Retry-After: 5 is set).
503Entity state requires reconciliation.Persisted entity/receipt state failed integrity checks (logged for operators).
503Service unavailableAn unclassified server error occurred.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/entities" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f2d6b7a-9d61-4e3a-8c2a-5e7b1f0a6c9d" \
  -d '{
  "legalName": "example"
}'
GET/api/v1/entities/{entityId}Get an entity

Reads one entity. Restricted entities are indistinguishable from absent ones for keys without restricted_records. The response carries an ETag holding the entity revision, usable in a later PATCH's If-Match.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
entityIdpathstringRequiredEntity document id.

Response

200The stored entity document: id plus every persisted field (the create/patch fields above, plus server-stamped slug, revision, workspaceId, createdAt, updatedAt and provenance fields). registryCheck (Companies House evidence) is included only while the evidence is current — stale evidence is stripped by stripNonCurrentEntityRegistryCheck.

Headers: ETag

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/entities/entity_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/entities/{entityId}Update an entity

Optimistically-concurrent profile patch. Requires Idempotency-Key and If-Match (the entity revision, bare or quoted, e.g. "3"). On revision mismatch the route returns 412 with currentRevision in the body and an ETag of the current revision. null clears nullable optional fields. Emits entity.updated via the durable outbox.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
entityIdpathstringRequiredEntity document id.

Request headers

Idempotency-Keyrequired
Client-chosen idempotency token, 8–200 chars. Missing → 400.
If-Matchrequired
Expected entity revision (numeric, optionally quoted). Missing → 428; malformed → 400.

Request body

Strict object (unknown keys rejected); at least one field. Validated by EntityProfilePatchSchema — identity fields are optional but not nullable; profile fields accept null to clear.

FieldTypeRequiredDescription
legalNamestringOptionalLegal name, 1–300 chars.
displayNamestringOptionalDisplay name, 1–200 chars.
jurisdictionstringOptionalJurisdiction.Allowed: "UK", "Luxembourg", "Jersey", "Guernsey", "Isle of Man", "Ireland", "Netherlands", "Belgium", "France", "Germany", "Austria", "Switzerland", "Liechtenstein", "Spain", "Portugal", "Italy", "Malta", "Cyprus", "Greece", "Poland", "Czechia", "Slovakia", "Hungary", "Romania", "Bulgaria", "Croatia", "Slovenia", "Estonia", "Latvia", "Lithuania", "Denmark", "Sweden", "Finland", "Norway", "Iceland", "Cayman Islands", "British Virgin Islands", "Bermuda", "Gibraltar", "Mauritius", "Other"
jurisdictionCodestringOptionalStable ISO 3166-1 alpha-2 country scope.
entityTypestringOptionalEntity type.Allowed: "UK_LTD", "UK_PLC", "UK_LLP", "UK_LP", "LU_SCSP", "LU_SCS", "LU_SARL", "LU_SA", "LU_RAIF", "LU_SECURITISATION", "JE_COMPANY", "JE_LP", "JE_UNIT_TRUST", "OTHER"
statusstringOptionalLifecycle status.Allowed: "active", "dormant", "in_liquidation", "sold", "dissolved", "proposed", "historic", "advisory", "archived"
legalFormstring| nullOptionalLegal form label (max 160 chars).
legalFormElfCodestring| nullOptionalCountry-scoped four-character ISO 20275 ELF code.
legalFormJurisdictionCodestring| nullOptionalGLEIF accepted legal jurisdiction (country or ISO 3166-2 subdivision) for the ELF identity.
legalFormVariantCodestring| nullOptionalJurisdiction-qualified convenience variant key; never implies cross-country equivalence.
legalFormNameOriginalstring| nullOptionalExact native/source or Custom/Other text (max 3000 chars).
legalFormFamilystring| nullOptionalBroad product behaviour family; unclassified is retained when no reviewed mapping exists.Allowed: "company", "partnership", "cooperative", "association", "foundation", "trust", "fund", "public-law-body", "sole-trader", "branch", "supranational-eu", "other", "unclassified"
legalFormSourcestring| nullOptionalStructured legal-form provenance; product overlays are never represented as raw ISO labels.Allowed: "ISO_20275", "product_overlay", "custom"
legalFormSourceVersionstring| nullOptionalPinned provenance version: ISO 20275 1.6 or the versioned product-overlay mapping.
registrationNumberstring| nullOptionalRegistry number (max 100 chars).
registryTypestring| nullOptionalRegister family/code, distinct from the registration number (max 50 chars).
registryAuthoritystring| nullOptionalRegister court or authority (max 300 chars).
registeredSeatstring| nullOptionalLegal/statutory seat, distinct from postal address (max 300 chars).
headOfficeSiretstring| nullOptionalFrench head-office SIRET; distinct from SIREN and tax reference (max 50 chars).
rneRegistrationstring| nullOptionalFrench RNE registration/evidence reference (max 300 chars).
rcsRegistrationstring| nullOptionalFrench conditional RCS registration/city text (max 300 chars).
apeNafCodestring| nullOptionalFrench APE/NAF activity code (max 50 chars).
eoristring| nullOptionalOptional EORI identifier (max 50 chars).
economicIdentificationNumberstring| nullOptionalOptional German W-IdNr. (max 100 chars).
incorporationDatestring| nullOptionalISO date (YYYY-MM-DD).
registeredOfficeobject| nullOptionalAddress object: line1 (required), line2, city, county, region, postalCode, optional ISO countryCode, and exact country text (required). Full-object replace.
taxReferencestring| nullOptionalTax reference (max 100 chars).
vatNumberstring| nullOptionalVAT number (max 100 chars).
leistring| nullOptionalLegal Entity Identifier — exactly 20 letters/digits.
yearEndstring| nullOptionalAccounting year end (max 100 chars).
regionstring| nullOptionalRegion label (max 120 chars).
businessPurposestring| nullOptionalBusiness purpose (max 5,000 chars).
agmDatestring| nullOptionalAGM date text (max 200 chars).
fiscalYearEndstring| nullOptionalFiscal year end (max 32 chars).
internationalLocalCounselstring| nullOptionalLocal counsel (max 300 chars).
significantSubsidiaryboolean| nullOptionalSignificant-subsidiary flag.
taxTypestring| nullOptionalTax type label (max 120 chars).
dbaNamesarray<string>| nullOptionalTrading names (max 50, unique case-insensitively).
auditorsstring| nullOptionalAuditors (max 500 chars).
administratorsstring| nullOptionalAdministrators (max 500 chars).
lawyersstring| nullOptionalLawyers (max 500 chars).
registeredAgentstring| nullOptionalRegistered agent (max 500 chars).
serviceProviderIdsarray<string>| nullOptionalPerson/entity ids of service providers (max 100, unique).
colourstring| nullOptionalSix-digit hex colour, e.g. #4A6741.
fundNavobject| nullOptionalLatest NAV snapshot: { value: number ≥ 0, currency: ISO-4217 code, asOf: ISO date }. Full-object replace.
fatcaCrsobject| nullOptionalFATCA/CRS classification: fatcaStatus, giin, crsStatus, crsClassification, selfCertifiedAt (ISO date), notes — at least one field. Full-object replace.
tagsarray<string>OptionalTag ids (max 100, unique).
previousNamesarray<object>| nullOptionalPrevious names: { name (required), from?: ISO date, to?: ISO date } (max 100).
customFieldsobject| nullOptionalWorkspace-defined custom fields: string values (max 2,000 chars), at most 100 keys.
restrictedbooleanOptionalRecord-level ACL flag. Changing it requires the restricted_records capability.
viewerIdsarray<string>OptionalExplicit viewer ids for restricted records (max 500). Changing it requires the restricted_records capability.
notesstring| nullOptionalFree notes (max 10,000 chars).

Response

200The updated entity record when the key also has read scope; otherwise only { id, revision? }. The stored entity document: id plus every persisted field (the create/patch fields above, plus server-stamped slug, revision, workspaceId, createdAt, updatedAt and provenance fields). registryCheck (Companies House evidence) is included only while the evidence is current — stale evidence is stripped by stripNonCurrentEntityRegistryCheck.

Headers: Idempotency-Replayed, ETag

Errors (14)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Idempotency-Key header is required. | If-Match must contain one numeric entity revision.The Idempotency-Key header is absent, or If-Match is present but not a single non-negative integer.
428If-Match header is required.The If-Match header is absent.
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
412Entity revision does not match.If-Match does not equal the stored revision. Body carries currentRevision; ETag header carries the current revision.
409Entity conflict | Entity limit reached. | Idempotency key conflicts with an earlier request.A conflicting entity exists, the free-tier entity cap is reached, or the Idempotency-Key was already used with a different request body.
503Entity mutations are temporarily unavailable.The workspace's entity-mutation mode is transitioning (Retry-After: 5 is set).
503Entity state requires reconciliation.Persisted entity/receipt state failed integrity checks (logged for operators).
503Service unavailableAn unclassified server error occurred.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/entities/entity_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f2d6b7a-9d61-4e3a-8c2a-5e7b1f0a6c9d" \
  -H "If-Match: 3" \
  -d '{
  "legalName": "example"
}'
DELETE/api/v1/entities/{entityId}Delete an entity (approved deletions only)

Executes a previously APPROVED four-eyes deletion request. A valid entityDeletionRequests record (requested and approved in-app by two different members) must exist for the entity; without one — or when the entity is restricted and the key lacks restricted_records — the route returns 404. On success the entity and its references are removed and entity.deleted is emitted via the durable outbox.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
entityIdpathstringRequiredEntity document id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundThe entity does not exist, has no approved deletion request, or is a restricted record the key cannot access.
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/entities/entity_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

People

Directory of individuals and corporate contacts. PII fields (email, phone, nationality, countryOfResidence, residentialAddress) are ALWAYS masked in responses and REJECTED in request bodies — API keys carry no PII capability.

GET/api/v1/peopleList people

Lists people with cursor paging. Every record is passed through maskPerson, blanking the five PII fields.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Person[], nextCursor: string | null }. Each element: id, fullName, type, firstName, lastName, companyId, title, isServiceProvider, status, tags, piiSeparated, workspaceId, createdAt, updatedAt, provenance fields — PII fields removed.

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/people" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/peopleCreate a person

Creates a person. Any supplied PII field is rejected with 422 ("PII is not accepted by this API key"). type defaults to "individual"; the server stamps piiSeparated: true. Fires the person.created webhook.

scope: writemodule: tithe

Request body

Strict object validated by PublicApiPersonCreateSchema.

FieldTypeRequiredDescription
fullNamestringRequiredFull name, 1–300 chars.
typestringOptionalDefaults to "individual".Allowed: "individual", "corporate"
firstNamestringOptionalMax 150 chars.
lastNamestringOptionalMax 150 chars.
companyIdstringOptionalLinked company (entity/person) id.
titlestringOptionalJob title, max 150 chars.
isServiceProviderbooleanOptionalMarks the person as a service provider.
statusstringOptionalDirectory status.Allowed: "active", "archived"
tagsarray<string>OptionalTag ids (max 100, unique).

Response

201The created person record (id, submitted fields, piiSeparated: true, workspaceId, createdAt, updatedAt, createdVia: "api").

Errors (8)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/people" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "fullName": "example"
}'
GET/api/v1/people/{personId}Get a person

Reads one person, PII masked.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
personIdpathstringRequiredPerson document id.

Response

200The person record with PII fields removed.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/people/person_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/people/{personId}Update a person

Merge-patches a person. PII fields are rejected with 422. Nullable fields (firstName, lastName, companyId, title) accept null to clear. Fires person.updated.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
personIdpathstringRequiredPerson document id.

Request body

Strict object, at least one field (PublicApiPersonPatchSchema).

FieldTypeRequiredDescription
fullNamestringOptionalFull name, 1–300 chars.
typestringOptionalPerson type.Allowed: "individual", "corporate"
firstNamestring| nullOptionalMax 150 chars; null clears.
lastNamestring| nullOptionalMax 150 chars; null clears.
companyIdstring| nullOptionalLinked company id; null clears.
titlestring| nullOptionalMax 150 chars; null clears.
isServiceProviderbooleanOptionalService-provider flag.
statusstringOptionalDirectory status.Allowed: "active", "archived"
tagsarray<string>OptionalTag ids (max 100, unique).

Response

200The merged person record, PII masked.

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/people/person_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "fullName": "example"
}'
DELETE/api/v1/people/{personId}Delete a person

Deletes a person. Fires person.deleted.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
personIdpathstringRequiredPerson document id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/people/person_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Deals

Acquisition-pipeline deals (the Pipeline/Socage module). Workflow fields — stage, locked, icSubmission, acquiringEntityId, parentHoldcoId, activity, foundationDesignId — are service-layer-owned: rejected as unknown keys on CREATE and silently stripped on PATCH, so stage transitions and IC state can only change through the app.

GET/api/v1/dealsList deals

Lists deals with cursor paging.

scope: readmodule: socage

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Deal[], nextCursor: string | null }. Each element: The stored deal document: id plus the fields above, stage, activity (audit trail; the create route stamps an initial 'Deal added to the pipeline' entry), defaulted parties/tags arrays and GBP currency, any workflow fields set by the service layer (locked, icSubmission, acquiringEntityId, parentHoldcoId, reference, foundationDesignId), workspaceId and audit stamps (createdAt, updatedAt, createdVia: "api").

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/deals" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/dealsCreate a deal

Creates a deal. nation must be England, Wales or Scotland. stage (optional, default "identified") is validated against the workspace's RESOLVED pipeline — canonical plus custom stage ids. Domain defaults (parties/activity/tags arrays, GBP) and an initial activity entry are applied server-side. Fires deal.created.

scope: writemodule: socage

Request body

Strict object validated by PublicApiDealCreateSchema. Server-owned workflow fields (reference, locked, icSubmission, acquiringEntityId, parentHoldcoId, activity, foundationDesignId) are rejected as unknown keys.

FieldTypeRequiredDescription
namestringRequiredDeal name, 1–300 chars.
nationstringRequiredUK nation. Any other value → 422.Allowed: "England", "Wales", "Scotland"
stagestringOptionalPipeline stage id, validated against the workspace's resolved stages (canonical + custom). Defaults to "identified".
slugstringOptionalURL slug (max 200 chars).
siteAddressobjectOptionalAddress: line1 (required), line2, city, county, region, postalCode, country (required).
assetClassstringOptionalAsset-class id from the workspace's ASSET_CLASS_LABELS set.
investmentTypestringOptionalInvestment-type id from INVESTMENT_TYPE_LABELS.
proposedEntityNamestringOptionalProposed acquiring-entity name (max 300 chars).
proposedEntityJurisdictionstringOptionalProposed entity jurisdiction (max 100 chars).
pricenumberOptionalPrice ≥ 0.
currencystringOptionalCurrency code (max 10 chars). Defaults to GBP on create.
siteSizeobjectOptional{ value: number ≥ 0, unit: sqm | sqft | acre }.
depositobjectOptional{ kind: percent | amount, value: number ≥ 0 }.
purchaseConditionsarray<object>OptionalArray (max 300) of { id, label, met: boolean }.
targetsarray<object>OptionalArray (max 300) of milestones { id, label, kind: stage | custom, stage?, targetDate?, actualDate? (ISO dates) }.
partiesarray<object>OptionalArray (max 300) of { role (deal-party role id), name, companyId?, companyName?, personId?, entityId?, contact? }.
keyDatesobjectOptional{ hotSigned?, exclusivityEnds?, targetExchange?, exchanged?, targetCompletion?, completed?, planningDecisionExpectedDate? } — all ISO dates.
appraisalobjectOptional{ gdv?: number ≥ 0, totalCost?: number ≥ 0 }.
appraisalScenariosarray<object>OptionalArray (max 50) of { name, gdv?, totalCost?, holdingYears? }.
sourcestringOptionalDeal source (max 300 chars).
regionMarketstringOptionalRegion/market label (max 200 chars).
askingPricenumberOptionalAsking price ≥ 0.
agreedPricenumberOptionalAgreed price ≥ 0.
headlineMetricTypestringOptionalHeadline metric type (max 100 chars).
headlineMetricValuestringOptionalHeadline metric value (max 100 chars).
unitCountnumberOptionalUnit count ≥ 0.
businessPlanSummarystringOptionalBusiness-plan summary (max 5,000 chars).
keyRiskstringOptionalKey risk (max 2,000 chars).
nextActionTextstringOptionalNext action (max 500 chars).
nextActionDueDatestringOptionalISO date.
hotsStatusstringOptionalHoTs status id from HOTS_STATUS.
planningStatusstringOptionalPlanning status id from PLANNING_STATUS.
currentPlanningStatusstringOptionalCurrent planning status id from CURRENT_PLANNING_STATUS_LABELS.
creditTermsobjectOptional{ borrowerSponsor?, facilityType?, loanAmount?, ltv?, marginCoupon?, termMaturity?, seniority?, securityCollateral?, covenantSummary? }.
abortReasonstringOptionalAbort reason (max 1,000 chars).
ddStatusstringOptionalDue-diligence status id from DD_STATUS.
legalStatusstringOptionalLegal status id from LEGAL_STATUS.
prioritystringOptionalPriority id from DEAL_PRIORITY.
customFieldsobjectOptionalWorkspace-defined custom fields: string | number | boolean | null values, at most 100 keys.
dueDiligencearray<object>OptionalArray (max 300) of { id, label, done: boolean, category? }.
tasksarray<object>OptionalArray (max 300) of { id, title, dueDate? (ISO date), done: boolean }.
projectIdstringOptionalLinked project id.
tagsarray<string>OptionalTag ids (max 100, unique).
colourstringOptionalSix-digit hex colour.
notesstringOptionalFree notes (max 10,000 chars).

Response

201The stored deal document: id plus the fields above, stage, activity (audit trail; the create route stamps an initial 'Deal added to the pipeline' entry), defaulted parties/tags arrays and GBP currency, any workflow fields set by the service layer (locked, icSubmission, acquiringEntityId, parentHoldcoId, reference, foundationDesignId), workspaceId and audit stamps (createdAt, updatedAt, createdVia: "api").

Errors (8)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/deals" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example",
  "nation": "England"
}'
GET/api/v1/deals/{dealId}Get a deal

Reads one deal (raw stored document).

scope: readmodule: socage

Parameters

ParameterInTypeRequiredDescription
dealIdpathstringRequiredDeal document id.

Response

200The stored deal document: id plus the fields above, stage, activity (audit trail; the create route stamps an initial 'Deal added to the pipeline' entry), defaulted parties/tags arrays and GBP currency, any workflow fields set by the service layer (locked, icSubmission, acquiringEntityId, parentHoldcoId, reference, foundationDesignId), workspaceId and audit stamps (createdAt, updatedAt, createdVia: "api").

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/deals/deal_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/deals/{dealId}Update a deal

Merge-patches a deal. Accepts everything CREATE does (nullable to clear) plus reference; the workflow fields (stage, locked, icSubmission, acquiringEntityId, parentHoldcoId, activity, foundationDesignId) are ACCEPTED in the body — so read-modify-write round-trips don't 422 — but silently stripped from the write. Fires deal.updated.

scope: writemodule: socage

Parameters

ParameterInTypeRequiredDescription
dealIdpathstringRequiredDeal document id.

Request body

Strict object, at least one field (PublicApiDealPatchSchema).

FieldTypeRequiredDescription
namestringOptionalDeal name, 1–300 chars.
nationstringOptionalBounded string on PATCH (the England/Wales/Scotland value check runs on create only).
referencestring| nullOptionalDeal reference (settable post-create; protected on create).
slugstring| nullOptionalURL slug (max 200 chars).
siteAddressobject| nullOptionalAddress: line1 (required), line2, city, county, region, postalCode, country (required).
assetClassstring| nullOptionalAsset-class id from the workspace's ASSET_CLASS_LABELS set.
investmentTypestring| nullOptionalInvestment-type id from INVESTMENT_TYPE_LABELS.
proposedEntityNamestring| nullOptionalProposed acquiring-entity name (max 300 chars).
proposedEntityJurisdictionstring| nullOptionalProposed entity jurisdiction (max 100 chars).
pricenumber| nullOptionalPrice ≥ 0.
currencystring| nullOptionalCurrency code (max 10 chars). Defaults to GBP on create.
siteSizeobject| nullOptional{ value: number ≥ 0, unit: sqm | sqft | acre }.
depositobject| nullOptional{ kind: percent | amount, value: number ≥ 0 }.
purchaseConditionsarray<object>OptionalArray (max 300) of { id, label, met: boolean }.
targetsarray<object>OptionalArray (max 300) of milestones { id, label, kind: stage | custom, stage?, targetDate?, actualDate? (ISO dates) }.
partiesarray<object>OptionalArray (max 300) of { role (deal-party role id), name, companyId?, companyName?, personId?, entityId?, contact? }.
keyDatesobject| nullOptional{ hotSigned?, exclusivityEnds?, targetExchange?, exchanged?, targetCompletion?, completed?, planningDecisionExpectedDate? } — all ISO dates.
appraisalobject| nullOptional{ gdv?: number ≥ 0, totalCost?: number ≥ 0 }.
appraisalScenariosarray<object>OptionalArray (max 50) of { name, gdv?, totalCost?, holdingYears? }.
sourcestring| nullOptionalDeal source (max 300 chars).
regionMarketstring| nullOptionalRegion/market label (max 200 chars).
askingPricenumber| nullOptionalAsking price ≥ 0.
agreedPricenumber| nullOptionalAgreed price ≥ 0.
headlineMetricTypestring| nullOptionalHeadline metric type (max 100 chars).
headlineMetricValuestring| nullOptionalHeadline metric value (max 100 chars).
unitCountnumber| nullOptionalUnit count ≥ 0.
businessPlanSummarystring| nullOptionalBusiness-plan summary (max 5,000 chars).
keyRiskstring| nullOptionalKey risk (max 2,000 chars).
nextActionTextstring| nullOptionalNext action (max 500 chars).
nextActionDueDatestring| nullOptionalISO date.
hotsStatusstring| nullOptionalHoTs status id from HOTS_STATUS.
planningStatusstring| nullOptionalPlanning status id from PLANNING_STATUS.
currentPlanningStatusstring| nullOptionalCurrent planning status id from CURRENT_PLANNING_STATUS_LABELS.
creditTermsobject| nullOptional{ borrowerSponsor?, facilityType?, loanAmount?, ltv?, marginCoupon?, termMaturity?, seniority?, securityCollateral?, covenantSummary? }.
abortReasonstring| nullOptionalAbort reason (max 1,000 chars).
ddStatusstring| nullOptionalDue-diligence status id from DD_STATUS.
legalStatusstring| nullOptionalLegal status id from LEGAL_STATUS.
prioritystring| nullOptionalPriority id from DEAL_PRIORITY.
customFieldsobjectOptionalWorkspace-defined custom fields: string | number | boolean | null values, at most 100 keys.
dueDiligencearray<object>OptionalArray (max 300) of { id, label, done: boolean, category? }.
tasksarray<object>OptionalArray (max 300) of { id, title, dueDate? (ISO date), done: boolean }.
projectIdstring| nullOptionalLinked project id.
tagsarray<string>OptionalTag ids (max 100, unique).
colourstring| nullOptionalSix-digit hex colour.
notesstring| nullOptionalFree notes (max 10,000 chars).
stageobjectOptionalAccepted but IGNORED (service-layer-owned; silently stripped from the write).
lockedobjectOptionalAccepted but IGNORED (silently stripped).
icSubmissionobjectOptionalAccepted but IGNORED (silently stripped).
acquiringEntityIdobjectOptionalAccepted but IGNORED (silently stripped).
parentHoldcoIdobjectOptionalAccepted but IGNORED (silently stripped).
activityobjectOptionalAccepted but IGNORED (silently stripped).
foundationDesignIdobjectOptionalAccepted but IGNORED (silently stripped).

Response

200The merged deal record.

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/deals/deal_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example"
}'
DELETE/api/v1/deals/{dealId}Delete a deal

Deletes a deal. Fires deal.deleted.

scope: writemodule: socage

Parameters

ParameterInTypeRequiredDescription
dealIdpathstringRequiredDeal document id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/deals/deal_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Documents

Document metadata records. No module gate — documents belong to both persisted application modules (key scope + Enterprise are the authority). The API cannot upload bytes: created documents are metadata/link records and storagePath is always server-set to the empty string. Restricted documents are hidden from keys without restricted_records; setting restricted/viewerIds requires that capability.

GET/api/v1/documentsList documents

Lists documents with cursor paging. Records with restricted: true are filtered out unless the key has restricted_records.

scope: read

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Document[], nextCursor: string | null }. Each element: id, name, category, kind, source, storagePath (always "" for API-created records), externalUrl, contentType, sizeBytes, projectId, entityId, entityIds, agreementId, dealId, tags, archived, restricted, viewerIds, workspaceId, audit stamps — plus any app-written fields on documents created in-app.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid pagination cursor.The cursor is malformed or was tampered with.
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/documents" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/documentsRegister a document (metadata/link only)

Creates a metadata-only document record. category defaults to "other", kind to "uploaded", source to "link"; storagePath is forced to "". Setting restricted/viewerIds without the restricted_records capability → 403. Fires document.created.

scope: write

Request body

Strict object validated by PublicApiDocumentCreateSchema. storagePath, signing, sharePoint, currentVersionId, version, uploadedAt/uploadedBy are server-owned and rejected as unknown keys.

FieldTypeRequiredDescription
namestringRequiredDocument name, 1–300 chars.
categorystringOptionalDefaults to "other".Allowed: "incorporation", "constitutional", "registers", "accounts", "tax", "board_minutes", "resolutions", "agreement", "filings", "kyc", "banking", "other"
kindstringOptionalDefaults to "uploaded".Allowed: "uploaded", "generated"
sourcestringOptionalDefaults to "link". The API cannot upload bytes regardless of this value.Allowed: "upload", "sharepoint", "link"
externalUrlstringOptionalLink target URL (max 2,048 chars).
contentTypestringOptionalMIME type (max 200 chars).
sizeBytesnumberOptionalSize in bytes ≥ 0.
projectIdstringOptionalLinked project id.
entityIdstringOptionalPrimary linked entity id.
entityIdsarray<string>OptionalLinked entity ids (max 200, unique).
agreementIdstringOptionalLinked agreement id.
dealIdstringOptionalLinked deal id.
tagsarray<string>OptionalTag ids (max 100, unique).
archivedbooleanOptionalArchive flag.
restrictedbooleanOptionalRecord-level ACL flag — requires restricted_records.
viewerIdsarray<string>OptionalExplicit viewer ids (max 500) — requires restricted_records.

Response

201The created document record (id, fields above, storagePath: "", workspaceId, audit stamps, createdVia: "api").

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
403Forbidden: The restricted_records capability is required to change record access.restricted or viewerIds supplied without the capability.
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/documents" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example"
}'
GET/api/v1/documents/{docId}Get a document

Reads one document record. Restricted records the key cannot access return 404.

scope: read

Parameters

ParameterInTypeRequiredDescription
docIdpathstringRequiredDocument id.

Response

200The document record.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/documents/doc_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/documents/{docId}Update a document

Merge-patches a document (same fields as create, nullable where clearable). Changing restricted/viewerIds requires restricted_records (403). Fires document.updated.

scope: write

Parameters

ParameterInTypeRequiredDescription
docIdpathstringRequiredDocument id.

Request body

Strict object, at least one field (PublicApiDocumentPatchSchema). Same field set as create; externalUrl, contentType, sizeBytes, projectId, entityId, agreementId, dealId accept null to clear.

FieldTypeRequiredDescription
namestringOptionalDocument name, 1–300 chars.
categorystringOptionalCategory.Allowed: "incorporation", "constitutional", "registers", "accounts", "tax", "board_minutes", "resolutions", "agreement", "filings", "kyc", "banking", "other"
kindstringOptionalKind.Allowed: "uploaded", "generated"
sourcestringOptionalSource.Allowed: "upload", "sharepoint", "link"
externalUrlstring| nullOptionalLink URL; null clears.
contentTypestring| nullOptionalMIME type; null clears.
sizeBytesnumber| nullOptionalSize in bytes; null clears.
projectIdstring| nullOptionalProject id; null clears.
entityIdstring| nullOptionalEntity id; null clears.
entityIdsarray<string>OptionalLinked entity ids (max 200).
agreementIdstring| nullOptionalAgreement id; null clears.
dealIdstring| nullOptionalDeal id; null clears.
tagsarray<string>OptionalTag ids (max 100).
archivedbooleanOptionalArchive flag.
restrictedbooleanOptionalRequires restricted_records.
viewerIdsarray<string>OptionalRequires restricted_records.

Response

200The merged document record.

Errors (10)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
403Forbidden: The restricted_records capability is required to change record access.restricted or viewerIds supplied without the capability.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/documents/doc_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example"
}'
DELETE/api/v1/documents/{docId}Delete a document

Deletes a document record (metadata only). Fires document.deleted.

scope: write

Parameters

ParameterInTypeRequiredDescription
docIdpathstringRequiredDocument id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/documents/doc_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Properties

Real-estate object layer (PropCo/AssetCo holdings). READ-ONLY over the API — the routes export GET only.

GET/api/v1/propertiesList properties

Lists property records with cursor paging. Raw stored documents — the API applies no reshaping.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Property[], nextCursor: string | null }. Each element (Property type): id, workspaceId, name, entityId, titleNumber, tenure, useClass, address, status, acquisitionDate, acquisitionPrice, acquisitionCurrency, valuation, leases, notes, audit stamps.

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/properties" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
GET/api/v1/properties/{propertyId}Get a property

Reads one property record.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
propertyIdpathstringRequiredProperty document id.

Response

200The property record (see list response).

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/properties/property_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Fund commitments

LP capital-account commitments into fund vehicles. READ-ONLY over the API (list only; no single-record route exists).

GET/api/v1/commitmentsList fund commitments

Lists commitment records with cursor paging. Raw stored documents — no reshaping.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: FundCommitment[], nextCursor: string | null }. Each element (FundCommitment type): id, workspaceId, fundEntityId, investorId, investorType (person | entity), amount, currency, commitmentDate, flows (capital calls/distributions), audit stamps.

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/commitments" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Cap table — Share classes

Share classes issued by an entity. entityId is checked to exist in the key's workspace on create and is immutable afterwards (a PATCH attempt is rejected as an unknown key).

GET/api/v1/cap-table/share-classesList share classes

Lists share classes with cursor paging.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: ShareClass[], nextCursor: string | null }. Each element: id plus the create fields below, workspaceId and audit stamps.

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/cap-table/share-classes" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/cap-table/share-classesCreate a share class

Creates a share class. entityId must reference an entity in the key's workspace (422 otherwise). votingRight defaults to "ordinary". Fires shareClass.created.

scope: writemodule: tithe

Request body

Strict object validated by PublicApiShareClassCreateSchema.

FieldTypeRequiredDescription
entityIdstringRequiredIssuing entity id — must exist in this workspace.
namestringRequiredClass name, 1–200 chars.
votingRightstringOptionalDefaults to "ordinary".Allowed: "ordinary", "non_voting", "multiple", "preference"
votesPerSharenumberOptionalVotes per share > 0.
parValuenumberOptionalPar value ≥ 0.
noParValuebooleanOptionalNo-par-value flag.
statedCapitalnumberOptionalStated capital ≥ 0.
currencystringOptionalCurrency code (max 10 chars).
authorisedSharesnumberOptionalAuthorised shares ≥ 0.
rightsobjectOptional{ preferredDividend?, liquidationPreference?, participating?, antiDilution? } — all booleans.
liquidationTermsobjectOptional{ liquidationMultiple? ≥ 0, participationCap? ≥ 0, seniority?: number }.
descriptionstringOptionalMax 2,000 chars.

Response

201The created share-class record.

Errors (8)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/cap-table/share-classes" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "entityId": "entity_123",
  "name": "example"
}'
GET/api/v1/cap-table/share-classes/{id}Get a share class

Reads one share class.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShare-class document id.

Response

200The share-class record.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/cap-table/share-classes/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/cap-table/share-classes/{id}Update a share class

Merge-patches a share class. entityId is immutable (unknown key → 422). Numeric/text/object fields accept null to clear. Fires shareClass.updated.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShare-class document id.

Request body

Strict object, at least one field (PublicApiShareClassPatchSchema).

FieldTypeRequiredDescription
namestringOptionalClass name, 1–200 chars.
votingRightstringOptionalVoting right.Allowed: "ordinary", "non_voting", "multiple", "preference"
votesPerSharenumber| nullOptionalVotes per share > 0; null clears.
parValuenumber| nullOptionalPar value ≥ 0; null clears.
noParValuebooleanOptionalNo-par-value flag.
statedCapitalnumber| nullOptionalStated capital; null clears.
currencystring| nullOptionalCurrency code; null clears.
authorisedSharesnumber| nullOptionalAuthorised shares; null clears.
rightsobject| nullOptionalRights object; null clears.
liquidationTermsobject| nullOptionalLiquidation terms; null clears.
descriptionstring| nullOptionalMax 2,000 chars; null clears.

Response

200The merged share-class record.

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/cap-table/share-classes/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "example"
}'
DELETE/api/v1/cap-table/share-classes/{id}Delete a share class

Deletes a share class. Fires shareClass.deleted.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShare-class document id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/cap-table/share-classes/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Cap table — Shareholdings

Holdings of a share class by an entity or person. entityId and shareClassId are referentially checked on create; entityId, shareClassId, holderId and holderType are immutable afterwards — a share transfer is a NEW shareholding, mirroring the internal transaction ledger.

GET/api/v1/cap-table/shareholdingsList shareholdings

Lists shareholdings with cursor paging.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
limitqueryintegerOptionalPage size. Default 50, maximum 200; non-numeric or non-positive values fall back to the default.
cursorquerystringOptionalOpaque cursor from the previous page's nextCursor. Treat as opaque — for keys without restricted_records it is an encrypted token.

Response

200{ data: Shareholding[], nextCursor: string | null }. Each element: id plus the create fields below, workspaceId and audit stamps.

Errors (5)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/cap-table/shareholdings" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/cap-table/shareholdingsCreate a shareholding

Creates a shareholding. entityId and shareClassId must exist in the key's workspace (422 with per-field messages otherwise). status defaults to "current" so the holding is visible to cap-table builds. Fires shareholding.created.

scope: writemodule: tithe

Request body

Strict object validated by PublicApiShareholdingCreateSchema.

FieldTypeRequiredDescription
entityIdstringRequiredIssuing entity id — must exist in this workspace.
shareClassIdstringRequiredShare-class id — must exist in this workspace.
holderIdstringRequiredHolder id (entity or person document id).
holderTypestringRequiredWhich collection holderId references.Allowed: "entity", "person"
sharesnumberRequiredShare count ≥ 0.
paidUpbooleanOptionalPaid-up flag.
amountUnpaidnumberOptionalUnpaid amount ≥ 0.
encumbrancestringOptionalEncumbrance.Allowed: "none", "pledge", "usufruct"
statusstringOptionalDefaults to "current".Allowed: "current", "historic"

Response

201The created shareholding record.

Errors (8)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/cap-table/shareholdings" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "entityId": "entity_123",
  "shareClassId": "shareclass_123",
  "holderId": "holder_123",
  "holderType": "entity",
  "shares": 1
}'
GET/api/v1/cap-table/shareholdings/{id}Get a shareholding

Reads one shareholding.

scope: readmodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShareholding document id.

Response

200The shareholding record.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/cap-table/shareholdings/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/cap-table/shareholdings/{id}Update a shareholding

Merge-patches a shareholding. entityId/shareClassId/holderId/holderType are immutable (unknown key → 422). Fires shareholding.updated.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShareholding document id.

Request body

Strict object, at least one field (PublicApiShareholdingPatchSchema).

FieldTypeRequiredDescription
sharesnumberOptionalShare count ≥ 0.
paidUpbooleanOptionalPaid-up flag.
amountUnpaidnumber| nullOptionalUnpaid amount; null clears.
encumbrancestring| nullOptionalEncumbrance; null clears.Allowed: "none", "pledge", "usufruct"
statusstringOptionalHolding status.Allowed: "current", "historic"

Response

200The merged shareholding record.

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedThe body is not a plain JSON object, contains unknown keys, or a field fails its schema; a fields map names each offending field.
413Request body too large.The JSON body exceeds 1 MiB (1,048,576 bytes).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/cap-table/shareholdings/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "shares": 1
}'
DELETE/api/v1/cap-table/shareholdings/{id}Delete a shareholding

Deletes a shareholding. Fires shareholding.deleted.

scope: writemodule: tithe

Parameters

ParameterInTypeRequiredDescription
idpathstringRequiredShareholding document id.

Response

200{ deleted: true, id: string }

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/cap-table/shareholdings/id_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Resource

Webhook subscriptions

Manage outbound webhook subscriptions. Every operation requires the manage_webhooks capability on top of the read/write scope; mutations additionally require the workspace's Enterprise webhook entitlement. A workspace may hold at most 25 subscriptions. The signingSecret is returned exactly once, in the POST response.

GET/api/v1/webhooksList webhook subscriptions

Lists all subscriptions (no paging — the collection is capped at 25).

scope: readcapability: manage_webhooks

Response

200{ data: WebhookSubscription[] } (no nextCursor). Each element: { id, url, events, recordAccess (open_only | restricted), enabled, createdAt?, updatedAt?, lastDeliveryAt?, lastDeliveryStatus? (success | failure) } — signingSecret is NEVER included after creation.

Errors (6)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/webhooks" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/webhooksCreate a webhook subscription

Registers an HTTPS endpoint. The URL must be public HTTPS (private/loopback/link-local/metadata hosts, credentials, fragments are rejected — SSRF guard), at most 2,048 chars. recordAccess: "restricted" requires the restricted_records capability. The response is the ONLY time signingSecret (whsec_ + 48 hex chars) is revealed.

scope: writecapability: manage_webhooks

Request body

Strict object — only url, events and recordAccess are allowed.

FieldTypeRequiredDescription
urlstringRequiredPublic HTTPS endpoint, max 2,048 chars, no credentials or fragment.
eventsarray<string>RequiredNon-empty array of subscribable event names (see webhooks.events), no duplicates. "ping" cannot be subscribed.
recordAccessstringOptionalDefaults to "open_only". "restricted" requires the restricted_records capability.Allowed: "open_only", "restricted"

Response

201{ id, url, events, recordAccess, enabled: true, signingSecret (shown ONCE), createdAt }

Errors (10)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
403Outbound webhooks require Enterprise.The workspace billing document is not an active/trialing Enterprise subscription.
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedUnknown keys, bad URL, unknown/duplicate events, or recordAccess: restricted without the capability — fields map names each.
409A workspace may have at most 25 webhook subscriptions.The 25-subscription cap is reached. Body carries limit: 25.
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/webhooks" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://example.com/hooks/alethia",
  "events": [
    "deal.created",
    "deal.updated"
  ]
}'
GET/api/v1/webhooks/{subId}Get a webhook subscription

Reads one subscription (strict public projection — secrets and internal principals never returned).

scope: readcapability: manage_webhooks

Parameters

ParameterInTypeRequiredDescription
subIdpathstringRequiredSubscription id.

Response

200{ id, url, events, recordAccess (open_only | restricted), enabled, createdAt?, updatedAt?, lastDeliveryAt?, lastDeliveryStatus? (success | failure) } — signingSecret is NEVER included after creation.

Errors (7)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl "https://app.alethiahq.com/api/v1/webhooks/sub_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
PATCH/api/v1/webhooks/{subId}Update a webhook subscription

Strictly permits enabled, url, events and recordAccess; anything else → 422. At least one updatable field must be supplied.

scope: writecapability: manage_webhooks

Parameters

ParameterInTypeRequiredDescription
subIdpathstringRequiredSubscription id.

Request body

Strict partial update.

FieldTypeRequiredDescription
enabledbooleanOptionalEnable/disable delivery.
urlstringOptionalNew public HTTPS endpoint (same validation as create).
eventsarray<string>OptionalReplacement event list (same validation as create).
recordAccessstringOptional"restricted" requires the restricted_records capability.Allowed: "open_only", "restricted"

Response

200The updated subscription projection.

Errors (10)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
403Outbound webhooks require Enterprise.The workspace billing document is not an active/trialing Enterprise subscription.
400Invalid JSON body.The request body is not parseable JSON.
422Validation failedUnknown keys, no updatable fields, or a field fails validation.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X PATCH "https://app.alethiahq.com/api/v1/webhooks/sub_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}" \
  -H "Content-Type: application/json" \
  -d '{
  "enabled": true
}'
DELETE/api/v1/webhooks/{subId}Delete a webhook subscription

Removes the subscription. Deleting immediately frees capacity against the 25-subscription cap.

scope: writecapability: manage_webhooks

Parameters

ParameterInTypeRequiredDescription
subIdpathstringRequiredSubscription id.

Response

200{ deleted: true, id: string }

Errors (7)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X DELETE "https://app.alethiahq.com/api/v1/webhooks/sub_123" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"
POST/api/v1/webhooks/{subId}/testSend a test (ping) delivery

Fires a synthetic "ping" event at the subscription's URL, signed with its signingSecret, and reports the outcome. The subscription must be enabled and structurally deliverable. Payload data: { message: "Test delivery from Alethia", subscriptionId }.

scope: writecapability: manage_webhooks

Parameters

ParameterInTypeRequiredDescription
subIdpathstringRequiredSubscription id.

Response

200{ ok: boolean, statusCode: number (0 on network failure), durationMs: number, skipped?: "ssrf" }

Errors (9)
StatusErrorWhen
401UnauthorizedMissing, malformed, unknown, revoked, or expired API key (no detail is leaked about which).
403Forbidden: <reason>The key lacks the required scope, the workspace subscription is not an active Enterprise plan, workspace access is suspended, or the required module is not on the plan.
429Rate limit exceededMore than 1,000 requests in the key's 15-minute window. Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset headers are set.
503The public API is not configured in this environment.The deployment has no API_KEY_PEPPER or Firebase Admin credentials (the feature is dormant).
403Forbidden: manage_webhooks capability requiredThe key does not carry the manage_webhooks capability.
403Outbound webhooks require Enterprise.The workspace billing document is not an active/trialing Enterprise subscription.
404Not foundNo record with this id exists in the key's workspace (restricted records the key cannot access are indistinguishable from absent ones).
409Webhook subscription is not deliverable.The stored subscription fails integrity validation (disabled, malformed URL/events/secret, or wrong workspace).
502Bad GatewayThe datastore read or write failed.

Example request

curl -X POST "https://app.alethiahq.com/api/v1/webhooks/sub_123/test" \
  -H "Authorization: Bearer tk_{workspaceId}_{secret}"

Questions about a specific integration?

Tell us what you're building and we'll walk through the resources and events that fit.