API Reference — Membership One

Base URL

http://localhost:8081/api

Authentication

All endpoints require a JWT Bearer token in the Authorization header, except public endpoints marked with [PUBLIC].

Authorization: Bearer eyJhbGciOiJSUzI1NiIs...

JWT Claims

{
  "sub": "42",
  "iss": "membership-one",
  "email": "admin@example.com",
  "roles": ["CLUB_ADMIN", "ACCOUNTANT"],
  "tenantId": 1,
  "iat": 1708000000,
  "exp": 1708000900
}

Token Lifecycle

  • Access token: 15 minutes
  • Refresh token: 7 days (SHA-256 hash stored server-side)
  • Rotation: Each refresh generates a new token pair

Auth Endpoints (/api/auth)

Register [PUBLIC]

POST /api/auth/register
Content-Type: application/json

{
  "email": "admin@myclub.com",
  "password": "SecureP@ss123",
  "firstName": "Max",
  "lastName": "Mustermann",
  "entityId": 1,
  "locale": "de"
}

Response: 201 CreatedUserDto

Login [PUBLIC]

POST /api/auth/login
Content-Type: application/json

{
  "email": "admin@myclub.com",
  "password": "SecureP@ss123",
  "entityId": 1
}

Response: 200 OK

{
  "accessToken": "eyJ...",
  "refreshToken": "eyJ...",
  "expiresIn": 900,
  "user": {
    "id": 42,
    "email": "admin@myclub.com",
    "firstName": "Max",
    "lastName": "Mustermann",
    "roles": ["CLUB_ADMIN"],
    "permissions": ["MEMBER_READ", "MEMBER_WRITE", "..."],
    "locale": "de",
    "entityId": 1
  }
}

Verify Email [PUBLIC]

POST /api/auth/verify-email?token={base64-token}

Response: 200 OK

Forgot Password [PUBLIC]

POST /api/auth/forgot-password
Content-Type: application/json

{ "email": "admin@myclub.com" }

Response: 200 OK (always, even if email not found — prevents enumeration)

Reset Password [PUBLIC]

POST /api/auth/reset-password
Content-Type: application/json

{ "token": "...", "newPassword": "NewSecure123!" }

Response: 200 OK

Refresh Token [PUBLIC]

POST /api/auth/refresh
Content-Type: application/json

{ "refreshToken": "eyJ..." }

Response: 200 OKLoginResponse (new token pair)

Logout

POST /api/auth/logout
Authorization: Bearer {token}

Response: 204 No Content

Change Password

POST /api/auth/change-password
Authorization: Bearer {token}
Content-Type: application/json

{ "currentPassword": "OldPass123", "newPassword": "NewPass456" }

Response: 200 OK

Get Current User

GET /api/auth/me
Authorization: Bearer {token}

Response: 200 OKUserDto

Update Profile

PUT /api/auth/me
Authorization: Bearer {token}
Content-Type: application/json

{ "firstName": "Maximilian", "locale": "en" }

Response: 200 OKUserDto


Entity Endpoints (/api/entity)

Create Organization

POST /api/entity
Authorization: Bearer {token}
Content-Type: application/json

{
  "name": "Fitness Club Berlin",
  "type": "CLUB",
  "contactEmail": "info@fitnessclub-berlin.de",
  "country": "DE",
  "city": "Berlin"
}

Response: 201 CreatedOrganizationDto

Get Organization

GET /api/entity/{id}

Search Organizations

GET /api/entity/search?name=fitness&type=CLUB&status=ACTIVE&page=0&size=20

Response: 200 OKPageResponse<OrganizationDto>

Update Organization

PUT /api/entity/{id}

Get Children (Franchise)

GET /api/entity/{id}/children

Response: 200 OKList<OrganizationDto>

Get/Update Settings

GET /api/entity/{id}/settings
PUT /api/entity/{id}/settings

Member Endpoints (/api/members)

Create Member

POST /api/members
Authorization: Bearer {token}
Content-Type: application/json

{
  "entityId": 1,
  "firstName": "Anna",
  "lastName": "Schmidt",
  "email": "anna@example.com",
  "dateOfBirth": "1990-05-15",
  "gender": "FEMALE",
  "joinDate": "2026-02-22"
}

