# ORION IDC Operations API v1

Base: `https://hlncorp.space/api/v1/idc`. This service belongs to ORION/HLN. It is separate from the Apex StarComm Dispatch API.

**HorizonOS is not required.** ORION runs the brokerage, financial review and Group operations workflows itself. This API is available for optional external adapters; it does not imply that HorizonOS currently provides contracts, bids, delivery records or Dispatch. Raw game logs are not an integration requirement. Public Apex Atlas/Alerts reads and any future private Apex integration are separate from HorizonOS.

## Register and delegate

1. Generate an Ed25519 key pair on the integrating server. Export only its public JWK (`kty: OKP`, `crv: Ed25519`, `x`). Keep the private key in the server secret store.
2. A Corporate personnel administrator opens **IDC Brokerage → Access & integrations → Register a client**, selects the active registered organization, public JWK, approved scopes and expiry. Registration creates no accounts, memberships or financial instructions.
3. An authorized organization signatory signs in through UCI, opens the same page, chooses the registered client and Civitas institution, and delegates only required scopes for up to 90 days. Copy that delegation ID to the integrating server. Its organization must match the client registration.
4. Sign every request. Registrations and delegations can be revoked in the same page. Current personnel status, organization membership and financial signatory authority are checked on every call. A delegation cannot increase the person's existing rights.

## Scopes

| Scope | Allowed operations |
| --- | --- |
| `contracts.read` | Read visible organization requests and contracts. Open tender briefs are available to admitted providers. No private competing bids or account balances. |
| `tenders.write` | Create an organization draft, edit an unpublished draft, publish or cancel an unfunded request. |
| `bids.write` | Submit/update or withdraw the organization's bid. |
| `deliveries.write` | Submit the contracted organization's delivery report. A report does not authorize settlement. |
| `records.write` | Attach a fresh organization-attested source reference from an authenticated ORION/partner server. This is evidence, not automatic proof of delivery. |
| `events.read` | Poll durable organization events with a persisted event cursor. |

No external scope permits selecting or awarding a bid, approving funding, funding escrow, accepting delivery, settling, resolving a dispute, appointing officers or accessing another organization's private records. Those actions remain in the authenticated workspace with the existing independent approvals.

## Signing

Headers: `X-Orion-Client`, `X-Orion-Delegation`, `X-Orion-Timestamp` (ISO UTC), `X-Orion-Nonce` (fresh UUID), `X-Orion-Signature` (unpadded base64url Ed25519 signature).

Sign UTF-8 lines joined with LF, without a final newline:

```
ORION-IDC-1
METHOD
/api/v1/idc?exact=query&in=original-order
ISO-UTC-TIMESTAMP
NONCE-UUID
DELEGATION-UUID
LOWERCASE-SHA256-OF-EXACT-UTF8-BODY
```

GET signs an empty body. Timestamp tolerance is 120 seconds. A nonce is unique per client. Redirects must not be followed. Request bodies are limited to 40 KB. The supplied Node client implements this format.

## Read and paginate

`GET ?view=contracts&after=UUID` returns `{items, nextCursor}` (50 items maximum). UUID order is stable; use `contract` and events for changes rather than treating the list cursor as a change feed.

`GET ?view=contract&tender=UUID` returns the authorized request, current revision and contract summary. Missing/unknown references never expose a different party's account.

`GET ?view=events&after=INTEGER` returns `{items, nextCursor}` (100 maximum). Save the cursor after successfully handling the batch; deduplicate by event `id`. Events and financial instructions are committed in the same database transaction. Polling is the supported delivery transport; an email, Discord post or browser notification is not a settlement queue. Initial adoption should list contracts, then replay the event feed from cursor 0; deduplication makes that overlap safe.

## Commands and retries

POST `{key: UUID, action: string, data: object}`. `key` is the durable business instruction ID. Generate and save it **before** sending. After a timeout or 5xx, reuse the same key and unchanged body, with a new signed timestamp and nonce. Reusing a key for different content is rejected. The client does not silently retry mutations.

