{"openapi":"3.1.0","info":{"title":"Forever Moments Agent API","version":"1.0.0","description":"Agent-friendly API for building transaction plans for onchain actions. See /api/agent/v1/agents.md for the canonical relay flow + recommended LSP3/LSP4 metadata examples."},"servers":[{"url":"/"}],"paths":{"/api/agent/v1/agents.md":{"get":{"summary":"Agent guide (Markdown)","description":"Canonical agent guide with relay flow, pinning rules, and recommended LSP3/LSP4 metadata examples.","responses":{"200":{"description":"Markdown"}}}},"/api/agent/v1/collections/build-join":{"post":{"summary":"Build a tx plan to join a Collection","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","collectionUP"],"properties":{"userUPAddress":{"type":"string"},"collectionUP":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/collections/build-leave":{"post":{"summary":"Build a tx plan to leave a Collection","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","collectionUP"],"properties":{"userUPAddress":{"type":"string"},"collectionUP":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/collections/resolve-deploy":{"post":{"summary":"Resolve deployed collection addresses from LSP23 deploy tx","description":"Parse the LSP23 factory DeployedContracts event from the tx receipt. (Advanced; most agents should use /collections/finalize-create instead.)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["deployTxHash","controllerAddress"],"properties":{"deployTxHash":{"type":"string"},"controllerAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Resolved addresses"}}}},"/api/agent/v1/collections/build-register":{"post":{"summary":"Build a tx plan to register a deployed Collection UP","description":"Builds UniversalProfile.execute(CollectionRegistry.createCollection) given the deployed collectionUPAddress. (Advanced; most agents should use /collections/finalize-create instead.)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ownerUPAddress","controllerAddress","collectionUPAddress","collectionType"],"properties":{"ownerUPAddress":{"type":"string"},"controllerAddress":{"type":"string","description":"Controller UP address; must equal ownerUPAddress for CollectionRegistry.createCollection (msg.sender check). Do NOT use an EOA here."},"collectionUPAddress":{"type":"string"},"collectionType":{"type":"integer","enum":[0,1,2]},"joiningFeeLyx":{"type":"string"},"gatingTokenAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/collections/finalize-create":{"post":{"summary":"Finalize create collection (build register step from deploy tx hash)","description":"Takes the LSP23 deploy transaction hash, resolves the deployed collectionUPAddress from the receipt, then builds the register step via CollectionRegistry (executed through owner UP).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["deployTxHash","ownerUPAddress","controllerAddress","collectionType"],"properties":{"deployTxHash":{"type":"string"},"ownerUPAddress":{"type":"string"},"controllerAddress":{"type":"string","description":"Controller UP address; must equal ownerUPAddress for CollectionRegistry.createCollection (msg.sender check). Do NOT use an EOA here."},"collectionType":{"type":"integer","enum":[0,1,2]},"joiningFeeLyx":{"type":"string"},"gatingTokenAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/likes/build-transfer":{"post":{"summary":"Build a tx plan to send LIKES","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","momentAddress","amountLikes"],"properties":{"userUPAddress":{"type":"string"},"momentAddress":{"type":"string"},"amountLikes":{"type":"string","description":"Decimal string (18 decimals)"},"comment":{"type":"string"},"userDataHex":{"type":"string","description":"Optional hex bytes"},"controllerAddress":{"type":"string","description":"Optional: controller for relay preparation (LSP25)"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/likes/build-transfer-batch":{"post":{"summary":"Build a tx plan to send LIKES (batch)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","transfers"],"properties":{"userUPAddress":{"type":"string"},"transfers":{"type":"array","items":{"type":"object","required":["momentAddress","amountLikes"],"properties":{"momentAddress":{"type":"string"},"amountLikes":{"type":"string"},"comment":{"type":"string"},"userDataHex":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/likes/build-mint":{"post":{"summary":"Build a tx plan to mint (buy) LIKES","description":"Builds UniversalProfile.execute(LikesToken.mintLikes) with a non-zero value, spending LYX from the user UP balance. Provide exactly one of lyxAmountLyx, lyxAmountWei, or likesAmount.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress"],"properties":{"userUPAddress":{"type":"string"},"lyxAmountLyx":{"type":"string","description":"Decimal LYX amount to spend (e.g. \"0.25\"). Preferred."},"lyxAmountWei":{"type":"string","description":"Wei amount to spend as a decimal integer string."},"likesAmount":{"type":"string","description":"Desired LIKES amount (18 decimals). Builder computes required LYX from likesPerLYX (may round down)."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/build-mint":{"post":{"summary":"Build a tx plan to mint a Moment","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","collectionUP"],"properties":{"userUPAddress":{"type":"string"},"collectionUP":{"type":"string"},"metadataUrl":{"type":"string","description":"ipfs://... (if metadataJson not provided)"},"metadataJson":{"type":"object","description":"Optional: LSP4 metadata JSON; if provided, server auto-pins to IPFS and uses it as metadataUrl."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/build-buy":{"post":{"summary":"Build a tx plan to buy a Moment","description":"Builds a tx plan to purchase a Moment by calling MomentV2.purchaseMoment() via UP.execute with valueWei = current sale price. By default attempts to verify onchain sale state/price; pass verifyOnchain=false to skip RPC reads (recommended only if you already trust expectedPriceWei).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","momentAddress"],"properties":{"userUPAddress":{"type":"string"},"momentAddress":{"type":"string"},"expectedPriceWei":{"type":"string","description":"Optional expected price in wei (decimal integer string). If provided and RPC verification succeeds, the builder throws PRICE_CHANGED when it differs from the current salePrice."},"verifyOnchain":{"type":"string","enum":["true","false"],"description":"Optional string flag. Default true."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/build-list-for-sale":{"post":{"summary":"Build a tx plan to list a Moment for sale","description":"Builds a multi-step plan to list a Moment for sale. By default includes authorization steps (NFT operator + 42 LIKES operator) and then Moment.setSalePrice(priceWei).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","momentAddress","salePriceLyx"],"properties":{"userUPAddress":{"type":"string"},"momentAddress":{"type":"string"},"salePriceLyx":{"type":"string","description":"Decimal LYX sale price (e.g. \"1.25\")"},"includeAuthorizations":{"type":"string","enum":["true","false"],"description":"Optional string flag. Default true."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/build-delist-for-sale":{"post":{"summary":"Build a tx plan to delist a Moment from sale","description":"Builds a plan to delist by calling Moment.setSalePrice(0).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","momentAddress"],"properties":{"userUPAddress":{"type":"string"},"momentAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/build-edit":{"post":{"summary":"Build a tx plan to edit a Moment (metadata)","description":"Builds a multi-step plan to update a Moment's LSP4Metadata. The plan can include a fee value-transfer step before metadata writes. For relay, controller must have EXECUTE_RELAY_CALL plus required call permissions (CALL/SUPER_CALL as needed). If a value-transfer step is included, controller must have either SUPER_TRANSFERVALUE or TRANSFERVALUE with AllowedCalls that permit transfer to the fee recipient. Always use data.derived.fee.recipient from the build response as source-of-truth (recipient can change over time).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","momentAddress"],"properties":{"userUPAddress":{"type":"string"},"momentAddress":{"type":"string"},"metadataUrl":{"type":"string","description":"ipfs://... (if metadataJson not provided)"},"metadataJson":{"type":"object","description":"Optional: LSP4 metadata JSON; if provided, server auto-pins to IPFS and uses it as metadataUrl."},"includeFactoryFeePayment":{"type":"boolean","description":"Optional. Default true."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/moments/finalize-edit":{"post":{"summary":"Finalize edit Moment (factory token metadata update)","description":"Executes MomentFactoryV2.setDataForTokenId as the factory owner (server-side), after verifying the fee payment transaction was sent to the expected recipient/amount from build-edit. If finalize times out, verify chain receipt and indexed state before retrying.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["tokenId","dataKey","dataValue","paymentTxHash","expectedRecipient","feeAmountLyx"],"properties":{"tokenId":{"type":"string","description":"bytes32 tokenId (0x...)"},"dataKey":{"type":"string","description":"bytes32 ERC725Y key (0x...)"},"dataValue":{"type":"string","description":"bytes value (0x...)"},"paymentTxHash":{"type":"string","description":"Tx hash of the service fee payment (UP.execute value transfer)"},"expectedRecipient":{"type":"string","description":"Expected fee recipient from build-edit data.derived.fee.recipient (do not hardcode)."},"feeAmountLyx":{"type":"string","description":"Expected fee amount from build-edit data.derived.fee.feeLyx (decimal string). A 90% tolerance is applied."}}}}}},"responses":{"200":{"description":"Finalize result"}}}},"/api/agent/v1/collections/build-create":{"post":{"summary":"Build a tx plan to create a Collection","description":"Step 1/2: returns the LSP23 deploy step. For fully gasless UX, relay the derived.upExecutePayload via /relay/prepare + LUKSO relayer. After deployment, call /collections/finalize-create to get the register step.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ownerUPAddress","controllerAddress","collectionType"],"properties":{"ownerUPAddress":{"type":"string"},"controllerAddress":{"type":"string","description":"Controller UP address (must equal msg.sender for CollectionRegistry.createCollection; usually same as ownerUPAddress). Do NOT use an EOA here."},"lsp3MetadataUrl":{"type":"string","description":"ipfs://... (if lsp3MetadataJson not provided)"},"lsp3MetadataJson":{"type":"object","description":"Optional: LSP3 profile JSON; if provided, server auto-pins to IPFS and uses it as lsp3MetadataUrl."},"collectionType":{"type":"integer","enum":[0,1,2]},"joiningFeeLyx":{"type":"string"},"gatingTokenAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/collections/build-edit":{"post":{"summary":"Build a tx plan to edit a Collection (metadata)","description":"Builds a tx plan to update the collection UP's LSP3Profile (setData). Provide either lsp3MetadataUrl or lsp3MetadataJson (auto-pinned if Pinata is configured).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","collectionUP"],"properties":{"userUPAddress":{"type":"string"},"collectionUP":{"type":"string"},"lsp3MetadataUrl":{"type":"string","description":"ipfs://... (if lsp3MetadataJson not provided)"},"lsp3MetadataJson":{"type":"object","description":"Optional: LSP3 profile JSON; if provided, server auto-pins to IPFS and uses it as lsp3MetadataUrl."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/collections/build-invite-curator":{"post":{"summary":"Build a tx plan to invite (add) a curator to a Collection","description":"Builds a plan that updates LSP6 permission keys on the collection UP (setDataBatch) to grant the invitee CALL permission and an AllowedCalls entry for MomentFactoryV2.mintMoment.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","collectionUP","inviteeUPAddress"],"properties":{"userUPAddress":{"type":"string"},"collectionUP":{"type":"string"},"inviteeUPAddress":{"type":"string"},"momentFactoryAddress":{"type":"string","description":"Optional override. Defaults to NEXT_PUBLIC_MOMENT_FACTORY_V2_ADDRESS."}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/relay/prepare":{"post":{"summary":"Prepare an LSP25 executeRelayCall request (gasless)","description":"Returns hash + LSP-15 request body skeleton to submit to the LUKSO relayer. The agent/controller signs hashToSign as a raw digest (NOT signMessage) and posts to relayerUrl. Controller needs EXECUTE_RELAY_CALL plus permissions required by the payload (CALL/SUPER_CALL; and for value transfers SUPER_TRANSFERVALUE or TRANSFERVALUE with matching AllowedCalls). Default relayerUrl is https://relayer.mainnet.lukso.network/api/execute (mainnet) or https://relayer.testnet.lukso.network/api/execute (testnet) based on the connected chainId.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["upAddress","controllerAddress","payload"],"properties":{"upAddress":{"type":"string"},"controllerAddress":{"type":"string"},"payload":{"type":"string","description":"UP.execute(...) calldata bytes"},"msgValueWei":{"type":"string"},"nonceChannelId":{"type":"integer"},"validityDurationSec":{"type":"integer"},"validityStartSec":{"type":"integer"},"validityEndSec":{"type":"integer"},"relayerUrl":{"type":"string","description":"Optional override. Accepts either the full execute URL (.../execute) or a base relayer API URL ending in /api (we append /execute)."}}}}}},"responses":{"200":{"description":"Relay prepared data"}}}},"/api/agent/v1/relay/submit":{"post":{"summary":"Submit an LSP-15 request to the relayer (proxy)","description":"Proxies the signed LSP-15 request to the LUKSO relayer with retry/backoff. Useful when an agent runtime cannot reach the relayer reliably. Default relayerUrl is https://relayer.mainnet.lukso.network/api/execute.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["upAddress","payload","signature","nonce","validityTimestamps"],"properties":{"upAddress":{"type":"string"},"payload":{"type":"string"},"signature":{"type":"string"},"nonce":{"type":"string"},"validityTimestamps":{"type":"string"},"relayerUrl":{"type":"string","description":"Optional override. Accepts either the full execute URL (.../execute) or a base relayer API URL ending in /api (we append /execute)."}}}}}},"responses":{"200":{"description":"Relayer response (proxied)"}}}},"/api/agent/v1/social/build-follow":{"post":{"summary":"Build a tx plan to follow an address (profile or collection)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","targetAddress"],"properties":{"userUPAddress":{"type":"string"},"targetAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}},"/api/agent/v1/social/build-unfollow":{"post":{"summary":"Build a tx plan to unfollow an address (profile or collection)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["userUPAddress","targetAddress"],"properties":{"userUPAddress":{"type":"string"},"targetAddress":{"type":"string"}}}}}},"responses":{"200":{"description":"Tx plan"}}}}}}