ECDS Progress Board
For the frontend team

Connect to the staging API

The NYSC staging API is live. This page is everything you need to point your app at it. Each step is short; technical detail sits inside the grey boxes.

Updated 5 October 2026 · staging runs main as it stood on 1 October (up to ECDS-18). Staff accounts (ECDS-49) are on main but not on staging yet

Staging is up. The health check answers {"status":"ok"}.

Four steps to get going

  1. Add the API address to your app

    Put this line in your .env.local file. Every request your app makes starts with this address.

    NEXT_PUBLIC_API_BASE_URL=https://nysc-api-staging.80.241.222.89.sslip.io/api/v1

    On Vite, the same value goes in a variable starting with VITE_, for example VITE_API_BASE_URL.

  2. Check that you can reach it

    Open the health check in a browser, or run the command. You should see {"status":"ok"}.

    curl https://nysc-api-staging.80.241.222.89.sslip.io/api/v1/health

    Open the health check

  3. Run your app on an allowed address

    The browser only lets your app call the API from these two addresses. Anything else is blocked by CORS (see the glossary).

    http://localhost:3000http://localhost:5173

    Deploying a preview (for example on Vercel or Netlify)? Send the backend team the exact address so it can be added. Until then, calls from that address will fail in the browser even though the API is up.

  4. Use the contract, not Swagger

    Swagger at /docs is turned off on purpose, because staging runs in production mode. The reviewed contract lives in the repo:

    Every endpoint and field
    docs/api/openapi.v1.json
    How to use it
    docs/api/README.md
    User stories S1 to S11
    docs/api/user-stories.md

    Tip: drop openapi.v1.json into editor.swagger.io, Postman or Insomnia to browse it, or generate a typed client from it.

Before you start testing

Rules for staging

  • This is staging, not production. Use test accounts and test data only.
  • Never enter a real corps member's state code, phone number or email.
  • 16 of 24 endpoints work today. The other 8 answer 501, which means "not built yet". See the API reference.
  • Check-in only works for members matched to the official roster, and roster upload isn't built yet (ECDS-8). On staging every check-in is refused with a reason, which is useful for testing your error screens.
  • A member can only have one phone registered for check-in at a time.
  • The login is locked after 5 wrong passwords in a row. Use a fresh test account if you lock yourself out.

What the backend team checked

  • Public HTTPS with a valid Let's Encrypt certificate.
  • Plain HTTP is sent to HTTPS automatically.
  • The API has its own PostgreSQL database and storage volume on TNT.
  • Database migrations ran successfully.
  • CORS allows localhost:3000 and localhost:5173 only. Other web addresses are refused.
  • Existing routes on the shared proxy were left alone; only this hostname was added.
  • The deployed code (main, up to ECDS-18) passed 312 tests, with 8 skipped.

A starter API helper

One small function that every screen can use. It reads the address from your env file and sends JSON.

// lib/api.ts
const BASE = process.env.NEXT_PUBLIC_API_BASE_URL!;

export async function api<T>(path: string, init: RequestInit = {}, token?: string): Promise<T> {
  const res = await fetch(`${BASE}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...init.headers,
    },
  });
  if (res.status === 501) throw new Error(`${path} is not built yet (501)`);
  if (!res.ok) throw await res.json().catch(() => new Error(res.statusText));
  return res.status === 204 ? (undefined as T) : res.json();
}

// usage
const health = await api<{ status: string }>("/health");

The helper assumes the access token is sent as Authorization: Bearer …. Confirm how tokens are sent and the exact error shape in docs/api/README.md.

Where to go next

Eti-Osa CDS · attendance backend

ECDS Progress Board

What is finished, what we are building now, and what the app can already call. Read it top to bottom: the plan, what is next, each stage in detail, then the full list of endpoints.

As of 5 October 2026 · this board shows main only · main has ECDS-3, ECDS-4, ECDS-5, ECDS-6, ECDS-17, ECDS-18 and ECDS-49 · staging runs main up to ECDS-18 · next up: ECDS-19

16 of 24endpoints the app can call today
323automated checks on main, all passing (8 more set aside for now)
6 of 12areas of work built
Stagingis live for the frontend team
1 · Roadmap

Six stages, in the order we build them

Done Built, not closed Partly built Not started
    2 · Open items

    What needs doing next

    Taken from the unfinished tasks below. The order in each column is a suggestion.

    Finish what is built

    1. ECDS-17Tell the frontend team that sign-up now asks for three more thingsCovered on the Start here and API pages

    Start next

    1. ECDS-31Confirm a member's email and phoneNow ticket ECDS-31
    2. ECDS-49Staff accounts for the LGI and NYSC staff are done (PR #16, merged 5 October). Next: permissions (ECDS-19), the LGI managing officials (ECDS-48), roster upload (ECDS-20) and matching (ECDS-21)Decisions needed first. Until matching lands nobody can check in for real

    Platform and housekeeping

    1. ECDS-50Connect a real email providerBlocks the LGI setting a password, and members' password resets, on staging
    2. ECDS-16Write down how we back up and restore the database
    3. ECDS-15Finish the one-command setup for a developer's machine
    4. HulyTidy up Huly: add these stages and group the loose tickets
    3 · Milestones

    The work in each stage

    4 · Endpoints

    Every endpoint the app can use

    Grouped by the epic that delivers it. Payloads are on the API reference page. Paths are under /api/v1.

    MethodPathStoryState

    Where this comes from

    Statuses come from Huly (project ECDS), read on 30 September 2026. Huly has no stages set up yet, so the six here are our proposal, based on what depends on what.

    Notes

    The bars count tasks that are built or done. Requests to change a member's details sit under ECDS-8 because an official has to approve them. Also live: GET /api/v1/health. Location data comes from OCHA / HDX, used under CC BY-IGO.

    Story by story

    How each flow works

    One diagram per user story. Read each one top to bottom. Dashed green boxes are checks the server makes; a red box to the side is what happens when a check fails.

    Member (the person) App (your frontend) Server (the API) Official
    Endpoints and payloads

    API reference

    Every endpoint in version one. Open a row to see what it does, what to send and what comes back. All paths start with your NEXT_PUBLIC_API_BASE_URL.

    Field names are examples. The JSON below shows the shape of each request and reply so you know what to expect. The exact field names, types and error bodies are in docs/api/openapi.v1.json, which is the source of truth. If anything here differs from that file, the file wins.

    Who uses ECDS

    User roles

    Four kinds of people use the system. Today only visitors and corps members exist in the API; officials and administrators arrive with ECDS-8 and ECDS-9.

    Who can do what

    ✓ Works now◔ Planned— Not allowed
    ActionVisitorCorps memberOfficial / LGIAdministrator

    * Needs a roster match first, which arrives with ECDS-8. The exact split of powers between a CDS official and an LGI is still to be decided inside ECDS-8, so they share a column for now.

    States a member moves through

    Account

    RegisteredSigned up with a state code
    →
    VerifiedMatched to the official roster

    Roster matching is part of ECDS-8, which is not built yet, so accounts on staging stay Registered for now.

    Attendance record

    PendingChecked in
    →
    Confirmed
    →
    Completed

    A record only ever moves forward one step at a time. It can't skip a step or go back.

    Why it works the way it does

    Backend decisions

    The choices the backend team has made, in plain words. Each card says what was decided, why, and what it means for the screens you build.

    Plain-language meanings

    Glossary

    Every term used on these pages, explained simply. Type to search.