Improved

Summer release note - announcements, surveys & registrations go API-first, MCP & OAuth 2.1 for agentic systems

Two months of work, one release note. Edusign's API can now be driven by AI agents over OAuth 2.1, and three journeys that used to require the back-office, announcing, surveying, and opening registrations, are fully automatable end to end.

Everything below is live in production today.

📘

TL;DR

🤖 Connect Claude (or any MCP host) to your Edusign account — OAuth 2.1, PKCE, read/write scopes.
📣📝🎟️ Three journeys go API-first — push announcements, survey templates, training registration forms.
20+ new endpoints, 18 routes out of beta, and a full timezone-consistency pass.


🤖 Bring your own AI agent

Remote MCP server · NEW

https://mcp.edusign.com

Connect Claude, ChatGPT or any MCP-compatible host to your Edusign account and let it read and act on your data — in your users' name, with your permissions.

The server holds no privileges of its own: it verifies your token and replays it against the API, which stays the sole authorization judge. No shared API key, no standing access.

OAuth 2.1 authentication · NEW

https://auth.edusign.com/api/auth

The API now accepts OAuth 2.1 bearer tokens alongside classic API keys. Authorization code with PKCE, refresh tokens, dynamic client registration and RFC 9728 protected-resource discovery — so compliant clients configure themselves.

ScopeGrants
edusign:api.readEvery read endpoint
edusign:api.writeCreates, updates, archives
offline_accessA refresh token, so long-running integrations stay connected
👍

Your existing API keys keep working exactly as before. Nothing to migrate.


📣 Reach your learners — from your own systems

Send a push announcement · NEW

POST /v3/notifications/announcementsreference