Response: 201 CreatedMemberDto (includes auto-generated memberNumber)

Search Members

GET /api/members/search?query=anna&status=ACTIVE&page=0&size=20&sort=lastName,asc

Response: 200 OKPageResponse<MemberListItemDto>

Get Member

GET /api/members/{id}

Update Member

PUT /api/members/{id}
Content-Type: application/json

{ "phone": "+4930123456", "notes": "VIP member" }

Delete (Soft)

DELETE /api/members/{id}

Sets status=INACTIVE and exitDate=today.

Audit History

GET /api/members/{id}/audit?page=0&size=20

Response: 200 OKPageResponse<AuditLog>

POST /api/members/{id}/link-user?userId=42

Contract Endpoints

Membership Templates (/api/membership-templates)

Create Template

POST /api/membership-templates
Content-Type: application/json

{
  "entityId": 1,
  "name": "Premium Membership",
  "price": 49.90,
  "billingCycle": "MONTHLY",
  "minimumTermMonths": 12,
  "cancellationNoticeDays": 30,
  "autoRenew": true,
  "ageMin": 16,
  "features": "[\"Pool\", \"Sauna\", \"Group Classes\"]"
}

List Templates (Admin)

GET /api/membership-templates?page=0&size=20

Public Catalog [PUBLIC]

GET /api/membership-templates/catalog/{entityId}

Returns visible + active templates only, sorted by sortOrder.

Update / Archive

PUT /api/membership-templates/{id}
DELETE /api/membership-templates/{id}

Contracts (/api/contracts)

Purchase Membership

POST /api/contracts
Content-Type: application/json

{
  "memberId": 42,
  "templateId": 1,
  "startDate": "2026-03-01"
}

Creates contract with status=PENDING_SIGNATURE and locks in price.

Sign Contract

POST /api/contracts/{id}/sign
Content-Type: application/json

{ "signatureIp": "192.168.1.1", "signatureUserAgent": "Mozilla/5.0..." }

Transitions to status=ACTIVE.

Cancel Contract

POST /api/contracts/{id}/cancel
Content-Type: application/json

{ "reason": "Moving to another city" }

Validates cancellation notice period.

Get Contract / List by Member

GET /api/contracts/{id}
GET /api/contracts/member/{memberId}?page=0&size=20

Product Endpoints (/api/products)

Create Product

POST /api/products
X-Entity-Id: 1
Content-Type: application/json

{
  "entityId": 1,
  "name": "Personal Training Session",
  "categoryCd": "PERSONAL_TRAINING",
  "typeCd": "PER_SESSION",
  "price": 59.00,
  "vatRate": 19.00,
  "vatIncluded": true,
  "durationMinutes": 60
}

List Products (Admin)

GET /api/products?category=COURSE&status=ACTIVE&page=0&size=20
X-Entity-Id: 1

Public Catalog [PUBLIC]

GET /api/products/catalog/{entityId}

Update / Archive

PUT /api/products/{id}
DELETE /api/products/{id}

Document Endpoints (/api/documents)

Documents

Method Path Description
POST /api/documents/upload Upload document (multipart)
GET /api/documents/{id} Get document metadata
GET /api/documents/{id}/download Download file
DELETE /api/documents/{id} Delete document
GET /api/documents?linkedType=X&linkedId=Y List documents by link
GET /api/documents/pdf/contract/{contractId} Generate contract PDF
GET /api/documents/pdf/invoice/{transactionId} Generate invoice PDF
GET /api/documents/pdf/member-card/{memberId} Generate member card PDF

Data Import Endpoints (/api/imports)

Data Import

Method Path Description
POST /api/imports/upload Upload CSV + create import job
POST /api/imports/{jobId}/validate Run dry-run validation
GET /api/imports/{jobId}/preview Get validation results
POST /api/imports/{jobId}/execute Execute import
GET /api/imports/{jobId}/status Get import progress
GET /api/imports/{jobId}/errors Download error report CSV
GET /api/imports List import jobs
GET /api/imports/templates List available templates

Pagination

All paginated endpoints accept standard Spring Data parameters:

