Appearance
Skills for AI Agents
A capability map and decision tree for LLM-based callers. Read this before making your first request — it is shorter than the reference docs and will save you from probing endpoints that are empty by design.
If you are the developer wiring an agent up to this API, paste this page (or /llms-full.txt) into your agent's system prompt or skill folder.
TL;DR — what an agent must internalize before the first call
- Three docs, in order: Agent Keys (credentials & scopes) → Conventions (auth header, errors, rate limits) → this page (capabilities & dead ends) → Agent recipes (copy-paste workflows).
- Base URL:
https://portal.eprospera.com(production) orhttps://staging-portal.eprospera.com(staging). There is noapi.eprospera.com. - Every Agent Key request is scope-checked.
403means the key is missing the scope, not that the resource is absent. - A
404fromGET /api/v1/legal_entities/{id}usually means "created outside the API", not "no such entity." Agent Keys can only see API-created records — see Why your call might return empty. - There are no webhooks. Long-running operations (application review, payment processing) must be polled — see Polling, not webhooks.
Capability matrix
What you can do with each credential type, what to call, what scope you need, and the most common dead-end. All paths are relative to the base URL above.
Discovery & registry reads
| I want to… | Call | Credentials | Required scope | Common dead-end |
|---|---|---|---|---|
| Confirm an RPN exists | POST /api/v1/verify_rpn | sk-, ak- | agent:verify_rpn | Rate-limited: 5,000/day, 50/minute per key. |
| Search the registry by name/RPN | POST /api/v1/registries/legal_entities/search | sk-, ak- | agent:registry.search | Empty results ≠ bug. Try fewer words; the server already splits input. |
| Fetch one legal entity by ID | GET /api/v1/legal_entities/{id} | sk-, ak- | agent:entity.read | Agent Keys see only API-created entities. 404 is the most common response for IDs the agent did not itself produce. |
| Fetch entity documents | GET /api/v1/legal_entities/{id}/documents | sk-, ak- | agent:entity.documents.read | Same limitation as above. |
Personal data of the key owner
These endpoints accept Agent Keys and OAuth tokens, but not standard sk- keys.
| I want to read… | Call | Credentials | Required scope |
|---|---|---|---|
| The owner's profile | GET /api/v1/me/natural-person | ak-, OAuth | agent:person.details.read / eprospera:person.details.read |
| The owner's residency status | GET /api/v1/me/natural-person/residency | ak-, OAuth | agent:person.residency.read / eprospera:person.residency.read |
| The owner's ID-verification artifacts | GET /api/v1/me/natural-person/id-verification | ak-, OAuth | agent:person.id_verification.read / eprospera:person.id_verification.read |
Entity formation (writes)
Write scopes require an active signed Manifestation of Will on the key owner's account. Headless incorporation additionally requires the Agreement of Coexistence for the target residency type to be pre-accepted during MoW signing — otherwise the create call returns a nextSteps.signature URL that needs a human browser session.
| I want to… | Call | Credentials | Required scope |
|---|---|---|---|
| List my API-created applications | GET /api/v1/legal_entity_applications | sk-, ak- | agent:entity.application.read |
| Get one application | GET /api/v1/legal_entity_applications/{id} | sk-, ak- | agent:entity.application.read |
| Create an LLC application | POST /api/v1/legal_entity_applications | sk-, ak- | agent:entity.application.create |
| Pay an application with a fully-discount coupon | POST /api/v1/legal_entity_applications/{id}/pay/coupon | sk-, ak- | agent:entity.application.pay |
| Start a hosted Stripe / crypto checkout | POST /api/v1/legal_entity_applications/{id}/checkout_session | sk- only | n/a — temporarily disabled for Agent Keys |
For a copy-paste end-to-end flow, see Recipe 2 — Fully automated LLC incorporation.
OAuth-only: acting on behalf of a user across their entities
Use OAuth (with PKCE) when the calling user has consented to share their entity portfolio — typically a sign-in-with-e-Próspera integration. Agent Keys are not accepted on /me/legal-entities*; calls with an ak- token return 401.
| I want to… | Call | Required scope |
|---|---|---|
| List all entities the user represents | GET /api/v1/me/legal-entities | eprospera:entity.read |
| Fetch one of those entities | GET /api/v1/me/legal-entities/{id} | eprospera:entity.read |
| Fetch its documents | GET /api/v1/me/legal-entities/{id}/documents | eprospera:entity.documents.read |
See the OAuth overview for the authorization-code flow.
Decision tree — pick the right endpoint
Walk this top-down. Stop at the first row that matches your goal.
You have an RPN string and want to know if it is real and active. →
POST /api/v1/verify_rpnwithagent:verify_rpn.You have a human-readable name (or a partial RPN) and want to find the entity. →
POST /api/v1/registries/legal_entities/searchwithagent:registry.search. Ifresultsis empty, broaden the query — do not retry the same input.You have a legal-entity ID that your own agent created earlier. →
GET /api/v1/legal_entities/{id}withagent:entity.read.You have a legal-entity ID that came from outside this API (a human formed it in the portal, or a different account formed it). → Not reachable with an Agent Key. Either ask the entity owner to authenticate via OAuth and call
/api/v1/me/legal-entities/{id}, or have them transfer the formation through the API. Do not retry the Agent Key call — the404will not change.You want data about the human who owns the Agent Key (or the OAuth user). →
GET /api/v1/me/natural-person*with the matchingagent:person.*oreprospera:person.*scope. Standardsk-keys are rejected here.You want a list of all legal entities a user represents (not just API-created ones). → OAuth only.
GET /api/v1/me/legal-entitieswitheprospera:entity.read. An Agent Key on this path returns401.You want to incorporate a new LLC. → See Recipe 2. The prerequisites (MoW + pre-accepted AOC + funding coupon) must be confirmed by the human owner before the agent starts — there is no headless path around them.
You want to know when an application is approved. → Poll
GET /api/v1/legal_entity_applications/{id}— see Polling, not webhooks.
Why your call might return empty
Read this section any time a response is unexpectedly empty, 404, 401, or 403. Most of these are by design, not bugs.
| Symptom | Cause | Fix |
|---|---|---|
GET /legal_entity_applications returns { "data": [] } | Agent Keys see only API-created applications (createdViaAPI: true). Applications started in the portal are invisible. | If the owner started the application in the portal, the agent cannot list it. Restart it through the API, or have the owner finish it in the portal. |
GET /legal_entities/{id} returns 404 | Either the entity does not exist, or it was created outside the API and is invisible to Agent Keys. There is no way to disambiguate. | If you expect the entity to exist, use OAuth and /me/legal-entities/{id} instead. |
GET /me/legal-entities* returns 401 | You sent an Agent Key (ak-...). This route family is OAuth-only. | Switch to an OAuth access token; the user must complete the consent flow first. |
Any endpoint returns 403 | The Agent Key is missing the required scope. It does not mean the resource is missing. | The owner must regenerate the key with the scope (visible in the scope reference). |
POST /legal_entity_applications returns 200 with nextSteps.signature | The Agreement of Coexistence for that residency type was not pre-accepted on the owner's account. | The owner opens that URL once in a browser to sign. After that, future creates of the same residency type are fully headless. |
Any endpoint returns 429 | Per-key rate limit. verify_rpn and registries/legal_entities/search are capped at 50/minute and 5,000/day. | Respect the Retry-After header. Spread bursty work; the limits are per-key, so spinning up more keys does not help. |
Search returns { "results": [] } | Query was too narrow or used punctuation the registry does not index. | Reduce to the most distinctive single word. The server already tokenizes multi-word input on whitespace. |
verify_rpn returns "not_found" | The RPN string is malformed or unknown. | Do not retry the same RPN. Treat as terminal. |
Polling, not webhooks
There are no webhook callbacks today. Two state machines require polling:
| Operation | Endpoint to poll | Suggested cadence | Terminal states |
|---|---|---|---|
| Legal-entity application | GET /api/v1/legal_entity_applications/{id} | Every 30 s, with backoff to 5 min after the first 10 minutes. | Approved (then fetch the new legal_entities/{id}), Rejected. |
| Coupon payment | Same endpoint — the application transitions through Paid once the coupon clears. | Every 10 s for ~1 minute. | Paid (or PaymentFailed). |
Always include a hard timeout in your polling loop (the recipes use 30 minutes) and surface the last response to the human if you exit without a terminal state.
Machine-readable resources
If your agent has fetch capability, ingest these instead of scraping rendered pages:
/llms.txt— short Markdown index of every doc page, per the llms.txt standard./llms-full.txt— every endpoint, scope, request/response shape, and convention concatenated into a single plain-text file. This is the densest single artifact for system-prompt injection./openapi.yaml— OpenAPI 3.1 spec. Use for client generation or schema-driven tool definitions (MCP, function-calling).
Where to go next
- Pick credentials: Agent Keys — what they are, who can issue them, scope reference, limitations.
- Get the shared rules right: Conventions — auth header, response envelopes, error envelope, status codes, timestamps, rate limits.
- Copy a working workflow: Agent recipes — RPN lookup, automated LLC incorporation, resident-paid incorporation, profile reads.
- Long-form incorporation walkthrough: Incorporating an entity.
- Sign in with e-Próspera: OAuth overview.