Every mutation of an existing request needs `tender` and its current `revision`. A 409 requires refreshing and reviewing the record; do not overwrite a competing edit. Successful commands return `{accepted: true, instructionId, tenderId}`. Use the returned tenderId to fetch the created or changed request and obtain its new revision.

`tender_create`: `institution`, `fund`, `title` (4–160), `service` (`ESCORT`, `FREIGHT`, `RECON`, `RECOVERY`, `INDUSTRY`, `RESCUE`), `brief` (20–8000), `budget` (integer minor HCC, 100–100000000000), `origin`, `destination`, `system` (Atlas codes or empty), `deadline` and `due` (ISO UTC). Institution must be the delegated organization. Due must follow the future bid deadline before publishing.

`edit_draft`: same content plus `tender`, `revision`; funding organization stays fixed and `fund` is omitted. `publish` / `cancel`: `tender`, `revision`.

`bid`: `tender`, `revision`, `provider`, `price` (minor HCC, within budget), `terms` (20–8000), `validUntil` (after bid deadline). `withdraw_bid`: `tender`, `revision`, `bid`.

`deliver`: `tender`, `revision`, `summary` (20–8000), `reference` (4–200). Provider must be the accepted contracted organization.

`attest_link`: `tender`, `revision`, `tenant` (the registered source tenant slug), `kind` (`DISPATCH`, `CONVOY`, `MATERIALS`, `MISSION`, `RECEIPT`), `source` (UUID), `state` (1–60), `digest` (SHA256 of the source's deliberately shared projection), `observedAt` (UTC, within five minutes), `actorSubject` (authenticated local user's UCI subject; must equal the delegation holder). The integrating server must check local OPE and source access before signing. Do not send exact crew positions, medical details or private dispatch threads. Observations remain immutable and never release funds.

## Errors and limits

Errors use `application/problem+json` with status and detail. 401: invalid signature/timestamp; 403: revoked/expired client or delegation, scope or current authority; 409: stale revision, reused instruction or nonce, business-state conflict; 429: 120 admitted requests/client/minute, honor `Retry-After`; 503: temporary service failure. Do not log private keys, signatures or full contract bodies. GET and POST responses are private and must not be shared-cached.

## Separate Apex services

Public Apex Atlas and Alerts can be consumed independently. Private Apex crew routes require a player-specific UCI token whose audience is `https://apexstarcomm.space`, plus the operator's current responder/dispatcher grant and manually registered client. An ORION token or this IDC signing key is not an Apex token. Third-party beacon creation is not offered by the documented crew API. ORION does not publish emergency alerts or fabricate private Dispatch access.

ORION does not need a HorizonOS client or private Apex registration to run IDC. If a private Apex crew connection is separately requested, confirm registration, scopes and redirect URLs with the Apex operator. This guide does not assign that work to Panasync or imply that HorizonOS owns Apex's crew workflows.

## ORION integration references

See [Full ORION OS API guide](ORION-OS-API-Guide.md) and [Panasync handover](Panasync-Handover.md). The former includes the complete supported App SDK methods, file formats, lifecycle, package submission and external integration boundaries.

For the native ORION bridge, configure the server-only `ORION_IDC_CLIENTS` map per tenant with `{clientId,privateKey}`. Do not include these values in a browser or submission package. Client source tenants are explicit: Corp organization `hln` normally maps to `hln-corp`, `hln-group` to `hln`, and SATO to `sato`. Each source attestation must use the registration's source tenant and the actual delegation holder's UCI subject. No API keys or registrations are preinstalled.

Current event payloads contain `id`, `type`, `tenderId`, `occurredAt`; clients must tolerate new event types. Poll with jitter rather than spinning on an unchanged cursor. The caller must obtain current institution/fund/provider identifiers through its authorized operator setup; this API deliberately does not expose bank directory or balance enumeration.

## Calendar contract

Member-facing dates use the same calendar day with the real year plus 930 (20 October 2026 displays as 20 October 2956). Date-entry controls label the in-game calendar and convert once on submission. Store timestamps, signatures, expiry comparisons and API date-time fields in real UTC; never send a year-2956 timestamp to an API that expects real UTC. The public feed exposes the separate `settingYear` for presentation. Relative durations are unchanged.
