Tax and legal-entity data
See which tax filings are due, review past returns, download tax documents, and access information about businesses you represent, with your permission.
These APIs let an app show someone their tax records and information about businesses they represent. The person signs in and chooses what to share. For a business, they must select it and remain an active representative.
What each tax information API does
These four APIs help people keep track of VAT and annual income tax:
| API | What it does for the user |
|---|---|
| Tax overview | Shows which filing periods are open or overdue and their due dates. It also shows whether a recorded lump-sum tax election is active or expired. This is an overview of filing obligations, not a payment balance or proof that every tax obligation has been satisfied. |
| Filing history | Lists returns already submitted, with the option to narrow the list by tax type and year. It helps someone find a past VAT or annual income-tax filing; unfinished drafts are not included. |
| Filing details | Opens one submitted return to show its reported figures, calculated tax, submission date, linked invoice status, and available documents. |
| Download tax documents | Downloads an assessment PDF showing the tax calculation for a filed return. Annual income-tax filings also support a separate filed-return PDF; VAT currently provides the assessment PDF. |
These APIs only show or download information. They do not prepare, change, submit, or pay a return. To prepare and submit an original quarterly VAT filing in US dollars, use the Quarterly VAT APIs, with the person's separate permission to file.
Available data
An authorized user can:
- view personal tax obligations, including open and overdue periods;
- list submitted income-tax and VAT filings;
- inspect a submitted filing and its calculated amounts;
- download an assessment or filed-return PDF;
- list legal entities selected during OAuth consent;
- read a selected entity's profile and available documents; and
- perform the same read-only tax operations for a selected entity they still actively represent.
Tax summaries are calculated without creating draft statements. Use the HTTP walkthrough to connect your own app, or the official CLI to explore records from the terminal.
Access boundaries
| Data | Required scope | Additional checks |
|---|---|---|
| Personal tax records | eprospera:person.tax.read | The OAuth user can only request their own records. |
| Legal-entity profile | eprospera:entity.read | The entity must be selected during consent. |
| Legal-entity documents | eprospera:entity.documents.read | The entity must be selected during consent. |
| Personal documents | eprospera:person.documents.read | The OAuth user can only request their own documents, such as the signed Agreement of Coexistence. |
| Legal-entity tax records | eprospera:entity.tax.read | The entity must be selected during consent and the user must remain an active representative. |
Selecting an entity during consent does not permanently bypass membership checks. If the user stops representing that entity, subsequent requests stop returning its data.
Direct API endpoints
| Operation | Endpoint |
|---|---|
| List consented entities | GET /api/v1/me/legal-entities |
| Read one entity | GET /api/v1/me/legal-entities/{id} |
| Read entity documents | GET /api/v1/me/legal-entities/{id}/documents |
| Read personal documents | GET /api/v1/me/natural-person/documents |
| Read tax status | GET /api/v1/me/tax/summary |
| List submitted filings | GET /api/v1/me/tax/filings |
| Read one filing | GET /api/v1/me/tax/filings/{filingId} |
| Download a tax document | GET /api/v1/me/tax/filings/{filingId}/documents/{document} |
Use subject=personal for the authenticated user's records or
subject=<entity-uuid> for a consented legal entity. Tax endpoints accept the
matching personal or entity tax scope; having one does not grant the other.
Prepare your first request
Request an OAuth client through the Help Center chat and complete the OAuth authorization flow. Ask for personal tax read permission, business tax read permission, or both, according to what your app needs. For example, an app that reads selected businesses' tax records can request:
openid profile eprospera:entity.tax.readUse the resulting access token, not an ID token, Standard Key, Agent Key, or Partner Key. The person must select the businesses during consent. An entity-read permission alone does not grant access to its taxes.
These terminal examples use curl with --fail-with-body support and jq. Start
with a separately provisioned staging client:
export BASE_URL='https://stg.portal.eprospera.com'
export ACCESS_TOKEN='<your-staging-oauth-access-token>'
TAX_SUBJECT='personal'To read business records instead, set TAX_SUBJECT to a business UUID returned
by the tax overview or the consented entity list.
The latter also requires eprospera:entity.read. Do not send an RPN as subject.
Omitting subject from summary/list requests returns data for all taxpayers
accessible through the token. Sending subject= with no value is invalid.
All IDs, names, dates, and amounts shown below are fictional. Replace them with
your own authorized values. Stop on HTTP errors before using the response;
--fail-with-body returns a nonzero exit code and keeps the error body visible.
Read the tax overview
Call tax summary to show outstanding filing periods without creating a draft:
TAX_SUMMARY="$(curl --fail-with-body -sS -G \
"$BASE_URL/api/v1/me/tax/summary" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "subject=$TAX_SUBJECT")"
printf '%s\n' "$TAX_SUMMARY" | jq .Example response for a person with an open VAT quarter:
{
"data": {
"subjects": [
{
"subject": {
"type": "natural_person",
"id": "33333333-3333-4333-8333-333333333333",
"name": "Alex Example",
"residentPermitNumber": "90123456789012"
},
"obligations": [
{
"type": "vat",
"period": { "year": 2026, "quarter": 3 },
"dueDate": "2026-10-15T23:59:59.999Z",
"status": "open",
"filingId": null
}
],
"lumpSumElections": []
}
]
}
}- Show the returned taxpayer name, type of tax, period, due date, and
openoroverduestatus. Use the returned due date rather than calculating a deadline in your app; reviewed requirements can affect the result. - VAT uses quarter numbers 1–4. Annual income-tax periods use
quarter: null. - An obligation's
filingIdmay refer to an unfinished draft. The submitted-filing endpoint below will not return drafts. Use the separately authorized VAT draft workflow to work on an original USD VAT draft. lumpSumElectionsshows recorded personal lump-sum tax elections. It is an empty list for businesses and when no personal election is recorded.- An empty obligations list means no open/overdue periods were returned. It is not a payment statement or a Certificate of Good Standing.
If you omit subject and get subjects: [], check which permissions and businesses
were granted. An explicitly requested taxpayer outside that access returns 404.
List submitted filings
Call filing history to find completed returns:
TAX_TYPE='vat'
TAX_YEAR=2026
TAX_FILINGS="$(curl --fail-with-body -sS -G \
"$BASE_URL/api/v1/me/tax/filings" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "subject=$TAX_SUBJECT" \
--data-urlencode "type=$TAX_TYPE" \
--data-urlencode "year=$TAX_YEAR" \
--data-urlencode 'limit=20')"
printf '%s\n' "$TAX_FILINGS" | jq '{
filings: [.data[] | {id, type, period, submittedAt}],
nextCursor: .meta.nextCursor
}'Example output from the jq selection after a return has been submitted:
{
"filings": [
{
"id": "44444444-4444-4444-8444-444444444444",
"type": "vat",
"period": { "year": 2026, "quarter": 3 },
"submittedAt": "2026-10-04T18:00:00.000Z"
}
],
"nextCursor": null
}The HTTP response contains full filing objects in data, with the same fields
as filing details, plus meta.nextCursor. The example
above only prints the fields needed for a history list. Results are newest first
by submission date, with ID as the tie-breaker.
| Query parameter | How to use it |
|---|---|
subject | personal or a consented business UUID. Omit to include all accessible taxpayers. |
type | vat or income. Omit to include both. |
year | The filing's tax year, from 2020 through 9999. Omit for all years. |
limit | Page size, 1–100; defaults to 50. |
cursor | The previous response's meta.nextCursor. Omit on the first request. |
An empty data array with nextCursor: null means no submitted filings matched
these filters. It does not tell you whether a draft exists or a return is due.
Fetch the next page
If meta.nextCursor is non-null, pass it back unchanged and URL-encoded. Keep
the same subject, tax type, and year while paging. Do not decode it or use a
filing ID as the cursor.
NEXT_CURSOR="$(printf '%s' "$TAX_FILINGS" | jq -r '.meta.nextCursor // empty')"
if [ -n "$NEXT_CURSOR" ]; then
TAX_FILINGS="$(curl --fail-with-body -sS -G \
"$BASE_URL/api/v1/me/tax/filings" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
--data-urlencode "subject=$TAX_SUBJECT" \
--data-urlencode "type=$TAX_TYPE" \
--data-urlencode "year=$TAX_YEAR" \
--data-urlencode 'limit=20' \
--data-urlencode "cursor=$NEXT_CURSOR")"
printf '%s\n' "$TAX_FILINGS" | jq .
fiRepeat for each returned cursor until it is null. A malformed cursor returns
400 with error: "invalid_cursor"; restart from the first page if necessary.
Read a submitted filing
Let the person select an ID from filing history, then call filing details. Replace the fictional ID here with that selection:
FILING_ID='44444444-4444-4444-8444-444444444444'
TAX_FILING="$(curl --fail-with-body -sS \
"$BASE_URL/api/v1/me/tax/filings/$FILING_ID" \
-H "Authorization: Bearer $ACCESS_TOKEN")"
printf '%s\n' "$TAX_FILING" | jq .Example 200 response for a submitted personal VAT return:
{
"data": {
"id": "44444444-4444-4444-8444-444444444444",
"subject": {
"type": "natural_person",
"id": "33333333-3333-4333-8333-333333333333",
"name": "Alex Example",
"residentPermitNumber": "90123456789012"
},
"type": "vat",
"period": { "year": 2026, "quarter": 3 },
"submittedAt": "2026-10-04T18:00:00.000Z",
"amended": false,
"currency": "usd",
"accountingMethod": "cash",
"reported": { "grossIncome": "0", "taxCredit": "0", "taxWithheld": "0" },
"usdEquivalent": null,
"taxLiability": "0",
"exchangeRate": null,
"invoice": null,
"availableDocuments": ["assessment"]
}
}reported holds the original figures in the filing's currency. Amounts are
decimal strings, and a null figure means unavailable, not zero. BTC filings can
also include frozen USD equivalents and exchange-rate information; do not replace
those with today's rate. taxLiability is the USD liability recorded for the
filing. amended identifies an amended return.
The linked invoice can be null, as in a zero-tax filing. Its status is useful
context, but do not infer the user's total outstanding balance from this one
return. This endpoint reads submitted returns only; use the VAT draft endpoint
to track a filing still being prepared.
Download a tax document
Read availableDocuments on the selected filing and call
download tax document:
| Document | Available for | Result |
|---|---|---|
assessment | Submitted VAT and annual income-tax filings | Notice of assessment PDF. |
return | Submitted annual income-tax filings | Filed income-tax return PDF. |
Download an assessment into a new private directory:
umask 077
DOWNLOAD_DIR="$(mktemp -d)"
curl --fail -sS \
"$BASE_URL/api/v1/me/tax/filings/$FILING_ID/documents/assessment" \
-H "Authorization: Bearer $ACCESS_TOKEN" \
-o "$DOWNLOAD_DIR/assessment.pdf"A successful response is binary PDF data with Content-Type: application/pdf
and a download filename in Content-Disposition. It has no JSON data wrapper.
The example uses --fail so an HTTP error body is not saved as a PDF. Check the
exit status before opening the file, and keep downloaded tax documents private.
For a filing whose availableDocuments contains return, use the same command
with /documents/return and a suitable output filename. VAT has no separate
filed-return PDF through this endpoint.
Assessments accept ?history_years=1 through 5, defaulting to 1, to control
the included assessment history. Do not send history_years for a return
download; that combination returns 400.
Handle missing records and errors
Check HTTP status first. Error responses contain error; a data field is not
present on every response. For example, an inaccessible submitted filing returns
404:
{ "error": "Tax filing not found" }| Result | What your app should do |
|---|---|
200 with an empty list | Show an empty state for the selected filters. Check the overview separately for outstanding periods. |
400 | Fix the subject, filters, cursor, or document request. A VAT return download is unsupported. |
401 | Refresh an expired access token when supported, or reconnect if it was revoked or refresh fails. |
403 | Request the matching tax read permission and obtain consent. Entity profile access or VAT write access alone is insufficient. |
404 | Check the ID, environment, consented business, and current representative role. A draft cannot be read through the submitted-filing endpoint. |
500 or a connection failure | Retry these read requests with backoff. Do not treat missing results as proof of a missing filing or no tax due. |
For VAT write errors and recovery, follow the separate filing guide; interrupted writes need different handling.
Use the official CLI
Install the official CLI, then authorize it in a browser. For staging, select the environment before login and keep it selected for later commands:
export EPROSPERA_ENV=staging
export EPROSPERA_BASE_URL=https://stg.portal.eprospera.com
eprospera auth login --oauthThe browser consent page shows the requested permissions and lets the user select which legal entities to share. The CLI client has no embedded secret and requests only the published user and entity scopes.
List the entities available to the CLI, then replace the sample ENTITY_ID
with a returned business ID before reading its details:
eprospera --json me legal-entities list
ENTITY_ID='11111111-1111-4111-8111-111111111111'
eprospera --json me legal-entities get "$ENTITY_ID"
eprospera --json me legal-entities documents "$ENTITY_ID"Read personal tax information, selecting a returned FILING_ID before reading
or downloading that filing:
eprospera --json tax status --subject personal
eprospera --json tax list --subject personal --type income --year 2025
FILING_ID='44444444-4444-4444-8444-444444444444'
eprospera --json tax get "$FILING_ID"
eprospera tax download "$FILING_ID" --document assessmentFor entity taxes, use a consented business UUID and select a filing from that business's returned list before downloading:
eprospera --json tax status --subject "$ENTITY_ID"
eprospera --json tax list --subject "$ENTITY_ID" --type vat --year 2026
FILING_ID='22222222-2222-4222-8222-222222222222'
eprospera tax download "$FILING_ID" --document assessment --output vat-assessment.pdftax list returns an opaque cursor for the next page when more filings are
available. Pass that value back with --cursor; do not parse or modify it.
Entity detail fields
Both API-key entity detail reads and consented OAuth entity detail reads return the same additional profile fields. OAuth still requires consent and current representation; API keys still require representation, with Agent Keys limited to API-incorporated entities.
| Field | Meaning |
|---|---|
id | Legal-entity UUID used in API paths. |
residentPermitNumber | 14-digit RPN, or null when unavailable. |
jurisdictionOfFormation | Recorded jurisdiction of formation. |
formationDate | Recorded formation date, formatted YYYY-MM-DD. |
status | dissolved when dissolution has taken effect; otherwise active if residency is current, or inactive. |
residencyStatus | Whether a residency term is currently active. |
residency | Current residency type, effective date, and termination date, or null. |
registeredAgent | Current agent's provider ID, name, attention line, website, RPN, term dates, and office/mailing addresses, or null. |
registeredAddress | Current registered agent's office address, or null. |
principalOfficeAddress | The entity's separately recorded principal-office address. |
Only terms that have started and have not terminated are returned. Missing
registered-office data is not replaced with a principal-office or mailing
address. The detail fields are additive; the entity-list endpoint remains a
summary. This API does not expose a separate registrationNumber; use the UUID
and RPN as distinct identifiers.
An active status is a residency/registration indicator, not proof of tax
compliance or good standing. Use the
Certificate of Good Standing workflow
when a certificate is required.
Handling sensitive information
Tax amounts, filing history, assessments, returns, and some legal-entity documents are confidential financial information.
- Do not place access tokens, refresh tokens, tax responses, or downloaded documents in source control or shared logs.
- Treat JSON and human-readable terminal output as sensitive; shell redirection and CI log capture can persist it.
- Tax PDFs are created with owner-only file permissions on supported platforms.
The CLI refuses to overwrite an existing file unless
--yesis supplied. - Use
eprospera --yes auth logoutto revoke the remote OAuth session and remove the locally stored credential.
The CLI stores credentials in the operating-system keychain when available. Its protected local-file fallback is intended for a single-user workstation, not a shared machine.
OAuth 2.0 / OpenID Connect
e-Próspera provides an OAuth 2.0 and OpenID Connect authorization server so third-party applications can authenticate users and access their data with consent.
Quarterly VAT filing
See how an app can help someone choose a taxpayer, prepare a quarterly VAT filing, check the amount due, and submit it with their permission.