API para desarrolladores
La API /v1 es la misma que usa este portal. Con una clave de API podés consultar una entidad, leer su perfil de riesgo, monitorearla y comprar su informe sin abrir una sesión en el navegador.
Primeros pasos
Instalá el SDK, que se genera desde el contrato OpenAPI y tiene un método por operación con sus parámetros y respuestas tipados. Una respuesta de error lanza AustralApiError con el código estable de la tabla de errores.
import { createAustralClient, AustralApiError } from '@austral/sdk'
const austral = createAustralClient({
baseUrl: 'https://api.austral.example',
apiKey: process.env.AUSTRAL_API_KEY!,
})
const lookup = await austral.createLookup({
body: { identifier: { type: 'cuit', value: '30-11111111-1' } },
})
if (lookup.status === 'ready') {
const entityId = lookup.entity.entityId
const risk = await austral.getEntityRiskProfile({ path: { entityId } })
await austral.createWatch({ body: { entityId } })
await austral.createReport({
header: { 'idempotency-key': crypto.randomUUID() },
body: { entityId },
})
}Autenticación
Cada solicitud lleva la clave en el encabezado Authorization: Bearer <clave>.
Una clave pertenece a un espacio de trabajo, no a una persona: no hace falta enviar el espacio en cada solicitud. Se muestra una sola vez, al crearla; guardala como un secreto.
Una clave sólo puede lo que permiten sus alcances y sus finalidades. Para ampliarlos, se revoca y se crea otra.
Alcances
| entities:read | Leer entidades | Resolver identificadores y leer el perfil de una empresa o una persona. |
|---|---|---|
| risk:read | Leer perfiles de riesgo | Leer el perfil multidimensional y sus evaluaciones por dimensión. |
| history:read | Leer historial | Leer la evolución del score y de la deuda informada, y el registro de lo que se informó sobre una entidad. |
| reports:read | Leer informes | Listar informes emitidos, consultar su estado y descargarlos. |
| reports:write | Generar informes | Pedir la generación de un informe. Consume un crédito. |
| watches:read | Leer monitoreos | Listar las entidades bajo monitoreo. |
| watches:write | Administrar monitoreos | Activar y desactivar el monitoreo de una entidad. |
| monitoring:read | Leer eventos de monitoreo | Leer los eventos de monitoreo, la cartera y las preferencias de aviso. |
| notifications:write | Administrar notificaciones | Cambiar las preferencias de aviso del espacio de trabajo. |
| webhooks:read | Leer webhooks | Listar los endpoints configurados. |
| webhooks:write | Administrar webhooks | Crear, probar, pausar y eliminar endpoints de notificación. |
| usage:read | Leer consumo | Consultar el consumo del espacio contra sus límites. |
| bulk:write | Consultas masivas | Enviar lotes de identificadores en una sola operación. |
Personas humanas y finalidad
Toda consulta, perfil de riesgo, monitoreo o informe sobre una persona humana declara una finalidad. Se valida antes de consultar cualquier fuente y queda registrada en cada divulgación, junto con la clave que la hizo.
Se declara como purposeCode en el cuerpo, o como purpose en la consulta del perfil de riesgo. Una finalidad que la clave no tiene permitida se rechaza con FORBIDDEN. Si la clave tiene exactamente una finalidad, se usa esa.
En una consulta masiva cada persona lleva su propio purposeCode: el lote no tiene una finalidad común, y tampoco se usa la única finalidad de la clave. Una persona sin finalidad, o con una que la clave no tiene permitida, falla sola con FORBIDDEN y errorMessage dice por qué; el resto del lote sigue. Cada persona queda registrada y consume como una consulta individual.
Nunca se consultan personas de forma anónima, ni por nombre.
| self_lookup | Consulta sobre mí mismo | La persona consultada sos vos. No se aplica a consultas sobre terceros. |
|---|---|---|
| rental_applicant_screening | Evaluación de un postulante a alquiler | Evaluás a quien se postuló para alquilar un inmueble, en el marco de esa postulación. |
| customer_credit_risk | Riesgo crediticio de un cliente | Evaluás el riesgo de un cliente propio con quien tenés o vas a tener una relación comercial con financiamiento. |
| supplier_counterparty_check | Verificación de una contraparte o proveedor | Verificás a una contraparte antes de contratar o de operar con ella. |
| financial_onboarding | Alta de un cliente financiero | Incorporás a la persona como cliente de un servicio financiero y aplicás los controles que ese alta requiere. |
| authorized_professional_verification | Verificación profesional autorizada | Actuás en ejercicio de una función profesional que te habilita a verificar los datos de la persona. |
Respuestas asincrónicas
Una consulta responde 200 con el resultado si lo obtiene dentro del presupuesto sincrónico, y 202 con una operación si no. Consultá GET /v1/lookups/{lookupId} cada pollAfterMs milisegundos hasta que deje de estar pending.
Una consulta masiva (POST /v1/bulk-lookups, hasta 100 identificadores de empresas y personas) responde 202 y se completa a medida que responden las fuentes. Leer el lote o sus resultados es lo que actualiza sus ítems.
Un informe se crea en estado generating con un encabezado Idempotency-Key: repetir la solicitud con la misma clave devuelve el mismo informe, sin cobrar otro.
Una fuente desactualizada devuelve los datos que hay con su frescura y encola una actualización; nunca devuelve un resultado vacío en su lugar.
const job = await austral.createBulkLookup({
body: {
items: [
{ identifier: { type: 'cuit', value: '30-11111111-1' }, clientReference: 'proveedor-1' },
{
identifier: { type: 'cuil', value: '20-11111111-1' },
clientReference: 'inquilino-1',
purposeCode: 'rental_applicant_screening',
},
],
},
})
const { items } = await austral.listBulkLookupResults({
path: { bulkLookupId: job.bulkLookupId },
})
for (const item of items) {
if (item.status === 'failed') console.warn(item.clientReference, item.errorCode, item.errorMessage)
}Consumo y límites
GET /v1/usage/current informa el consumo del mes calendario (UTC) contra los límites del plan, y GET /v1/usage/history los meses anteriores. Requieren el alcance usage:read.
Una unidad de consulta es una entidad distinta por mes, no una solicitud: consultar la misma empresa de nuevo en el mes no consume otra. Una consulta pendiente o fallida no consume nada.
Cuando se supera un límite de frecuencia la respuesta es 429 RATE_LIMITED, con details.retryAfterMs; el SDK lo expone como retryAfterSeconds. Las consultas exitosas informan RateLimit-Limit, RateLimit-Remaining y RateLimit-Reset.
Errores
| VALIDATION_ERROR | 400 | La solicitud no es válida; details dice qué campo. |
|---|---|---|
| AUTH_REQUIRED | 401 | Falta la clave, o ya no es válida. |
| FORBIDDEN | 403 | La clave no tiene el alcance o la finalidad necesarios, o el identificador es de otro tipo de sujeto. |
| NOT_FOUND | 404 | No existe, o pertenece a otro espacio de trabajo. |
| CONFLICT | 409 | Choca con el estado actual, como una Idempotency-Key reutilizada con otro cuerpo, o un informe que todavía se está generando. |
| RATE_LIMITED | 429 | Demasiadas solicitudes; esperá lo que indica details.retryAfterMs. |
| ENTITLEMENT_REQUIRED | 402 | El plan no incluye la función, o se alcanzó su límite. |
| SOURCE_UNAVAILABLE | 503 | Una fuente necesaria no respondió; reintentá más tarde. |
| LOOKUP_PENDING | 202 | El resultado todavía no está; consultá la operación. |
| INTERNAL_ERROR | 500 | Falla de la plataforma; el requestId identifica la solicitud. |
| FEATURE_UNAVAILABLE | 503 | Esta instalación funciona sin un servicio que la función necesita, como el almacenamiento de informes; reintentar no cambia la respuesta. |
Referencia
Cada operación del contrato, agrupada por área. El nombre entre paréntesis es el método del SDK.
lookups
Identifier lookups for legal entities.
POST /v1/lookups (createLookup)
Look up a legal entity by exact identifier.
Returns 200 with the result when it can be produced inside the configured synchronous budget, and 202 with a lookup operation otherwise. A stale source returns the existing data with freshness metadata and enqueues a refresh; it never returns an empty result.
GET /v1/lookups/{lookupId} (getLookup)
Poll a lookup operation.
GET /v1/entities/{entityId} (getEntity)
Canonical entity profile.
persons
Protected natural-person intelligence. Authenticated, purpose-bound, audited and never SEO-indexable.
POST /v1/persons/lookups (createPersonLookup)
Protected natural-person lookup.
Requires an authenticated workspace actor and a declared purposeCode. The purpose is validated before any source executes. Every call writes an audit event and a person-disclosure ledger row.
POST /v1/persons/full-report (createPersonFullReport)
Full natural-person report from a DNI, CUIL or CUIT.
Asks every connected source in parallel and merges the answers. Every field names the adapter and source it came from, the source observation time where known and the retrieval time. A source that fails or misses its deadline is listed with that status and the rest are still served; `complete` is true only when every source answered. A DNI yields both CUIL candidates (prefix 20 and 27, with the 23 fallback); neither is presented as the person's CUIL without evidence. Requires a declared purposeCode, validated before any source is asked; writes a `person.full_report` audit event and a person-disclosure ledger row, in addition to the events of each source read. With saveReport the answer is frozen as a report in the workspace (PDF, GET /v1/reports, public verification) and savedReport names it; saving is refused before any source is asked when the caller may not create reports or the deployment has no object storage. sex is for a DNI only, for the traffic portals that refuse a DNI without it.
GET /v1/persons/full-reports/{reportId} (getSavedPersonFullReport)
A saved full person report, read back from its frozen document.
Returns the answer a saveReport request froze, exactly as it was. No source is asked and nothing is refreshed. Audited as report.view. NOT_FOUND for an unknown, another workspace's, an expired or a non-person report alike: past expiresAt the retention policy has ended it.
companies
Public company discovery. Returns candidates for a human to choose between and resolves nothing: a name is not an identifier, two companies share trade names, and entity-resolution.md section 11 requires the user to select the exact company before anything executes against it. There is no equivalent for natural persons and there will not be (security-privacy-compliance.md section 3).
GET /v1/companies/search (searchCompanies)
Find companies by name, for a human to choose between.
Searches the canonical legal entities the platform has already observed, by the comparison form of their name. It is not a registry query: an empty `results` is a statement that nothing known matched, never that no such company exists. The response carries no score, rank or best match - resolution is a separate `POST /v1/lookups` carrying the exact identifier the user picked. Natural persons are never returned.
GET /v1/companies/{cuit}/overview (publicCompanyOverview)
The anonymous company preview, keyed on CUIT.
The free preview of `reports.md` section 4, without a credential. It is a separate route from `GET /v1/entities/{entityId}/intelligence` rather than a relaxation of it: that one is keyed on an internal UUID, and an anonymous route keyed on UUIDs is an enumeration surface with nothing to enumerate towards. This one is keyed on the identifier a human can type, which is what a publicly indexable page needs. The field set is two independently switchable groups. `identity` is public registry data and is on by default; `credit` is the nine BCRA-derived fields and is off by default, because `reuseScope = global` governs internal reuse across customers and publication to a search engine is a different act. `fieldGroups` states which are present. A disabled group has no key in the body at all - never a null - so a client renders what it was given rather than inferring absence from a shape. The route resolves nothing, fetches nothing and creates no entity: a CUIT the platform has never observed answers `NOT_FOUND`. A natural person`s CUIL answers `NOT_FOUND` too, refused on the identifier prefix before the database is consulted and again on the resolved subject type (security-privacy-compliance.md section 3, reports.md section 4). It draws on the anonymous rate-limit bucket keyed on the client address, the same one anonymous company search uses.
risk
Multi-dimensional risk profiles. Decision support, never an automatic acceptance or rejection. The profile of a natural person is purpose-bound, audited and recorded in the disclosure ledger.
GET /v1/entities/{entityId}/intelligence (getEntityIntelligence)
The free company overview.
The free side of reports.md section 4's boundary: identity, the exact score or a range or an insufficient-data state, the effective level, completeness and data depth, the current total reported debt with its creditor count, the rejected-cheque counts, up to three material signals and the last refresh time. It has no key for anything on the paid list - no nulled factors, no empty evidence array - because a preview that returns the paid fields emptied is blur, and section 4 requires the paid report to add depth rather than remove blur. paidReportAdds carries that list by name so a caller can decide whether to spend a credit from the response itself. Authenticated despite being the free tier: the route is keyed on an internal UUID, and an anonymous route keyed on UUIDs is an enumeration surface with nothing to enumerate towards. A natural-person entity id is NOT_FOUND - section 4 does not support person previews, and FORBIDDEN would confirm that a probed UUID names a real person.
GET /v1/entities/{entityId}/credit (getEntityCredit)
Reported credit position, debt history and rejected cheques.
The BCRA-backed credit detail of portal.md sections 8 and 9: the latest reported period with its total, worst situation, maximum days past due and breakdown by reporting institution; the debt history for the horizon the response states in historyMonths; and the rejected-cheque counts and recent events. Situation 0 is a reported state meaning the relationship exists with nothing outstanding, never a missing value. Amounts are exact decimal strings with their currency, periods are YYYY-MM and cheque dates are YYYY-MM-DD, because a calendar value carried as an instant changes when it is formatted in another timezone. A cheque count of null means the source has never answered for this subject, which is not the same as zero; dataStatus says which. A natural-person entity id is NOT_FOUND: this route has no purpose gate and writes no disclosure row.
GET /v1/entities/{entityId}/evidence (getEntityEvidence)
The observations behind everything the platform says about one entity.
The live evidence appendix of portal.md section 4's /app/entidades/{id}/evidencia: every observation on file for the subject, with its source and operator, the instant the platform read it, the date the source says it became true, the source record key and two hashes. contentHash is over the normalized payload and normalizer version and is what a report appendix cites; snapshotHash is over the raw bytes and is the value on the stored snapshot, so a dispute about what a source said is settled by looking it up. observedAt is an instant and effectiveAt is a source calendar date carried as a UTC midnight - formatting the second in a local timezone moves it a day. An observation with status absent is the source answering that it holds no records, which is evidence and is listed; superseded is a claim a later observation corrected, and it is listed too, because deleting it would erase the evidence that a correction happened. Entries carry no reference number: appendix numbering belongs to one frozen report manifest whose rows cite it, and a number here would shift whenever a new observation arrived. Newest first, capped at limit, with total stating how many exist. Requires the evidence.appendix entitlement, checked before the entity is resolved. A natural-person entity id is NOT_FOUND: this route has no purpose gate and writes no disclosure row.
GET /v1/entities/{entityId}/risk-history (getEntityRiskHistory)
Stored assessments for one entity, and the deltas between them.
Every assessment of the credit dimension inside the window the response states, newest first, each carrying the model code and version that produced it, plus the 30- and 90-day deltas risk-engine.md section 23 permits. Nothing is interpolated: the points are the assessments that exist, so a window holding one assessment has one point and there is no daily series. A delta is refused rather than approximated - MODEL_VERSION_CHANGED when the two came from different model versions, because two versions scoring the same subject differ because the model changed; RANGE_AND_EXACT_SCORE_NOT_COMPARABLE when one side is a range, because subtracting a range from an exact score produces a movement that is an artefact of a source outage. Points from an earlier model version are returned rather than filtered, because they are real history; a client must segment on model rather than join across it, and `current` names the identity to segment by. A natural-person entity id is NOT_FOUND: this route has no purpose gate and writes no disclosure row.
GET /v1/entities/{entityId}/risk-profile (getEntityRiskProfile)
Multi-dimensional risk profile for one entity.
Returns every dimension of the subject type, including ones that are not_applicable or not_enabled - a dimension the platform cannot assess says so rather than being omitted. A partial assessment returns scoreRange with score null; it is never collapsed to a midpoint. When the subject is a natural person the request requires a declared purpose, is audited, and is recorded in the person-disclosure ledger. The result is decision support: it is not a probability of default, not a guarantee of future behaviour, and not an approval or rejection.
traffic
Traffic-fine coverage per jurisdiction. Kept apart from credit risk and excluded from every purpose unless a workflow explicitly authorizes it (traffic-fines.md section 11).
GET /v1/traffic-fines/coverage (getTrafficCoverage)
Which jurisdictions a traffic-fine lookup can check today.
The traffic jurisdiction registry for all 23 provinces and CABA, with every source found in the source audit: the national SINAI source and each direct provincial or municipal portal, its access class, its production gate and whether an adapter exists. coverage lists what a lookup would report per jurisdiction and source. Only checked means a source answered; a source whose gate is not approved is access_restricted. summary.uncheckedJurisdictions names every jurisdiction no source can answer for, and a zero result is clear only for summary.checkedJurisdictions. Traffic data never feeds credit risk. No personal data is returned.
reports
Issued report documents. Download is workspace-scoped, scope-gated and audited; the bytes themselves live in a private bucket and are reached through a short-lived signed URL.
GET /v1/reports (listReports)
The workspace's reports, newest first.
Cursor paginated on (createdAt, id) rather than on createdAt alone, so two reports requested in the same millisecond cannot straddle a page boundary and lose one. A summary rather than the full status: the coverage matrix of every report on a page is a response nobody wants. failureCategory is carried because it is the one thing a list is scanned for.
POST /v1/reports (createReport)
Request a paid intelligence report.
Spends one report credit and starts the pipeline of reports.md section 5. The Idempotency-Key header is required, not optional: without it every retry is a second purchase, so a request that omits one is refused with VALIDATION_ERROR rather than being given a generated key. A replay of the same key with the same body returns the existing report with created false and status 200; the same key with a different body is a CONFLICT. A report about a natural person requires a declared purposeCode, which is validated before the credit is consumed - refusing a caller and charging them is the one ordering nobody would defend. The response is the same shape as GET /v1/reports/{reportId}, because section 31 makes polling the delivery mechanism and two shapes for one resource means two parsers.
GET /v1/reports/{reportId} (getReport)
One report: how far it has got, or why it stopped.
The polling surface of reports.md section 31, and the only way an API-only consumer learns a report is ready. status is the state of the row and stage is where the work reached; they are separate vocabularies on purpose, because collapsing them would make superseded a peer of rendering. A failure carries section 32's category, its retryability, the source operations that blocked it and whether the credit was given back - no customer should have to open a support conversation to find out whether they were charged for a report that never arrived. assessment is the headline the report froze, read from its own manifest rather than from the entity, so it keeps saying what the document says after the subject has moved; it is null until the manifest exists. No download URL: that is a separate short-lived audited act, and a status poll that handed one out would put a bearer capability into every polling loop.
GET /v1/reports/{reportId}/download (downloadReport)
A short-lived signed URL for one issued report.
Workspace scoped and gated on the reports:read scope and permission. Every call is audit logged, including the ones that are refused. Returns a URL into the private bucket that expires in minutes; the URL is a bearer capability and is never logged. A superseded or revoked report still downloads - its bytes are unchanged - and the response says so through lifecycleStatus so a caller cannot present a withdrawn document as current.
POST /v1/reports/{reportId}/supersede (supersedeReport)
Replace an issued report with a newer one about the same subject.
reports.md section 29: a correction never mutates an issued PDF. The bytes, the manifest and the SHA-256 stay exactly as issued; the report becomes superseded and its public verification page names the replacement. Owner and admin only (reports:manage_lifecycle), from a signed-in session - an API key is refused even with reports:write. A refused attempt by a member of the workspace is audit logged; another workspace's report, or replacement, is NOT_FOUND.
POST /v1/reports/{reportId}/revoke (revokeReport)
Withdraw an issued report from reliance. Terminal.
The second transition of reports.md section 29. The bytes and the SHA-256 stay verifiable; the public verification page says revoked from then on. Same authorization and audit as supersede. An already revoked report is CONFLICT.
verification
Public, unauthenticated verification of an issued report. It reports issuance and lifecycle and publishes the canonical SHA-256 of the issued file. It never asserts that any particular file matches: that comparison happens in the reader's browser against the published digest (reports.md section 23).
GET /v1/report-verifications/{publicVerificationId} (verifyReport)
Verification-safe metadata for an issued report.
Anonymous. Proves that the identifier printed in a report QR code was issued by the platform, and reports the current lifecycle state and any replacement. It returns no report body, no evidence, no risk figures, no person identifiers, no workspace metadata and no storage URL; a natural person's display name is withheld. fileIntegrity is always not_verified: the server has not seen the caller's file. To check byte integrity, hash the local PDF and compare it with canonicalFileSha256.
api-keys
API key lifecycle, from a browser session only. The plaintext of a key is returned by the creation response and by nothing else, ever: only its SHA-256 digest is stored, so a key that is not copied at creation is a key that has to be replaced. A key carries scopes and allowed purpose codes, and the second of those bounds what it can ever be used to learn about a natural person.
GET /v1/api-keys (listApiKeys)
The workspace's API keys, with no plaintext.
Every key of the active workspace, active and revoked alike. A revoked key is kept and marked rather than removed, because the question asked after a leak is which credential was revoked and when. `masked` is `aus_<prefix>_...`; there is no response, here or anywhere, that can return the secret half.
POST /v1/api-keys (createApiKey)
Create an API key and receive its plaintext, once.
Requires a browser session and the `api_keys:manage` permission - an API key cannot create another API key, because a leaked credential that could mint replacements for itself would make revocation meaningless. The account must have a verified email address. The `key` field of the response is the only time the plaintext exists outside your own storage: it is not recoverable, and a key that is lost is replaced rather than retrieved.
DELETE /v1/api-keys/{keyId} (revokeApiKey)
Revoke an API key, effective immediately.
Status is read on every verification and there is no cache to invalidate, so the next request presenting this key is refused. A key belonging to another workspace answers 404 rather than 403: knowing the UUID achieves nothing.
watches
Following an entity for material changes (monitoring.md). A watch of a natural person requires a `purposeCode` the actor may declare, validated before the watch is created; without one the request is refused. The active-watch limit of the plan is enforced. Requires `watches:read` or `watches:write` on an API key.
GET /v1/watches (listWatches)
The workspace's watches.
POST /v1/watches (createWatch)
Watch an entity.
201 when a watch was created, 200 when the entity was already watched by this workspace. A natural person requires `purposeCode`.
POST /v1/watches/bulk (createWatchesInBulk)
Watch up to 500 entities by id.
One outcome per entity id; one bad id never fails the batch.
GET /v1/watches/{watchId} (getWatch)
One watch.
PATCH /v1/watches/{watchId} (updateWatch)
Change a watch's mode, policy or status.
DELETE /v1/watches/{watchId} (deleteWatch)
Stop watching. The watch is disabled and its history kept.
monitoring
What the watches found: material events, the portfolio overview and the workspace's notification preferences. Requires `monitoring:read`, and `notifications:write` to change preferences.
GET /v1/monitoring/events (listMonitoringEvents)
Material events on watched entities, newest first.
GET /v1/monitoring/events/{eventId} (getMonitoringEvent)
One event, with its evidence.
GET /v1/entities/{entityId}/monitoring-events (listEntityMonitoringEvents)
One entity's material events, newest first.
GET /v1/monitoring/portfolio (getMonitoringPortfolio)
The watched portfolio at a glance.
GET /v1/notification-preferences (getNotificationPreferences)
The workspace's default notification preferences.
PATCH /v1/notification-preferences (updateNotificationPreferences)
Change the workspace's notification preferences.
webhooks
Endpoints that receive signed monitoring events. The signing secret is shown once, on creation. Requires the webhooks.access entitlement and `webhooks:read` or `webhooks:write` on an API key.
GET /v1/webhook-endpoints (listWebhookEndpoints)
The workspace's endpoints.
POST /v1/webhook-endpoints (createWebhookEndpoint)
Register an endpoint. The signing secret is in this response only.
GET /v1/webhook-endpoints/{endpointId} (getWebhookEndpoint)
One endpoint.
PATCH /v1/webhook-endpoints/{endpointId} (updateWebhookEndpoint)
Change, pause or resume an endpoint.
DELETE /v1/webhook-endpoints/{endpointId} (deleteWebhookEndpoint)
Delete an endpoint. Deliveries still pending to it are not sent.
GET /v1/webhook-endpoints/{endpointId}/deliveries (listWebhookDeliveries)
An endpoint's recent deliveries and their outcome.
POST /v1/webhook-endpoints/{endpointId}/test (testWebhookEndpoint)
Send one signed test event now and report what the endpoint answered.
usage
What the workspace has spent this month and in past months, against its plan. A lookup unit is a distinct entity per calendar month (UTC), not a request: looking the same company up again in the same month spends nothing. A pending or failed lookup spends nothing. HTTP requests are not metered.
GET /v1/usage/current (getCurrentUsage)
This month's usage against the workspace's limits.
Counters for the current calendar month (UTC), the number of active watches, and each limit with what has been used against it. `enforced` says whether the platform refuses past a limit today: the active-watch limit is enforced, the monthly lookup allowance is reported and not yet enforced. Requires the `usage:read` scope on an API key.
GET /v1/usage/history (listUsageHistory)
Usage per calendar month, newest first.
One item per month from the current one back to the month the workspace was created, including months with nothing in them. Cursor paginated. Requires the `usage:read` scope on an API key.
bulk
Many lookups submitted at once and answered later. Every item is a lookup: it spends a lookup unit when it settles ready, exactly as a single lookup would, plus one bulk item unit. A natural-person item declares its own purposeCode - there is no job-wide purpose - and is a protected person lookup in every respect: the person rate limit, the purpose check, the audit event and the disclosure ledger. A person item without a purpose, or with one the caller may not declare, fails on its own with FORBIDDEN. Reading a job settles the items whose sources have answered. Requires the bulk.access entitlement and, on an API key, the `bulk:write` scope on every route.
POST /v1/bulk-lookups (createBulkLookup)
Submit up to 100 lookups.
Answers 202 with the job. Every identifier is accounted to the enumeration controls before anything is created, so a job that walks consecutive identifiers is refused with 429 and leaves nothing behind. An item whose identifier does not normalize fails with VALIDATION_ERROR; the rest of the job runs. An item is a natural person when its CUIT/CUIL prefix says so or it is a DNI; such an item needs its own purposeCode and fails with FORBIDDEN, with errorMessage saying why, when the purpose is missing or not permitted, or while person lookups are not enabled on the platform. A person item carries no risk summary; read the person's risk profile with a purpose instead.
GET /v1/bulk-lookups/{bulkLookupId} (getBulkLookup)
A bulk job and its counts.
Settles items whose sources have answered, then reports the job.
GET /v1/bulk-lookups/{bulkLookupId}/results (listBulkLookupResults)
A bulk job's items, in submission order.
Each item carries its status, the entity it resolved to and, once ready, a summary of the credit dimension. Risk summaries are included only for a caller that may read risk: an API key with `risk:read`. Cursor paginated.
disclosures
The person-disclosure ledger, which answers the six-month recipient/history request of Ley 25.326.
GET /v1/entities/{entityId}/disclosures (listEntityDisclosures)
Disclosure history for one entity.
Cursor paginated. Defaults to the preceding six months, which is the window Ley 25.326 art. 26 makes answerable to a data subject.
publications
GET /v1/entities/{entityId}/publications/coverage (getPublicationCoverage)
Which jurisdictions and archive periods were actually searched.
Coverage for all twenty-five publication jurisdictions - AR-NATIONAL, CABA and the 23 provinces - over the period asked about, defaulting to the last ten years. Every jurisdiction appears on every call, including the ones no source has been integrated for, because a list assembled only from the rows that exist would omit them silently and an answer covering one province would read as complete. An entry carries the source and operation, the class of key searched, the range queried, the archive the adapter knows the source to hold, the source's legal and technical state at the moment of the attempt, and a limitation code where the answer falls short: NO_MACHINE_ACCESS, ARCHIVE_GAP, IDENTIFIER_NOT_INDEXED, JURISDICTION_NOT_INTEGRATED or SOURCE_UNAVAILABLE. resultCount is null unless the status is an answer - a count of zero beside an outage reads as "nothing filed" and means "we could not ask". scope is nationwide only when all twenty-five cover the period, and it is the only basis on which an empty result may be described as an absence of filings in Argentina. A natural-person entity id is NOT_FOUND.
GET /v1/entities/{entityId}/publications (listEntityPublications)
Official notices and registry filings for one company.
Reverse chronological by the source's own publication date, never by when the platform read it - the first ingest of a bulk archive is decades of filings observed in one morning, and ordering by observation time would present every one of them as current. publishedAt and effectiveAt are both returned and neither substitutes for the other: an assembly is filed on one date and held on another. Both are instants carrying a UTC midnight for a publisher that states a calendar date, so rendering either in a local timezone moves it a day. Items carry normalized metadata, the match and extraction state, the document-access state and the evidence observation - never the raw source payload, and never a personal identifier. An extractionStatus of partial or failed describes the parser and not the filing: the document stays listed with its evidence. Provisional and rejected matches are absent unless includeProvisional is set, because a provisional match is a document the platform declined to attach to this company. A natural-person entity id is NOT_FOUND.
GET /v1/entities/{entityId}/publications/{publicationId} (getEntityPublication)
One publication, with its permitted excerpt and link.
Everything the list item carries, plus a normalized evidence excerpt and the official document link where the source permits one. Never the raw source payload and never the document body: documentAccess says what may be offered, and metadata_only - the common case for an open filing register - means the source publishes that a filing exists and no document to open. Scoped to the company in the path: a publication belonging to another entity is NOT_FOUND rather than the document, so the route cannot be used to walk the table by guessing ids.
GET /v1/entities/{entityId}/events (listEntityCorporateEvents)
The material-events timeline, each entry citing its documents.
A curated event view rather than a publication dump. Every entry names the publications that support it in publicationIds, which is what makes the claim checkable: the ids resolve through the publication detail route to the document and its evidence observation. effectiveAt is when the event took effect per the source and publishedAt is when the source published it; both are calendar dates carried as UTC midnights. sourceNativeType preserves what the publisher called the event, which is what keeps other_corporate_event from being opaque - the normalized vocabulary having no name for it does not mean the source was vague. Events with no effective date are absent: they are stored, and the document that produced each is on the publication feed, but a chronology is the one place an undated claim cannot honestly be put. Newest first. A natural-person entity id is NOT_FOUND.
relationships
GET /v1/entities/{entityId}/relationships (listEntityRelationships)
Who is attached to this company, and what disagrees with it.
The canonical interpretation of the relationship claims held about a company, with the claims that support it and the claims that materially conflict with it. Both lists are always present: a caller who did not know to ask for the conflict is the caller who needed to see it, and corporate-relationships-entity-graph.md section 12 forbids overwriting evidence to make a disagreement disappear. Storage direction is PERSON -> COMPANY, so subject is the person and target is the company, whichever end the caller asked from. asOf reconstructs the answer as it stood on a past date, from the claims that spoke to that date; relationshipId is null for such an answer because a reconstruction was never a stored row. status is unknown far more often than it is active, and that is not a defect: a source that lists a person without stating when the role began, whether it ended, or that it still holds has not asserted an active relationship, and section 6 requires unknown when currentness is uncertain. Three confidences are separate. extractionConfidence says whether the parser read the source correctly, resolutionConfidence whether the person is who we think, and relationshipConfidence how strongly the evidence supports this state; a high parser confidence implies nothing about identity. Claims below 0.75 are not projected at all. Actors the sources named and the platform has not identified are returned separately, in unresolvedActors, as source text: the name the register wrote, the source-native role, the period the claim states and the claim to cite. Every entry is marked kind=unresolved_actor and carries no subject identity of any kind - no entity id, no null one, and no document number, masked or otherwise. Nothing on such an entry can be followed to a second company; the reverse direction, what else a person directs, is a separate route behind a declared purpose. unresolvedActorCount always equals unresolvedActors.length, and both are filtered and reconstructed on the same terms as items, so an asOf answer excludes an actor a later package named. A natural-person entity id is NOT_FOUND.
GET /v1/entities/{entityId}/management (getCompanyManagement)
Who currently manages this company, per section 16.
corporate-relationships-entity-graph.md section 16: management is the canonical active relationships in management categories, and that is the management list. Roles a source records without saying whether they are current - the IGJ register states no dates - are in uncertain, and roles a source says ended are in historical; section 6 forbids presenting either as current. Ownership types (partner, shareholder) never appear in any of the three lists, because corporate-publications.md section 3 forbids inferring one from the other. asOf reconstructs the projection on a past date from the claims that spoke to it. Requires the corporate.graph entitlement, checked before the entity is resolved, so a 402 says nothing about whether an id exists. A natural-person entity id is NOT_FOUND.
GET /v1/entities/{entityId}/relationships/timeline (getRelationshipTimeline)
Appointments, resignations and other relationship claims, newest first.
Every dated relationship claim about the company, newest first. occurredOn is the date the claim states - the end date for a resignation or removal, the start date otherwise - and dateBasis is published when the claim states no effective date and the publication date stands in. A resolved actor is a canonical person; an actor nobody has identified is kind=unresolved_actor with the source name and nothing that can be followed. Claims with no date, and resolved claims below the 0.75 confidence floor, are not on the timeline and are counted in omitted. Requires the corporate.graph entitlement, checked before the entity is resolved, so a 402 says nothing about whether an id exists. A natural-person entity id is NOT_FOUND.
GET /v1/entities/{entityId}/graph (getEntityGraph)
The bounded corporate graph around a company.
Rooted at a company. depth=1 (the default) is the company and its people; depth=2 adds the other companies each of them is linked to by a stable identifier, which is a person reverse link and therefore requires a declared purpose - each person whose links are read is audited and recorded in the disclosure ledger. Every edge is PERSON -> COMPANY and carries its layer (management, ownership or other), so a directorship is never read as a shareholding. Unresolved actors are counted, never nodes. Capped at depth 2, 100 nodes, 250 edges and 2000 ms; a capped answer names the cap in truncatedBy. Requires the corporate.graph entitlement, checked before the entity is resolved, so a 402 says nothing about whether an id exists. A natural-person root is NOT_FOUND.
GET /v1/entities/{entityId}/corporate-links (getPersonCorporateLinks)
The companies a person is linked to. Person intelligence.
corporate-relationships-entity-graph.md section 17: current, uncertain and historical company roles of one natural person, with source-native role, period, company status, confidence and evidence count. Only claims that resolved the person by a stable identifier are read, so a person matched by name alone has no links here. Never anonymous; requires a declared purpose, and every call is audited and recorded in the disclosure ledger whether or not anything is found. Requires the corporate.graph entitlement, checked before the entity is resolved, so a 402 says nothing about whether an id exists. Anything that is not a natural person is NOT_FOUND.