?page=0&size=20&sort=lastName,asc&sort=firstName,asc

Response format (PageResponse<T>):

{
  "content": [...],
  "page": 0,
  "size": 20,
  "totalElements": 142,
  "totalPages": 8
}

Error Responses

All errors return ErrorResponse:

{
  "code": "ENTITY_NOT_FOUND",
  "message": "Member not found with id: 999",
  "details": null
}

HTTP Status Codes

Code Meaning
200 Success
201 Created
204 No Content (successful delete/logout)
400 Bad Request (validation errors)
401 Unauthorized (missing/invalid JWT)
403 Forbidden (insufficient permissions)
404 Not Found
409 Conflict (duplicate email, etc.)
429 Too Many Requests (rate limited)
500 Internal Server Error

Bank Account Endpoints (/api/bank-accounts)

Create Bank Account

POST /api/bank-accounts
Authorization: Bearer {token}
Content-Type: application/json

{
  "memberId": 1,
  "accountHolder": "Max Mustermann",
  "iban": "DE89370400440532013000",
  "bic": "COBADEFFXXX",
  "bankName": "Commerzbank",
  "mandateSignDate": "2026-02-22",
  "mandateTypeCd": "CORE"
}

Response: 201 CreatedBankAccountDto

Get Member Bank Accounts

GET /api/bank-accounts/member/{memberId}

Response: 200 OKList<BankAccountDto>

Update Bank Account

PUT /api/bank-accounts/{id}
Authorization: Bearer {token}
Content-Type: application/json

{
  "accountHolder": "Max Mustermann-Schmidt",
  "bic": "COBADEFFXXX",
  "bankName": "Commerzbank AG"
}

Response: 200 OKBankAccountDto

Set Default Bank Account

PUT /api/bank-accounts/{id}/set-default
Authorization: Bearer {token}

Response: 200 OKBankAccountDto

Revoke Bank Account

DELETE /api/bank-accounts/{id}
Authorization: Bearer {token}

Response: 204 No Content


Transaction Endpoints (/api/transactions)

Get Transaction by ID

GET /api/transactions/{id}
Authorization: Bearer {token}

Response: 200 OKTransactionDto

Search Transactions

GET /api/transactions?statusCd=PENDING&typeCd=MEMBERSHIP_FEE&memberId=1&page=0&size=20
Authorization: Bearer {token}

Response: 200 OKPageResponse<TransactionDto>

Get Member Transactions

GET /api/transactions/member/{memberId}?page=0&size=20

Response: 200 OKPageResponse<TransactionDto>

Get Member Balance

GET /api/transactions/member/{memberId}/balance

Response: 200 OKMemberBalanceDto

{
  "memberId": 1,
  "outstandingBalance": 58.0000,
  "openTransactionCount": 2
}

Full Storno (Cancel Transaction)

POST /api/transactions/{id}/storno
Authorization: Bearer {token}
Content-Type: application/json

{
  "reason": "Customer request — duplicate charge"
}

Response: 200 OKTransactionDto (credit note)

Partial Storno

POST /api/transactions/{id}/storno-partial
Authorization: Bearer {token}
Content-Type: application/json

{
  "amount": 10.0000,
  "reason": "Partial refund — service not used"
}

Response: 200 OKTransactionDto (partial credit note)

Record Manual Payment

POST /api/transactions/{id}/record-payment
Authorization: Bearer {token}
Content-Type: application/json

{
  "amount": 29.0000,
  "paymentMethod": "CASH"
}

Response: 200 OKTransactionDto


Billing Endpoints (/api/billing)

Trigger Billing Run

POST /api/billing/trigger
Authorization: Bearer {token}

Response: 200 OK

{
  "transactionsCreated": 15,
  "entityId": 1
}

Submit Pending to Cash360

POST /api/billing/submit
Authorization: Bearer {token}

Response: 200 OK

{
  "transactionsSubmitted": 15,
  "entityId": 1
}

Get Billing Report

GET /api/billing/report
Authorization: Bearer {token}

Response: 200 OKBillingReportDto

