Skip to content

Agent recipes

End-to-end Agent Key workflows you can copy, paste, and run. Each recipe lists the required scopes, the prerequisites the human owner of the key must satisfy, and the terminal states the agent should watch for.

Base URL throughout: https://portal.eprospera.com. See Conventions for shared rules (auth, errors, timestamps, pagination, rate limits).

Substitutions used below

  • $AK — your Agent Key (ak-...)
  • $BASEhttps://portal.eprospera.com in production, https://staging-portal.eprospera.com in staging

Recipe 1 — RPN lookup → registry search → fetch entity

Resolve a free-text query to a single legal entity, then fetch its full record.

Required scopes: agent:verify_rpn, agent:registry.search, agent:entity.readPrerequisites: Read-only Agent Key. Manifestation of Will is not required. Note: GET /api/v1/legal_entities/{id} only returns entities created via the API (see Agent Keys → Important Limitations).

bash
# 1. If you have an RPN, confirm it exists and is active
curl -s -X POST "$BASE/api/v1/verify_rpn" \
  -H "Authorization: Bearer $AK" \
  -H "Content-Type: application/json" \
  -d '{"rpn": "80000000000012"}'
# → {"result":"found_legal_entity","active":true}

# 2. If you only have a name, search the registry
curl -s -X POST "$BASE/api/v1/registries/legal_entities/search" \
  -H "Authorization: Bearer $AK" \
  -H "Content-Type: application/json" \
  -d '{"query": "Acme Holdings"}'
# → {"results":[{"id":"...","name":"Acme Holdings","extension":"LLC","residentPermitNumber":"80..."}]}

# 3. Fetch the entity by id
curl -s "$BASE/api/v1/legal_entities/<id>" \
  -H "Authorization: Bearer $AK"

Watch for

  • verify_rpn returns "not_found" → the RPN string is malformed or unknown; do not retry.
  • Search returns an empty results array → broaden the query, or split multi-word queries on whitespace (the server already does this for matching).
  • 404 on GET /legal_entities/{id} → either the entity does not exist, or it was created outside the API and is therefore invisible to Agent Keys. There is no way to disambiguate.

Recipe 2 — Fully automated LLC incorporation

Create an LLC application, pay it with a fully-discounting coupon, and pick up the resulting legal-entity record. Zero browser hops.

Required scopes: agent:entity.application.create, agent:entity.application.pay, agent:entity.application.read, agent:entity.readPrerequisites:

  • Active Manifestation of Will signed by the Agent Key owner (required for any write scope).
  • The Agreement of Coexistence for the relevant residency type (Resident or e-Resident LLC) must be pre-accepted during MoW signing. Without this, step 1's response includes a nextSteps.signature URL that requires a human browser session.
  • A coupon code that fully covers the application invoice and is owned by the key owner.
  • The owner is an active e-Resident or Resident.
bash
# 1. Create the application
curl -s -X POST "$BASE/api/v1/legal_entity_applications" \
  -H "Authorization: Bearer $AK" \
  -H "Content-Type: application/json" \
  -d '{
    "applicationData": {
      "residencyType": "e-Resident",
      "entityType": "llc",
      "name": "Acme Robotics",
      "extension": "LLC",
      "principalOffice": {
        "country": "US",
        "line1": "100 Main St",
        "line2": null,
        "city": "Wilmington",
        "state": "DE",
        "postalCode": "19801"
      },
      "contactEmail": "owner@example.com",
      "registeredAgentProvider": "prospera_employment_solutions"
    }
  }'
# → {"data":{"id":"<APP_ID>","statusId":"Draft",...},"nextSteps":{"signature":null}}
#    If "nextSteps.signature" is non-null, the AOC was not pre-accepted — stop and ask the
#    owner to accept the AOC in Developer settings, then retry from step 1.

# 2. Apply the coupon to fully pay the invoice
curl -s -X POST "$BASE/api/v1/legal_entity_applications/<APP_ID>/pay/coupon" \
  -H "Authorization: Bearer $AK" \
  -H "Content-Type: application/json" \
  -d '{"couponCode": "FOUNDER100"}'
# → {"success":true,"data":{"statusId":"Pending Review",...}}

# 3. Poll for approval (every 30s, with backoff)
curl -s "$BASE/api/v1/legal_entity_applications/<APP_ID>" \
  -H "Authorization: Bearer $AK"
# → watch data.statusId for "Approved" (terminal) or "Rejected" (terminal)

