OpenAPI tanımı
Okul entegrasyon API'sinin makine tarafından okunabilir tanımı — OpenAPI 3.1, 960 satır. İnsan için yazılmış anlatım referans spesifikasyonda.
Bu sayfa dosyanın kendisidir. Aşağıdaki metin depodaki docs/api/openapi.yaml dosyasının birebir içeriğidir; kod üreteci ya da Swagger'a vermek için ham dosyayı indirin.
openapi: 3.1.0
info:
title: Yoklama Okul Entegrasyon API'si
version: "1.0.0"
summary: Okulların yoklama sistemlerine veri sağlamak için implement edeceği referans arayüz
description: |
Okulların ve üniversitelerin kendi Öğrenci Bilgi Sistemlerinde (ÖBS/OBS/UBYS/LMS)
implement edeceği standart arayüz. Bu arayüz mevcutsa, yoklama uygulamaları
ekran kazıma (screen scraping), tarayıcı otomasyonu veya öğretmen şifresi saklama
gibi yöntemlere ihtiyaç duymaz.
Veri modeli OneRoster v1.2 Rostering'i taban alır; yoklama katmanı Ed-Fi'nin
StudentSectionAttendanceEvent yapısından esinlenir (OneRoster'da yoklama kavramı yoktur).
ÖNEMLİ — VERİ MİNİMİZASYONU:
Bu API'de hiçbir biyometrik alan tanımlı değildir ve tanımlanmayacaktır.
TCKN gibi hassas kimlik alanları istenmez; eşleştirme için öğrenci numarası yeterlidir.
Yoklama uçlarına gönderilen tek şey karardır, ham veri değil.
license:
name: CC BY 4.0
url: https://creativecommons.org/licenses/by/4.0/
contact:
name: Yoklama Projesi
servers:
- url: https://{host}/yoklama-api/v1
description: Kurumun kendi sunucusu
variables:
host:
default: obs.ornek.edu.tr
tags:
- name: discovery
description: Yetenek keşfi
- name: auth
description: Kimlik doğrulama
- name: roster
description: Kurum, dönem, ders, kullanıcı, kayıt verileri (salt okunur)
- name: schedule
description: Haftalık program ve istisnalar (salt okunur)
- name: attendance
description: Yoklama oturumu ve kayıtları (okuma + yazma)
security:
- oauth2: [roster.readonly]
paths:
/.well-known/yoklama-configuration:
get:
tags: [discovery]
summary: Yetenek keşfi
description: |
İstemci, kurumun hangi yetenekleri desteklediğini buradan öğrenir ve
davranışını ona göre ayarlar. Kimlik doğrulama gerektirmez.
security: []
operationId: getConfiguration
responses:
"200":
description: Yapılandırma
content:
application/json:
schema: { $ref: "#/components/schemas/Configuration" }
/oauth/token:
post:
tags: [auth]
summary: Erişim belirteci al (OAuth 2.0 Client Credentials)
security: []
operationId: getToken
requestBody:
required: true
content:
application/x-www-form-urlencoded:
schema:
type: object
required: [grant_type, client_id, client_secret]
properties:
grant_type: { type: string, enum: [client_credentials] }
client_id: { type: string }
client_secret: { type: string, format: password }
scope:
type: string
example: "roster.readonly attendance.write"
responses:
"200":
description: Belirteç
content:
application/json:
schema:
type: object
required: [access_token, token_type, expires_in]
properties:
access_token: { type: string }
token_type: { type: string, enum: [Bearer] }
expires_in: { type: integer, example: 3600 }
scope: { type: string }
"401": { $ref: "#/components/responses/Unauthorized" }
/orgs:
get:
tags: [roster]
summary: Kurumlar (okul, fakülte, bölüm hiyerarşisi)
operationId: listOrgs
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- $ref: "#/components/parameters/ifNoneMatch"
responses:
"200":
description: Kurum listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
ETag: { $ref: "#/components/headers/ETag" }
content:
application/json:
schema:
type: object
required: [orgs]
properties:
orgs:
type: array
items: { $ref: "#/components/schemas/Org" }
"304": { description: Değişiklik yok }
"401": { $ref: "#/components/responses/Unauthorized" }
"429": { $ref: "#/components/responses/RateLimited" }
/terms:
get:
tags: [roster]
summary: Akademik dönemler
operationId: listTerms
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
responses:
"200":
description: Dönem listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [terms]
properties:
terms:
type: array
items: { $ref: "#/components/schemas/Term" }
"401": { $ref: "#/components/responses/Unauthorized" }
/courses:
get:
tags: [roster]
summary: Ders kataloğu
operationId: listCourses
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- name: orgSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Ders listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [courses]
properties:
courses:
type: array
items: { $ref: "#/components/schemas/Course" }
"401": { $ref: "#/components/responses/Unauthorized" }
/sections:
get:
tags: [roster]
summary: Şubeler / ders açılışları
description: Bir dersin belirli bir dönemde açılan örneği. Yoklamanın bağlandığı temel varlıktır.
operationId: listSections
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- name: termSourcedId
in: query
schema: { type: string }
- name: orgSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Şube listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [sections]
properties:
sections:
type: array
items: { $ref: "#/components/schemas/Section" }
"401": { $ref: "#/components/responses/Unauthorized" }
/sections/{sourcedId}/students:
get:
tags: [roster]
summary: Şubedeki öğrenciler
description: Uygulamanın en sık kullandığı uç — tek çağrıda sınıf listesi.
operationId: listSectionStudents
parameters:
- $ref: "#/components/parameters/sourcedId"
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
responses:
"200":
description: Öğrenci listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [users]
properties:
users:
type: array
items: { $ref: "#/components/schemas/User" }
"404": { $ref: "#/components/responses/NotFound" }
/sections/{sourcedId}/teachers:
get:
tags: [roster]
summary: Şubenin öğretim elemanları
operationId: listSectionTeachers
parameters:
- $ref: "#/components/parameters/sourcedId"
responses:
"200":
description: Öğretmen listesi
content:
application/json:
schema:
type: object
required: [users]
properties:
users:
type: array
items: { $ref: "#/components/schemas/User" }
"404": { $ref: "#/components/responses/NotFound" }
/teachers/{sourcedId}/sections:
get:
tags: [roster]
summary: Öğretmenin dersleri
description: Öğretmen uygulamaya girdiğinde o dönemki derslerini görmesi için.
operationId: listTeacherSections
parameters:
- $ref: "#/components/parameters/sourcedId"
- name: termSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Şube listesi
content:
application/json:
schema:
type: object
required: [sections]
properties:
sections:
type: array
items: { $ref: "#/components/schemas/Section" }
"404": { $ref: "#/components/responses/NotFound" }
/classrooms:
get:
tags: [roster]
summary: Derslikler
operationId: listClassrooms
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
responses:
"200":
description: Derslik listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [classrooms]
properties:
classrooms:
type: array
items: { $ref: "#/components/schemas/Classroom" }
/users:
get:
tags: [roster]
summary: Kullanıcılar (öğrenci, öğretmen, yönetici)
operationId: listUsers
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- name: role
in: query
schema: { type: string, enum: [student, teacher, administrator, guardian] }
- name: orgSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Kullanıcı listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [users]
properties:
users:
type: array
items: { $ref: "#/components/schemas/User" }
/enrollments:
get:
tags: [roster]
summary: Ders kayıtları (kim hangi şubede, hangi rolle)
operationId: listEnrollments
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- name: sectionSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Kayıt listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [enrollments]
properties:
enrollments:
type: array
items: { $ref: "#/components/schemas/Enrollment" }
/schedules:
get:
tags: [schedule]
summary: Haftalık ders programı
operationId: listSchedules
parameters:
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
- $ref: "#/components/parameters/since"
- name: sectionSourcedId
in: query
schema: { type: string }
- name: teacherSourcedId
in: query
schema: { type: string }
responses:
"200":
description: Program listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [schedules]
properties:
schedules:
type: array
items: { $ref: "#/components/schemas/Schedule" }
/schedules/exceptions:
get:
tags: [schedule]
summary: Program istisnaları (tatil, telafi, derslik değişikliği)
operationId: listScheduleExceptions
parameters:
- $ref: "#/components/parameters/since"
- name: from
in: query
schema: { type: string, format: date }
- name: to
in: query
schema: { type: string, format: date }
responses:
"200":
description: İstisna listesi
content:
application/json:
schema:
type: object
required: [exceptions]
properties:
exceptions:
type: array
items: { $ref: "#/components/schemas/ScheduleException" }
/attendance/sessions:
post:
tags: [attendance]
summary: Yoklama oturumu oluştur
description: |
Idempotent. `sourcedId` istemci tarafından deterministik üretilir.
Aynı `sourcedId` ile ikinci POST 200 döner ve yeni kayıt oluşmaz.
operationId: createAttendanceSession
security:
- oauth2: [attendance.write]
parameters:
- $ref: "#/components/parameters/idempotencyKey"
requestBody:
required: true
content:
application/json:
schema: { $ref: "#/components/schemas/AttendanceSession" }
responses:
"201":
description: Oluşturuldu
headers:
Location:
schema: { type: string }
content:
application/json:
schema: { $ref: "#/components/schemas/AttendanceSession" }
"200":
description: Zaten mevcut (idempotent)
content:
application/json:
schema: { $ref: "#/components/schemas/AttendanceSession" }
"400": { $ref: "#/components/responses/BadRequest" }
"401": { $ref: "#/components/responses/Unauthorized" }
"403": { $ref: "#/components/responses/Forbidden" }
/attendance/sessions/{sourcedId}:
get:
tags: [attendance]
summary: Oturum detayı
operationId: getAttendanceSession
security:
- oauth2: [attendance.readonly]
parameters:
- $ref: "#/components/parameters/sourcedId"
responses:
"200":
description: Oturum
content:
application/json:
schema: { $ref: "#/components/schemas/AttendanceSession" }
"404": { $ref: "#/components/responses/NotFound" }
patch:
tags: [attendance]
summary: Oturumu güncelle / kapat
operationId: patchAttendanceSession
security:
- oauth2: [attendance.write]
parameters:
- $ref: "#/components/parameters/sourcedId"
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
endedAt: { type: string, format: date-time }
status: { type: string, enum: [open, finalized, voided] }
notes: { type: string, nullable: true }
responses:
"200":
description: Güncellendi
content:
application/json:
schema: { $ref: "#/components/schemas/AttendanceSession" }
"409":
description: |
Düzeltme penceresi kapalı. Kurum politikası, kapatılmış oturumun
ne kadar süre düzeltilebileceğini belirler.
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
/attendance/records:
post:
tags: [attendance]
summary: Yoklama kayıtlarını gönder (toplu, idempotent upsert)
description: |
Anahtar: (sessionSourcedId, userSourcedId). Aynı çift yeniden gönderilirse
kayıt güncellenir, çift kayıt oluşmaz. Maksimum 500 kayıt / istek.
BİYOMETRİK VERİ YOKTUR. Gönderilen tek şey karardır.
operationId: postAttendanceRecords
security:
- oauth2: [attendance.write]
parameters:
- $ref: "#/components/parameters/idempotencyKey"
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [sessionSourcedId, records]
properties:
sessionSourcedId: { type: string }
records:
type: array
maxItems: 500
items: { $ref: "#/components/schemas/AttendanceRecord" }
responses:
"200":
description: Tümü kabul edildi
content:
application/json:
schema: { $ref: "#/components/schemas/BatchResult" }
"207":
description: Kısmi başarı
content:
application/json:
schema: { $ref: "#/components/schemas/BatchResult" }
"400": { $ref: "#/components/responses/BadRequest" }
"403": { $ref: "#/components/responses/Forbidden" }
get:
tags: [attendance]
summary: Yoklama kayıtlarını oku (mutabakat için)
operationId: listAttendanceRecords
security:
- oauth2: [attendance.readonly]
parameters:
- name: sectionSourcedId
in: query
required: true
schema: { type: string }
- name: from
in: query
schema: { type: string, format: date }
- name: to
in: query
schema: { type: string, format: date }
- $ref: "#/components/parameters/limit"
- $ref: "#/components/parameters/offset"
responses:
"200":
description: Kayıt listesi
headers:
X-Total-Count: { $ref: "#/components/headers/XTotalCount" }
content:
application/json:
schema:
type: object
required: [records]
properties:
records:
type: array
items: { $ref: "#/components/schemas/AttendanceRecordRead" }
components:
securitySchemes:
oauth2:
type: oauth2
description: |
OAuth 2.0 Client Credentials. Öğretmen şifresi asla istenmez, asla saklanmaz.
Yetki kurumdan gelir; iptal edilebilir ve denetlenebilir.
flows:
clientCredentials:
tokenUrl: /yoklama-api/v1/oauth/token
scopes:
roster.readonly: Kurum, dönem, ders, şube, derslik, kullanıcı, kayıt, program okuma
attendance.write: Yoklama oturumu ve kaydı oluşturma/güncelleme
attendance.readonly: Yoklama kaydı okuma
parameters:
limit:
name: limit
in: query
description: Sayfa başına kayıt (varsayılan 100, maksimum 1000)
schema: { type: integer, minimum: 1, maximum: 1000, default: 100 }
offset:
name: offset
in: query
schema: { type: integer, minimum: 0, default: 0 }
since:
name: since
in: query
description: Bu tarihten sonra dateLastModified değişen kayıtlar (artımlı çekim)
schema: { type: string, format: date-time }
sourcedId:
name: sourcedId
in: path
required: true
schema: { type: string }
ifNoneMatch:
name: If-None-Match
in: header
schema: { type: string }
idempotencyKey:
name: Idempotency-Key
in: header
description: İsteğin tekrarını güvenli kılan istemci üretimli anahtar
schema: { type: string, maxLength: 128 }
headers:
XTotalCount:
description: Filtreye uyan toplam kayıt sayısı
schema: { type: integer }
ETag:
description: Koleksiyonun sürüm etiketi
schema: { type: string }
responses:
Unauthorized:
description: Geçersiz veya eksik belirteç
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
Forbidden:
description: Kapsam yetersiz veya kurum bu istemciyi bu kaynak için yetkilendirmemiş
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
NotFound:
description: Kaynak bulunamadı
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
BadRequest:
description: Geçersiz istek
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
RateLimited:
description: Hız sınırı aşıldı
headers:
Retry-After:
schema: { type: integer }
content:
application/problem+json:
schema: { $ref: "#/components/schemas/Problem" }
schemas:
Problem:
type: object
description: RFC 9457 Problem Details
properties:
type: { type: string, format: uri }
title: { type: string }
status: { type: integer }
detail: { type: string }
instance: { type: string }
Base:
type: object
required: [sourcedId, status, dateLastModified]
properties:
sourcedId:
type: string
description: Kurumun kendi benzersiz kimliği
status:
type: string
enum: [active, tobedeleted]
description: Kayıtlar silinmez, pasifleştirilir
dateLastModified: { type: string, format: date-time }
Configuration:
type: object
required: [specVersion, endpoints, capabilities]
properties:
specVersion: { type: string, example: "1.0" }
institution:
type: object
properties:
name: { type: string }
sourcedId: { type: string }
endpoints:
type: object
properties:
base: { type: string, format: uri }
token: { type: string, format: uri }
capabilities:
type: object
properties:
roster.read: { type: boolean }
schedules.read: { type: boolean }
classrooms.read: { type: boolean }
attendance.write: { type: boolean }
attendance.read: { type: boolean }
attendance.sessionModel: { type: string, enum: [single, sweeps] }
delta.since: { type: boolean }
etag: { type: boolean }
attendanceStatuses:
type: array
items: { type: string }
timezone: { type: string, example: "Europe/Istanbul" }
contact: { type: string }
Org:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [name, type]
properties:
name: { type: string }
type:
type: string
enum: [institution, faculty, department, school, program]
identifier: { type: string, nullable: true }
parentSourcedId: { type: string, nullable: true }
Term:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [title, type, startDate, endDate]
properties:
title: { type: string }
type: { type: string, enum: [semester, term, schoolYear, summerSchool] }
startDate: { type: string, format: date }
endDate: { type: string, format: date }
schoolYear: { type: string, example: "2026-2027" }
orgSourcedId: { type: string }
Course:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [title, courseCode]
properties:
title: { type: string }
courseCode: { type: string }
orgSourcedId: { type: string }
credits: { type: number, nullable: true }
ects: { type: number, nullable: true }
theoreticalHours: { type: integer, nullable: true }
practicalHours: { type: integer, nullable: true }
Section:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [title, courseSourcedId, termSourcedId]
properties:
title: { type: string }
sectionCode: { type: string, nullable: true }
courseSourcedId: { type: string }
termSourcedId: { type: string }
orgSourcedId: { type: string }
language: { type: string, default: "tr" }
deliveryMode: { type: string, enum: [faceToFace, online, hybrid] }
maxEnrollment: { type: integer, nullable: true }
attendanceRequired: { type: boolean, nullable: true }
attendanceThreshold:
type: number
minimum: 0
maximum: 1
nullable: true
description: |
Kurumun devam eşiği. YÖK devam kuralını birim kurullarına bıraktığı için
ulusal sabit bir eşik yoktur; kurum kendi eşiğini burada bildirir.
Classroom:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [name]
properties:
name: { type: string }
building: { type: string, nullable: true }
capacity: { type: integer, nullable: true }
type: { type: string, enum: [classroom, amphitheater, laboratory, studio, online] }
orgSourcedId: { type: string, nullable: true }
User:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [role, givenName, familyName]
description: |
VERİ MİNİMİZASYONU: TCKN alanı tanımlı değildir ve istenmez.
Eşleştirme için identifier (öğrenci/personel numarası) yeterlidir.
Kurum ek alan döndürürse istemci bunları yok sayar ve saklamaz.
properties:
role: { type: string, enum: [student, teacher, administrator, guardian] }
username: { type: string, nullable: true }
givenName: { type: string }
familyName: { type: string }
identifier:
type: string
description: Öğrenci numarası veya personel sicil numarası
email: { type: string, format: email, nullable: true }
orgSourcedIds:
type: array
items: { type: string }
grade: { type: integer, nullable: true }
title: { type: string, nullable: true }
enrollmentStatus: { type: string, nullable: true }
guardianSourcedIds:
type: array
nullable: true
items: { type: string }
description: 18 yaş altı için veli rızası akışı gerekiyorsa
Enrollment:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [sectionSourcedId, userSourcedId, role]
properties:
sectionSourcedId: { type: string }
userSourcedId: { type: string }
role: { type: string, enum: [student, teacher, assistant] }
primary: { type: boolean, default: false }
beginDate: { type: string, format: date, nullable: true }
endDate: { type: string, format: date, nullable: true }
Schedule:
allOf:
- $ref: "#/components/schemas/Base"
- type: object
required: [sectionSourcedId, dayOfWeek, startTime, endTime]
properties:
sectionSourcedId: { type: string }
classroomSourcedId: { type: string, nullable: true }
dayOfWeek:
type: integer
minimum: 1
maximum: 7
description: ISO 8601 — 1 = Pazartesi, 7 = Pazar
startTime: { type: string, pattern: '^([01]\d|2[0-3]):[0-5]\d$' }
endTime: { type: string, pattern: '^([01]\d|2[0-3]):[0-5]\d$' }
recurrence: { type: string, enum: [weekly, biweekly, once], default: weekly }
validFrom: { type: string, format: date, nullable: true }
validUntil: { type: string, format: date, nullable: true }
teacherSourcedIds:
type: array
items: { type: string }
ScheduleException:
type: object
required: [sourcedId, date, type]
properties:
sourcedId: { type: string }
scheduleSourcedId: { type: string }
date: { type: string, format: date }
type: { type: string, enum: [cancelled, makeup, roomChange, timeChange] }
startTime: { type: string, nullable: true }
endTime: { type: string, nullable: true }
classroomSourcedId: { type: string, nullable: true }
reason: { type: string, nullable: true }
AttendanceSession:
type: object
required: [sourcedId, sectionSourcedId, teacherSourcedId, date]
properties:
sourcedId:
type: string
description: İstemci üretimli, deterministik. Idempotency anahtarı.
sectionSourcedId: { type: string }
classroomSourcedId: { type: string, nullable: true }
scheduleSourcedId: { type: string, nullable: true }
teacherSourcedId: { type: string }
date: { type: string, format: date }
startedAt: { type: string, format: date-time, nullable: true }
endedAt: { type: string, format: date-time, nullable: true }
sweepCount:
type: integer
minimum: 1
default: 1
description: Ders içinde yapılan tarama turu sayısı
method:
type: string
enum: [face-1to1, proximity, qr, pin, manual, mixed]
source: { type: string, example: "yoklama-app" }
status: { type: string, enum: [open, finalized, voided], default: open }
notes: { type: string, nullable: true }
AttendanceRecord:
type: object
required: [userSourcedId, status]
description: |
BİYOMETRİK ALAN YOKTUR. Yüz şablonu, görüntü veya ham canlılık verisi
bu API'de taşınmaz. Gönderilen tek şey karardır.
properties:
userSourcedId: { type: string }
status:
type: string
enum: [present, absent, late, excused, partial]
presenceRatio:
type: number
minimum: 0
maximum: 1
nullable: true
description: Onaylanan tur / toplam tur
sweepResults:
type: array
nullable: true
items: { type: boolean }
description: Tur bazlı sonuçlar; erken çıkış tespiti için
method:
type: string
nullable: true
enum: [face-1to1, proximity, qr, pin, manual]
verifiedAt: { type: string, format: date-time, nullable: true }
flags:
type: array
items:
type: string
enum: [ERKEN_AYRILDI, GEC_KATILDI, MANUEL, SADECE_BLE, ITIRAZ_VAR]
note: { type: string, nullable: true }
AttendanceRecordRead:
allOf:
- $ref: "#/components/schemas/AttendanceRecord"
- type: object
properties:
sessionSourcedId: { type: string }
date: { type: string, format: date }
dateLastModified: { type: string, format: date-time }
BatchResult:
type: object
required: [accepted, rejected]
properties:
accepted: { type: integer }
rejected: { type: integer }
errors:
type: array
items:
type: object
properties:
userSourcedId: { type: string }
code:
type: string
enum: [user_not_found, user_not_enrolled, session_finalized, invalid_status, duplicate]
message: { type: string }
Bu sayfa depodaki docs/api/openapi.yaml dosyasından scripts/belgeleri-uret.py ile üretilir. Elle düzenlenmez; değişiklik kaynağa yapılır.