{
  "totalPayoutAmount": 12500.0000,
  "fees": 125.0000,
  "directDebitReturnAmount": 87.0000,
  "reminderCasesAmount": 350.0000,
  "pendingAmount": 2100.0000,
  "outstandingBalance": 4500.0000
}

Get SEPA Exports

GET /api/billing/sepa-exports
Authorization: Bearer {token}

Response: 200 OKList<Cash360SepaExportResponse>


Webhook Endpoints (/api/webhooks) [PUBLIC]

Cash360 Webhook

POST /api/webhooks/cash360
X-Webhook-Signature: {hmac-sha256-hex}
Content-Type: application/json

{
  "type": "TRANSACTION_STATUS_CHANGED",
  "transactionId": 999,
  "statusCd": "PAID",
  "collectionTypeCd": "DIRECT_DEBIT",
  "amountDue": 0.00
}

Response: 200 OK (always, to prevent retries)

Transaction Status Mapping (Cash360 → Membership)

Cash360 Status Membership Status
NEW, ACCEPTED, EXPORTED SUBMITTED
PAID PAID
SETTLED SETTLED
RETURNED, REJECTED FAILED
CANCELLED CANCELLED
FOR_DUNNING OVERDUE
SENT_TO_INKASSO DEBT_COLLECTION

Check-in & Access Control

Check-in Endpoints

Method Path Description
POST /api/checkin Perform check-in (QR/NFC/BLE/MANUAL)
POST /api/checkin/checkout Record check-out
GET /api/checkin/logs Check-in log list (paginated, filterable by zone/date/method)
GET /api/checkin/analytics Check-in analytics (totals by method, zone, time)
GET /api/checkin/history Member's own check-in history

Access Zone Endpoints (Admin)

Method Path Description
GET /api/admin/access-zones List access zones
POST /api/admin/access-zones Create access zone
GET /api/admin/access-zones/{id} Get access zone details
PUT /api/admin/access-zones/{id} Update access zone
DELETE /api/admin/access-zones/{id} Delete access zone

Access Rule Endpoints (Admin)

Method Path Description
GET /api/admin/access-rules List access rules
POST /api/admin/access-rules Create access rule
PUT /api/admin/access-rules/{id} Update access rule
DELETE /api/admin/access-rules/{id} Delete access rule

Credential Endpoints (Admin)

Method Path Description
GET /api/admin/credentials List credentials
POST /api/admin/credentials Create credential
GET /api/admin/credentials/member/{memberId} Credentials for a member
DELETE /api/admin/credentials/{id} Revoke credential

Resources & Bookings

Resource Endpoints (Admin)

Method Path Description
GET /api/admin/resources List resources (paginated)
POST /api/admin/resources Create resource
GET /api/admin/resources/{id} Get resource details
PUT /api/admin/resources/{id} Update resource
DELETE /api/admin/resources/{id} Delete resource
GET /api/admin/resources/{id}/availability Check resource availability

Booking Endpoints (Admin)

Method Path Description
GET /api/admin/bookings List bookings (filterable by date range)
POST /api/admin/bookings Create booking
GET /api/admin/bookings/{id} Get booking details
PUT /api/admin/bookings/{id} Update booking
DELETE /api/admin/bookings/{id} Cancel booking
GET /api/admin/resources/{id}/bookings Bookings for a resource

Resource & Booking Endpoints (Consumer)

Method Path Description
GET /api/resources Consumer: list bookable resources
GET /api/resources/{id}/slots Consumer: available time slots for date
POST /api/bookings Consumer: create booking

Courses

Course Endpoints (Admin)

Method Path Description
GET /api/admin/courses List courses (paginated)
POST /api/admin/courses Create course
GET /api/admin/courses/{id} Get course details
PUT /api/admin/courses/{id} Update course
DELETE /api/admin/courses/{id} Delete course
GET /api/admin/courses/{id}/registrations List course registrations
POST /api/admin/courses/{id}/attendance Mark attendance

Course Endpoints (Consumer)

Method Path Description
GET /api/courses Consumer: browse available courses
GET /api/courses/{id} Consumer: course details
POST /api/courses/{id}/register Consumer: register for course
POST /api/courses/{id}/cancel Consumer: cancel registration

