Step 6 - Set Up the /api Folder + Magmar Routes
In this step we wire up every server-side call your dApp needs.
You’ll create four HTTP endpoints in /app/api
that rely on the Magmar SDK stack.
Endpoint
Purpose
Magmar module
/api/get-signer
Deterministically derive the owner address behind a Smart-Contract Wallet (SCW)
@magmar/aa-core
/api/get-user-nfts
Fetch NFTs owned by an SCW for dashboard display
magmar-nft-sdk
/api/mint-nft-user-op
Send a sponsored UserOperation that mints an NFT to the user’s SCW
@magmar/aa-core
+ @magmar/aa-paymaster
/api/get-user
Retrieve a user’s encrypted private key from Userbase (demo only)
axios
6.1 Install Magmar Server-Side Dependencies
npm i @magmar/aa-core @magmar/aa-paymaster magmar-nft-sdk axios
6.2 Project Structure
/app
/api
/get-signer
route.ts
/get-user-nfts
route.ts
/mint-nft-user-op
route.ts
/get-user
route.ts
6.3 /get-signer/route.ts
/get-signer/route.ts
import { withMagmarPaymaster } from "@magmar/aa-paymaster";
import {
LocalAccountSigner,
SimpleSmartContractAccount,
SmartAccountProvider,
type SimpleSmartAccountOwner,
} from "@magmar/aa-core";
import { NextRequest, NextResponse } from "next/server";
import { sepolia } from "viem/chains";
const RPC_URL = process.env.SEPOLIA_RPC_URL!;
const ENTRYPOINT = process.env.SEPOLIA_ENTRYPOINT_ADDRESS as `0x${string}`;
const FACTORY = process.env.SEPOLIA_SIMPLE_ACCOUNT_FACTORY_ADDRESS as `0x${string}`;
const POLICY_ID = process.env.SEPOLIA_PAYMASTER_POLICY_ID!; // created in Step 2
export async function POST(req: NextRequest) {
const { pk } = await req.json(); // raw private-key hex
const owner: SimpleSmartAccountOwner =
LocalAccountSigner.privateKeyToAccountSigner(`0x${pk}`);
const provider = new SmartAccountProvider(RPC_URL, ENTRYPOINT, sepolia);
let signer = provider.connect(
(rpc) =>
new SimpleSmartContractAccount({
entryPointAddress: ENTRYPOINT,
chain: sepolia,
owner,
factoryAddress: FACTORY,
rpcClient: rpc,
}),
);
/* Attach Magmar paymaster for sponsored gas */
signer = withMagmarPaymaster(signer, { policyId: POLICY_ID });
const ownerAddress = (signer.account as any).owner.owner.address;
return NextResponse.json({ data: ownerAddress });
}
6.4 /get-user-nfts/route.ts
/get-user-nfts/route.ts
import { NextRequest, NextResponse } from "next/server";
import { MagmarNFT } from "magmar-nft-sdk";
const nft = new MagmarNFT({ rpcUrl: process.env.SEPOLIA_RPC_URL! });
export async function POST(req: NextRequest) {
const { address } = await req.json();
const nfts = await nft.getNftsForOwner(address);
return NextResponse.json({ data: nfts });
}
6.5 /mint-nft-user-op/route.ts
(sponsored mint)
/mint-nft-user-op/route.ts
(sponsored mint)import { withMagmarPaymaster } from "@magmar/aa-paymaster";
import {
LocalAccountSigner,
SimpleSmartContractAccount,
SmartAccountProvider,
SendUserOperationResult,
type SimpleSmartAccountOwner,
} from "@magmar/aa-core";
import nftAbi from "@common/utils/NFTContract.json";
import axios from "axios";
import { encodeFunctionData, parseEther } from "viem";
import { sepolia } from "viem/chains";
import { NextRequest, NextResponse } from "next/server";
const RPC_URL = process.env.SEPOLIA_RPC_URL!;
const ENTRYPOINT = process.env.SEPOLIA_ENTRYPOINT_ADDRESS as `0x${string}`;
const FACTORY = process.env.SEPOLIA_SIMPLE_ACCOUNT_FACTORY_ADDRESS as `0x${string}`;
const POLICY_ID = process.env.SEPOLIA_PAYMASTER_POLICY_ID!;
const NFT_ADDR = process.env.SEPOLIA_NFT_ADDRESS as `0x${string}`;
export async function POST(req: NextRequest) {
const { userId, userScwAddress } = await req.json();
/* 1 – Load demo private key from Userbase */
const { data } = await axios.get(
`https://v1.userbase.com/v1/admin/users/${userId}`,
{ headers: { Authorization: `Bearer ${process.env.USERBASE_ACCESS_TOKEN}` } },
);
const pk = data?.profile?.pk as string;
/* 2 – Create signer */
const signer = await buildSigner(pk);
/* 3 – Encode `mint(address)` call */
const callData = encodeFunctionData({
abi: nftAbi,
functionName: "mint",
args: [userScwAddress],
});
/* 4 – Send sponsored UserOperation */
const result: SendUserOperationResult = await signer.sendUserOperation({
target: NFT_ADDR,
data: callData,
value: parseEther("0"),
});
/* 5 – Wait for inclusion */
const txHash = await signer.waitForUserOperationTransaction(result.hash);
const receipt = await signer.rpcClient.waitForTransactionReceipt({ hash: txHash });
return NextResponse.json({ receipt });
}
async function buildSigner(rawPk: string) {
const owner: SimpleSmartAccountOwner =
LocalAccountSigner.privateKeyToAccountSigner(`0x${rawPk}`);
const provider = new SmartAccountProvider(RPC_URL, ENTRYPOINT, sepolia);
let signer = provider.connect(
(rpc) =>
new SimpleSmartContractAccount({
entryPointAddress: ENTRYPOINT,
chain: sepolia,
owner,
factoryAddress: FACTORY,
rpcClient: rpc,
}),
);
return withMagmarPaymaster(signer, { policyId: POLICY_ID });
}
6.6 /get-user/route.ts
(demo-only key fetch)
/get-user/route.ts
(demo-only key fetch)import axios from "axios";
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const { userId } = await req.json();
const { data } = await axios.get(
`https://v1.userbase.com/v1/admin/users/${userId}`,
{ headers: { Authorization: `Bearer ${process.env.USERBASE_ACCESS_TOKEN}` } },
);
return NextResponse.json({ response: data });
}
6.7 Update .env.local
.env.local
# Chain & RPC
SEPOLIA_RPC_URL=https://sepolia.infura.io/v3/your-key
# Magmar AA
SEPOLIA_ENTRYPOINT_ADDRESS=0x...
SEPOLIA_SIMPLE_ACCOUNT_FACTORY_ADDRESS=0x...
SEPOLIA_NFT_ADDRESS=0x5700D74F864CE224fC5D39a715A744f8d1964429
SEPOLIA_PAYMASTER_POLICY_ID=your-magmar-policy-id
# Userbase
USERBASE_ACCESS_TOKEN=your-userbase-token
Result
/sign-up
and/login
now compile without red errorsA new user can register, mint an NFT, and view it all gas-free using Magmar Paymaster sponsorship
PreviousStep 5 – Utility Modules & Environment VariablesNextStep 7 - Set Up Your Home Route for Magmar
Last updated