CredAxis Developer Docs
CredAxis is an on-chain academic credential infrastructure built on Base (EVM). Universities deploy their own Registry smart contracts to issue tamper-proof transcripts. External parties — employers, graduate schools, regulators — verify credentials instantly without contacting the institution.
https://credaxis.app/api — the Render backend is proxied and never exposed publicly.For Institutions
Universities & schools deploy a Registry contract, whitelist students, and issue on-chain transcripts with one click. The registrar dashboard handles everything.
For Students
Students connect their wallet, request their transcript, and share a cryptographic proof link with anyone. No PDFs that can be faked.
For Verifiers
Employers, graduate schools, or HR systems call our Verify API with a record ID or student ID and receive instant, on-chain confirmation.
For Developers
Integrate CredAxis into your LMS, HR platform, or verification portal with our REST API and institutional API tokens.
Platform Architecture
Base L2 (EVM)
Hono + PostgreSQL
Metadata + PDF Hash
credaxis.app/api
GET /api/public/verify
Authentication
Most read endpoints are public and require no authentication. Write operations and private data endpoints require a Privy JWT (for registered users) or a CredAxis institutional API token (prefixed ct_) passed as a Bearer token.
PublicNo token required. Read-only access to public registry data.
Privy JWTIssued on login via Privy. Required for student & registrar write actions.
ct_ tokenInstitutional API key. Issued by admin. Used for server-to-server verification.
Quickstart Guide
Integrate CredAxis transcript verification into your system in under 5 minutes. No blockchain knowledge required.
Get an API Token (for private lookups)
Public transcript verification by record ID requires no token. For private student ID lookups, request an institutional API token from your CredAxis admin or via support@credaxis.app.
ct_ and passed as a Bearer token in the Authorization header.Verify a Transcript by Record ID (Public)
This is the simplest integration — just call the public verify endpoint with the transcript's record ID (a 66-character 0x hash from the blockchain).
curl -X GET \
"https://credaxis.app/api/public/verify?recordId=0xaa877681f268a7a927036de034fd930a854f2aec555795b6b612edb479ae2987"{
"transcript": {
"recordId": "0xaa877681...",
"registryAddr": "0x0487722E...",
"issuedAt": "2025-12-01T10:00:00.000Z",
"status": "Active",
"fileHash": "0xabc123...",
"studentHash": "0xdef456..."
},
"student": {
"fullName": "John Doe",
"studentId": "UG/CS/2021/001",
"walletAddress": "0xC52A..."
},
"university": {
"name": "Kwame Nkrumah University",
"contractAddr": "0x0487722E...",
"logoUrl": "https://..."
},
"authorizedBy": "Direct QR Code / Record ID Link"
}Verify by Student ID (Requires Token)
To look up a transcript by student ID (instead of the on-chain record hash), pass your institutional token.
curl -X GET \
"https://credaxis.app/api/public/verify?studentId=UG/CS/2021/001&token=ct_your_token_here"JavaScript / TypeScript Integration
const BASE_URL = "https://credaxis.app/api"
async function verifyTranscript(recordId: string) {
const res = await fetch(
`${BASE_URL}/public/verify?recordId=${recordId}`
)
if (!res.ok) {
const err = await res.json()
throw new Error(err.error || "Verification failed")
}
const data = await res.json()
// data.transcript.status === "Active" means valid
return {
isValid: data.transcript?.status === "Active",
student: data.student,
university: data.university,
issuedAt: data.transcript?.issuedAt,
}
}
// Usage
const result = await verifyTranscript("0xaa877681...")
console.log(result.isValid) // true
console.log(result.student) // { fullName: "John Doe", ... }Register Your Institution
To request transcripts on behalf of your organisation, register as an institution:
curl -X POST https://credaxis.app/api/institutions/register \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Graduate School",
"email": "admissions@acme.edu",
"walletAddress": "0xYourWalletAddress"
}'Verify API
The Verify API is the primary public interface for external systems to check the authenticity of academic credentials on-chain.
/api/public/verifyVerify a transcript by its on-chain Record ID or by Student ID (with token). Querying by record ID is fully public — no token needed. Querying by student ID requires a valid institutional token for privacy protection.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
recordId | string | No | The 0x-prefixed on-chain record ID (keccak256 hash). No token required. |
studentId | string | No | The university student ID. Requires a valid token parameter. |
token | string | No | Institutional API key (ct_...) or student-approved access token (req_...). |
recordId or studentId. Both together defaults to recordId.Response — Authorized (Full Data)
{
"transcript": {
"recordId": "0xaa877681f268...",
"registryAddr": "0x0487722E60f4...",
"studentHash": "0xdef456abc...",
"fileHash": "0x1234abcdef...",
"issuedAt": "2025-12-01T10:00:00.000Z",
"status": "Active",
"issuer": "0xregistrar_address",
"universityId": 1
},
"student": {
"fullName": "John Doe",
"studentId": "UG/CS/2021/001",
"email": "john.doe@example.com",
"walletAddress": "0xC52A761..."
},
"university": {
"name": "Kwame Nkrumah University of Science and Technology",
"contractAddr": "0x0487722E60f4...",
"logoUrl": "https://ipfs.io/ipfs/...",
"stampUrl": "https://ipfs.io/ipfs/..."
},
"authorizedBy": "Institutional API Key (Acme Graduate School)"
}Response — Public Limited (No Token, Student ID Query)
{
"transcript": {
"recordId": "0xaa877681f268...",
"registryAddr": "0x0487722E60f4...",
"issuedAt": "2025-12-01T10:00:00.000Z",
"status": "Active"
},
"university": {
"name": "Kwame Nkrumah University",
"logoUrl": "https://...",
"contractAddr": "0x0487722E..."
},
"requestAccessRequired": true
}/api/public/request-accessAllows an external verifier (employer, institution) to request permission from a student to view their full transcript details. The student receives an email and can approve or deny with one click.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
recordId | string | Yes | The on-chain transcript record ID. |
requesterName | string | Yes | Full name of the requester. |
requesterOrg | string | Yes | Organisation or company name. |
requesterEmail | string | Yes | Email where the access token will be sent upon approval. |
curl -X POST https://credaxis.app/api/public/request-access \
-H "Content-Type: application/json" \
-d '{
"recordId": "0xaa877681f268...",
"requesterName": "Dr. Mary Asante",
"requesterOrg": "Accra Graduate School",
"requesterEmail": "m.asante@agsgh.edu"
}'{
"success": true,
"message": "Verification request sent to student email."
}/api/public/email-transcriptSends a formatted, verified transcript receipt email directly to any email address. Useful for sharing proof without exposing the dashboard URL.
curl -X POST https://credaxis.app/api/public/email-transcript \
-H "Content-Type: application/json" \
-d '{
"to": "employer@company.com",
"recordId": "0xaa877681f268...",
"registryAddress": "0x0487722E60f4...",
"studentName": "John Doe",
"studentId": "UG/CS/2021/001",
"gpa": "3.85",
"major": "BSc Computer Science",
"gradYear": "2025",
"universityName": "KNUST"
}'/api/stats/platformReturns real-time platform statistics.
{
"totalUniversities": 8,
"activeUniversities": 6,
"totalTranscripts": 342,
"totalVerifications": 1024
}Transcript API
Endpoints for reading transcript records indexed from on-chain events. All transcript data is sourced from the Base blockchain indexer.
/api/transcripts/:recordIdFetch a single transcript by its on-chain record ID.
curl https://credaxis.app/api/transcripts/0xaa877681f268a7a927036de034fd930a854f2aec555795b6b612edb479ae2987{
"id": 1,
"recordId": "0xaa877681...",
"studentHash": "0x...",
"fileHash": "0x...",
"registryAddr": "0x0487722E...",
"issuer": "0x6912bC40...",
"issuedAt": "2025-12-01T10:00:00.000Z",
"status": "Active",
"universityId": 1
}/api/transcripts/by-student/:studentHashReturns all transcripts for a student identified by their studentHash (keccak256 of the student's wallet address).
studentHash: keccak256(abi.encodePacked(walletAddress))import { keccak256, encodePacked } from "viem"
const studentHash = keccak256(
encodePacked(["address"], ["0xC52A761304DE7DFEea1570361bf190803fF55b6c"])
)
// → "0xdef456abc..."curl https://credaxis.app/api/transcripts/by-student/0xdef456abc.../api/transcripts/by-registrar/:addressReturns all transcripts issued by a registrar address.
curl https://credaxis.app/api/transcripts/by-registrar/0x6912bC40f1446Dd8A2201F797f2c09dca3CeB88c/api/transcripts/by-registry/:addrReturns all transcripts issued through a specific registry contract address.
curl https://credaxis.app/api/transcripts/by-registry/0x0487722E60f437F5588BC97501177d1384c84E19/api/transcripts/requestA student submits a request for their transcript. If an active transcript already exists on-chain, it is auto-delivered by email. If not, the registrar is notified to issue one.
| Parameter | Type | Required | Description |
|---|---|---|---|
studentWallet | string | Yes | The student's EVM wallet address. |
email | string | No | Student email (optional override). |
curl -X POST https://credaxis.app/api/transcripts/request \
-H "Content-Type: application/json" \
-d '{
"studentWallet": "0xC52A761304DE7DFEea1570361bf190803fF55b6c"
}'{
"status": "sent",
"message": "Official transcript found! A verification receipt has been emailed to you."
}{
"status": "requested",
"message": "Transcript request submitted to your university registrar."
}/api/ipfs/metadata/:cidReturns the full IPFS metadata JSON pinned to Pinata for a given CID.
curl https://credaxis.app/api/ipfs/metadata/bafybeig.../api/ipfs/upload🔐 Auth RequiredUpload transcript metadata to IPFS via Pinata. Only authenticated registrars can call this. Returns the CID and gateway URL.
| Parameter | Type | Required | Description |
|---|---|---|---|
studentAddress | string | Yes | Student wallet address. |
studentName | string | Yes | Full student name. |
studentId | string | Yes | University student ID. |
universityName | string | Yes | Name of the university. |
registryAddress | string | Yes | Registry contract address. |
gpa | string | No | Cumulative GPA (e.g. '3.85'). |
major | string | No | Degree program / major. |
level | string | No | Academic level (e.g. 'MPhil', 'System Design Level'). |
gradYear | string | No | Year of graduation. |
fileHash | string | No | SHA-256 hash of the PDF document. |
Institution API
External institutions — graduate schools, employers, regulators — can register on CredAxis to gain API access for requesting and verifying student transcripts in bulk.
Institution Lifecycle
POST /api/institutions/register/api/institutions/registerRegister a new institution on the CredAxis platform.
| Parameter | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Official institution name. |
email | string | Yes | Primary contact email for the institution. |
walletAddress | string | Yes | EVM wallet address for the institution. |
curl -X POST https://credaxis.app/api/institutions/register \
-H "Content-Type: application/json" \
-d '{
"name": "MIT Graduate Admissions",
"email": "admissions@mit.edu",
"walletAddress": "0xYourEthAddress"
}'{
"success": true,
"institution": {
"id": 12,
"name": "MIT Graduate Admissions",
"email": "admissions@mit.edu",
"walletAddress": "0x...",
"status": "pending"
}
}/api/institutions/profile/:walletLook up an institution's profile and approval status by wallet address.
curl https://credaxis.app/api/institutions/profile/0xYourEthAddress{
"id": 12,
"name": "MIT Graduate Admissions",
"email": "admissions@mit.edu",
"walletAddress": "0x...",
"status": "approved",
"actionAt": "2025-12-10T09:00:00.000Z"
}/api/institutions/requestsAn approved institution requests access to a student's transcript. The student receives an email notification and must consent before the institution can view full transcript details.
| Parameter | Type | Required | Description |
|---|---|---|---|
institutionId | number | Yes | Your institution's ID from the profile endpoint. |
studentName | string | Yes | Student's full name. |
studentId | string | Yes | Student's university ID. |
studentEmail | string | Yes | Student's email address for the consent notification. |
curl -X POST https://credaxis.app/api/institutions/requests \
-H "Content-Type: application/json" \
-d '{
"institutionId": 12,
"studentName": "Ama Osei",
"studentId": "KNUST/EE/2022/045",
"studentEmail": "ama.osei@student.knust.edu.gh"
}'{
"success": true,
"request": {
"id": 88,
"institutionId": 12,
"studentName": "Ama Osei",
"status": "pending"
}
}/api/institutions/requests/:walletGet all transcript requests made by an institution.
curl https://credaxis.app/api/institutions/requests/0xYourEthAddress/api/institutions/update-profileUpdate institution name, email, or wallet address.
| Parameter | Type | Required | Description |
|---|---|---|---|
oldWallet | string | Yes | Current wallet address (used for lookup). |
name | string | Yes | New institution name. |
email | string | Yes | New email. |
walletAddress | string | Yes | New wallet address. |
University Registry Endpoints
/api/universitiesReturns all registered universities and their smart contract addresses.
curl https://credaxis.app/api/universities[
{
"universityId": 1,
"name": "Kwame Nkrumah University of Science and Technology",
"contractAddr": "0x0487722E60f437F5588BC97501177d1384c84E19",
"registrar": "0x6912bC40f1446Dd8A2201F797f2c09dca3CeB88c",
"registrarEmail": "registrar@knust.edu.gh",
"isActive": true,
"deployedAt": "2025-11-15T08:00:00.000Z",
"txHash": "0x..."
}
]/api/universities/by-address/:addrResolve a university by its registry smart contract address.
curl https://credaxis.app/api/universities/by-address/0x0487722E60f437F5588BC97501177d1384c84E19Student API
Endpoints for student onboarding, profile management, and consent control over who can access their credentials.
/api/studentsRegister a new student profile. If the student's email or ID matches a registrar-whitelisted record, they are automatically approved. Otherwise, the application is queued for registrar review.
| Parameter | Type | Required | Description |
|---|---|---|---|
walletAddress | string | Yes | Student's EVM wallet address. |
fullName | string | Yes | Student's full legal name. |
studentId | string | Yes | University-issued student ID. |
universityId | number | Yes | ID of the university (from /api/universities). |
email | string | Yes | Student's email address. |
curl -X POST https://credaxis.app/api/students \
-H "Content-Type: application/json" \
-d '{
"walletAddress": "0xC52A761304DE7DFEea1570361bf190803fF55b6c",
"fullName": "John Ato Mensah",
"studentId": "UG/CS/2021/001",
"universityId": 1,
"email": "john.mensah@student.ug.edu.gh"
}'{
"status": "approved",
"message": "Onboarding completed. Profile automatically approved via registrar whitelist."
}{
"status": "pending",
"message": "Application submitted. Awaiting registrar approval."
}/api/students/profile/:walletAddressGet a student's full profile by their wallet address.
curl https://credaxis.app/api/students/profile/0xC52A761304DE7DFEea1570361bf190803fF55b6c{
"id": 5,
"walletAddress": "0xC52A761...",
"fullName": "John Ato Mensah",
"studentId": "UG/CS/2021/001",
"email": "john.mensah@student.ug.edu.gh",
"universityId": 1,
"status": "approved",
"createdAt": "2025-11-20T10:00:00.000Z"
}/api/students/profile/by-email/:emailLook up a student by email. Used primarily for the Privy email-auth embedded wallet auto-bind flow.
curl https://credaxis.app/api/students/profile/by-email/john.mensah%40student.ug.edu.gh/api/students/profile-by-id/:studentIdFind a student by student ID, email, wallet address, or full name (case-insensitive search across all four fields).
curl https://credaxis.app/api/students/profile-by-id/UG%2FCS%2F2021%2F001/api/students/search?q=:queryFull-text search across all student records (name, email, ID, wallet). Used by registrars in the dashboard search.
curl "https://credaxis.app/api/students/search?q=john+mensah"/api/students/:id/self-bind-walletStudents with a Privy embedded wallet (email login) can self-bind their wallet to a whitelisted record that has no wallet yet.
| Parameter | Type | Required | Description |
|---|---|---|---|
walletAddress | string | Yes | New wallet address to bind. |
email | string | Yes | Email must match the whitelisted record. |
/api/student/institution-requests/:emailReturns all institution access requests for a student (by email).
curl https://credaxis.app/api/student/institution-requests/john.mensah%40student.ug.edu.gh[
{
"id": 88,
"studentName": "John Ato Mensah",
"status": "pending",
"institutionName": "MIT Graduate Admissions",
"createdAt": "2025-12-05T..."
}
]/api/student/institution-requests/:id/approveStudent approves an institution's access request. Requires the record ID.
| Parameter | Type | Required | Description |
|---|---|---|---|
recordId | string | Yes | The on-chain record ID the institution is requesting access to. |
/api/student/institution-requests/:id/rejectStudent rejects an institution's access request.
API Keys & Tokens
CredAxis issues institutional API tokens (prefixed ct_) for server-to-server verification. Tokens are issued by admins or registrars and can be revoked at any time.
/api/tokens/issue🔐 Auth RequiredIssue a new institutional API token. Requires Privy JWT authentication.
| Parameter | Type | Required | Description |
|---|---|---|---|
institutionName | string | Yes | Name of the institution receiving the token. |
expiresDays | number | No | Token expiry in days. Null = never expires. |
issuerAddress | string | No | Wallet address of the issuer (registrar or admin). |
role | string | No | Role of the issuer: 'registrar' or 'admin'. |
curl -X POST https://credaxis.app/api/tokens/issue \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <privy_jwt>" \
-d '{
"institutionName": "Accra Employment Agency",
"expiresDays": 365,
"issuerAddress": "0xRegistrarAddress",
"role": "registrar"
}'{
"success": true,
"token": "ct_x8k2m4n7p9r1j3w5l8q0v1641234567",
"institutionName": "Accra Employment Agency",
"expiresAt": "2026-12-01T00:00:00.000Z"
}/api/tokens🔐 Auth RequiredList all issued tokens. Admins see all tokens; registrars see only tokens they issued.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
issuerAddress | string | No | Filter by issuer wallet address. |
role | string | No | Pass 'admin' to see all tokens. |
curl -H "Authorization: Bearer <privy_jwt>" \
"https://credaxis.app/api/tokens?role=admin"/api/tokens/:id🔐 Auth RequiredRevoke (deactivate) an institutional API token by its database ID.
curl -X DELETE \
-H "Authorization: Bearer <privy_jwt>" \
"https://credaxis.app/api/tokens/15?operator=0xAdminAddress"{
"success": true,
"message": "Token revoked successfully"
}Using Tokens for Verification
Once you have a ct_ token, use it in the token query parameter of the Verify API:
curl "https://credaxis.app/api/public/verify?studentId=UG/CS/2021/001&token=ct_x8k2m4n7p9r1j3w5l8q0v1641234567"This grants full access to the student's transcript details (name, GPA, major, etc.) without requiring individual student consent — the token represents institutional-level trust.
On-Chain Contracts
CredAxis deploys a Factory + Registry pattern on Base Sepolia. The Factory contract deploys individual Registry contracts for each university. All transcript records are stored immutably on-chain.
Deployed Contracts
0x9632D1a3194947CD888b37020261952A6aC52613The master factory that deploys per-university Registry contracts. Managed by the platform admin.
View on BaseScan ↗0x0487722E60f437F5588BC97501177d1384c84E19Kwame Nkrumah University of Science and Technology — registry contract for issuing and managing transcript records.
View on BaseScan ↗0x8bc95ae597deaE61b087F45efCA355AF07BBF32BUniversity of Ghana registry contract.
View on BaseScan ↗0x862942e757351E5EB84F10d4cA3E143cdF0e2F86University of Cape Coast registry contract.
View on BaseScan ↗Registry Contract Interface
Each Registry contract exposes the following key functions. You can interact with them directly via ethers.js / viem or through our REST API.
// Register a transcript record on-chain
function registerTranscript(
bytes32 studentHash, // keccak256(abi.encodePacked(studentAddress))
bytes32 fileHash, // SHA-256 of the transcript PDF
string calldata ipfsURI
) external onlyRegistrar returns (bytes32 recordId);
// Get a transcript record
function getTranscript(bytes32 recordId) external view returns (
bytes32 studentHash,
bytes32 fileHash,
string memory ipfsURI,
uint256 issuedAt,
TranscriptStatus status
);
// Update transcript status (Active, Revoked, Amended)
function updateTranscriptStatus(
bytes32 recordId,
TranscriptStatus newStatus,
string calldata reason
) external onlyRegistrar;
// Grant access to a verifier
function grantAccess(
bytes32 recordId,
address verifier
) external;
// Revoke access
function revokeAccess(
bytes32 recordId,
address verifier
) external;On-Chain Events (Indexed by Backend)
The backend micro-indexer listens for these events in real-time and syncs them to the PostgreSQL database:
event TranscriptRegistered(
bytes32 indexed recordId,
bytes32 indexed studentHash,
bytes32 fileHash,
address indexed registrar
);
event TranscriptStatusChanged(
bytes32 indexed recordId,
TranscriptStatus oldStatus,
TranscriptStatus newStatus,
string reason
);
event AccessGranted(
bytes32 indexed recordId,
address indexed verifier,
address indexed granter
);
event AccessRevoked(
bytes32 indexed recordId,
address indexed verifier
);
event UniversityRegistered(
uint256 indexed universityId,
string name,
address registryContract,
address registrar
);Reading Contracts with viem
import { createPublicClient, http } from "viem"
import { baseSepolia } from "viem/chains"
const client = createPublicClient({
chain: baseSepolia,
transport: http("https://sepolia.drpc.org"),
})
// Read a transcript directly from the registry
const result = await client.readContract({
address: "0x0487722E60f437F5588BC97501177d1384c84E19",
abi: registryABI,
functionName: "getTranscript",
args: ["0xaa877681f268a7a927036de034fd930a854f2aec555795b6b612edb479ae2987"],
})
console.log(result)
// [studentHash, fileHash, ipfsURI, issuedAt, status]SDK & Integration Guide
Step-by-step guides for integrating CredAxis verification into your existing systems — whether it's a school management system, HR platform, or government portal.
1. School Management System (LMS) Integration
If you're a school or university that wants to integrate CredAxis into your existing LMS (Moodle, Canvas, etc.), follow these steps:
Contact CredAxis Admin
Email support@credaxis.app to request a university registry deployment. We'll deploy a smart contract specifically for your institution.
Whitelist Students via CSV
Upload your student roster using the bulk whitelist endpoint. This pre-approves students so they can auto-onboard.
const response = await fetch("https://credaxis.app/api/students/bulk", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
registrarAddress: "0xYourRegistrarWallet",
studentsList: [
{ fullName: "Kofi Asante", studentId: "KNUST/EE/2022/001", email: "kofi@student.knust.edu.gh" },
{ fullName: "Ama Osei", studentId: "KNUST/EE/2022/002", email: "ama@student.knust.edu.gh" },
// ... hundreds of students
]
})
})
const result = await response.json()
// { success: true, processed: 250, details: [...] }Issue Transcripts via API
When a student graduates, upload their transcript metadata to IPFS and register it on-chain through the registrar dashboard or programmatically via the IPFS upload API.
2. HR / Employer Integration
Automate transcript verification in your hiring pipeline:
// In your applicant processing pipeline
async function verifyApplicantCredentials(
studentId: string,
apiToken: string
) {
const res = await fetch(
`https://credaxis.app/api/public/verify?studentId=${encodeURIComponent(studentId)}&token=${apiToken}`
)
if (!res.ok) {
const err = await res.json()
return { verified: false, error: err.error, code: err.code }
}
const data = await res.json()
return {
verified: data.transcript?.status === "Active",
studentName: data.student?.fullName,
university: data.university?.name,
gpa: data.transcript?.fileHash ? "Available via IPFS" : "N/A",
issuedAt: data.transcript?.issuedAt,
onChainRecord: data.transcript?.recordId,
}
}
// Usage in your hiring workflow
const result = await verifyApplicantCredentials(
"UG/CS/2021/001",
"ct_your_institutional_token"
)
if (result.verified) {
console.log(`✅ ${result.studentName} — verified from ${result.university}`)
} else {
console.log(`❌ Verification failed: ${result.error}`)
}3. Python Integration
import requests
BASE_URL = "https://credaxis.app/api"
API_TOKEN = "ct_your_institutional_token"
def verify_transcript(record_id=None, student_id=None):
params = {}
if record_id:
params["recordId"] = record_id
elif student_id:
params["studentId"] = student_id
params["token"] = API_TOKEN
resp = requests.get(f"{BASE_URL}/public/verify", params=params)
resp.raise_for_status()
data = resp.json()
return {
"is_valid": data.get("transcript", {}).get("status") == "Active",
"student": data.get("student"),
"university": data.get("university"),
}
# Verify by record ID (public, no token needed)
result = verify_transcript(record_id="0xaa877681f268...")
print(result["is_valid"]) # True
# Verify by student ID (needs token)
result = verify_transcript(student_id="UG/CS/2021/001")
print(result["student"]["fullName"]) # "John Doe"4. Webhook / Batch Processing
const API_TOKEN = "ct_your_token"
const studentIds = [
"UG/CS/2021/001",
"KNUST/EE/2022/045",
"UCC/BA/2023/012",
]
const results = await Promise.all(
studentIds.map(async (id) => {
const res = await fetch(
`https://credaxis.app/api/public/verify?studentId=${encodeURIComponent(id)}&token=${API_TOKEN}`
)
const data = await res.json()
return {
studentId: id,
verified: data.transcript?.status === "Active",
name: data.student?.fullName || "Unknown",
}
})
)
console.table(results)
// ┌─────────────────────┬──────────┬────────────────┐
// │ studentId │ verified │ name │
// ├─────────────────────┼──────────┼────────────────┤
// │ UG/CS/2021/001 │ true │ John Doe │
// │ KNUST/EE/2022/045 │ true │ Ama Osei │
// │ UCC/BA/2023/012 │ false │ Unknown │
// └─────────────────────┴──────────┴────────────────┘Webhooks & Email Notifications
CredAxis sends automated email notifications at every critical step in the credential lifecycle. These replace the need for manual follow-up and ensure all parties stay informed.
Email Notification Triggers
Student Onboarding Request
Recipient: Registrar / Admin
Trigger: Student submits a profile via POST /api/students
Contains: Student name, ID, email, university. One-click Approve/Reject buttons.
Application Approved
Recipient: Student
Trigger: Registrar clicks "Approve" (email or dashboard)
Contains: Confirmation with link to student dashboard.
Application Rejected
Recipient: Student
Trigger: Registrar clicks "Reject"
Contains: Rejection notice with guidance to contact admin.
Transcript Secured (Auto-Delivery)
Recipient: Student
Trigger: Student requests transcript and an active one exists on-chain
Contains: Transcript details (name, major, GPA) with a "View Transcript" link.
Transcript Request (No Active Record)
Recipient: Registrar
Trigger: Student requests transcript but none exists on-chain
Contains: Student details with "Issue Transcript Now" button.
Access Request (External Verifier)
Recipient: Student
Trigger: Verifier calls POST /api/public/request-access
Contains: Requester details with Approve/Deny buttons. Access valid for 30 days.
Institution Access Request
Recipient: Student
Trigger: Approved institution calls POST /api/institutions/requests
Contains: Institution name and link to manage access permissions in the dashboard.
Access Granted
Recipient: External verifier
Trigger: Student approves access request
Contains: Unique link to view the full verified transcript (30-day expiry).
backend/utils/email.ts.One-Click Email Actions
Several emails include one-click action buttons that call backend endpoints directly from the email:
| Action | Endpoint | Description |
|---|---|---|
| Approve Student | GET /api/students/approve-via-token?token=... | Registrar one-click approves a student from email. |
| Reject Student | GET /api/students/reject-via-token?token=... | Registrar one-click rejects from email. |
| Approve Access | GET /api/public/access-requests/approve?token=... | Student one-click approves verifier access from email. |
| Reject Access | GET /api/public/access-requests/reject?token=... | Student one-click rejects verifier access from email. |
Error Codes & Responses
All API errors return a JSON object with an error field and an HTTP status code. Some endpoints also include a code field for programmatic error handling.
HTTP Status Codes
| Code | Meaning | Typical Cause |
|---|---|---|
200 | Success | Request completed. Response body contains the requested data. |
400 | Bad Request | Missing required fields, invalid parameters, or duplicate entry. |
401 | Unauthorized | Missing or invalid Bearer token. JWT expired or malformed. |
403 | Forbidden | Valid auth but insufficient permissions. Or: token expired/invalid for verify endpoint. |
404 | Not Found | Transcript, student, or university record does not exist. |
409 | Conflict | Wallet already bound, duplicate registration. |
429 | Too Many Requests | Semester quota exceeded (max 3 transcript requests per 6 months). |
500 | Internal Server Error | Database or server error. Contact support if persistent. |
502 | Bad Gateway | Pinata/IPFS upstream failure. |
503 | Service Unavailable | Pinata credentials not configured on the server. |
Verify API Error Codes
The GET /api/public/verify endpoint returns a code field for specific error conditions:
| Code | HTTP Status | Description |
|---|---|---|
MISSING_PARAMS | 400 | Neither recordId nor studentId was provided. |
NOT_FOUND | 404 | No transcript record matches the given parameters. |
INVALID_TOKEN | 403 | The provided access token does not exist or has been revoked. |
EXPIRED_TOKEN | 403 | The token exists but has passed its expiration date. |
Example Error Response
// 404 Not Found
{
"error": "Transcript record not found in the registry.",
"code": "NOT_FOUND"
}
// 403 Forbidden
{
"error": "The provided access token is invalid or expired.",
"code": "INVALID_TOKEN"
}
// 429 Rate Limited
{
"error": "Semester quota exceeded: You have reached the maximum of 3 official transcript requests for this term."
}
// 400 Bad Request
{
"error": "Missing required fields"
}Contact Support
If you encounter persistent 500 errors or unexpected behaviour, please reach out:
API Playground
Simulate real-time requests directly against the live proxy API. Ensure your parameters conform to the public API requirements.
Query Parameters
// Click 'Send Request' to trigger API call...