Skip to main content

Line Items

A line item is a column in your gradebook — one gradeable thing, with a maximum score. Tools create line items so they have somewhere to put the grades they later post.

Five request types cover the full lifecycle: LINEITEMS_GET, LINEITEMS_POST, LINEITEM_GET, LINEITEM_PUT and LINEITEM_DELETE.

caution

Requires Assignment and Grades enabled on your account. Reading needs LINEITEMS_READ in the tool's permissions; creating, updating and deleting need LINEITEMS_READ_WRITE.

The Shape of a Line Item

{
"id": "412",
"label": "My first grade line",
"scoreMaximum": 99,
"resourceLinkId": "412",
"tag": "new_tag"
}
FieldRequiredMeaning
idyesYour stable identifier. LTIAAS builds the tool-facing URL from it.
labelyesThe column name a teacher sees
scoreMaximumyesHighest possible score
resourceLinkIdnoTies the line item to one activity
tagnoA tool-defined label, used to group or find its own line items
caution

id must be stable. The tool stores the URL built from it and uses that URL for every later read and write. If your IDs move, the tool's grade writes start landing in the wrong place — or nowhere.

List Line Items

LINEITEMS_GET may carry optional filters. Apply them when present.

{
"type": "LINEITEMS_GET",
"parameters": {
"context": "2022CSEa5e6c431b91",
"clientId": "348080fn9du9b9ufvb92rfb9l",
"filters": { "resourceLinkId": "17", "tag": "myLineItems" }
}
}
async function handleLineItemsList(decoded, res) {
const { context, filters = {} } = decoded.parameters

let lineItems = await db.lineItems.forCourse(context)
if (filters.resourceLinkId) {
lineItems = lineItems.filter(li => li.resourceLinkId === filters.resourceLinkId)
}
if (filters.tag) {
lineItems = lineItems.filter(li => li.tag === filters.tag)
}

return res.status(200).json(lineItems.map(serializeLineItem))
}

Return an array — an empty one is fine when nothing matches.

Create a Line Item

LINEITEMS_POST carries the proposed line item under parameters.lineItem. Store it and return the stored record, including the id you assigned.

async function handleLineItemCreate(decoded, res) {
const { context, lineItem } = decoded.parameters

const created = await db.lineItems.create({
courseId: context,
label: lineItem.label,
scoreMaximum: lineItem.scoreMaximum,
resourceLinkId: lineItem.resourceLinkId ?? null,
tag: lineItem.tag ?? null
})

return res.status(200).json(serializeLineItem(created))
}
note

Return 200, not 201 — LTIAAS converts your response into the status the tool expects.

Fetch One

async function handleLineItemGet(decoded, res) {
const { context, lineItemId } = decoded.parameters

const lineItem = await db.lineItems.find(lineItemId)
if (!lineItem || lineItem.courseId !== context) {
return res.status(404).json({ error: 'Line item not found' })
}

return res.status(200).json(serializeLineItem(lineItem))
}

Checking that the line item actually belongs to the requested context is worth the extra line — it stops a tool in one course from reading grade lines in another.

Update

LINEITEM_PUT carries both lineItemId and a lineItem object. Apply the change and return the stored record.

async function handleLineItemUpdate(decoded, res) {
const { context, lineItemId, lineItem } = decoded.parameters

const existing = await db.lineItems.find(lineItemId)
if (!existing || existing.courseId !== context) {
return res.status(404).json({ error: 'Line item not found' })
}

const updated = await db.lineItems.update(lineItemId, {
label: lineItem.label,
scoreMaximum: lineItem.scoreMaximum,
resourceLinkId: lineItem.resourceLinkId ?? null,
tag: lineItem.tag ?? null
})

return res.status(200).json(serializeLineItem(updated))
}

Delete

Remove it and return 200 with an empty body.

async function handleLineItemDelete(decoded, res) {
const { context, lineItemId } = decoded.parameters

const existing = await db.lineItems.find(lineItemId)
if (!existing || existing.courseId !== context) {
return res.status(404).json({ error: 'Line item not found' })
}

await db.lineItems.delete(lineItemId)
return res.status(200).send()
}
tip

Deleting a line item usually means deleting real grades. Consider soft-deleting and hiding the column instead — teachers who lose a gradebook column to a tool's cleanup routine are rarely pleased.

A Shared Serializer

function serializeLineItem(li) {
return {
id: String(li.id),
label: li.label,
scoreMaximum: li.scoreMaximum,
...(li.resourceLinkId && { resourceLinkId: String(li.resourceLinkId) }),
...(li.tag && { tag: li.tag })
}
}

id and resourceLinkId must be strings. Numeric IDs from your database will fail LTIAAS's schema validation, which is a common first bug here.

Next Steps

Scores and results — putting grades into these columns.

All trademarks, logos, and service marks displayed on this website are the property of their respective owners. LTIAAS is a trademark of GatherAct, LLC, doing business as LTIAAS. Learning Tools Interoperability (LTI)® and LTI® are trademarks of 1EdTech Consortium, Inc. LTIAAS is not affiliated with, endorsed or sponsored by 1EdTech Consortium, Inc. or by any other owners of third-party trademarks used on this website. LTIAAS is not responsible for the content, quality, or accuracy of any websites linked to or from this website that are not owned by LTIAAS. If you have any questions or concerns about the use of any trademarks or content on this website, please contact us.