e-Próspera

Conventions

Shared rules that apply across every endpoint of the e-Próspera API. Most reference pages link here instead of restating these conventions.

View as Markdown

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:

EnvironmentOrigin
Productionhttps://portal.eprospera.com
Staginghttps://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 / shapeTypeNotes
sk-...Standard API keyPersonal / first-party use. Never share. Not scoped.
ak-...Agent KeyDelegated, scope-checked. See Agent Keys.
pk-...Partner KeyAdmin-issued, expiring, organization-scoped. See Partner Keys.
JWT (RS256)OAuth 2.0 access tokenIssued 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 POST endpoints are application/json unless the endpoint documents another type. Private proof uploads use multipart/form-data.
  • OAuth /api/oauth/token is application/x-www-form-urlencoded per RFC 6749.
  • All responses are application/json unless explicitly noted.

Response envelopes

Most endpoints wrap successful payloads:

Endpoint shapeEnvelope
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

StatusMeaning in this API
200Success.
400Validation error or conflicting state (e.g. application already submitted).
401Missing, malformed, invalid, expired, or revoked credential; inactive Partner Integration.
403Credential is valid but lacks the required Agent/Partner Key scope or sufficient OAuth scope.
404Resource does not exist or the caller cannot see it. The two are intentionally indistinguishable.
409Conflict (e.g. legal-entity name, stale partner version, or idempotency-key reuse).
429Rate limit exceeded. See Rate limits.
500Server 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:

EndpointLimits
POST /api/v1/verify_rpn5,000 requests / 24 h and 50 / minute, per API key
POST /api/v1/registries/legal_entities/search5,000 / 24 h and 50 / minute, per API key
Partner reads120/min per key; 300/min per integration
Partner updates and submission60/min per key; 150/min per integration
Partner application creation10/min per key; 50/hour per integration
Partner uploads20/min per key; 100/hour per integration
Partner payments and vouchers5/min per key; 20/hour per integration
Other endpointsNo 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.

On this page