Document requests API
Every Document requests action (7) and data model (3): endpoints, scopes, input, preconditions, events and examples.
Ask a lead for documents with a link — no sign-in needed.
Module code lead_documents · 7 actions · 3 data models · 6 events. A key or token never does more here than the person behind it can; row-level security applies exactly as in the app. Scopes: lead_documents (everything), lead_documents:read (read only) or lead_documents:<capability>.
Resources
| Resource | Table | List and read | POST | PATCH | DELETE |
|---|---|---|---|---|---|
lead_document_links | lead_document_link | /api/v1/lead_document_links | |||
lead_document_requests | lead_document_request | /api/v1/lead_document_requests | |||
lead_documents | lead_document | /api/v1/lead_documents |
Lists take limit (up to 200), cursor, order (e.g. -created_at), fields and q; every other query parameter is a column filter: ?status=paid, ?total[gte]=100, ?id[in]=a,b, ?x=null.
Actions
| Action | Needs | What it does |
|---|---|---|
lead_documents.issue_link | lead_documents:write | Ask a lead for documents |
lead_documents.renew_link | lead_documents:write | Give a lead’s document link more time |
lead_documents.review | lead_documents:write | Accept or reject a document |
lead_documents.revoke_link | lead_documents:write | Close a lead’s document link |
lead_documents.set_request | lead_documents:manage | Add or change a document request |
lead_documents.set_request_active | lead_documents:manage | Open or close a document request |
lead_documents.submit | lead_documents:write | File a document a lead sent |
lead_documents.issue_link
Ask a lead for documents — Opens a files upload link for one lead (as the platform, so a rep needs no Files permission) and ties it to the documents it asks for.
Needs lead_documents:write · changes data
https://app.getera.io/api/v1/lead_document_links/actions/issue_link- Canonical address:
POST /api/v1/actions/lead_documents.issue_link
Input
| Field | Type | Required | Notes |
|---|---|---|---|
leadId | uuid | yes | Lead · id of lead |
fileUploadLinkId | uuid | Upload link · Leave empty and the link is opened here. · id of file_upload_link | |
requestIds | object / array | Documents | |
expiresInDays | number | Open for (days) · min 1 · max 90 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
lead_not_found | The lead must exist. |
lead_archived | An archived lead is not asked for anything. |
no_requests | At least one open document request must exist or be picked. |
request_not_available | Every picked request must be open. |
upload_link_not_open | The files upload link must exist and be open. |
upload_link_taken | One upload link serves one lead. |
Events it publishes: lead_documents.link_issued
What it writes: lead_document_link (insert) — Ties the link to the lead and retires the previous one
curl -X POST https://app.getera.io/api/v1/lead_document_links/actions/issue_link \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"leadId":"LEAD_ID"}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.link_issued"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocumentLinks.issueLink({
leadId: "LEAD_ID"
})era lead_document_links issue_link \
--lead-id "LEAD_ID"{
"name": "era__lead_documents__issue_link",
"arguments": {
"leadId": "LEAD_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 lead_not_found, lead_archived, no_requests, request_not_available, upload_link_not_open, upload_link_taken · 429 slow down
lead_documents.renew_link
Give a lead’s document link more time — Moves the expiry of the link a lead was sent, keeping the address they already have.
Needs lead_documents:write · changes data
https://app.getera.io/api/v1/actions/lead_documents.renew_linkInput
| Field | Type | Required | Notes |
|---|---|---|---|
leadId | uuid | yes | Lead · id of lead |
days | number | yes | Open for (days from now) · min 1 · max 90 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
lead_not_found | The lead must exist. |
lead_archived | An archived lead is restored first. |
no_open_link | The lead must have an open document link. |
Events it publishes: lead_documents.link_renewed
curl -X POST https://app.getera.io/api/v1/actions/lead_documents.renew_link \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"leadId":"LEAD_ID","days":1}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.link_renewed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.actions.run("lead_documents.renew_link", {
leadId: "LEAD_ID",
days: 1
})era run lead_documents.renew_link \
--lead-id "LEAD_ID" \
--days 1{
"name": "era__lead_documents__renew_link",
"arguments": {
"leadId": "LEAD_ID",
"days": 1
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 lead_not_found, lead_archived, no_open_link · 429 slow down
lead_documents.review
Accept or reject a document — Records a decision about what was sent; a rejection tells the person why.
Needs lead_documents:write · changes data
https://app.getera.io/api/v1/lead_documents/{id}/actions/review- Canonical address:
POST /api/v1/actions/lead_documents.review
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Document · id of lead_document |
decision | string (enum) | yes | Decision · Allowed values: accepted, rejected |
reason | string | Why · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The document must exist. |
already_in_that_state | The decision must change something. |
reason_required | A rejection carries the reason the person is shown. |
Events it publishes: lead_documents.reviewed
What it writes: lead_document (update) — Records the decision
curl -X POST https://app.getera.io/api/v1/lead_documents/LEAD_DOCUMENT_ID/actions/review \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"decision":"accepted"}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.reviewed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocuments.review("LEAD_DOCUMENT_ID", {
decision: "accepted"
})era lead_documents review LEAD_DOCUMENT_ID \
--decision "accepted"{
"name": "era__lead_documents__review",
"arguments": {
"id": "LEAD_DOCUMENT_ID",
"decision": "accepted"
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_in_that_state, reason_required · 429 slow down
lead_documents.revoke_link
Close a lead’s document link — Stops the link a lead was sent from working. What they already sent stays.
Needs lead_documents:write · removes or cannot be undone · asks a person to confirm when Era runs it
https://app.getera.io/api/v1/lead_document_links/actions/revoke_link- Canonical address:
POST /api/v1/actions/lead_documents.revoke_link
Input
| Field | Type | Required | Notes |
|---|---|---|---|
leadId | uuid | yes | Lead · id of lead |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
lead_not_found | The lead must exist. |
lead_archived | An archived lead is restored first. |
no_open_link | The lead must have an open document link. |
Events it publishes: lead_documents.link_revoked
What it writes: lead_document_link (update) — Retires the join; files closes the link
curl -X POST https://app.getera.io/api/v1/lead_document_links/actions/revoke_link \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"leadId":"LEAD_ID"}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.link_revoked"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocumentLinks.revokeLink({
leadId: "LEAD_ID"
})era lead_document_links revoke_link \
--lead-id "LEAD_ID"{
"name": "era__lead_documents__revoke_link",
"arguments": {
"leadId": "LEAD_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 lead_not_found, lead_archived, no_open_link · 429 slow down
lead_documents.set_request
Add or change a document request — What the business asks a lead to send — a passport, a diploma — and what files it accepts.
Needs lead_documents:manage · changes data
https://app.getera.io/api/v1/lead_document_requests/{id}/actions/set_request- Canonical address:
POST /api/v1/actions/lead_documents.set_request
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | Filled from the path {id} · Request · id of lead_document_request | |
name | string | yes | Name · max 255 |
description | string | Instructions · max 2000 | |
isRequired | boolean | Required | |
sortOrder | number | Order · min 0 | |
allowedTypes | object / array | Accepted files | |
maxFileSizeMb | number | Largest file (MB) · min 1 · max 50 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The request being changed must exist. |
name_taken | Two requests may not share a name. |
Events it publishes: lead_documents.request_changed
What it writes: lead_document_request (upsert) — Writes the request
curl -X POST https://app.getera.io/api/v1/lead_document_requests/LEAD_DOCUMENT_REQUEST_ID/actions/set_request \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"name":"Name"}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.request_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocumentRequests.setRequest("LEAD_DOCUMENT_REQUEST_ID", {
name: "Name"
})era lead_document_requests set_request LEAD_DOCUMENT_REQUEST_ID \
--name "Name"{
"name": "era__lead_documents__set_request",
"arguments": {
"id": "LEAD_DOCUMENT_REQUEST_ID",
"name": "Name"
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, name_taken · 429 slow down
lead_documents.set_request_active
Open or close a document request — Stops asking for a document without touching what was already sent.
Needs lead_documents:manage · changes data
https://app.getera.io/api/v1/lead_document_requests/{id}/actions/set_request_active- Canonical address:
POST /api/v1/actions/lead_documents.set_request_active
Input
| Field | Type | Required | Notes |
|---|---|---|---|
id | uuid | yes | Filled from the path {id} · Request · id of lead_document_request |
active | boolean | yes | Open |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
not_found | The request must exist. |
already_in_that_state | It is already open, or already closed. |
Events it publishes: lead_documents.request_changed
What it writes: lead_document_request (update) — Opens or closes it
curl -X POST https://app.getera.io/api/v1/lead_document_requests/LEAD_DOCUMENT_REQUEST_ID/actions/set_request_active \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"active":true}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.request_changed"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocumentRequests.setRequestActive("LEAD_DOCUMENT_REQUEST_ID", {
active: true
})era lead_document_requests set_request_active LEAD_DOCUMENT_REQUEST_ID \
--active true{
"name": "era__lead_documents__set_request_active",
"arguments": {
"id": "LEAD_DOCUMENT_REQUEST_ID",
"active": true
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:manage · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 not_found, already_in_that_state · 429 slow down
lead_documents.submit
File a document a lead sent — Attaches an uploaded file to the lead, against the document it was sent for.
Needs lead_documents:write · reaches outside (sends, publishes or charges)
https://app.getera.io/api/v1/lead_documents/actions/submit- Canonical address:
POST /api/v1/actions/lead_documents.submit
Input
| Field | Type | Required | Notes |
|---|---|---|---|
token | string | yes | Link token · max 128 |
requestId | uuid | yes | Document · id of lead_document_request |
fileId | uuid | yes | File · id of file |
uploaderName | string | Sent by · max 200 | |
uploaderNote | string | Note · max 2000 |
Preconditions
The action is refused with 409 and one of these codes:
| Code | Refused when |
|---|---|
link_unknown | The link must exist and be open. |
link_expired | The link must not have expired. |
request_not_on_link | The link must ask for that document. |
file_not_found | The file must have come in through this link and not be filed already. |
Events it publishes: lead_documents.submitted
What it writes: lead_document (insert) — Files the document; lead_document_link (update) — Stamps when the link was last used
curl -X POST https://app.getera.io/api/v1/lead_documents/actions/submit \
-H "Authorization: Bearer $ERA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{"token":"Link token","requestId":"LEAD_DOCUMENT_REQUEST_ID","fileId":"FILE_ID"}'{
"ok": true,
"result": "…",
"events": [
"lead_documents.submitted"
]
}import { createEra } from "@getera/sdk"
const era = createEra({ apiKey: process.env.ERA_API_KEY })
const res = await era.leadDocuments.submit({
token: "Link token",
requestId: "LEAD_DOCUMENT_REQUEST_ID",
fileId: "FILE_ID"
})era lead_documents submit \
--token "Link token" \
--request-id "LEAD_DOCUMENT_REQUEST_ID" \
--file-id "FILE_ID"{
"name": "era__lead_documents__submit",
"arguments": {
"token": "Link token",
"requestId": "LEAD_DOCUMENT_REQUEST_ID",
"fileId": "FILE_ID"
}
}Errors: 401 no or expired credential · 403 the credential does not hold lead_documents:write · 404 the record or module is outside what it may reach · 422 invalid input (problems[]) · 409 link_unknown, link_expired, request_not_on_link, file_not_found · 429 slow down
Data models
LeadDocumentLink
Table lead_document_link · Resource lead_document_links
GET /api/v1/lead_document_linksGET /api/v1/lead_document_links/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
lead_id | string (uuid) · uuid | lead | ||
is_active | boolean · bool | |||
expires_at | string (date-time) · timestamptz | yes | ||
created_by_user_id | string (uuid) · uuid | yes | app_user | |
created_at | string (date-time) · timestamptz | |||
request_ids | string[] · uuid[] | |||
last_used_at | string (date-time) · timestamptz | yes | ||
updated_at | string (date-time) · timestamptz | |||
file_upload_link_id | string (uuid) · uuid | yes | file_upload_link |
Primary key: id
LeadDocumentRequest
Table lead_document_request · Resource lead_document_requests
GET /api/v1/lead_document_requestsGET /api/v1/lead_document_requests/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
name | string · text | |||
description | string · text | yes | ||
is_required | boolean · bool | |||
sort_order | integer · int4 | |||
allowed_types | string[] · text[] | |||
max_file_size_mb | integer · int4 | |||
is_active | boolean · bool | |||
created_at | string (date-time) · timestamptz | |||
updated_at | string (date-time) · timestamptz |
Primary key: id
Checks:
CHECK ((max_file_size_mb > 0))
LeadDocument
Table lead_document · Resource lead_documents
GET /api/v1/lead_documentsGET /api/v1/lead_documents/{id}
| Column | Type | Nullable | Allowed values | References |
|---|---|---|---|---|
id | string (uuid) · uuid | |||
organization_id | string (uuid) · uuid | organization | ||
workspace_id | string (uuid) · uuid | workspace | ||
lead_id | string (uuid) · uuid | lead | ||
document_request_id | string (uuid) · uuid | yes | lead_document_request | |
link_id | string (uuid) · uuid | yes | lead_document_link | |
file_id | string (uuid) · uuid | file | ||
uploader_name | string · text | yes | ||
uploader_note | string · text | yes | ||
uploaded_at | string (date-time) · timestamptz | |||
status | string · text | received, accepted, rejected | ||
reviewed_by_user_id | string (uuid) · uuid | yes | app_user | |
reviewed_at | string (date-time) · timestamptz | yes | ||
rejection_reason | string · text | yes | ||
updated_at | string (date-time) · timestamptz |
Primary key: id
Events
Workflows and webhooks react to these events.
| Event | What happens | Payload |
|---|---|---|
lead_documents.link_issued | A lead was asked for documents through an upload link. | id, leadId, fileUploadLinkId, requestIds |
lead_documents.link_renewed | A lead’s document link was given more time. | id, leadId, expiresAt |
lead_documents.link_revoked | A lead’s document link was closed. | id, leadId |
lead_documents.request_changed | What the business asks for changed. | id |
lead_documents.reviewed | A sent document was accepted or rejected. | id, leadId, decision |
lead_documents.submitted | A lead sent a document. | id, leadId, requestId, fileId, person, document, fileName, ownerUserId |