# Fjf2or partner API — offline contract

Version: partner-preview-1, 10 October 2026. **No public HTTP server, deployed base URL or production approval.** `openapi.json` is a draft description of prospective HTTP mappings; its `servers` list is empty. The actual implementation is the existing in-process `analysis/auto-creator-api.js`. This page is a static presentation and never calls that module.

## Existing implementation and boundaries

The existing adapter uses `pilot-launch.build` and `launch-policy`. It accepts only public creator/mint/name/symbol/uri fields. Fjf2or, MSTRx, curve rule and fee recipients are fixed; there is no client-selected arbitrary platform_config in this API. An integrator evaluates Fjf2or as a separate preset, not as a substitution for another platform's configuration.

The local handler contract is:

```js
const {createOfflineApi} = require('../auto-creator-api');
const handle = createOfflineApi();
const profile = await handle({method: 'GET', path: '/v1/platform'});
// No listener, RPC or wallet operation is invoked by this profile call.
```

Relative import above assumes a Node script in analysis/partner-demo; it is documentation, not a browser script. **Do not invoke launch/build in an unrestricted export script:** the existing canonical builder's dependency chain imports rpc-readonly, which loads the project's RPC environment file. This demo deliberately consumes the already archived public fixture and does not import that chain or read secrets. Production modules remain unchanged.

## Routes

### GET /v1/platform — anonymous profile

In-process request: `{method:'GET', path:'/v1/platform'}`.

Selected response fields (abridged):

```json
{
  "status": 200,
  "body": {
    "mode": "OFFLINE_PROTOTYPE",
    "platform": "Fjf2orw2gsxoX7wW498JorwPomz2S1EBBG5mngdeMr2C",
    "feeWallet": "AshmihxhhEhCZgmbbwvVJN537nLoZAxc76pBDiXLjHhR",
    "withdrawAuthority": "AshmihxhhEhCZgmbbwvVJN537nLoZAxc76pBDiXLjHhR",
    "termsStatus": "DEMO_NOT_A_LAUNCH_AGREEMENT",
    "creatorBpsImplemented": 5000,
    "productionApproved": false,
    "publicServer": false
  }
}
```

The implementation also returns demo `termsHash` and signing description. Obtain the exact hash from the actual profile response; never substitute an agreement hash or infer consent from the demo hash.

### POST /v1/auth/challenge — creator-bound message

```json
{
  "creator": "FVen3X669xLzsi6N2V91DoiyzHzg1uAgqiT8jZ9nS96Z",
  "termsHash": "<exact demo hash from profile>"
}
```

Response shape: `{status:200,body:{id,message,expiresAt,productionApproved:false}}`. Nonce is random, challenge expires after 60 seconds and includes creator, audience `offline-demo`, terms hash and expiry. The example address is a public fixture, not an approved user. The browser demo does not request a challenge or a signature.

### POST /v1/auth/verify — public proof verification

```json
{"id":"<issued challenge id>","signatureBase64":"<64-byte client-supplied Ed25519 proof>"}
```

Response shape: `{status:200,body:{bearer,expiresAt,scope:'offline:launch-draft',productionApproved:false}}`. This proves control of the public creator key only if a real proof passes; it does not prove independence or acceptance of production terms. The existing adapter consumes the challenge even after a bad proof. Session duration is one hour. It stores a bearer hash in memory; sessions do not survive restart. No real challenge is signed in this demo.

### POST /v1/launch/build — canonical unsigned draft

In-process envelope:

```js
await handle({
  method: 'POST', path: '/v1/launch/build',
  bearer: '<creator-bound session>',
  idempotencyKey: 'partner_review_001',
  body: {
    creator: 'FVen3X669xLzsi6N2V91DoiyzHzg1uAgqiT8jZ9nS96Z',
    mint: '4Qrizztktt7NqKQs5xUCE44nZ43rYtLNViTqEuNNY1sV',
    name: 'Fjf2or API Demo', symbol: 'DEMO',
    uri: 'https://ipfs.io/ipfs/bafyOfflineDemo'
  }
});
```

Prospective HTTP mapping, **not deployed**: `Authorization: Bearer <session>`, `Idempotency-Key: partner_review_001`, JSON body as above. Do not run curl against an invented base URL.

