Manage Modules
API integration guide for creating, updating, and removing course modules
Manage Modules
Teachers can create, update, and remove learning modules within a course in a single batch transaction. Each module represents a Student Learning Target (SLT) and holds the criteria students must satisfy to earn credit.
Summary
| Property | Value |
|---|---|
| System | Course |
| Role | Teacher |
| Type Key | modules_manage |
| Build Endpoint | POST /api/v2/tx/course/teacher/modules/manage |
| DB Sync | Yes |
| Service Fee | 0 ADA |
| Est. Wallet Cost | ~1.86 ADA per module |
The wallet cost scales with the number of modules: transaction fee ~0.27 ADA + UTxO deposit ~1.59 ADA per module minted. Approximate costs: 5 modules ~8.4 ADA, 10 modules ~16.5 ADA. UTxO deposits are recoverable when modules are burned.
Build Transaction
Endpoint
POST /api/v2/tx/course/teacher/modules/manage
Request Body
{
"alias": "teacher1",
"courseId": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
"modulesToMint": [
{
"slts": ["Learner can deploy a smart contract to preprod"],
"allowedStudents_V2": [],
"prerequisiteAssignments_V2": []
},
{
"slts": ["Learner can write unit tests for a Plutus validator"],
"allowedStudents_V2": [],
"prerequisiteAssignments_V2": ["9f3a1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a"]
}
],
"modulesToUpdate": [],
"modulesToBurn": [],
"walletData": {
"usedAddresses": ["addr1qx2fxv..."],
"changeAddress": "addr1qx2fxv..."
}
}| Field | Type | Required | Description |
|---|---|---|---|
alias | string (Alias) | Yes | The teacher's access token alias. Must be in the course's teacher list. |
courseId | string (GYMintingPolicyId) | Yes | The 56-character hex course policy ID. |
modulesToMint | MintModuleV2[] | Yes | Array of new modules to create. Pass an empty array if not creating any. |
modulesToMint[].slts | string[] | Yes | Student Learning Targets — descriptions of what the student must demonstrate. |
modulesToMint[].allowedStudents_V2 | string[] (GYMintingPolicyId[]) | Yes | Policy IDs of courses whose students may access this module. Empty array means open to all enrolled students. |
modulesToMint[].prerequisiteAssignments_V2 | string[] (SltHash[]) | Yes | 64-character hex hashes of modules that must be completed before this one. Empty array means no prerequisites. |
modulesToUpdate | UpdateModuleV2[] | Yes | Array of existing modules to update. Pass an empty array if not updating any. |
modulesToUpdate[].sltHash | string (SltHash) | Yes | 64-character hex hash identifying the module to update. |
modulesToUpdate[].allowedStudents_V2 | string[] (GYMintingPolicyId[]) | Yes | Updated list of allowed student course policy IDs. |
modulesToUpdate[].prerequisiteAssignments_V2 | string[] (SltHash[]) | Yes | Updated list of prerequisite module hashes. |
modulesToBurn | string[] (SltHash[]) | Yes | 64-character hex hashes of modules to remove. Pass an empty array if not removing any. |
walletData | WalletData | No | Object containing usedAddresses (string[]) and changeAddress (string). |
Response
{
"unsignedTxCBOR": "84a800..."
}The response contains the unsigned transaction CBOR, ready for the user's wallet to sign.
Register Transaction
After the user signs and submits the transaction, register it with the state machine:
POST /api/v2/tx/register
{
"tx_hash": "64-char hex hash from wallet.submitTx()",
"tx_type": "modules_manage"
}No metadata is required. On confirmation, the state machine batch-confirms all created modules and removes all burned modules from the database.
Related API Endpoints
| Endpoint | Description |
|---|---|
GET /api/v2/courses/{course_id}/modules | List all modules for the course, including SLT hashes and prerequisite chains |
Example: Full Lifecycle
const API_URL = "https://api.andamio.io";
// 1. Build — create two modules, one with a prerequisite
const buildRes = await fetch(`${API_URL}/api/v2/tx/course/teacher/modules/manage`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
"Authorization": `Bearer ${userJwt}`,
},
body: JSON.stringify({
alias: "teacher1",
courseId: "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4",
modulesToMint: [
{
slts: ["Learner can deploy a smart contract to preprod"],
allowedStudents_V2: [],
prerequisiteAssignments_V2: [],
},
],
modulesToUpdate: [],
modulesToBurn: [],
walletData: {
usedAddresses: [walletAddress],
changeAddress: walletAddress,
},
}),
});
const { unsignedTxCBOR } = await buildRes.json();
// 2. Sign
const signedTx = await wallet.signTx(unsignedTxCBOR);
// 3. Submit
const txHash = await wallet.submitTx(signedTx);
// 4. Register
await fetch(`${API_URL}/api/v2/tx/register`, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-API-Key": API_KEY,
"Authorization": `Bearer ${userJwt}`,
},
body: JSON.stringify({
tx_hash: txHash,
tx_type: "modules_manage",
}),
});
// 5. Monitor (SSE)
const events = new EventSource(
`${API_URL}/api/v2/tx/stream/${txHash}`
);
events.addEventListener("state_change", (e) => {
const data = JSON.parse(e.data);
console.log(`State: ${data.old_state} → ${data.new_state}`);
});
events.addEventListener("complete", (e) => {
const data = JSON.parse(e.data);
console.log(`Final: ${data.final_state}`);
events.close();
});See Also
- Transaction State Machine -- Lifecycle overview
- Teacher: Assess Assignments -- Evaluate student work
- Student: Commit to Assignment -- Students begin working on modules