Push a message to your white-label app straight from your LMS, ERP or CRM. Enrolment confirmed, room changed, deadline tomorrow — your systems already know it, now they can say it.

  • Choose your audience — everyone, authenticated users only, or up to 1,000 targeted users or groups, addressed by Edusign ID or by your own external reference.
  • Choose your channelpush_and_inbox (push plus a trace in the app's Messages tab) or push_only (lock screen only).
  • Schedule it — set sendAt to any future ISO 8601 datetime and get a 202; omit it and it goes out now.
  • Add links — inline Markdown links render as real links in the in-app message.
  • Speak their languagefr, en, es, it, defaulting to the school language.

Titles are capped at 60 characters, bodies at 1,500 — 120 for push_only, where the OS only shows a preview.

Availability: schools with a white-label app and the Messaging feature enabled.


📝 Own your feedback loop

Survey templates, full lifecycle · NEW

Endpoint
CreatePOST /v3/survey-templatesreference
ReplacePUT /v3/survey-templates/:idreference · by reference
ArchiveDELETE /v3/survey-templates/:idreference · by reference
RestorePOST /v3/survey-templates/:id/restorereference · by reference

Version your questionnaires in your own repository and push them to Edusign — no more copy-pasting questions into the back-office when a form changes. Every route has a by-reference-id twin, so your connector never has to store an Edusign ID.

Know when a survey actually goes out · NEW

on_survey_sent
on_scheduled_survey_sent

Two new webhook events close the loop between "I scheduled a survey" and "it reached its recipients":

  • on_survey_sent fires per recipient, on manual and scheduled sends alike, carrying surveyId, recipientId and recipientType (student, professor or external).
  • on_scheduled_survey_sent fires once per scheduled batch, when the auto-send job completes, carrying surveyId, recipientCount and the originating courseId or trainingId.

Subscribe for a per-person audit trail, for a single "your programmed survey went out" signal, or both. Each is also available as an automation trigger.

Find the responses you're looking for · IMPROVED

GET /v3/surveys accepts completionDateFrom and completionDateTo to fetch only the responses submitted in a window — the incremental pull your reporting job actually wants. Responses now also carry the respondent's externalReferenceId, so you can join them to your own records without a lookup round-trip.


🎟️ Open your trainings to registrations

Training registration forms · NEW

GET · PUT /v3/trainings/:id/registration-formread · configure

Configure the public registration form of a training program and retrieve its link — so a new session published on your website can open its own registrations, automatically. Custom variables are referenced by name, which keeps payloads readable and portable across environments. Both routes have by-reference-id twins.


🏫 Rooms, groups and rosters

Classrooms CRUD · NEW

MethodEndpoint
GET/v3/classroomsreference
POST/v3/classroomsreference
PATCH/v3/classrooms/:idreference · by reference
DELETE/v3/classrooms/:idreference · by reference

Sync your room inventory like any other resource, by Edusign ID or by external reference. Each classroom carries an optional linkTo URL — the natural home for a virtual-classroom or video-conference link.

Archive and restore a group · NEW

DELETE /v3/groups/:idreference · by reference
POST /v3/groups/:groupId/restorereference · by reference

A soft archive with explicit semantics — worth reading before you wire it up:

  • The group is hidden and detached from its parent. Student memberships are preserved.
  • Direct child groups are orphaned, not archived — their parent link is cleared and they stay active.
  • No cascade to courses, students, trainings or alerts.
  • Archiving an already-archived group returns 409 ARCHIVED_GROUP_EXISTS; restoring an active one returns 409 GROUP_NOT_ARCHIVED.
  • A restored group comes back as a root group — the previous parent link is not re-established.
  • GROUP_DELETED and GROUP_UNREMOVED webhooks fire on success.

Restore an archived professor · NEW

POST /v3/professors/:professorId/restorereference · by reference

Closes the archive/restore loop for professors, matching students and groups.

Batch upsert groups, now addressable by internal ID · IMPROVED

POST /v3/groups/batch-upsert matches on externalReferenceId or groupId, and accepts parentGroupId to build hierarchies in one pass. Circular hierarchies are rejected per item (CIRCULAR_HIERARCHY) instead of corrupting your tree. Batch assign students to groups now handles up to 1,000 assignments per call.

Unarchive during a training batch upsert · IMPROVED

POST /v3/trainings/batch-upsert accepts options.allowUnarchive to bring an archived training back and update it in the same call, instead of failing with ARCHIVED_TRAINING_EXISTS.


🔄 Keep your systems in sync

Incremental student sync · IMPROVED

GET /v3/students accepts updatedAfter (ISO 8601) to pull only what changed since your last run, and isArchived to include or isolate archived students. Nightly full-table syncs can retire.

See your webhook registrations · NEW

GET /v3/webhooksreference

List the webhooks configured for your school, paginated and filterable. Debugging "why didn't I receive that event?" no longer requires opening a ticket.


✅ Out of beta

18 high-usage routes are now stable. Selection was driven by real 30-day production usage across students, professors, courses, groups, subjects and assessments — the [BETA] tag is gone from the reference and from the OpenAPI spec. Same paths, same payloads: no action needed.


🛠️ Fixed & hardened

Dates behave the same on the way in and on the way out · FIXED

We found and closed an asymmetry: some resources persisted datetimes in UTC while reading them back in the school's timezone, which could shift a value by the school's offset. Courses, assessments, submissions, subjects, grades, trainings and surveys now consistently store and return datetimes in the school's timezone.

🚧

If you previously compensated for a drift on those resources, remove your workaround.

Validation errors you can forward to a user · IMPROVED

Schema validation messages were rewritten in plain wording — "body must be at most 1500 characters" rather than raw validator output — so you can surface them in your own UI without translating them first.

One limit for external references, everywhere · IMPROVED

externalReferenceId is capped at 64 characters and externalReferenceType at 30 across every resource; these previously varied by domain. Group logoUrl now accepts only http(s) URLs.

More accurate batch responses · IMPROVED

updatedFields reports only genuinely changed fields, and no-op updates no longer fire TRAINING_EDITED. Batch assignment rejects archived groups and duplicate pairs up front.


🗒️ Also live, and now fully documented

Shipped over the spring and never given a proper announcement — every one of these has a reference page today:


📌 Good to know

  • Nothing breaking. Every change above is additive. Existing calls and API keys behave exactly as before.
  • apiId / apiType remain deprecated in favour of externalReferenceId / externalReferenceType. They still work; new integrations should use the standardized fields.
  • by-reference-id everywhere. Every new mutation route ships with an external-reference twin, so a connector never has to persist an Edusign ID.

📘

Building something with these?

We read every message — tell us what you're wiring up and what's still missing. The endpoints above exist because integrators asked for them.