# 4. Fetch the resulting legal-entity record
curl -s "$BASE/api/v1/legal_entities/<legalEntityId from step 3>" \
  -H "Authorization: Bearer $AK"

Terminal application states: Approved (success — data.legalEntityId is populated) and Rejected (failure — inspect the application in the portal for review notes).

Watch for

  • 400 on step 1 with details → schema validation failed; fix and retry.
  • 409 on step 1 → entity name collides with an existing entity of the same type; pick a new name.
  • 400 on step 2 with application is not in Draft status → it was already paid or already submitted.
  • 500 on step 2 mentioning coupon → coupon is missing, expired, or under-funds the invoice. The owner is notified by email automatically.
  • 403 on any step → the Agent Key is missing the required scope, or the MoW was revoked (which auto-revokes write-capable keys).

Recipe 3 — Hosted-checkout incorporation

Same as Recipe 2 but the agent owner pays interactively in a browser instead of with a coupon.

Required scopes: agent:entity.application.create, agent:payment.initiate, agent:entity.application.read, agent:entity.readPrerequisites: All of Recipe 2 except the coupon. AOC pre-acceptance still required for the application to auto-submit after payment.

bash
# 1. Create the application (same as Recipe 2 step 1)

# 2. Create a checkout session and hand the URL to the owner
curl -s -X POST "$BASE/api/v1/legal_entity_applications/<APP_ID>/checkout_session" \
  -H "Authorization: Bearer $AK" \
  -H "Content-Type: application/json" \
  -d '{
    "paymentProvider": "stripe",
    "redirectUrl": "https://your-app.example/post-checkout",
    "email": "owner@example.com"
  }'
# → {"data":{"url":"https://checkout.stripe.com/..."},"invoiceId":"<INVOICE_ID>"}

# 3. Owner completes payment in the browser. After return, poll the application:
curl -s "$BASE/api/v1/legal_entity_applications/<APP_ID>" \
  -H "Authorization: Bearer $AK"

# 4. Fetch the legal-entity record once approved (same as Recipe 2 step 4).

Supported paymentProvider values: stripe, stripe-crypto, lnbits, solana-pay-ptc.

Watch for

  • 400 with application is not in Draft status → already paid; skip to polling.
  • redirectUrl must be a valid absolute URL — it is required by the payment providers.

Recipe 4 — Read account holder profile

Fetch the human owner's identity, residency status, and (if available) ID-verification artifacts. Useful for KYC review, compliance summaries, or pre-filling forms on the agent owner's behalf.

Required scopes: agent:person.details.read, agent:person.residency.read, agent:person.id_verification.readPrerequisites: Read-only Agent Key. MoW not required.

bash
# 1. Personal details
curl -s "$BASE/api/v1/me/natural-person" \
  -H "Authorization: Bearer $AK"

# 2. Residency status
curl -s "$BASE/api/v1/me/natural-person/residency" \
  -H "Authorization: Bearer $AK"

# 3. ID verification (signed URLs valid for ~1 hour — download promptly)
curl -s "$BASE/api/v1/me/natural-person/id-verification" \
  -H "Authorization: Bearer $AK"

Watch for

  • /api/v1/me/natural-person returning null → the owner has no approved residency yet, so there is no natural-person record to read.
  • /residency returning activeResidency: null with wasEverResident: true → the owner is a former resident; treat as inactive.
  • /id-verification returning all-null document URLs → the owner has not completed ID verification.
  • These endpoints accept OAuth tokens and Agent Keys — but not standard sk- keys.

Polling guidance

For Recipes 2 and 3, poll GET /api/v1/legal_entity_applications/{id} every 30 seconds for the first 2 minutes, then back off to every 5 minutes. There are no webhooks today (see Conventions → Webhooks). Approved and Rejected are terminal — stop polling.

Common errors quick-reference

StatusLikely cause
400Request body fails Zod validation (details lists offending paths) or state precondition fail.
401Missing/invalid Authorization header, or the Agent Key was revoked.
403The Agent Key lacks a required scope, or the MoW was revoked (auto-revoking write-capable keys).
404Resource does not exist or is invisible to your Agent Key (e.g. entity was created outside the API).
409Entity name conflict on POST /legal_entity_applications.
429Rate limit exceeded on verify_rpn / registries/.../search (5,000/day, 50/minute per key).
500Server error. Retry with exponential back-off only for idempotent (read) operations.