frontier-os-app-builder 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +92 -0
  2. package/agents/fos-executor.md +460 -0
  3. package/agents/fos-plan-checker.md +386 -0
  4. package/agents/fos-planner.md +416 -0
  5. package/agents/fos-researcher.md +358 -0
  6. package/agents/fos-verifier.md +491 -0
  7. package/bin/fos-tools.cjs +794 -0
  8. package/bin/install.js +234 -0
  9. package/commands/fos/add-feature.md +29 -0
  10. package/commands/fos/discuss.md +31 -0
  11. package/commands/fos/execute.md +35 -0
  12. package/commands/fos/new-app.md +39 -0
  13. package/commands/fos/new-milestone.md +28 -0
  14. package/commands/fos/next.md +29 -0
  15. package/commands/fos/plan.md +37 -0
  16. package/commands/fos/ship.md +29 -0
  17. package/commands/fos/status.md +22 -0
  18. package/package.json +30 -0
  19. package/references/app-patterns.md +501 -0
  20. package/references/deployment.md +395 -0
  21. package/references/module-inference.md +349 -0
  22. package/references/sdk-surface.md +1622 -0
  23. package/references/verification-rules.md +404 -0
  24. package/templates/app/gitignore +25 -0
  25. package/templates/app/index.css +111 -0
  26. package/templates/app/index.html +19 -0
  27. package/templates/app/layout.tsx +45 -0
  28. package/templates/app/main-router.tsx +17 -0
  29. package/templates/app/main-simple.tsx +19 -0
  30. package/templates/app/package.json +36 -0
  31. package/templates/app/postcss.config.js +5 -0
  32. package/templates/app/router.tsx +22 -0
  33. package/templates/app/sdk-context.tsx +33 -0
  34. package/templates/app/test-setup.ts +19 -0
  35. package/templates/app/tsconfig.json +22 -0
  36. package/templates/app/vercel.json +127 -0
  37. package/templates/app/vite.config.ts +15 -0
  38. package/templates/state/context.md +248 -0
  39. package/templates/state/manifest.json +11 -0
  40. package/templates/state/plan.md +187 -0
  41. package/templates/state/project.md +118 -0
  42. package/templates/state/requirements.md +133 -0
  43. package/templates/state/roadmap.md +129 -0
  44. package/templates/state/state.md +131 -0
  45. package/templates/state/summary.md +273 -0
  46. package/workflows/add-feature.md +234 -0
  47. package/workflows/discuss.md +310 -0
  48. package/workflows/execute-plan.md +222 -0
  49. package/workflows/execute.md +338 -0
  50. package/workflows/new-app.md +331 -0
  51. package/workflows/new-milestone.md +258 -0
  52. package/workflows/next.md +157 -0
  53. package/workflows/plan.md +310 -0
  54. package/workflows/ship.md +296 -0
  55. package/workflows/status.md +145 -0