Communication & Notifications

Notification Endpoints

Method Path Description
POST /api/communications/send Send single notification
POST /api/communications/bulk Bulk send via queue
GET /api/communications List notifications (paginated)

Template Endpoints

Method Path Description
GET /api/communication-templates List templates
POST /api/communication-templates Create template
PUT /api/communication-templates/{id} Update template
DELETE /api/communication-templates/{id} Delete template
POST /api/communication-templates/{id}/preview Preview with variables

Events

Event Endpoints (Admin)

Method Path Description
POST /api/events Create event
GET /api/events List events (admin)
GET /api/events/{id} Event detail
PUT /api/events/{id} Update event
POST /api/events/{id}/publish Publish event
POST /api/events/{id}/cancel Cancel event

Event Endpoints (Consumer)

Method Path Description
POST /api/events/{id}/register Register for event
DELETE /api/events/{id}/register Cancel registration
GET /api/events/upcoming/{entityId} Public upcoming events

Homepage [PUBLIC]

Method Path Description
GET /p/{slug} Public entity homepage (Thymeleaf SSR)
GET /p/sitemap.xml Sitemap

Onboarding & Provisioning

Provisioning Endpoints

Method Path Description
POST /api/onboarding/provision Start provisioning job
GET /api/onboarding/provision/{jobId} Get provisioning status

Start Provisioning

POST /api/onboarding/provision
Authorization: Bearer {token}
Content-Type: application/json

{
  "organizationName": "FitClub Munich",
  "adminEmail": "admin@fitclub-munich.de",
  "adminName": "Max Mustermann",
  "tier": "STARTER",
  "scenario": "FOUNDER",
  "industryTemplate": "FITNESS_STUDIO",
  "locale": "de",
  "currency": "EUR",
  "timezone": "Europe/Berlin"
}

Response: 201 Created -> ProvisioningStatusDto

{
  "id": 1,
  "status": "IN_PROGRESS",
  "currentStep": "CREATE_ORGANIZATION",
  "totalSteps": 7,
  "completedSteps": 0,
  "startedAt": "2026-02-23T10:00:00Z"
}

Get Provisioning Status

GET /api/onboarding/provision/{jobId}
Authorization: Bearer {token}

Response: 200 OK -> ProvisioningStatusDto

Wizard Endpoints

Method Path Description
GET /api/onboarding/wizard Get wizard state for current entity
PUT /api/onboarding/wizard Save wizard step
GET /api/onboarding/wizard/templates List industry templates

Go-Live Endpoints

Method Path Description
GET /api/onboarding/go-live/{entityId} Get Go-Live checklist

Response: 200 OK -> GoLiveChecklistDto

{
  "profileComplete": true,
  "membershipPlanActive": true,
  "paymentConfigured": false,
  "teamMemberInvited": false,
  "membersAdded": true,
  "welcomeEmailCustomized": false,
  "testTransactionRun": false,
  "brandingSet": false,
  "completedCount": 3,
  "totalCount": 8,
  "completedAt": null
}

Health Scoring

Health Score Endpoints

Method Path Description
GET /api/health-score/{entityId} Get current health score
GET /api/health-score/at-risk List at-risk organizations
GET /api/health-score/history/{entityId} Health score history (12 weeks)
GET /api/health-score/config Get health score configuration

Get Health Score

GET /api/health-score/{entityId}
Authorization: Bearer {token}

Response: 200 OK -> HealthScoreDto

{
  "entityId": 1,
  "overallScore": 72,
  "loginFrequencyScore": 85,
  "featureAdoptionScore": 60,
  "memberActivityScore": 75,
  "paymentHealthScore": 80,
  "supportSentimentScore": 65,
  "calculatedAt": "2026-02-23T02:00:00Z",
  "trend": "UP",
  "organizationName": "FitClub Munich"
}

Get At-Risk Organizations

GET /api/health-score/at-risk
Authorization: Bearer {token}

Response: 200 OK -> List<HealthScoreDto> (organizations with score < 70)


Swagger UI

Interactive API documentation available at:

http://localhost:8081/api/swagger-ui.html

API spec (JSON):

http://localhost:8081/api/api-docs