# Standard API Keys (/standard-keys)

Standard API keys (`sk-`) are the first-party credential for your own backend, CLI, and personal automation. They are unscoped: they act as you on every standard-key route, including registry lookups, owned entity records, incorporation, hosted checkout, and referral attribution.



## Base URL [#base-url]

| Environment | Origin                                 |
| ----------- | -------------------------------------- |
| Production  | `https://portal.eprospera.com`         |
| Staging     | `https://staging-portal.eprospera.com` |

All endpoint paths in this document are relative to that origin. The API ships from the same host as the consumer portal — there is no separate `api.eprospera.com`.

## TL;DR [#tldr]

* Create a key in [Developer → API keys](https://portal.eprospera.com/developer/api-keys). The raw `sk-...` value is shown **once**.
* Send it as `Authorization: Bearer sk-...` on every request, or store it for the [official CLI](/cli).
* Standard keys are **not scoped**. They can call every standard-key route as the account owner. Do not share them with an agent or third party — use an [Agent Key](/agent-keys) (`ak-`) for that.
* Writes do **not** require a Manifestation of Will. The Agreement of Coexistence still needs a browser signature unless you switch to an Agent Key with a pre-accepted AOC.
* Voucher payment and hosted checkout only work on **API-created Draft** applications. You can still *list* portal-created applications.
* Shared rules (errors, status codes, timestamps, rate limits, pagination) are documented once in [Conventions](/conventions).
* CLI source repository: [Honduras-Prospera-inc/eprospera-cli](https://github.com/Honduras-Prospera-inc/eprospera-cli).

## What Standard API Keys Are [#what-standard-api-keys-are]

A standard API key is the personal, first-party credential for the account that created it. It is the default key type in Developer settings.

| Credential                   | Prefix | Who issues it                          | Scoped?                          | Typical caller                                    |
| ---------------------------- | ------ | -------------------------------------- | -------------------------------- | ------------------------------------------------- |
| **Standard API key**         | `sk-`  | Account owner in Developer settings    | No — full first-party API access | Your backend, CLI, and personal automation        |
| [Agent Key](/agent-keys)     | `ak-`  | Account owner, with explicit scopes    | Yes — per-request scope check    | An AI agent or service the owner has delegated to |
| [Partner Key](/partner-keys) | `pk-`  | e-Próspera admins, for one integration | Yes — partner residency scopes   | An approved organization onboarding applicants    |
| [OAuth](/oauth-overview)     | JWT    | Authorization server after consent     | Yes — consented OAuth scopes     | A signed-in user in your app or the official CLI  |

Standard keys are additive with Agent Keys. Creating an `ak-` key does not change what an `sk-` key can do.

## Who Can Create Them [#who-can-create-them]

Only the signed-in account owner can create a standard API key.

* Open [Developer → API keys](https://portal.eprospera.com/developer/api-keys)
* Give the key a label (1–50 characters)
* Optionally list **allowed checkout origins** (comma-separated origins such as `https://app.example.com`) if you will create hosted checkout sessions. Origins must be HTTPS (HTTP is allowed only for loopback in staging/dev), with no path, query, fragment, or credentials. At most 10 origins.
* Copy the `sk-...` value immediately — e-Próspera stores only a SHA-256 hash and a short prefix (`sk-` plus four characters)
* Delete the key in the same settings page to revoke it immediately

Standard keys do **not** expire on a timer. Partner Keys expire after 90 days; standard keys stay valid until you delete them.

## Authentication [#authentication]

With the CLI, pass the key once per command or store it locally:

```bash
export EPROSPERA_API_KEY="sk-..."
eprospera --json entity verify 80000000000012

eprospera --api-key "$EPROSPERA_API_KEY" auth login --standard-key
eprospera --json auth whoami
```

With direct HTTP:

```text
Authorization: Bearer sk-...
```

There is no scope header and no Manifestation of Will. If the key is valid, the request is authorized as the owner. A missing or unknown key returns `401`. Partner Keys (`pk-`) are not accepted on these routes. An Agent Key on a standard-key-only route such as referrals returns `403`; hosted checkout currently returns `503` for Agent Keys.

## CLI With a Standard Key [#cli-with-a-standard-key]

Install once, then prefer JSON output for anything you will parse:

```bash
npm install -g @prospera/eprospera-cli
eprospera --help
eprospera schema
```

| Flag / env                  | What it does                                                                                     |
| --------------------------- | ------------------------------------------------------------------------------------------------ |
| `--api-key sk-...`          | Override the resolved credential for one command                                                 |
| `EPROSPERA_API_KEY`         | Default credential when `--api-key` is omitted                                                   |
| `auth login --standard-key` | Store the `sk-` key for later commands                                                           |
| `--json`                    | Machine-readable JSON on stdout; diagnostics on stderr                                           |
| `--raw`                     | Compact single-line JSON                                                                         |
| `--fields id,statusId,name` | Trim a read response to selected top-level fields                                                |
| `--yes`                     | Skip confirmation prompts on write commands                                                      |
| `--dry-run`                 | Validate locally and print the request that would be sent (use this before `application create`) |
| `EPROSPERA_ENV=staging`     | Point the CLI at `https://staging-portal.eprospera.com`                                          |
| `EPROSPERA_BASE_URL`        | Override the API origin for a trusted endpoint                                                   |

Useful inspection commands that work with a stored standard key:

```bash
eprospera --json auth whoami
eprospera --json config list
eprospera schema
```

Visitor-pass submission is a **public** CLI/API flow and does **not** use the key. See [event visitor passes](/use-cases/event-visitor-passes) and `eprospera --json --yes visitor-pass create`.

## What Information You Can Pull [#what-information-you-can-pull]

This is the first-party read surface. Standard keys never return another person's profile, residency, ID-verification artifacts, or tax records.

Response envelopes differ by endpoint: verify returns a flat `{ "result", "active" }` object, search returns `{ "results": [...] }`, and the rest wrap a single resource or array in `{ "data": ... }`. See [Conventions](/conventions#response-envelopes).

### Public registry lookups [#public-registry-lookups]

These two endpoints look up **any** known RPN or registered legal entity. They do not require that you represent the subject. Search is a case-insensitive name match and a partial RPN match. The `query` string must be 1–100 characters after trim.

| CLI command                         | Direct endpoint                                 | What comes back                                                                                |
| ----------------------------------- | ----------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `eprospera entity verify <rpn>`     | `POST /api/v1/verify_rpn`                       | `result` (`found_legal_entity`, `found_natural_person`, or `not_found`) and `active` (boolean) |
| `eprospera entity search "<query>"` | `POST /api/v1/registries/legal_entities/search` | Matching entities: `id`, `name`, `extension`, `residentPermitNumber` (`null` until assigned)   |

RPNs are 14-digit numeric strings: legal entities start with `8`, natural persons with `9`. `verify_rpn` does **not** return a name, UUID, address, or documents — only whether the RPN exists and whether that residency is currently active. Use search when you need an entity UUID.

Both endpoints are rate-limited to **5,000 requests / 24 h** and **50 / minute** per API key. Other standard-key routes have no documented limit today.

### Legal entities you represent [#legal-entities-you-represent]

Once you have an entity UUID, you can read the full record and its public documents **only if you are a current representative**. Unlike Agent Keys, this includes entities formed in the portal, not only records created through the API.

| CLI command                       | Direct endpoint                             | What comes back                                                                                                                                                                                 |
| --------------------------------- | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `eprospera entity get <id>`       | `GET /api/v1/legal_entities/{id}`           | `id`, `optionId`, `type`, `name`, `extension`, `nameStartsWithExtension`, `formationDate`, `createdAt`, `principalOfficeAddress`, `registrationDate`, `dissolutionDate`, `residentPermitNumber` |
| `eprospera entity documents <id>` | `GET /api/v1/legal_entities/{id}/documents` | Non-admin documents: `id`, `name`, `createdAt`, `slug`, `version`, `fileUrl`                                                                                                                    |

`principalOfficeAddress` is an address object (`line1`, optional `line2`, `city`, optional `state`, `postalCode`, `country`) or `null`. Dates are ISO 8601 UTC strings, or `null` when unknown. Document `fileUrl` can be `null`; `slug` and `version` are optional.

A `404` means the entity does not exist **or** you are not a representative — the two are indistinguishable. There is no `GET /api/v1/legal_entities` list endpoint.

### Entity applications you own [#entity-applications-you-own]

Standard keys list and read **every** legal-entity application on the account, including drafts created in the portal. Agent Keys only see applications with `createdViaAPI: true`.

| CLI command                      | Direct endpoint                              | What comes back             |
| -------------------------------- | -------------------------------------------- | --------------------------- |
| `eprospera application list`     | `GET /api/v1/legal_entity_applications`      | Array of owned applications |
| `eprospera application get <id>` | `GET /api/v1/legal_entity_applications/{id}` | One application             |

Each application object includes:

| Field                | Meaning                                               |
| -------------------- | ----------------------------------------------------- |
| `id`                 | Application UUID                                      |
| `statusId`           | `Draft`, `Pending Review`, `Approved`, or `Rejected`  |
| `applicationData`    | Submitted entity application payload                  |
| `applicationVersion` | Application version string                            |
| `createdAt`          | When the application was created                      |
| `submittedAt`        | When it left Draft, or `null`                         |
| `approvedAt`         | Approval timestamp, or `null`                         |
| `rejectedAt`         | Rejection timestamp, or `null`                        |
| `legalEntityId`      | Resulting legal-entity UUID after approval, or `null` |

There is currently no pagination — the full list is returned under `data`.

Listing a portal-created application does **not** mean you can pay it through the API. Voucher payment and hosted checkout reject applications that were not created via `POST /api/v1/legal_entity_applications`.

### Catalyst referrals you own [#catalyst-referrals-you-own]

Referral attribution is **standard-key only**. Agent Keys cannot call this route.

| CLI command                      | Direct endpoint                               | What comes back                                                                                                      |
| -------------------------------- | --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `eprospera referral list <code>` | `GET /api/v1/referral-codes/{code}/referrals` | `code`, referred `naturalPersons` (`fullName`, `referredAt`), referred `legalEntities` (`name`, `rpn`, `referredAt`) |

You can only query a code that belongs to you (your personal code, or a code owned by an entity you represent). `fullName` is `null` until the referred person has applied or been approved. Legal-entity `referredAt` can be `null`. The response reports attribution only — not invoice or discount state. See [Catalyst Program](/catalyst-program).

### What a standard key cannot read [#what-a-standard-key-cannot-read]

| Data                                              | Use instead                                                                         |
| ------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Your profile, address, phone, date of birth       | [Agent Key](/agent-keys) or [OAuth](/oauth-overview) on `/api/v1/me/natural-person` |
| Your residency status and type                    | Agent Key or OAuth on `/api/v1/me/natural-person/residency`                         |
| ID-verification documents and selfie              | Agent Key or OAuth on `/api/v1/me/natural-person/id-verification`                   |
| Consented legal entities of a signed-in user      | OAuth on `/api/v1/me/legal-entities*`                                               |
| Personal or entity tax filings                    | OAuth — [Tax and legal-entity data](/tax-and-entity-data)                           |
| Another organization's residency applications     | [Partner Key](/partner-keys)                                                        |
| Another person's personal data without delegation | Agent Key issued by that person, or OAuth consent                                   |

## Create, Pay, and Watch [#create-pay-and-watch]

The full tutorial is [Incorporating an entity](/incorporating-entity). This section is the standard-key contract.

The key owner must be an active `e-Resident` or `Resident`. `POST /api/v1/legal_entity_applications` is **not** idempotent — retrying can create a duplicate Draft. Validate locally first:

```bash
eprospera --json --dry-run application create --file application.json
eprospera --json --yes application create --file application.json
```

### Create request [#create-request]

| Field                                     | Required | Notes                                                                                                                                                     |
| ----------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `applicationData.residencyType`           | yes      | `e-Resident` or `Resident`                                                                                                                                |
| `applicationData.entityType`              | yes      | `llc` only today                                                                                                                                          |
| `applicationData.name`                    | yes      | Unique per LLC name, case-insensitive. Different extension spellings count as the same entity.                                                            |
| `applicationData.extension`               | yes      | `LLC`, `L.L.C.`, `Limited Liability Company`, `S. de R.L.`, `SRL`, `Limited Company`, `L.C.`, `LC`, `Limited Liability Co.`, `Limited Co.`, or `Ltd. Co.` |
| `applicationData.principalOffice`         | yes      | Address: `line1`, `city`, `postalCode`, `country`; optional `line2` and `state`                                                                           |
| `applicationData.contactEmail`            | yes      | Email                                                                                                                                                     |
| `applicationData.registeredAgentProvider` | one of   | `prospera_employment_solutions`, **or** `null` if you send custom details                                                                                 |
| `applicationData.registeredAgentDetails`  | one of   | Custom agent: `attn`, `residentPermitNumber` (active resident), `officeAddress`, `mailingAddress`                                                         |
| `applicationData.analytics`               | no       | String-to-string map                                                                                                                                      |
| `referralCode`                            | no       | Catalyst attribution. Self-referral is skipped unless an admin enabled it.                                                                                |
| `redirectUrl`                             | no       | Where the signer is sent after the Agreement of Coexistence page                                                                                          |

Provide **exactly one** registered-agent mode: `registeredAgentProvider` **or** `registeredAgentDetails`, not both and not neither.

### Create response [#create-response]

The body is `{ "data": { …application }, "nextSteps": { "signature": "<url-or-null>" } }`.

For a standard key, `nextSteps.signature` is the portal URL where the owner signs the Agreement of Coexistence. Standard keys do not carry a Manifestation of Will, so they cannot skip this browser step. Payment and signature can happen in either order; the application leaves `Draft` only after **both** are complete.

### Pay with a voucher [#pay-with-a-voucher]

```bash
eprospera --json --yes application pay <id> --voucher FOUNDER100
```

```bash
curl -X POST https://portal.eprospera.com/api/v1/legal_entity_applications/<id>/pay/voucher \
  -H "Authorization: Bearer sk-..." \
  -H "Content-Type: application/json" \
  -d '{"voucherCode": "FOUNDER100"}'
```

The voucher must fully cover the invoice. The application must be a **Draft created through the API**. If the AOC is already signed, payment also submits. If it is not signed yet, the endpoint still succeeds with `statusId: "Draft"` and a reminder `message`. Envelope: `{ "success": true, "data": { … }, "message": "..." }`.

In staging, the reusable test voucher is `API1234`. It applies to every product and unpaid invoice, not only entity incorporation. See [Testing in staging](/testing-in-staging).

The deprecated alias `POST /api/v1/legal_entity_applications/{id}/pay/coupon` accepts `{ "couponCode": "..." }`; use the voucher path instead.

### Hosted checkout (`sk-` only) [#hosted-checkout-sk--only]

Agent Keys cannot create checkout sessions (they currently get `503`). With a standard key:

```bash
eprospera --json --yes application checkout <application-id> \
  --redirect-url https://example.com/return \
  --provider stripe
```

```json
{
  "paymentProvider": "stripe",
  "redirectUrl": "https://example.com/return",
  "email": "contact@example.com"
}
```

Send **exactly one** of `paymentProvider` or `paymentMethod`. Supported `paymentProvider` values: `stripe`, `stripe-crypto`, `blink`, `blink-onchain`, `solana-pay-ptc`. `email` is optional. `redirectUrl` is required and its **origin** must be on the key's allowed checkout origins.

The application must be an API-created Draft with an unpaid open invoice. Response: `{ "data": { /* provider payload */ }, "invoiceId": "<uuid>" }`. Send the user to the returned checkout URL, then poll.

In staging, complete Stripe checkout with card `ACCT-000015` (any future expiry, any CVC and ZIP). See [Testing in staging](/testing-in-staging).

See [hosted checkout](/reference/post-legal-entity-applications-id-checkout-session).

### Watch until a terminal status [#watch-until-a-terminal-status]

There are no public webhooks. Prefer the CLI watcher, or poll `GET /api/v1/legal_entity_applications/{id}` every 30 seconds for the first 2 minutes, then every 5 minutes.

```bash
eprospera --json application watch <id> --timeout 30m
```

`Approved` and `Rejected` are the only terminal `statusId` values. After `Approved`, `legalEntityId` is set — fetch the entity and its documents.

A declined or abandoned checkout does **not** add a payment-failure `statusId`; the application stays `Draft`. Stop polling, then retry payment or apply a voucher. The CLI watcher exits `10` for that case.

## Supported Commands And Endpoints [#supported-commands-and-endpoints]

### Reads [#reads]

| CLI command                         | Direct endpoint                                 | Notes                                            |
| ----------------------------------- | ----------------------------------------------- | ------------------------------------------------ |
| `eprospera entity verify <rpn>`     | `POST /api/v1/verify_rpn`                       | Any RPN                                          |
| `eprospera entity search "<query>"` | `POST /api/v1/registries/legal_entities/search` | Public registry; query max 100 characters        |
| `eprospera entity get <id>`         | `GET /api/v1/legal_entities/{id}`               | Entities you represent, including portal-created |
| `eprospera entity documents <id>`   | `GET /api/v1/legal_entities/{id}/documents`     | Same visibility as `entity get`                  |
| `eprospera application list`        | `GET /api/v1/legal_entity_applications`         | All owned applications                           |
| `eprospera application get <id>`    | `GET /api/v1/legal_entity_applications/{id}`    | All owned applications                           |
| `eprospera application watch <id>`  | `GET /api/v1/legal_entity_applications/{id}`    | Polls until a terminal status                    |
| `eprospera referral list <code>`    | `GET /api/v1/referral-codes/{code}/referrals`   | Standard-key only                                |
| `eprospera auth whoami`             | —                                               | Inspect the stored credential                    |

### Writes [#writes]

| CLI command                                                                        | Direct endpoint                                                | Notes                                                               |
| ---------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------- |
| `eprospera --yes application create --file application.json`                       | `POST /api/v1/legal_entity_applications`                       | Owner must be an active Resident or e-Resident; not idempotent      |
| `eprospera --yes application pay <id> --voucher <code>`                            | `POST /api/v1/legal_entity_applications/{id}/pay/voucher`      | API-created Draft; voucher must fully cover the invoice             |
| `eprospera --yes application checkout <id> --redirect-url <url> --provider <name>` | `POST /api/v1/legal_entity_applications/{id}/checkout_session` | Standard-key only; API-created Draft; origin allowlisted on the key |

## Important Limitations [#important-limitations]

* `/api/v1/me/*` does **not** accept standard API keys — including profile, residency, ID verification, consented entities, and tax
* There is no `/api/v1/legal_entities` list endpoint; resolve UUIDs through registry search or from applications you own
* `GET /api/v1/legal_entities/{id}` only returns entities you currently represent
* Voucher payment and hosted checkout cannot be used on portal-created applications
* Partner residency routes (`/api/v1/partner/*`) reject `sk-` keys
* Visitor-pass submission is public and does not use a key
* Standard-key requests are **not** written to the Agent Key audit log and do **not** email the owner on writes
* Treat the key like a password: store it server-side or in a secret manager, never in a browser, repo, or chat

## Common Errors [#common-errors]

| Status | Typical `error`                                                       | Meaning                                                           |
| ------ | --------------------------------------------------------------------- | ----------------------------------------------------------------- |
| `400`  | `Invalid request body`                                                | Payload does not match the schema                                 |
| `400`  | `Either registeredAgentProvider or registeredAgentDetails...`         | Provide exactly one registered-agent mode                         |
| `400`  | `Legal entity application is not in draft status`                     | Pay/checkout only work while the application is a Draft           |
| `400`  | `This endpoint can only be used for API-created applications`         | Pay/checkout are limited to applications created through this API |
| `400`  | `redirectUrl origin is not allowed for this API key`                  | Add the checkout origin when creating the key                     |
| `400`  | `Legal entity application invoice is already paid`                    | Do not create another checkout session                            |
| `401`  | `Missing API key` / `Invalid API key`                                 | Missing, malformed, or unknown `sk-` credential                   |
| `403`  | `You must be an active resident to create a legal entity application` | The key owner is not an active `e-Resident` or `Resident`         |
| `403`  | `API key type is not allowed on this endpoint`                        | You sent an `ak-` key to a standard-key-only route                |
| `404`  | `Legal entity not found` / `Legal entity application not found`       | Missing, or not visible to this account                           |
| `409`  | `An LLC with the name ... already exists`                             | Choose a different entity name                                    |
| `429`  | —                                                                     | `verify_rpn` or registry search rate limit; back off              |

CLI exit codes for the same failures are documented in [CLI → Exit Codes](/cli#exit-codes) (`3` auth, `4` authorization, `5` not found, `6` conflict, `7` rate limit, `8` validation).

## Recommended Usage Pattern [#recommended-usage-pattern]

Use:

* **Standard API keys (`sk-`)** for your own backend, CLI, hosted checkout, referrals, and personal automation
* **Agent Keys (`ak-`)** when an e-resident is delegating narrowly scoped access to an AI agent or third-party service
* **Partner Keys (`pk-`)** when an approved organization is onboarding natural-person applicants
* **OAuth** when your integration needs interactive user consent, identity login, or tax data
* **The CLI** when a shell command is acceptable and you want JSON output, local validation, polling, and stable exit codes
* **Direct HTTP** when you are building a custom client or need an endpoint the CLI does not cover

## Example [#example]

```bash
eprospera --api-key "sk-REDACTED" --json entity verify 80000000000012
eprospera --api-key "sk-REDACTED" --json entity search 80000000000012
eprospera --api-key "sk-REDACTED" --json entity get <id>
```

The equivalent direct HTTP requests are:

```bash
curl -X POST https://portal.eprospera.com/api/v1/verify_rpn \
  -H "Authorization: Bearer sk-REDACTED" \
  -H "Content-Type: application/json" \
  -d '{"rpn": "80000000000012"}'

curl -X POST https://portal.eprospera.com/api/v1/registries/legal_entities/search \
  -H "Authorization: Bearer sk-REDACTED" \
  -H "Content-Type: application/json" \
  -d '{"query": "80000000000012"}'

curl https://portal.eprospera.com/api/v1/legal_entities/<id> \
  -H "Authorization: Bearer sk-REDACTED"
```

## Reference [#reference]

* [POST verify\_rpn](/reference/post-verify-rpn)
* [POST registries/legal\_entities/search](/reference/post-search-entities)
* [GET legal\_entities/\{id}](/reference/get-legal-entities-id)
* [GET legal\_entities/\{id}/documents](/reference/get-legal-entities-id-documents)
* [GET legal\_entity\_applications](/reference/get-legal-entity-applications)
* [POST legal\_entity\_applications](/reference/post-legal-entity-applications)
* [GET legal\_entity\_applications/\{id}](/reference/get-legal-entity-applications-id)
* [POST …/pay/voucher](/reference/post-legal-entity-applications-id-pay-voucher)
* [POST …/checkout\_session](/reference/post-legal-entity-applications-id-checkout-session)
* [GET referral-codes/\{code}/referrals](/reference/get-referral-codes-code-referrals)
* [Incorporating an entity](/incorporating-entity)
* [CLI](/cli)
* [Testing in staging](/testing-in-staging)
