Skip to content

Perfxcel API Reference

Base URL: https://api.perfxcel.com/api/v1

All admin endpoints require Authorization: Bearer <supabase-jwt>. Public endpoints have no auth requirement but are rate-limited.

Courses

GET /courses

Returns all published, active courses. Supports filtering via query params.

Query params:

Param Type Description
category string Filter by category taxonomy slug
city string Filter by city taxonomy slug
association string Filter by association taxonomy slug
delivery_mode string Filter by delivery mode slug
search string Full-text search on title / description

Response:

{
  "status": "success",
  "results": 12,
  "data": [
    {
      "id": "uuid",
      "title": "ISO 9001 Foundation",
      "slug": "iso-9001-foundation",
      "description": "...",
      "is_published": true,
      "status": "active",
      "delivery_mode": "online",
      "duration_days": 2,
      "schedule": [...],
      "categories": [...],
      "cities": [...],
      "associations": [...]
    }
  ]
}

POST /courses (Admin)

Create a new course.

Body:

{
  "title": "ISO 9001 Foundation",
  "slug": "iso-9001-foundation",
  "description": "...",
  "delivery_mode": "online",
  "duration_days": 2,
  "is_published": false,
  "status": "active",
  "category_ids": ["uuid"],
  "city_ids": ["uuid"],
  "association_ids": ["uuid"]
}

Response: 201 Created with the created course object.


PATCH /courses/bulk (Admin)

Bulk-update is_published or status across multiple courses.

Body:

{
  "ids": ["uuid1", "uuid2"],
  "updates": { "is_published": true }
}

GET /courses/:id

Get a single course by id or slug.


PUT /courses/:id (Admin)

Full update of a course record. Same shape as POST /courses.


DELETE /courses/:id (Admin)

Soft-delete a course (sets status: 'deleted', deleted_at).


POST /courses/:id/interest (Public, Turnstile required)

Register a learner's interest in a course.

Body:

{
  "name": "Jane Smith",
  "email": "[email protected]",
  "phone": "+91-9876543210",
  "organisation": "Acme Ltd",
  "turnstileToken": "<cf-turnstile-token>"
}

Response: 201 Created


Taxonomies

GET /taxonomies

Returns all taxonomy items grouped by type.

Response:

{
  "status": "success",
  "data": {
    "categories": [{ "id": "uuid", "name": "Quality Management", "slug": "quality-management" }],
    "cities": [...],
    "associations": [...],
    "delivery_modes": [...]
  }
}

POST /taxonomies (Admin)

Create a taxonomy item.

Body:

{
  "name": "Quality Management",
  "slug": "quality-management",
  "type": "category"
}

PUT /taxonomies/:id (Admin)

Update a taxonomy item.


DELETE /taxonomies/:id (Admin)

Delete a taxonomy item.


Interests

GET /interests (Admin)

List all interest submissions with pagination.

Query params: page, limit, status, course_id

Response:

{
  "status": "success",
  "results": 5,
  "total": 42,
  "page": 1,
  "limit": 20,
  "data": [...]
}

PATCH /interests/:id (Admin)

Update the status of an interest submission (new, contacted, converted, closed).


Enrollments

GET /enrollments (Admin)

List enrollments with pagination and filters.


POST /enrollments (Admin)

Create an enrollment (typically from converting an interest).

Body:

{
  "course_id": "uuid",
  "interest_id": "uuid",
  "learner_name": "Jane Smith",
  "learner_email": "[email protected]",
  "organisation": "Acme Ltd",
  "scheduled_date": "2026-10-15"
}

PATCH /enrollments/:id (Admin)

Update enrollment status (pending, confirmed, completed, cancelled).


Enquiries

GET /enquiries (Admin)

List enquiries with pagination.


PATCH /enquiries/:id (Admin)

Update enquiry status (new, in_progress, resolved, closed).


Training Plan

GET /training-plan (Admin)

List training plan requests.


POST /training-plan (Public, Turnstile required)

Submit a training plan request.

Body:

{
  "organisation": "Acme Ltd",
  "contact_name": "John Doe",
  "contact_email": "[email protected]",
  "contact_phone": "+91-9876543210",
  "requirements": "We need ISO 9001 training for 50 staff across 3 sites.",
  "turnstileToken": "<cf-turnstile-token>"
}

Contact

POST /contact (Public, Turnstile required)

Submit a contact form message.

Body:

{
  "name": "Jane Smith",
  "email": "[email protected]",
  "message": "I'd like to know more about your courses.",
  "turnstileToken": "<cf-turnstile-token>"
}

Verify

GET /verify?certificate_number=PX-2026-00123

Verify a certificate by number.

Response (found):

{
  "status": "success",
  "data": {
    "valid": true,
    "learner_name": "Jane Smith",
    "course_title": "ISO 9001 Foundation",
    "completion_date": "2026-08-01",
    "certificate_number": "PX-2026-00123"
  }
}

Response (not found): 404 Not Found


Metrics

GET /metrics (Admin)

Returns platform-wide metrics for the admin dashboard.

Response:

{
  "status": "success",
  "data": {
    "total_courses": 24,
    "published_courses": 18,
    "total_interests": 342,
    "total_enrollments": 89,
    "total_enquiries": 56,
    "recent_interests": [...]
  }
}

Audit Logs

GET /audit-logs (Admin)

Paginated, filterable log of admin actions.

Query params: page, limit, action, entity_type, from, to


Error Format

All errors follow the standard @dotevolve/error-utils shape:

{
  "status": "error",
  "message": "Course not found",
  "correlationId": "uuid"
}

HTTP status codes: 400 validation, 401 unauthenticated, 403 unauthorized, 404 not found, 409 conflict, 500 server error.