@@ -0,0 +1,1622 @@
1
+ # Frontier SDK Surface Reference
2
+
3
+ Complete API reference for `@frontiertower/frontier-sdk`. Every method, type, and permission extracted from source.
4
+
5
+ Package: `@frontiertower/frontier-sdk`
6
+ Import paths:
7
+ - `@frontiertower/frontier-sdk` -- main SDK class and access modules
8
+ - `@frontiertower/frontier-sdk/ui-utils` -- detection and standalone helpers
9
+
10
+ ---
11
+
12
+ ## 1. SDK Initialization
13
+
14
+ ### Class: `FrontierSDK`
15
+
16
+ ```typescript
17
+ import { FrontierSDK } from '@frontiertower/frontier-sdk';
18
+ ```
19
+
20
+ #### Constructor
21
+
22
+ ```typescript
23
+ const sdk = new FrontierSDK();
24
+ ```
25
+
26
+ On construction the SDK:
27
+ 1. Instantiates all ten access modules (wallet, storage, chain, user, partnerships, thirdParty, communities, events, offices, navigation).
28
+ 2. Registers a `window.addEventListener('message', ...)` listener that routes `SDKResponse` messages from `window.parent`.
29
+ 3. Sends an `{ type: 'app:ready', payload: null }` postMessage to `window.parent` to notify the host that the app iframe is ready.
30
+
31
+ #### `destroy(): void`
32
+
33
+ Call when the app is being torn down. Removes the message event listener and clears all pending request promises.
34
+
35
+ #### Internal: `request(type: string, payload?: any): Promise<any>`
36
+
37
+ Used by all access classes. Sends an `SDKRequest` via `window.parent.postMessage` and returns a promise that resolves/rejects when the host responds. Requests time out after **30 000 ms**.
38
+
39
+ ### PostMessage Protocol Types
40
+
41
+ ```typescript
42
+ interface SDKRequest {
43
+ type: string; // e.g. 'wallet:getBalance'
44
+ requestId: string; // `${Date.now()}-${incrementingId}`
45
+ payload?: any;
46
+ }
47
+
48
+ interface SDKResponse {
49
+ type: 'response' | 'error';
50
+ requestId: string;
51
+ result?: any;
52
+ error?: string;
53
+ }
54
+ ```
55
+
56
+ ### Module Getters
57
+
58
+ | Getter | Returns | Module |
59
+ |---|---|---|
60
+ | `sdk.getWallet()` | `WalletAccess` | Wallet |
61
+ | `sdk.getStorage()` | `StorageAccess` | Storage |
62
+ | `sdk.getChain()` | `ChainAccess` | Chain |
63
+ | `sdk.getUser()` | `UserAccess` | User |
64
+ | `sdk.getPartnerships()` | `PartnershipsAccess` | Partnerships |
65
+ | `sdk.getThirdParty()` | `ThirdPartyAccess` | Third-Party |
66
+ | `sdk.getCommunities()` | `CommunitiesAccess` | Communities |
67
+ | `sdk.getEvents()` | `EventsAccess` | Events |
68
+ | `sdk.getOffices()` | `OfficesAccess` | Offices |
69
+ | `sdk.getNavigation()` | `NavigationAccess` | Navigation |
70
+
71
+ ---
72
+
73
+ ## 2. Wallet Module
74
+
75
+ Access via `sdk.getWallet()`. All methods use the current chain from the chain manager. Write operations require biometric authentication.
76
+
77
+ ### Methods
78
+
79
+ ```typescript
80
+ getBalance(): Promise<WalletBalance>
81
+ ```
82
+ Returns raw balance breakdown (bigint values). Permission: `wallet:getBalance`
83
+
84
+ ```typescript
85
+ getBalanceFormatted(): Promise<WalletBalanceFormatted>
86
+ ```
87
+ Returns display-formatted balance strings (e.g. `'$10.50'`). Permission: `wallet:getBalanceFormatted`
88
+
89
+ ```typescript
90
+ getAddress(): Promise<string>
91
+ ```
92
+ Returns the smart account contract address for the current chain. Permission: `wallet:getAddress`
93
+
94
+ ```typescript
95
+ getSmartAccount(): Promise<SmartAccount>
96
+ ```
97
+ Returns detailed smart account info including deployment status. Permission: `wallet:getSmartAccount`
98
+
99
+ ```typescript
100
+ transferERC20(
101
+ tokenAddress: string,
102
+ to: string,
103
+ amount: bigint,
104
+ overrides?: GasOverrides
105
+ ): Promise<UserOperationReceipt>
106
+ ```
107
+ Transfer ERC20 tokens. Amount in token's smallest unit. Permission: `wallet:transferERC20`
108
+
109
+ ```typescript
110
+ approveERC20(
111
+ tokenAddress: string,
112
+ spender: string,
113
+ amount: bigint,
114
+ overrides?: GasOverrides
115
+ ): Promise<UserOperationReceipt>
116
+ ```
117
+ Approve a spender for ERC20 tokens. Permission: `wallet:approveERC20`
118
+
119
+ ```typescript
120
+ transferNative(
121
+ to: string,
122
+ amount: bigint,
123
+ overrides?: GasOverrides
124
+ ): Promise<UserOperationReceipt>
125
+ ```
126
+ Transfer native currency (ETH). Amount in wei. Permission: `wallet:transferNative`
127
+
128
+ ```typescript
129
+ executeCall(
130
+ call: ExecuteCall,
131
+ overrides?: GasOverrides
132
+ ): Promise<UserOperationReceipt>
133
+ ```
134
+ Execute an arbitrary contract call. Permission: `wallet:executeCall`
135
+
136
+ ```typescript
137
+ executeBatchCall(
138
+ calls: ExecuteCall[],
139
+ overrides?: GasOverrides
140
+ ): Promise<UserOperationReceipt>
141
+ ```
142
+ Execute multiple calls atomically in a single transaction. Permission: `wallet:executeBatchCall`
143
+
144
+ ```typescript
145
+ transferFrontierDollar(
146
+ to: string,
147
+ amount: string,
148
+ overrides?: GasOverrides
149
+ ): Promise<UserOperationReceipt>
150
+ ```
151
+ Transfer FND (Frontier Network Dollar). Amount is human-readable string (e.g. `'10.5'`). Permission: `wallet:transferFrontierDollar`
152
+
153
+ ```typescript
154
+ transferInternalFrontierDollar(
155
+ to: string,
156
+ amount: string,
157
+ overrides?: GasOverrides
158
+ ): Promise<UserOperationReceipt>
159
+ ```
160
+ Transfer iFND (Internal Frontier Network Dollar). Amount is human-readable string. Permission: `wallet:transferInternalFrontierDollar`
161
+
162
+ ```typescript
163
+ transferOverallFrontierDollar(
164
+ to: string,
165
+ amount: string,
166
+ overrides?: GasOverrides
167
+ ): Promise<UserOperationReceipt>
168
+ ```
169
+ Transfer using iFND first, falling back to FND for the remainder. Permission: `wallet:transferOverallFrontierDollar`
170
+
171
+ ```typescript
172
+ payWithFrontierDollar(
173
+ to: string,
174
+ amount: string,
175
+ paymentId: string
176
+ ): Promise<UserOperationReceipt>
177
+ ```
178
+ Pay via PaymentRouter with a UUID payment reference. Uses iFND with priority, falling back to FND. Supports multi-token split in a single transaction. Permission: `wallet:payWithFrontierDollar`
179
+
180
+ ```typescript
181
+ getSupportedTokens(): Promise<string[]>
182
+ ```
183
+ Returns token symbols supported for swaps on the current chain (e.g. `['FND', 'USDC', 'WETH']`). Permission: `wallet:getSupportedTokens`
184
+
185
+ ```typescript
186
+ swap(
187
+ sourceToken: string,
188
+ targetToken: string,
189
+ sourceNetwork: string,
190
+ targetNetwork: string,
191
+ amount: string
192
+ ): Promise<SwapResult>
193
+ ```
194
+ Execute a token swap (same-chain or cross-chain). Amount is human-readable. Permission: `wallet:swap`
195
+
196
+ ```typescript
197
+ quoteSwap(
198
+ sourceToken: string,
199
+ targetToken: string,
200
+ sourceNetwork: string,
201
+ targetNetwork: string,
202
+ amount: string
203
+ ): Promise<SwapQuote>
204
+ ```
205
+ Get a swap quote without executing. Permission: `wallet:quoteSwap`
206
+
207
+ ```typescript
208
+ getUsdDepositInstructions(): Promise<OnRampResponse<UsdDepositInstructions>>
209
+ ```
210
+ Get US bank details for fiat-to-crypto on-ramp. Requires approved KYC. Permission: `wallet:getUsdDepositInstructions`
211
+
212
+ ```typescript
213
+ getEurDepositInstructions(): Promise<OnRampResponse<EurDepositInstructions>>
214
+ ```
215
+ Get SEPA bank details for EUR fiat-to-crypto on-ramp. Requires approved KYC. Permission: `wallet:getEurDepositInstructions`
216
+
217
+ ```typescript
218
+ getLinkedBanks(): Promise<LinkedBanksResponse>
219
+ ```
220
+ Get all linked bank accounts for off-ramp withdrawals. Requires approved KYC. Permission: `wallet:getLinkedBanks`
221
+
222
+ ```typescript
223
+ linkUsBankAccount(
224
+ accountOwnerName: string,
225
+ bankName: string,
226
+ routingNumber: string,
227
+ accountNumber: string,
228
+ checkingOrSavings: 'checking' | 'savings',
229
+ address: BillingAddress
230
+ ): Promise<LinkBankResponse>
231
+ ```
232
+ Link a US bank account for USD withdrawals via ACH. Requires approved KYC. Permission: `wallet:linkUsBankAccount`
233
+
234
+ ```typescript
235
+ linkEuroAccount(
236
+ accountOwnerName: string,
237
+ accountOwnerType: AccountOwnerType,
238
+ firstName: string,
239
+ lastName: string,
240
+ ibanAccountNumber: string,
241
+ bic?: string
242
+ ): Promise<LinkBankResponse>
243
+ ```
244
+ Link a EUR/IBAN bank account for SEPA withdrawals. Requires approved KYC. Permission: `wallet:linkEuroAccount`
245
+
246
+ ```typescript
247
+ deleteLinkedBank(bankId: string): Promise<void>
248
+ ```
249
+ Delete a linked bank account. Permission: `wallet:deleteLinkedBank`
250
+
251
+ ```typescript
252
+ getDeprecatedSmartAccounts(): Promise<DeprecatedSmartAccount[]>
253
+ ```
254
+ Get deprecated smart accounts that still have active gas sponsorship. Permission: `wallet:getDeprecatedSmartAccounts`
255
+
256
+ ### Wallet Types
257
+
258
+ ```typescript
259
+ interface SmartAccount {
260
+ id: number;
261
+ ownerAddress: string;
262
+ contractAddress: string | null;
263
+ network: string;
264
+ status: string;
265
+ deploymentTransactionHash: string;
266
+ createdAt: string;
267
+ }
268
+
269
+ interface WalletBalance {
270
+ total: bigint;
271
+ fnd: bigint;
272
+ internalFnd: bigint;
273
+ }
274
+
275
+ interface WalletBalanceFormatted {
276
+ total: string; // e.g. '$10.50'
277
+ fnd: string;
278
+ internalFnd: string;
279
+ }
280
+
281
+ interface UserOperationReceipt {
282
+ userOpHash: string;
283
+ transactionHash: string;
284
+ blockNumber: bigint;
285
+ success: boolean;
286
+ }
287
+
288
+ interface GasOverrides {
289
+ maxFeePerGas?: bigint;
290
+ maxPriorityFeePerGas?: bigint;
291
+ gasLimit?: bigint;
292
+ }
293
+
294
+ interface ExecuteCall {
295
+ target: string;
296
+ value?: bigint;
297
+ data: string;
298
+ }
299
+
300
+ interface SwapParams {
301
+ sourceToken: string;
302
+ targetToken: string;
303
+ sourceNetwork: string;
304
+ targetNetwork: string;
305
+ amount: string;
306
+ }
307
+
308
+ enum SwapResultStatus {
309
+ COMPLETED = 'COMPLETED',
310
+ SUBMITTED = 'SUBMITTED',
311
+ }
312
+
313
+ interface SwapResult {
314
+ sourceChain: object;
315
+ targetChain: object;
316
+ sourceToken: object;
317
+ targetToken: object;
318
+ status: SwapResultStatus;
319
+ }
320
+
321
+ interface SwapQuote {
322
+ sourceChain: object;
323
+ targetChain: object;
324
+ sourceToken: object;
325
+ targetToken: object;
326
+ expectedAmountOut: string;
327
+ minAmountOut: string;
328
+ }
329
+
330
+ interface UsdDepositInstructions {
331
+ currency: 'usd';
332
+ bankName: string;
333
+ bankAddress: string;
334
+ bankRoutingNumber: string;
335
+ bankAccountNumber: string;
336
+ bankBeneficiaryName: string;
337
+ paymentRail: string;
338
+ }
339
+
340
+ interface EurDepositInstructions {
341
+ currency: 'eur';
342
+ iban: string;
343
+ bic: string;
344
+ accountHolderName: string;
345
+ }
346
+
347
+ interface OnRampResponse<T = UsdDepositInstructions | EurDepositInstructions> {
348
+ currency: 'usd' | 'eur';
349
+ depositInstructions: T;
350
+ destinationAddress: string;
351
+ destinationNetwork: string;
352
+ }
353
+
354
+ interface LinkedBank {
355
+ id: string;
356
+ bankName: string;
357
+ last4: string;
358
+ withdrawalAddress: string;
359
+ network: string;
360
+ }
361
+
362
+ interface LinkedBanksResponse {
363
+ banks: LinkedBank[];
364
+ }
365
+
366
+ interface LinkBankResponse {
367
+ externalAccountId: string;
368
+ bankName: string;
369
+ withdrawalAddress: string;
370
+ network: string;
371
+ }
372
+
373
+ interface BillingAddress {
374
+ streetLine1: string;
375
+ streetLine2?: string;
376
+ city: string;
377
+ state: string;
378
+ postalCode: string;
379
+ country: string;
380
+ }
381
+
382
+ type AccountOwnerType = 'individual' | 'business';
383
+
384
+ interface DeprecatedSmartAccount {
385
+ id: number;
386
+ ownerAddress: string;
387
+ contractAddress: string;
388
+ network: string;
389
+ deprecatedAt: string;
390
+ version: number;
391
+ }
392
+ ```
393
+
394
+ ---
395
+
396
+ ## 3. Storage Module
397
+
398
+ Access via `sdk.getStorage()`. Provides persistent key-value storage scoped to the app.
399
+
400
+ ### Methods
401
+
402
+ ```typescript
403
+ get<T = any>(key: string): Promise<T>
404
+ ```
405
+ Read a value by key. Permission: `storage:get`
406
+
407
+ ```typescript
408
+ set(key: string, value: any): Promise<void>
409
+ ```
410
+ Write a value by key. Permission: `storage:set`
411
+
412
+ ```typescript
413
+ remove(key: string): Promise<void>
414
+ ```
415
+ Delete a key. Permission: `storage:remove`
416
+
417
+ ```typescript
418
+ clear(): Promise<void>
419
+ ```
420
+ Delete all keys. Permission: `storage:clear`
421
+
422
+ ### Storage Types
423
+
424
+ No additional types -- uses generic `T` for get, `any` for set.
425
+
426
+ ---
427
+
428
+ ## 4. Chain Module
429
+
430
+ Access via `sdk.getChain()`. Query and switch blockchain networks.
431
+
432
+ ### Methods
433
+
434
+ ```typescript
435
+ getCurrentNetwork(): Promise<string>
436
+ ```
437
+ Returns the current network identifier (e.g. `'base'`, `'base-sepolia'`). Permission: `chain:getCurrentNetwork`
438
+
439
+ ```typescript
440
+ getAvailableNetworks(): Promise<string[]>
441
+ ```
442
+ Returns all network identifiers the app can switch to. Permission: `chain:getAvailableNetworks`
443
+
444
+ ```typescript
445
+ switchNetwork(network: string): Promise<void>
446
+ ```
447
+ Switch active blockchain network. Affects all subsequent wallet operations. Permission: `chain:switchNetwork`
448
+
449
+ ```typescript
450
+ getCurrentChainConfig(): Promise<ChainConfig>
451
+ ```
452
+ Returns full chain configuration for the current network. Permission: `chain:getCurrentChainConfig`
453
+
454
+ ```typescript
455
+ getContractAddresses(): Promise<{
456
+ fnd: string;
457
+ iFnd: string | null;
458
+ paymentRouter: string;
459
+ subscriptionManager: string;
460
+ }>
461
+ ```
462
+ Returns addresses for FND, iFND (may be null), PaymentRouter, and SubscriptionManager contracts on the current chain. Permission: `chain:getContractAddresses`
463
+
464
+ ### Chain Types
465
+
466
+ ```typescript
467
+ enum Underlying {
468
+ USD = "USD",
469
+ }
470
+
471
+ interface Token {
472
+ name: string;
473
+ symbol: string;
474
+ decimals: number;
475
+ address: string;
476
+ }
477
+
478
+ interface StableCoin extends Token {
479
+ underlying: Underlying;
480
+ }
481
+
482
+ interface ChainConfig {
483
+ id: number;
484
+ name: string;
485
+ network: string;
486
+ bridgeSwapRouterFactoryAddress: string;
487
+ uniswapV3FactoryAddress: string;
488
+ nativeCurrency: {
489
+ name: string;
490
+ symbol: string;
491
+ decimals: number;
492
+ };
493
+ blockExplorer: {
494
+ name: string;
495
+ url: string;
496
+ };
497
+ stableCoins: StableCoin[];
498
+ supportedTokens: Token[];
499
+ testnet: boolean;
500
+ }
501
+ ```
502
+
503
+ ---
504
+
505
+ ## 5. User Module
506
+
507
+ Access via `sdk.getUser()`. Query user info, profiles, referrals, KYC, and access controls.
508
+
509
+ ### Methods
510
+
511
+ ```typescript
512
+ getDetails(): Promise<User>
513
+ ```
514
+ Returns basic user info (id, email, name, active/superuser status). Permission: `user:getDetails`
515
+
516
+ ```typescript
517
+ getProfile(): Promise<UserProfile>
518
+ ```
519
+ Returns detailed profile (social handles, preferences, community, notification settings). Permission: `user:getProfile`
520
+
521
+ ```typescript
522
+ getReferralOverview(): Promise<ReferralOverview>
523
+ ```
524
+ Returns referral statistics (count, ranking, referral link/code). Permission: `user:getReferralOverview`
525
+
526
+ ```typescript
527
+ getReferralDetails(page?: number): Promise<PaginatedResponse<ReferralDetails>>
528
+ ```
529
+ Returns paginated referral details. Permission: `user:getReferralDetails`
530
+
531
+ ```typescript
532
+ addUserContact(data: UserContactPayload): Promise<void>
533
+ ```
534
+ Submit contact information for the current user. Permission: `user:addUserContact`
535
+
536
+ ```typescript
537
+ getOrCreateKyc(redirectUri?: string): Promise<KycStatusResponse>
538
+ ```
539
+ Get or initiate KYC verification. Returns status and a KYC link if verification has been started. Permission: `user:getOrCreateKyc`
540
+
541
+ ```typescript
542
+ createSignupRequest(payload: CreateSignupRequestPayload): Promise<CreateSignupRequestResponse>
543
+ ```
544
+ Submit a new membership signup request with crypto payment. Permission: `user:createSignupRequest`
545
+
546
+ ```typescript
547
+ getVerifiedAccessControls(): Promise<AccessControlsPayload>
548
+ ```
549
+ Returns cryptographically verified access controls signed by the Frontier API server. The SDK verifies an ECDSA secp256k1 signature against hardcoded per-environment public keys inside the iframe. **Use this for all access-gating decisions** -- unsigned data from other SDK methods should not be trusted for feature gating. Throws if signature verification fails. Permission: `user:getVerifiedAccessControls`
550
+
551
+ ### User Types
552
+
553
+ ```typescript
554
+ interface User {
555
+ id: number;
556
+ email: string;
557
+ firstName: string;
558
+ lastName: string;
559
+ isActive: boolean;
560
+ dateJoined: string;
561
+ isSuperuser: boolean;
562
+ }
563
+
564
+ interface UserProfile {
565
+ id: number;
566
+ user: number;
567
+ firstName: string;
568
+ lastName: string;
569
+ nickname: string;
570
+ profilePicture: string;
571
+ phoneNumber: string;
572
+ community: string;
573
+ communityName: string;
574
+ organization: string;
575
+ organizationRole: string;
576
+ socialSite: string;
577
+ socialHandle: string;
578
+ githubHandle: string;
579
+ currentWork: string;
580
+ notableWork: string;
581
+ receiveUpdates: boolean;
582
+ notificationCommunityEvent: boolean;
583
+ notificationTowerEvent: boolean;
584
+ notificationUpcomingEvent: boolean;
585
+ notificationTweetPicked: boolean;
586
+ notifyEventInvites: boolean;
587
+ optInSms: boolean;
588
+ howDidYouHearAboutUs: string;
589
+ braggingStatement: string;
590
+ contributionStatement: string;
591
+ hasUsablePassword: string;
592
+ }
593
+
594
+ interface PaginatedResponse<T> {
595
+ count: number;
596
+ results: T[];
597
+ }
598
+
599
+ interface ReferralOverview {
600
+ referralCount: number;
601
+ ranking: number;
602
+ referralLink: string;
603
+ referralCode: string;
604
+ referredBy: string | null;
605
+ }
606
+
607
+ interface ReferralDetails {
608
+ name: string;
609
+ email: string;
610
+ referralDate: string;
611
+ reward: string;
612
+ status: string;
613
+ }
614
+
615
+ interface UserContact {
616
+ email: string;
617
+ phone: string;
618
+ name: string;
619
+ }
620
+
621
+ interface UserContactPayload {
622
+ contacts: UserContact[];
623
+ }
624
+
625
+ type KycStatus = 'not_started' | 'pending' | 'in_review' | 'approved' | 'rejected';
626
+ type TosStatus = 'pending' | 'approved';
627
+
628
+ interface KycStatusResponse {
629
+ status: KycStatus;
630
+ isApproved: boolean;
631
+ rejectionReason: string | null;
632
+ kycLinkId: string | null;
633
+ kycLink: string | null;
634
+ tosStatus: TosStatus | null;
635
+ tosLink: string | null;
636
+ }
637
+
638
+ interface CreateSignupRequestPayload {
639
+ subscriptionPlan: string;
640
+ subscriptionInterval: string;
641
+ firstName: string;
642
+ lastName: string;
643
+ email: string;
644
+ phoneNumber: string;
645
+ socialSite: string;
646
+ socialHandle: string;
647
+ currentWork: string;
648
+ howDidYouHearAboutUs: string;
649
+ braggingStatement: string;
650
+ contributionStatement: string;
651
+ billingFirstName: string;
652
+ billingLastName: string;
653
+ billingEmail: string;
654
+ billingPhoneNumber: string;
655
+ paymentProvider: 'crypto';
656
+ smartAccount: number;
657
+ community: string;
658
+ githubHandle?: string;
659
+ notableWork?: string;
660
+ referralCode?: string;
661
+ receiveUpdates?: boolean;
662
+ optInSms?: boolean;
663
+ organization?: string;
664
+ organizationRole?: string;
665
+ }
666
+
667
+ interface CreateSignupRequestResponse {
668
+ subscriptionUuid: string;
669
+ paymentProvider: string;
670
+ }
671
+ ```
672
+
673
+ ### Access Controls Types
674
+
675
+ ```typescript
676
+ interface AccessControlsPayload {
677
+ smartAccountAddress: string | null;
678
+ email: string;
679
+ isSuperuser: boolean;
680
+ subscriptionStatus: string | null; // 'active' | 'canceled' | 'awaiting_approval' | null
681
+ subscriptionPlan: string | null;
682
+ subscriptionInterval: string | null;
683
+ subscriptionType: string | null; // 'crypto' | 'stripe' | 'grant' | 'office' | 'internship' | null
684
+ addOns: string[];
685
+ communities: string[];
686
+ managedCommunities: string[];
687
+ timestamp: string;
688
+ kid: string;
689
+ }
690
+
691
+ interface SignedAccessControls {
692
+ accessControls: string; // Base64-encoded canonical JSON payload
693
+ stage: string; // API stage (e.g. 'production', 'sandbox')
694
+ signature: string; // Hex-encoded ECDSA signature (r||s, 128 hex chars)
695
+ }
696
+ ```
697
+
698
+ ---
699
+
700
+ ## 6. Partnerships Module
701
+
702
+ Access via `sdk.getPartnerships()`. Manage sponsors and sponsor passes.
703
+
704
+ ### Methods
705
+
706
+ ```typescript
707
+ createSponsorPass(payload: CreateSponsorPassRequest): Promise<SponsorPass>
708
+ ```
709
+ Create a new SponsorPass. Permission: `partnerships:createSponsorPass`
710
+
711
+ ```typescript
712
+ listActiveSponsorPasses(payload?: ListSponsorPassesParams): Promise<PaginatedResponse<SponsorPass>>
713
+ ```
714
+ List active (non-revoked) SponsorPasses, paginated. Permission: `partnerships:listActiveSponsorPasses`
715
+
716
+ ```typescript
717
+ listAllSponsorPasses(payload?: ListAllSponsorPassesParams): Promise<PaginatedResponse<SponsorPass>>
718
+ ```
719
+ List all SponsorPasses, optionally including revoked. Permission: `partnerships:listAllSponsorPasses`
720
+
721
+ ```typescript
722
+ listSponsors(payload?: ListSponsorsParams): Promise<PaginatedResponse<Sponsor>>
723
+ ```
724
+ List sponsors the user manages, paginated. Permission: `partnerships:listSponsors`
725
+
726
+ ```typescript
727
+ getSponsor(payload: { id: number }): Promise<Sponsor>
728
+ ```
729
+ Retrieve a Sponsor by ID. Permission: `partnerships:getSponsor`
730
+
731
+ ```typescript
732
+ getSponsorPass(payload: { id: number }): Promise<SponsorPass>
733
+ ```
734
+ Retrieve a SponsorPass by ID. Permission: `partnerships:getSponsorPass`
735
+
736
+ ```typescript
737
+ revokeSponsorPass(payload: { id: number }): Promise<void>
738
+ ```
739
+ Revoke (not delete) a SponsorPass. Permission: `partnerships:revokeSponsorPass`
740
+
741
+ ### Partnerships Types
742
+
743
+ ```typescript
744
+ type SponsorPassStatus = 'active' | 'revoked';
745
+
746
+ interface SponsorPass {
747
+ id: number;
748
+ sponsor: number;
749
+ sponsorName: string;
750
+ firstName: string;
751
+ lastName: string;
752
+ email: string;
753
+ status: SponsorPassStatus;
754
+ expiresAt: string | null;
755
+ createdAt: string;
756
+ updatedAt: string;
757
+ revokedAt: string | null;
758
+ }
759
+
760
+ interface CreateSponsorPassRequest {
761
+ sponsor: number;
762
+ firstName: string;
763
+ lastName: string;
764
+ email: string;
765
+ expiresAt?: string;
766
+ }
767
+
768
+ interface ListSponsorPassesParams {
769
+ limit?: number;
770
+ offset?: number;
771
+ }
772
+
773
+ interface ListAllSponsorPassesParams extends ListSponsorPassesParams {
774
+ includeRevoked?: boolean;
775
+ }
776
+
777
+ interface Sponsor {
778
+ id: number;
779
+ name: string;
780
+ dailyRate: string;
781
+ notes: string;
782
+ createdAt: string;
783
+ updatedAt: string;
784
+ }
785
+
786
+ interface ListSponsorsParams {
787
+ limit?: number;
788
+ offset?: number;
789
+ }
790
+ ```
791
+
792
+ ---
793
+
794
+ ## 7. Third-Party Module
795
+
796
+ Access via `sdk.getThirdParty()`. Manage developer accounts, registered apps, and webhooks.
797
+
798
+ ### Developer Methods
799
+
800
+ ```typescript
801
+ listDevelopers(payload?: ListParams): Promise<PaginatedResponse<Developer>>
802
+ ```
803
+ List developer accounts, paginated. Permission: `thirdParty:listDevelopers`
804
+
805
+ ```typescript
806
+ getDeveloper(payload: { id: number }): Promise<Developer>
807
+ ```
808
+ Get developer details by ID. Permission: `thirdParty:getDeveloper`
809
+
810
+ ```typescript
811
+ updateDeveloper(payload: { id: number; data: UpdateDeveloperRequest }): Promise<Developer>
812
+ ```
813
+ Update developer information. Permission: `thirdParty:updateDeveloper`
814
+
815
+ ```typescript
816
+ rotateDeveloperApiKey(payload: { id: number }): Promise<RotateKeyResponse>
817
+ ```
818
+ Rotate developer API key. New key is only shown once in the response. Permission: `thirdParty:rotateDeveloperApiKey`
819
+
820
+ ### App Methods
821
+
822
+ ```typescript
823
+ listApps(payload?: ListAppsParams): Promise<PaginatedResponse<App>>
824
+ ```
825
+ List registered apps, paginated. Optional `developerId` filter. Permission: `thirdParty:listApps`
826
+
827
+ ```typescript
828
+ createApp(payload: CreateAppRequest): Promise<App>
829
+ ```
830
+ Register a new app. Name, description, and icon are auto-fetched from URL metadata. Permission: `thirdParty:createApp`
831
+
832
+ ```typescript
833
+ getApp(payload: { id: number }): Promise<App>
834
+ ```
835
+ Get app details by ID. Permission: `thirdParty:getApp`
836
+
837
+ ```typescript
838
+ updateApp(payload: { id: number; data: UpdateAppRequest }): Promise<App>
839
+ ```
840
+ Update an app. Permission: `thirdParty:updateApp`
841
+
842
+ ```typescript
843
+ deleteApp(payload: { id: number }): Promise<void>
844
+ ```
845
+ Request app deactivation. Permission: `thirdParty:deleteApp`
846
+
847
+ ### Webhook Methods
848
+
849
+ ```typescript
850
+ listWebhooks(payload?: ListWebhooksParams): Promise<PaginatedResponse<Webhook>>
851
+ ```
852
+ List webhooks, paginated. Max 3 webhooks per developer. Optional `developerId` filter. Permission: `thirdParty:listWebhooks`
853
+
854
+ ```typescript
855
+ createWebhook(payload: CreateWebhookRequest): Promise<Webhook>
856
+ ```
857
+ Create a new webhook. Requires admin approval before going live. Permission: `thirdParty:createWebhook`
858
+
859
+ ```typescript
860
+ getWebhook(payload: { id: number }): Promise<Webhook>
861
+ ```
862
+ Get webhook details by ID. Permission: `thirdParty:getWebhook`
863
+
864
+ ```typescript
865
+ updateWebhook(payload: { id: number; data: UpdateWebhookRequest }): Promise<Webhook>
866
+ ```
867
+ Update a webhook. Config changes require admin re-approval. Permission: `thirdParty:updateWebhook`
868
+
869
+ ```typescript
870
+ deleteWebhook(payload: { id: number }): Promise<void>
871
+ ```
872
+ Delete a webhook. Permission: `thirdParty:deleteWebhook`
873
+
874
+ ```typescript
875
+ rotateWebhookSigningKey(payload: { id: number }): Promise<RotateWebhookKeyResponse>
876
+ ```
877
+ Rotate webhook signing key. New public key returned in response. Permission: `thirdParty:rotateWebhookSigningKey`
878
+
879
+ ### Third-Party Types
880
+
881
+ ```typescript
882
+ interface Developer {
883
+ id: number;
884
+ name: string;
885
+ description: string;
886
+ email: string;
887
+ apiKey: string;
888
+ createdAt: string;
889
+ updatedAt: string;
890
+ }
891
+
892
+ interface UpdateDeveloperRequest {
893
+ name?: string;
894
+ description?: string;
895
+ email?: string;
896
+ }
897
+
898
+ interface RotateKeyResponse {
899
+ message: string;
900
+ developer: Developer;
901
+ }
902
+
903
+ type AppStatus =
904
+ | 'in_review'
905
+ | 'accepted'
906
+ | 'released'
907
+ | 'rejected'
908
+ | 'request_deactivation'
909
+ | 'deactivated';
910
+
911
+ type AppPermission = string;
912
+
913
+ interface App {
914
+ id: number;
915
+ developer: number;
916
+ icon: string | null;
917
+ name: string;
918
+ readableId: string;
919
+ description: string;
920
+ url: string;
921
+ cnameEntry: string;
922
+ txtEntry: string | null;
923
+ permissions: AppPermission[];
924
+ permissionDisclaimer: string;
925
+ status: AppStatus;
926
+ reviewNotes: string;
927
+ createdAt: string;
928
+ updatedAt: string;
929
+ }
930
+
931
+ interface CreateAppRequest {
932
+ developer: number;
933
+ url: string;
934
+ cnameEntry: string;
935
+ txtEntry?: string;
936
+ permissions: AppPermission[];
937
+ permissionDisclaimer: string;
938
+ }
939
+
940
+ interface UpdateAppRequest {
941
+ developer?: number;
942
+ url?: string;
943
+ cnameEntry?: string;
944
+ txtEntry?: string;
945
+ permissions?: AppPermission[];
946
+ permissionDisclaimer?: string;
947
+ }
948
+
949
+ type WebhookStatus = 'IN_REVIEW' | 'LIVE' | 'REJECTED';
950
+ type WebhookEvent = string;
951
+ type WebhookScope = Record<string, number[] | '*'>;
952
+
953
+ interface WebhookConfig {
954
+ events: WebhookEvent[];
955
+ scope: WebhookScope;
956
+ }
957
+
958
+ interface Webhook {
959
+ id: number;
960
+ developer: number;
961
+ name: string;
962
+ description: string;
963
+ targetUrl: string;
964
+ config: WebhookConfig;
965
+ signingPublicKey: string;
966
+ status: WebhookStatus;
967
+ reviewNotes: string;
968
+ createdAt: string;
969
+ updatedAt: string;
970
+ }
971
+
972
+ interface CreateWebhookRequest {
973
+ developer: number;
974
+ name: string;
975
+ description: string;
976
+ targetUrl: string;
977
+ config: WebhookConfig;
978
+ }
979
+
980
+ interface UpdateWebhookRequest {
981
+ developer?: number;
982
+ name?: string;
983
+ description?: string;
984
+ targetUrl?: string;
985
+ config?: WebhookConfig;
986
+ }
987
+
988
+ interface RotateWebhookKeyResponse {
989
+ message: string;
990
+ webhook: Webhook;
991
+ }
992
+
993
+ interface ListParams {
994
+ limit?: number;
995
+ offset?: number;
996
+ }
997
+
998
+ interface ListAppsParams extends ListParams {
999
+ developerId?: number;
1000
+ }
1001
+
1002
+ interface ListWebhooksParams extends ListParams {
1003
+ developerId?: number;
1004
+ }
1005
+ ```
1006
+
1007
+ ---
1008
+
1009
+ ## 8. Communities Module
1010
+
1011
+ Access via `sdk.getCommunities()`. Manage communities, internship passes, and member reassignment requests.
1012
+
1013
+ Community listing is public. Internship passes require authentication, an active subscription, and community manager status. Reassign requests require authentication; creating requires managing the member's current community, accepting requires managing the target community. Superusers can access everything.
1014
+
1015
+ ### Methods
1016
+
1017
+ ```typescript
1018
+ listCommunities(payload?: ListCommunitiesParams): Promise<PaginatedResponse<Community>>
1019
+ ```
1020
+ List all visible communities, paginated. Permission: `communities:listCommunities`
1021
+
1022
+ ```typescript
1023
+ getCommunity(payload: { idOrSlug: string | number }): Promise<Community>
1024
+ ```
1025
+ Get a community by numeric ID or slug string. Permission: `communities:getCommunity`
1026
+
1027
+ ```typescript
1028
+ createInternshipPass(payload: CreateInternshipPassRequest): Promise<InternshipPass>
1029
+ ```
1030
+ Create an internship pass. Auto-creates an inactive account if the user does not exist. Permission: `communities:createInternshipPass`
1031
+
1032
+ ```typescript
1033
+ listInternshipPasses(payload?: ListInternshipPassesParams): Promise<PaginatedResponse<InternshipPass>>
1034
+ ```
1035
+ List internship passes for managed communities. Active only by default; set `includeRevoked: true` to include revoked. Permission: `communities:listInternshipPasses`
1036
+
1037
+ ```typescript
1038
+ getInternshipPass(payload: { id: number }): Promise<InternshipPass>
1039
+ ```
1040
+ Get an internship pass by ID. Permission: `communities:getInternshipPass`
1041
+
1042
+ ```typescript
1043
+ revokeInternshipPass(payload: { id: number }): Promise<void>
1044
+ ```
1045
+ Revoke an internship pass. Cannot revoke an already-revoked pass. Permission: `communities:revokeInternshipPass`
1046
+
1047
+ ```typescript
1048
+ createReassignRequest(payload: CreateReassignRequestPayload): Promise<ReassignRequest>
1049
+ ```
1050
+ Request to move a member to a different community. Caller must manage the member's current community. Permission: `communities:createReassignRequest`
1051
+
1052
+ ```typescript
1053
+ listReassignRequests(payload?: ListReassignRequestsParams): Promise<PaginatedResponse<ReassignRequest>>
1054
+ ```
1055
+ List pending reassign requests visible to the caller. Permission: `communities:listReassignRequests`
1056
+
1057
+ ```typescript
1058
+ getReassignRequest(payload: { id: number }): Promise<ReassignRequest>
1059
+ ```
1060
+ Get a reassign request by ID. Permission: `communities:getReassignRequest`
1061
+
1062
+ ```typescript
1063
+ acceptReassignRequest(payload: { id: number }): Promise<ReassignRequest>
1064
+ ```
1065
+ Accept a reassign request. Moves the member to the target community. Only target community managers (or superusers) can accept. Permission: `communities:acceptReassignRequest`
1066
+
1067
+ ```typescript
1068
+ rejectReassignRequest(payload: { id: number }): Promise<void>
1069
+ ```
1070
+ Reject a reassign request. Only pending requests can be rejected. Permission: `communities:rejectReassignRequest`
1071
+
1072
+ ### Communities Types
1073
+
1074
+ ```typescript
1075
+ interface Community {
1076
+ id: number;
1077
+ name: string;
1078
+ description: string;
1079
+ slug: string;
1080
+ iconName: string;
1081
+ splashVideo: string | null;
1082
+ }
1083
+
1084
+ interface ListCommunitiesParams {
1085
+ limit?: number;
1086
+ offset?: number;
1087
+ }
1088
+
1089
+ type InternshipPassStatus = 'active' | 'revoked';
1090
+
1091
+ interface InternshipPass {
1092
+ id: number;
1093
+ email: string;
1094
+ firstName: string;
1095
+ lastName: string;
1096
+ community: number;
1097
+ communityName: string;
1098
+ status: InternshipPassStatus;
1099
+ createdAt: string;
1100
+ revokedAt: string | null;
1101
+ updatedAt: string;
1102
+ }
1103
+
1104
+ interface CreateInternshipPassRequest {
1105
+ email: string;
1106
+ firstName: string;
1107
+ lastName: string;
1108
+ community: number;
1109
+ }
1110
+
1111
+ interface ListInternshipPassesParams {
1112
+ limit?: number;
1113
+ offset?: number;
1114
+ includeRevoked?: boolean;
1115
+ }
1116
+
1117
+ type ReassignRequestStatus = 'pending' | 'accepted' | 'rejected';
1118
+
1119
+ interface ReassignRequest {
1120
+ id: number;
1121
+ requester: number;
1122
+ requesterEmail: string;
1123
+ member: number;
1124
+ memberEmail: string;
1125
+ targetCommunity: number;
1126
+ targetCommunityName: string;
1127
+ status: ReassignRequestStatus;
1128
+ createdAt: string;
1129
+ resolvedAt: string | null;
1130
+ resolvedBy: number | null;
1131
+ resolvedByEmail: string | null;
1132
+ }
1133
+
1134
+ interface CreateReassignRequestPayload {
1135
+ memberEmail: string;
1136
+ targetCommunity: number;
1137
+ }
1138
+
1139
+ interface ListReassignRequestsParams {
1140
+ limit?: number;
1141
+ offset?: number;
1142
+ }
1143
+ ```
1144
+
1145
+ ---
1146
+
1147
+ ## 9. Events Module
1148
+
1149
+ Access via `sdk.getEvents()`. Manage events, locations (event spaces and rooms), and room bookings.
1150
+
1151
+ ### Methods
1152
+
1153
+ ```typescript
1154
+ listEvents(payload?: ListEventsParams): Promise<PaginatedResponse<Event>>
1155
+ ```
1156
+ List active events with optional filters (search, type, location, date range). Permission: `events:listEvents`
1157
+
1158
+ ```typescript
1159
+ createEvent(payload: CreateEventRequest): Promise<Event>
1160
+ ```
1161
+ Create a new event. Permission: `events:createEvent`
1162
+
1163
+ ```typescript
1164
+ addEventHost(payload: { eventId: number; email: string }): Promise<Event>
1165
+ ```
1166
+ Add a co-host to an event. Only the primary host can add co-hosts, and only to upcoming events. Permission: `events:addEventHost`
1167
+
1168
+ ```typescript
1169
+ listLocations(payload?: ListLocationsParams): Promise<Location[]>
1170
+ ```
1171
+ List available locations. Returns an array (not paginated). Optional `locationType` filter. Permission: `events:listLocations`
1172
+
1173
+ ```typescript
1174
+ listRoomBookings(payload?: ListRoomBookingsParams): Promise<PaginatedResponse<RoomBooking>>
1175
+ ```
1176
+ List approved room bookings with optional filters. Permission: `events:listRoomBookings`
1177
+
1178
+ ```typescript
1179
+ createRoomBooking(payload: CreateRoomBookingRequest): Promise<RoomBooking>
1180
+ ```
1181
+ Create a room booking. Location must be of type `'room'`. Permission: `events:createRoomBooking`
1182
+
1183
+ ### Events Types
1184
+
1185
+ ```typescript
1186
+ type EventType = 'public' | 'members_plus_one' | 'members_only' | 'community_only';
1187
+ type EventService = 'luma' | 'private' | 'test';
1188
+ type ReviewStatus = 'not_required' | 'approved' | 'rejected' | 'pending';
1189
+ type EventStatus = 'active' | 'suspended' | 'archived';
1190
+ type LocationType = 'event_space' | 'room';
1191
+
1192
+ interface Event {
1193
+ id: number;
1194
+ name: string;
1195
+ description: string;
1196
+ eventType: EventType;
1197
+ eventService: EventService;
1198
+ host: string;
1199
+ community: number | null;
1200
+ startsAt: string;
1201
+ endsAt: string;
1202
+ coverImage: string | null;
1203
+ eventId: string;
1204
+ location: string;
1205
+ locationName: string;
1206
+ displayLocation: string;
1207
+ url: string;
1208
+ additionalHosts: string[];
1209
+ color: string;
1210
+ reviewStatus: ReviewStatus;
1211
+ status: EventStatus;
1212
+ }
1213
+
1214
+ interface ListEventsParams {
1215
+ search?: string;
1216
+ eventType?: EventType;
1217
+ locationType?: LocationType;
1218
+ locationId?: string;
1219
+ date?: string; // YYYY-MM-DD
1220
+ startDate?: string; // YYYY-MM-DD
1221
+ endDate?: string; // YYYY-MM-DD
1222
+ page?: number;
1223
+ }
1224
+
1225
+ interface CreateEventRequest {
1226
+ name: string;
1227
+ eventType: EventType;
1228
+ startsAt: string; // ISO 8601
1229
+ endsAt: string; // ISO 8601
1230
+ location: string; // readable_id slug
1231
+ description?: string;
1232
+ coverImage?: string; // Base64 data URI
1233
+ additionalHosts?: string[];
1234
+ color?: string; // Hex color code
1235
+ }
1236
+
1237
+ interface Location {
1238
+ id: number;
1239
+ owner: number | null;
1240
+ readableId: string;
1241
+ name: string;
1242
+ maxCapacity: number;
1243
+ description: string;
1244
+ directions: string;
1245
+ locationType: LocationType;
1246
+ warmupBuffer: string; // e.g. "00:10:00"
1247
+ cooldownBuffer: string; // e.g. "00:15:00"
1248
+ openBooking: boolean;
1249
+ floorLocation: string;
1250
+ }
1251
+
1252
+ interface ListLocationsParams {
1253
+ locationType?: LocationType;
1254
+ }
1255
+
1256
+ interface RoomBooking {
1257
+ id: number;
1258
+ startsAt: string;
1259
+ endsAt: string;
1260
+ location: string;
1261
+ }
1262
+
1263
+ interface ListRoomBookingsParams {
1264
+ locationId?: string;
1265
+ date?: string; // YYYY-MM-DD
1266
+ startDate?: string; // YYYY-MM-DD
1267
+ endDate?: string; // YYYY-MM-DD
1268
+ page?: number;
1269
+ }
1270
+
1271
+ interface CreateRoomBookingRequest {
1272
+ startsAt: string; // ISO 8601
1273
+ endsAt: string; // ISO 8601
1274
+ location: string; // readable_id (must be room type)
1275
+ }
1276
+ ```
1277
+
1278
+ ---
1279
+
1280
+ ## 10. Offices Module
1281
+
1282
+ Access via `sdk.getOffices()`. Manage office access passes for membership contracts.
1283
+
1284
+ All endpoints require authentication, an active subscription, and manager status on the membership contract's organization (or superuser).
1285
+
1286
+ ### Methods
1287
+
1288
+ ```typescript
1289
+ createAccessPass(payload: CreateAccessPassRequest): Promise<AccessPass>
1290
+ ```
1291
+ Create an access pass for a membership contract. Auto-creates an inactive account if the user does not exist. Each user can only have one active pass per contract. Permission: `offices:createAccessPass`
1292
+
1293
+ ```typescript
1294
+ listAccessPasses(payload?: ListAccessPassesParams): Promise<PaginatedResponse<AccessPass>>
1295
+ ```
1296
+ List access passes for contracts the user manages. Active only by default; set `includeRevoked: true` for all. Ordered newest first. Permission: `offices:listAccessPasses`
1297
+
1298
+ ```typescript
1299
+ getAccessPass(payload: { id: number }): Promise<AccessPass>
1300
+ ```
1301
+ Get an access pass by ID. Permission: `offices:getAccessPass`
1302
+
1303
+ ```typescript
1304
+ revokeAccessPass(payload: { id: number }): Promise<void>
1305
+ ```
1306
+ Revoke an access pass. Cannot revoke an already-revoked pass. Permission: `offices:revokeAccessPass`
1307
+
1308
+ ### Offices Types
1309
+
1310
+ ```typescript
1311
+ type AccessPassStatus = 'active' | 'revoked';
1312
+
1313
+ interface AccessPass {
1314
+ id: number;
1315
+ email: string;
1316
+ firstName: string;
1317
+ lastName: string;
1318
+ status: AccessPassStatus;
1319
+ membershipContract: number;
1320
+ contractReference: string;
1321
+ createdAt: string;
1322
+ revokedAt: string | null;
1323
+ updatedAt: string;
1324
+ }
1325
+
1326
+ interface CreateAccessPassRequest {
1327
+ email: string;
1328
+ firstName: string;
1329
+ lastName: string;
1330
+ membershipContract: number;
1331
+ }
1332
+
1333
+ interface ListAccessPassesParams {
1334
+ limit?: number;
1335
+ offset?: number;
1336
+ includeRevoked?: boolean;
1337
+ }
1338
+ ```
1339
+
1340
+ ---
1341
+
1342
+ ## 11. Navigation Module
1343
+
1344
+ Access: `sdk.getNavigation()` returns `NavigationAccess`
1345
+
1346
+ App-to-app deep linking. Allows apps to navigate to other Frontier OS apps and receive incoming deep link data.
1347
+
1348
+ ### Methods
1349
+
1350
+ #### `openApp(appId: string, options?: NavigationOpenAppOptions): Promise<void>`
1351
+
1352
+ Navigate the host to another app in the Frontier OS ecosystem.
1353
+
1354
+ - **Permission:** `navigation:openApp` or `navigation:*`
1355
+ - `appId` — target app ID from the Frontier app registry
1356
+ - `options.path` — optional deep link path for the target app
1357
+ - `options.params` — optional key-value params for the target app
1358
+
1359
+ #### `close(): Promise<void>`
1360
+
1361
+ Close the current app and return to the previous screen.
1362
+
1363
+ - **Permission:** `navigation:close` or `navigation:*`
1364
+
1365
+ #### `onDeepLink(callback: (data: DeepLinkData) => void): () => void`
1366
+
1367
+ Register a callback for incoming deep link data. Called when this app was opened via another app's `openApp()` call. Returns an unsubscribe function.
1368
+
1369
+ No permission required (passive listener).
1370
+
1371
+ ### Types
1372
+
1373
+ ```typescript
1374
+ interface NavigationOpenAppOptions {
1375
+ path?: string;
1376
+ params?: Record<string, string>;
1377
+ }
1378
+
1379
+ interface DeepLinkData {
1380
+ path?: string;
1381
+ params?: Record<string, string>;
1382
+ }
1383
+ ```
1384
+
1385
+ ### Permissions
1386
+
1387
+ | Permission | Description |
1388
+ |---|---|
1389
+ | `navigation:openApp` | Navigate to another app |
1390
+ | `navigation:close` | Close current app |
1391
+ | `navigation:*` | All navigation permissions |
1392
+
1393
+ ---
1394
+
1395
+ ## 12. UI Utilities
1396
+
1397
+ Import from `@frontiertower/frontier-sdk/ui-utils`.
1398
+
1399
+ ### Detection
1400
+
1401
+ ```typescript
1402
+ function isInFrontierApp(): boolean
1403
+ ```
1404
+ Returns `true` if the window is embedded in an iframe (`window.self !== window.top`). Use to detect whether the app is running inside the Frontier Wallet host.
1405
+
1406
+ ```typescript
1407
+ function getParentOrigin(): string | null
1408
+ ```
1409
+ Returns the origin of the parent window (via `document.referrer` or `window.parent.location.origin`). Returns `null` if not in an iframe or origin cannot be determined.
1410
+
1411
+ ### Standalone Fallback
1412
+
1413
+ ```typescript
1414
+ function renderStandaloneMessage(container: HTMLElement, appName?: string): void
1415
+ ```
1416
+ Renders a styled "Frontier Wallet Required" message into the given container element. Default `appName` is `'Frontier App'`. Directs users to `os.frontiertower.io` to install the app.
1417
+
1418
+ ```typescript
1419
+ function createStandaloneHTML(appName?: string): string
1420
+ ```
1421
+ Returns the same styled "Frontier Wallet Required" message as an HTML string (with gradient background). Default `appName` is `'Frontier App'`.
1422
+
1423
+ ### Allowed Origins Constant
1424
+
1425
+ ```typescript
1426
+ const ALLOWED_ORIGINS: string[] = [
1427
+ 'http://localhost:5173',
1428
+ 'https://sandbox.os.frontiertower.io',
1429
+ 'https://alpha.os.frontiertower.io',
1430
+ 'https://beta.os.frontiertower.io',
1431
+ 'https://os.frontiertower.io',
1432
+ ];
1433
+ ```
1434
+
1435
+ ---
1436
+
1437
+ ## 12. Security
1438
+
1439
+ ### Allowed Origins
1440
+
1441
+ The SDK defines five allowed Frontier Wallet origins. Apps should only accept messages from these:
1442
+
1443
+ | Environment | Origin |
1444
+ |---|---|
1445
+ | Development | `http://localhost:5173` |
1446
+ | Sandbox | `https://sandbox.os.frontiertower.io` |
1447
+ | Alpha | `https://alpha.os.frontiertower.io` |
1448
+ | Beta | `https://beta.os.frontiertower.io` |
1449
+ | Production | `https://os.frontiertower.io` |
1450
+
1451
+ ### Access Controls Verification
1452
+
1453
+ The `user:getVerifiedAccessControls` method provides a tamper-proof way to verify user access. The flow:
1454
+
1455
+ 1. The PWA host relays a `SignedAccessControls` envelope from the Frontier API server.
1456
+ 2. The SDK decodes the Base64 payload, computes its SHA-256 hash, and verifies the ECDSA secp256k1 signature against a hardcoded public key for the current environment stage.
1457
+ 3. If the signature is valid, the decoded `AccessControlsPayload` is returned.
1458
+ 4. If invalid, the method throws -- the app should deny access.
1459
+
1460
+ Supported stages and their public keys (uncompressed secp256k1, hex):
1461
+
1462
+ | Stage(s) | Key |
1463
+ |---|---|
1464
+ | `test` | `04aab6c393...` (test-only key) |
1465
+ | `development`, `local`, `sandbox`, `staging` | `04dc3ab0e1...` (shared dev/sandbox key) |
1466
+ | `alpha`, `beta`, `production` | `045d1a0f9c...` (production key) |
1467
+
1468
+ **Rule: Always use `getVerifiedAccessControls()` for access-gating decisions.** Do not trust unsigned user data from other SDK methods for gating features, content, or permissions.
1469
+
1470
+ ### PostMessage Security
1471
+
1472
+ - The SDK sends requests to `window.parent` with `'*'` as the target origin.
1473
+ - The SDK only processes responses where `event.source === window.parent`.
1474
+ - Requests auto-expire after 30 seconds.
1475
+
1476
+ ---
1477
+
1478
+ ## 13. Complete Permissions List (76 permissions across 9 modules)
1479
+
1480
+ ### Wallet (23 permissions)
1481
+
1482
+ | Permission | Description |
1483
+ |---|---|
1484
+ | `wallet:getBalance` | Access wallet balance (raw bigint) |
1485
+ | `wallet:getBalanceFormatted` | Access formatted wallet balance (display strings) |
1486
+ | `wallet:getAddress` | Access wallet address |
1487
+ | `wallet:getSmartAccount` | Access smart account details |
1488
+ | `wallet:transferERC20` | Transfer ERC20 tokens |
1489
+ | `wallet:approveERC20` | Approve ERC20 token spending |
1490
+ | `wallet:transferNative` | Transfer native currency (ETH) |
1491
+ | `wallet:transferFrontierDollar` | Transfer FND (Frontier Network Dollar) |
1492
+ | `wallet:transferInternalFrontierDollar` | Transfer iFND (Internal Frontier Network Dollar) |
1493
+ | `wallet:transferOverallFrontierDollar` | Transfer using iFND first, fallback to FND |
1494
+ | `wallet:executeCall` | Execute arbitrary contract call |
1495
+ | `wallet:executeBatchCall` | Execute multiple contract calls atomically |
1496
+ | `wallet:getSupportedTokens` | Get supported token symbols for swaps |
1497
+ | `wallet:swap` | Execute token swap (same-chain or cross-chain) |
1498
+ | `wallet:quoteSwap` | Get swap quote without executing |
1499
+ | `wallet:getUsdDepositInstructions` | Get USD bank deposit instructions (on-ramp) |
1500
+ | `wallet:getEurDepositInstructions` | Get EUR/SEPA deposit instructions (on-ramp) |
1501
+ | `wallet:getLinkedBanks` | Get linked bank accounts (off-ramp) |
1502
+ | `wallet:linkUsBankAccount` | Link US bank account for USD withdrawals |
1503
+ | `wallet:linkEuroAccount` | Link EUR/IBAN bank account for EUR withdrawals |
1504
+ | `wallet:deleteLinkedBank` | Delete a linked bank account |
1505
+ | `wallet:getDeprecatedSmartAccounts` | Get deprecated smart accounts with active gas sponsorship |
1506
+ | `wallet:payWithFrontierDollar` | Pay via PaymentRouter with payment reference ID |
1507
+
1508
+ ### Storage (4 permissions)
1509
+
1510
+ | Permission | Description |
1511
+ |---|---|
1512
+ | `storage:get` | Read from persistent storage |
1513
+ | `storage:set` | Write to persistent storage |
1514
+ | `storage:remove` | Remove key from persistent storage |
1515
+ | `storage:clear` | Clear all persistent storage |
1516
+
1517
+ ### Chain (5 permissions)
1518
+
1519
+ | Permission | Description |
1520
+ |---|---|
1521
+ | `chain:getCurrentNetwork` | Get current network name |
1522
+ | `chain:getAvailableNetworks` | Get list of available networks |
1523
+ | `chain:switchNetwork` | Switch to a different network |
1524
+ | `chain:getCurrentChainConfig` | Get full chain configuration |
1525
+ | `chain:getContractAddresses` | Get FND, iFND, PaymentRouter, SubscriptionManager addresses |
1526
+
1527
+ ### User (8 permissions)
1528
+
1529
+ | Permission | Description |
1530
+ |---|---|
1531
+ | `user:getDetails` | Access current user details |
1532
+ | `user:getProfile` | Access current user profile |
1533
+ | `user:getReferralOverview` | Access referral statistics |
1534
+ | `user:getReferralDetails` | Access detailed referral information |
1535
+ | `user:addUserContact` | Add user contact information |
1536
+ | `user:getOrCreateKyc` | Get or create KYC verification status |
1537
+ | `user:createSignupRequest` | Submit membership signup request with crypto payment |
1538
+ | `user:getVerifiedAccessControls` | Get cryptographically verified access controls |
1539
+
1540
+ ### Communities (11 permissions)
1541
+
1542
+ | Permission | Description |
1543
+ |---|---|
1544
+ | `communities:listCommunities` | List all visible communities (paginated) |
1545
+ | `communities:getCommunity` | Get a community by ID or slug |
1546
+ | `communities:createInternshipPass` | Create an internship pass for a managed community |
1547
+ | `communities:listInternshipPasses` | List internship passes for managed communities |
1548
+ | `communities:getInternshipPass` | Retrieve an internship pass by ID |
1549
+ | `communities:revokeInternshipPass` | Revoke an internship pass |
1550
+ | `communities:createReassignRequest` | Create a member reassignment request |
1551
+ | `communities:listReassignRequests` | List pending reassignment requests |
1552
+ | `communities:getReassignRequest` | Retrieve a reassignment request by ID |
1553
+ | `communities:acceptReassignRequest` | Accept a reassignment request (moves member) |
1554
+ | `communities:rejectReassignRequest` | Reject a reassignment request |
1555
+
1556
+ ### Partnerships (7 permissions)
1557
+
1558
+ | Permission | Description |
1559
+ |---|---|
1560
+ | `partnerships:listSponsors` | List sponsors you manage (paginated) |
1561
+ | `partnerships:getSponsor` | Retrieve a Sponsor by ID |
1562
+ | `partnerships:createSponsorPass` | Create a SponsorPass |
1563
+ | `partnerships:listActiveSponsorPasses` | List active SponsorPasses (paginated) |
1564
+ | `partnerships:listAllSponsorPasses` | List all SponsorPasses (paginated) |
1565
+ | `partnerships:getSponsorPass` | Retrieve a SponsorPass by ID |
1566
+ | `partnerships:revokeSponsorPass` | Revoke a SponsorPass |
1567
+
1568
+ ### Third-Party (15 permissions)
1569
+
1570
+ | Permission | Description |
1571
+ |---|---|
1572
+ | `thirdParty:listDevelopers` | List developer accounts (paginated) |
1573
+ | `thirdParty:getDeveloper` | Get developer details by ID |
1574
+ | `thirdParty:updateDeveloper` | Update developer information |
1575
+ | `thirdParty:rotateDeveloperApiKey` | Rotate developer API key |
1576
+ | `thirdParty:listApps` | List registered apps (paginated) |
1577
+ | `thirdParty:createApp` | Register a new app |
1578
+ | `thirdParty:getApp` | Get app details by ID |
1579
+ | `thirdParty:updateApp` | Update an app |
1580
+ | `thirdParty:deleteApp` | Request app deactivation |
1581
+ | `thirdParty:listWebhooks` | List webhooks (paginated) |
1582
+ | `thirdParty:createWebhook` | Create a new webhook |
1583
+ | `thirdParty:getWebhook` | Get webhook details by ID |
1584
+ | `thirdParty:updateWebhook` | Update a webhook |
1585
+ | `thirdParty:deleteWebhook` | Delete a webhook |
1586
+ | `thirdParty:rotateWebhookSigningKey` | Rotate webhook signing key |
1587
+
1588
+ ### Events (6 permissions)
1589
+
1590
+ | Permission | Description |
1591
+ |---|---|
1592
+ | `events:listEvents` | List events with optional filters (paginated) |
1593
+ | `events:createEvent` | Create a new event |
1594
+ | `events:addEventHost` | Add a co-host to an event |
1595
+ | `events:listLocations` | List available locations (event spaces and rooms) |
1596
+ | `events:listRoomBookings` | List room bookings (paginated) |
1597
+ | `events:createRoomBooking` | Create a room booking |
1598
+
1599
+ ### Offices (4 permissions)
1600
+
1601
+ | Permission | Description |
1602
+ |---|---|
1603
+ | `offices:createAccessPass` | Create an access pass for a membership contract |
1604
+ | `offices:listAccessPasses` | List access passes for managed contracts (paginated) |
1605
+ | `offices:getAccessPass` | Retrieve an access pass by ID |
1606
+ | `offices:revokeAccessPass` | Revoke an access pass |
1607
+
1608
+ ### Wildcard Permissions
1609
+
1610
+ Each module supports a wildcard permission that grants access to all methods in that module:
1611
+
1612
+ | Wildcard | Grants |
1613
+ |---|---|
1614
+ | `wallet:*` | All wallet permissions |
1615
+ | `storage:*` | All storage permissions |
1616
+ | `chain:*` | All chain permissions |
1617
+ | `user:*` | All user permissions |
1618
+ | `communities:*` | All communities permissions |
1619
+ | `partnerships:*` | All partnerships permissions |
1620
+ | `thirdParty:*` | All third-party permissions |
1621
+ | `events:*` | All events permissions |
1622
+ | `offices:*` | All offices permissions |