EBITS PayREST API v1

EBITS Pay REST API (v1)

EBITS Pay has two layers:

Layer What it is Who uses it
Web portal (front end) The screens your staff use in a browser (Livewire). Each client sees its own logo, name and colours. Administrators, treasurers, secretaries
REST API (back end) JSON endpoints at /api/v1. They use the same database, permissions, payment rules and audit trail as the portal. Mobile apps, partner systems (HR/payroll), a future separate front end, scripts

Both layers run in the same Laravel application, so there is nothing extra to host. Anything done through the API shows up straight away in the portal and its audit trail, and the other way round.

Base URL: https://<your-domain>/api/v1. All responses are JSON.


1. Authentication

You can get a token in two ways:

POST /api/v1/auth/token
Content-Type: application/json

{ "email": "treasurer@ktwa.org", "password": "••••••••", "device_name": "Finance app (Android)" }
201 Created
{
  "token": "ebp_4Fq…",            // keep it secret; it is shown only this once
  "token_type": "Bearer",
  "expires_in_days": 90,
  "user": { "name": "Kwame Asante", "role": "Administrator", "permissions": ["members.view", "…"],
            "organisation": { "name": "…", "branding": { "logo_url": "…", "brand_color": "#0e7490", "palette": { "50": "#…", "…": "…" } } } }
}

Send the token on every request:

Authorization: Bearer ebp_4Fq…
Accept: application/json

EBITS platform users

EBITS (super-admin) accounts are not part of any client. To work inside a client, add the header X-Organisation: <organisation id or slug>. The role must include Open client portals.


2. Endpoints

Method Path Permission Purpose
POST /auth/token – Sign in and get a token
DELETE /auth/token – Revoke the token used in this request
GET /me – The signed-in user, their permissions and their organisation's branding
GET /organisations/{slug}/branding public Logo, name and colour palette, so an app can theme its sign-in screen
GET /dashboard dashboard.view Members, this month's collections, all-time totals, pending payments
GET /members members.view List members. Filters: search, group_id, status, per_page (max 100), page
GET /members/{id or Member ID} members.view One member, including total_paid
POST /members members.create Add a member
PATCH /members/{id or Member ID} members.edit Change only the fields you send
DELETE /members/{id or Member ID} members.delete Remove a member (their payment history is kept)
GET /groups members.view Member groups and how many members each has
GET /payment-types payment_types.view Dues, levies, items and their amounts/rules
GET /payments payments.view List payments. Filters: status, channel, member_id, payment_type_id, from, to (YYYY-MM-DD)
GET /payments/{reference} payments.view One payment, with its receipt link
POST /payments payments.record Record cash/bank, or send a Mobile Money prompt
GET /reports per report The reports this user may run
GET /reports/{key} per report A report's KPIs, chart data and tables. Filters as in the Reports centre: from, to, type, group, channel, status, member_status, period, member

Members

The Member ID (member_no) is the member's own staff or membership number, as imported. It must be unique within the organisation. Spaces are removed and letters are upper-cased ("ghs 4471" becomes "GHS4471").

POST /api/v1/members
{ "member_no": "GHS4471", "first_name": "Ama", "last_name": "Serwaa", "phone": "0244555666",
  "email": "ama@example.com", "gender": "female", "date_of_birth": "1988-04-12", "group_id": 3 }

Payments

POST /api/v1/payments
{ "member_no": "GHS4471", "payment_type_code": "DUES", "amount": 50, "channel": "cash" }

3. Responses and errors

Lists are paginated:

{ "data": [ … ], "links": { "next": "…" }, "meta": { "current_page": 1, "per_page": 25, "total": 342 } }
Status Meaning
200 / 201 OK / created
401 Missing, wrong, revoked or expired token
403 The role lacks the permission, the organisation is suspended, or the password must be changed
404 Not found, or it belongs to another organisation
422 Validation failed (errors lists each field), or X-Organisation is missing for an EBITS user
429 Too many requests; wait and retry

Every error has a message. Validation errors also have errors: { field: ["…"] }.


4. Quick test with curl

TOKEN=$(curl -s -X POST https://pay.example.com/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"email":"treasurer@ktwa.org","password":"password","device_name":"curl"}' | jq -r .token)

curl -s https://pay.example.com/api/v1/dashboard -H "Authorization: Bearer $TOKEN" | jq
curl -s "https://pay.example.com/api/v1/members?search=ama" -H "Authorization: Bearer $TOKEN" | jq

The machine-readable description is in docs/openapi.yaml. Import it into Postman, Insomnia or Swagger UI.