Skip to main content

Record types

Every credential carries a recordType, a 32-bit number in the signed fields and the anchor. It says what kind of credential it is (a degree, a transcript, a certificate). The number space has three ranges:

RangeKindWho defines the name
0 to 31Built inThe app, the same list for every issuer
32 to 999ReservedNobody yet. Refused at issuance.
1000 and upIssuer-definedEach issuer for itself, numbered per issuer

Issuer-defined ids are per issuer: issuer A's type 1000 and issuer B's type 1000 are different types with different names. A verifier therefore resolves a custom type with the credential's issuer, and the UI marks every custom name as issuer-defined ("This type name was chosen by the issuer"), because it is the issuer's own choice and not a shared vocabulary.

Built-in types​

IdNameIdName
0Transcript16Transfer Certificate
1Degree17Bills
2Marksheet18Fee Receipt
3Diploma19Scholarship Letter
4Certificate20Loan Document
5Provisional Certificate21Hostel Clearance
6Birth Certificate22Routine
7Citizenship23Notice
8National ID24Circular
9Passport Copy25News
10Character Certificate26Recommendation Letter
11Entrance Results27Internship Certificate
12Admit Card28Experience Letter
13Counseling Letter29Bonafide Certificate
14Seat Allotment Letter30No Objection Certificate
15Migration Certificate31Other

The names live in RECORD_TYPE_NAMES (src/types/records.ts) and are the same list v0.2 used. The contract only knows the numbers: isTypeAllowed(issuer, id) is true for any id up to 31.

Registering a type​

Preconditions: v0.3, an active issuer, the system not paused. The page is Record types (/records/types), "Add the kinds of credential your institution issues beyond the built-in ones, and switch a type off when you stop issuing it." It is linked from the issue form (Manage your record types) and from the Issue menu (Record types). A visitor without a wallet goes to /login, a v0.2 deployment to /dashboard, and a non-issuer to /records.

Section Add a record type ("Name it the way it should read on a credential."): Name and optional Description ("A line verifiers see under the name."), button Add type.

RuleWhereLimit or checkError
Hidden characters removedBrowserControls, bidirectional marks and isolates, zero-width characters, line separators
Name requiredBrowser and contractNot empty"The type name is required." (EmptyTypeName)
Name lengthBrowser and contractAt most 64 bytes (UTF-8)"The type name is too long." (TypeNameTooLong)
Description lengthBrowser and contractAt most 256 bytes"The type description is too long." (TypeDescriptionTooLong)
Unique per issuerContractNo other type of this issuer with the same exact name"You already have a record type with this name. Pick another name." (TypeNameInUse)
Active issuerContractRegistered and not retired"Your account is not registered as an issuer on this network, so it cannot manage record types." (NotIssuer)
Not pausedContractIssuerRegistry.paused() is false"The system is paused, so new record types cannot be added right now. Try again when it restarts." (SystemPaused)

The new id is 1000 + the number of types this issuer has registered, so ids are dense per issuer and never reused. A type cannot be renamed or deleted.

Switching a type off and on​

Section Your record types lists each type with its description and a badge Active or Inactive, and a button Turn off or Turn on. The call is setTypeActive(id, active); it emits RecordTypeActiveChanged only when the state changes. A retired issuer key cannot change its types (NotIssuer), and an id the issuer never registered gives "This record type does not exist for your account." (UnknownRecordType). Switching is not stopped by the pause.

An inactive type is no longer offered on the issue form and is refused at issuance (RecordTypeNotAllowed). Credentials already issued with it are untouched and still show its name.

Where types appear​

PlaceBehaviour
Issue form, Record TypeThe 32 built-in types, then the issuer's active custom types labelled "(issuer-defined)". If the custom types cannot be read: "Your own record types could not be loaded, so only the standard types are listed."
IssuanceThe CredentialRegistry calls isTypeAllowed(issuer, recordType). A reserved id, another issuer's id, an unregistered id or an inactive type reverts with RecordTypeNotAllowed: "This record type is not available to you. It may be switched off, or it may belong to another institution."
Verify page headingThe resolved name, with the issuer-defined badge for custom types. "Unknown type" for a reserved id or an id the registry does not know, "Type unavailable" when the lookup failed.
Holder inbox and dashboardThe same resolved name and badge
Bulk importrecordType is given by name, case-insensitive, matched against the built-in names and the issuer's types; a name two of the issuer's types share is refused. See Bulk import files.
Open Badge exportBuilt-in types map to an achievement type where one fits; others may not be exportable as a badge (the issued card then explains why).

Custom names are resolved with typeOf(issuer, id) and cached once found. A name not found yet is not cached, because a node can lag behind the issuer's transaction. All names pass through the same hidden-character filter before display.

Variants​

  • v0.2 (legacy) has only the built-in list; the issue form offers those 32 names.
  • Several contract sets. Each set has its own RecordTypeRegistry. An issuer's custom types in one set are not visible in another, so an issuer who moves to a new set registers its types there again.

Code map​

ConcernFile
Contractblockchain/contracts/v03/RecordTypeRegistry.sol
Names and rulessrc/types/records.ts, src/lib/record-types.ts (typeKind, validateTypeInput, cleanTypeText)
Servicesrc/services/domain/record-type-service.ts (register, setActive, typesOf, issuable, resolve)
Eventssrc/services/indexing/credential-index.ts (recordTypesOf)
Messagessrc/lib/record-type-errors.ts, src/lib/credential-errors.ts
Pagessrc/app/records/types/page.tsx, RecordTypesPanel.tsx, src/app/records/add/issue-types.ts, src/app/verify/ResolvedRecordType.tsx, src/components/RecordTypeLabel.tsx

Tests​

  • blockchain/test/v03/RecordTypeRegistry.test.ts, CredentialRecordTypes.test.ts
  • src/lib/record-types.test.ts, src/lib/record-type-errors.test.ts, src/services/domain/record-type-service.test.ts
  • src/app/records/types/RecordTypesPanel.test.tsx, src/app/records/add/issue-types.test.ts, src/app/verify/ResolvedRecordType.test.tsx, src/components/RecordTypeLabel.test.tsx