Input contract: name ≤32 UTF-8 bytes, symbol ≤10, URI ≤200; body ≤16 KiB; exactly five fields. Creator must match the session; mint must differ from creator/operator. API prototype accepts HTTPS `ipfs.io` or `arweave.net` with no credentials, port or fragment. The demo adds plain-text and 32-byte public-key validation for presentation. Publication integrity/DNS/metadata bytes remain the authoritative existing preflight's responsibility; URL validation does not prove availability.

Abridged archived response from `unsigned-draft.json`:

```json
{
  "mode": "OFFLINE_PROTOTYPE",
  "fixtureOnly": true,
  "productionApproved": false,
  "sendable": false,
  "placeholderBlockhash": true,
  "requiredSigners": [
    "FVen3X669xLzsi6N2V91DoiyzHzg1uAgqiT8jZ9nS96Z",
    "4Qrizztktt7NqKQs5xUCE44nZ43rYtLNViTqEuNNY1sV"
  ],
  "messageHash": "190a995ab39714405d83c4af78e1f9f93d7ab6229819fcda64e1734035414aaa",
  "metadataPublicationVerified": false,
  "currentBalanceVerified": false
}
```

Actual handler wraps it in `{status:200,body:...}` and includes unsigned bytes, cost, authorities, expiry and next gate. This archived fixture's expiry belongs to a synthetic test clock and is not usable. It has two zero signatures and a placeholder blockhash. Cost basis is historical rent, minimum 9,049,120 lamports, plus 1,000,000 reserve; **not a current launch quote**. UI edits generate a request preview only, never a corresponding transaction.

## Errors and retries

| Status | Existing code examples | Response to client |
|---|---|---|
| 400 | INVALID_DEMO_TERMS_OR_FIELDS, INVALID_CREATOR, INVALID_FIELDS, CREATOR_BINDING_OR_FIELDS, IDEMPOTENCY_REQUIRED, METADATA_HOST, METADATA_URL, CANONICAL_BUILD_REJECTED, INVALID_JSON_BODY | Correct public input; do not add private fields or instructions |
| 401 | UNAUTHORIZED, EXPIRED_OR_USED_CHALLENGE, INVALID_PROOF | Obtain a new challenge/session where appropriate |
| 409 | IDEMPOTENCY_CONFLICT, REBUILD_WITH_NEW_KEY | Reuse exact input or request a fresh draft with a new key |
| 413 | BODY_TOO_LARGE | Reduce JSON payload |
| 429 | OFFLINE_CAPACITY, OFFLINE_RATE_LIMIT | Back off; prototype limits are not a production SLA |
| 404 | NO_EXECUTION_ENDPOINT | There is no signing, send, buy, claim or payout route |

Errors include `productionApproved:false`. Idempotency is scoped to creator + key and canonical public input. Retry within 30 seconds returns the same draft; changed payload rejects; expired draft needs a new key. The prototype allows five new builds/minute/creator and bounded in-memory entries. These protections are not durable across workers or restarts and are not Sybil protection.

## Launch and settlement sequence

1. Review the fixed profile, rights and accepted future terms.
2. Future client obtains creator-bound authentication without disclosing keys.
3. Prepare public inputs and inspect the canonical unsigned package.
4. **Current blocking gate:** real published metadata, current mainnet costs/balance/configuration and unsigned simulation via existing `pilot-launch.prepareManifest`; custody and economic review still required.
5. Client-side payer + mint signing and submission are a future, separately approved responsibility. This demo implements neither.
6. Authorized fee collection/claim, actual sale when supported, verified per-mint quote receipts and ledger accrual must precede payout. Existing CAS ledger guards duplicate receipts and unresolved payouts.

The dashboard's 0.70 claim + 0.50 sale = 1.20 MSTRx, creator/operator allocation 0.60 each, synthetic creator paid 0.20 and due 0.40 are presentation fixtures. They are not mainnet receipts and create no liabilities. The 50/50 illustration reflects the existing offline rule, not a partner offer. Do not promise 85/15, returns, guaranteed payout or holder rewards.

## Required before a public API

Approved domain/audience and TLS; real terms and creator consent; durable sessions/idempotency using existing CAS infrastructure; rate limiting before JSON parse; secret-safe controlled read-only RPC transport; publication/DNS safeguards; full preflight and custody/economic gates; operator approval for any execution. Mainnet SDK compatibility does not imply that J7, Uxento or LaunchBlitz support Fjf2or. This static site can be published independently of a transactional API only after publication approval.
