Conventions
Shared rules that apply across every endpoint of the e-Próspera API. Most reference pages link here instead of restating these conventions.
If you are using the official CLI, start with CLI. The CLI handles most of these wire-level details for you while still using the same credentials, scopes, and API behavior.
Base URL
All paths in this documentation are relative to one of these origins:
| Environment | Origin |
|---|---|
| Production | https://portal.eprospera.com |
| Staging | https://staging-portal.eprospera.com |
So GET /api/v1/legal_entities/{id} in production is GET https://portal.eprospera.com/api/v1/legal_entities/{id}.
There is no separate api.eprospera.com host — the API ships from the same origin as the consumer portal.
Authentication
Every authenticated request uses the Authorization header with a Bearer token:
Authorization: Bearer <token>The token can be one of four things:
| Prefix / shape | Type | Notes |
|---|---|---|
sk-... | Standard API key | Personal / first-party use. Never share. Not scoped. |
ak-... | Agent Key | Delegated, scope-checked. See Agent Keys. |
pk-... | Partner Key | Admin-issued, expiring, organization-scoped. See Partner Keys. |
| JWT (RS256) | OAuth 2.0 access token | Issued by /api/oauth/token. Carries scopes from the user's consent grant. |
Not every endpoint accepts every credential — see the Authentication block on each reference page. In particular, /api/v1/me/* does not accept standard API keys.
Content type
- Request bodies on
POSTendpoints areapplication/jsonunless the endpoint documents another type. Private proof uploads usemultipart/form-data. - OAuth
/api/oauth/tokenisapplication/x-www-form-urlencodedper RFC 6749. - All responses are
application/jsonunless explicitly noted.
Response envelopes
Most endpoints wrap successful payloads:
| Endpoint shape | Envelope |
|---|---|
Single resource (GET /resource/{id}) | { "data": { ... } } |
Collection (GET /resource) | { "data": [ ... ] } (see Pagination) |
| Create flows | { "data": { ... }, "nextSteps": { ... } } |
| Voucher-pay endpoints | { "success": true, "data": { ... }, "message": "..." } |
Search (POST .../search) | { "results": [ ... ] } |
Verify (POST /verify_rpn) | { "result": "...", "active": true | false } |
OAuth and JWKS endpoints follow their own RFCs (RFC 6749 / RFC 7517 / OIDC Core 1.0) and do not use the data wrapper.
Error envelope
Errors return a non-2xx status and a JSON body shaped like:
{
"error": "short_machine_readable_code_or_message",
"error_description": "Human-readable explanation. Optional.",
"details": [
/* Zod issues or per-field errors. Optional. */
]
}Some legacy endpoints return only { "error": "..." }. Treat both shapes as the same contract: error is always present on a non-2xx response.
details is most often a Zod issue array on 400 responses:
{
"error": "Invalid request",
"details": [
{
"code": "invalid_type",
"expected": "string",
"received": "undefined",
"path": ["applicationData", "name"],
"message": "Required"
}
]
}HTTP status codes
| Status | Meaning in this API |
|---|---|
200 | Success. |
400 | Validation error or conflicting state (e.g. application already submitted). |
401 | Missing, malformed, invalid, expired, or revoked credential; inactive Partner Integration. |
403 | Credential is valid but lacks the required Agent/Partner Key scope or sufficient OAuth scope. |
404 | Resource does not exist or the caller cannot see it. The two are intentionally indistinguishable. |
409 | Conflict (e.g. legal-entity name, stale partner version, or idempotency-key reuse). |
429 | Rate limit exceeded. See Rate limits. |
500 | Server error. Safe to retry with backoff for idempotent operations only. |
Timestamps
All timestamps are strings in ISO 8601 / RFC 3339 UTC form, e.g. 2024-01-15T10:30:00.000Z. Never assume local time. Date-only fields (none currently in the API) would use YYYY-MM-DD.
Nullability
Optional fields are explicitly typed as T | null in this documentation and are present in responses with the value null rather than being omitted. If a field is documented as non-nullable, expect it to always be present.
IDs
All identifiers are RFC 4122 v4 UUIDs (string form, lowercased, dashed) unless noted. Resident Permit Numbers (RPNs) are 14-digit numeric strings that start with 8 (legal entity) or 9 (natural person).
Rate limits
Rate limiting is per-endpoint or credential class, not global. Currently:
| Endpoint | Limits |
|---|---|
POST /api/v1/verify_rpn | 5,000 requests / 24 h and 50 / minute, per API key |
POST /api/v1/registries/legal_entities/search | 5,000 / 24 h and 50 / minute, per API key |
| Partner reads | 120/min per key; 300/min per integration |
| Partner updates and submission | 60/min per key; 150/min per integration |
| Partner application creation | 10/min per key; 50/hour per integration |
| Partner uploads | 20/min per key; 100/hour per integration |
| Partner payments and vouchers | 5/min per key; 20/hour per integration |
| Other endpoints | No documented limit today. |
Partner throttling returns 429 with a Retry-After header. Invalid Partner Key attempts are limited to 20/minute per source IP. Other rate-limited endpoints may omit Retry-After; use exponential backoff when it is absent.
Pagination
Most list endpoints are not currently paginated. Two exceptions are /api/v1/nomadlayer/applications and the Partner Key application list. Partner applications use an opaque cursor:
GET /api/v1/partner/residency_applications?limit=50&cursor=<application-id>The partner limit defaults to 50 and cannot exceed 100. Read pagination.nextCursor for the next page.
The Nomad Layer endpoint uses page-based pagination:
{
"data": [
/* ... */
],
"pagination": {
"page": 1,
"pageSize": 20,
"totalCount": 134,
"pageCount": 7
}
}Other list endpoints return the full result set and have no pagination parameters today.
Versioning
All public endpoints live under /api/v1/. Breaking changes will go to a new /api/v2/ prefix; existing /api/v1/ endpoints remain stable. Additive changes (new fields, new optional query params, new endpoints) can land under /api/v1/ without notice — clients should ignore unknown fields rather than reject them.
Idempotency
Partner application creation, checkout creation, and voucher payment require Idempotency-Key. Keys are scoped to the integration and route and retained for 24 hours. Identical completed requests replay the saved response; different input or an in-progress duplicate returns 409.
POST /legal_entity_applications remains non-idempotent and can create a duplicate Draft when retried. Implement caller-side deduplication for that endpoint.
Webhooks
There are no public webhooks. Approval, payment, AOC, and verification state must be discovered by polling the relevant GET endpoint. Partner responses summarize the applicant-only AOC/Veriff prerequisites in nextSteps; they never expose Veriff URLs or decision payloads. Recommended polling cadence is 5–30 seconds during an active flow, then exponential back-off.
e-Próspera CLI
The official CLI wraps the public API in commands that are easier for humans, scripts, CI jobs, and AI agents to call safely. Use it when your runtime can execute shell commands. Use direct HTTP only when you are building your own client, need an endpoint the CLI does not cover, or cannot install Node tooling.
Agent Keys
Agent Keys let an e-resident delegate specific API capabilities to an AI agent, CLI workflow, or third-party service without sharing their personal standard API key.