Skip to content

Authentication

The SabiBooks API uses JWT (JSON Web Token) authentication. Unlike traditional username/password systems, SabiBooks authenticates via phone number + OTP (one-time password sent by SMS). This reflects how Nigerian merchants typically operate — by phone number, not email.

  1. Register your phone number to create an account.
  2. Verify the OTP sent via SMS to confirm your number.
  3. Login with your verified phone number to request a new OTP.
  4. Verify login OTP to receive access and refresh tokens.
  5. Use the access token in the Authorization header for all API requests.
  6. Refresh the token before it expires using the refresh token.

Create a new account with a Nigerian phone number.

Terminal window
curl -X POST https://app.sabibooks.com/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348012345678",
"first_name": "Chidi",
"last_name": "Okonkwo",
"business_name": "Chidi Provisions"
}'

Response:

{
"success": true,
"message": "Registration successful. OTP sent to +2348012345678",
"data": {
"user_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"phone": "+2348012345678",
"otp_expires_at": "2026-02-20T14:32:08Z"
},
"timestamp": "2026-02-20T14:22:08Z"
}

Verify the SMS code sent to your phone to activate the account.

Terminal window
curl -X POST https://app.sabibooks.com/api/v1/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348012345678",
"otp": "123456"
}'

Response:

{
"success": true,
"message": "Phone number verified successfully",
"data": {
"verified": true,
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600
},
"timestamp": "2026-02-20T14:23:15Z"
}

For returning users, request a login OTP:

Terminal window
curl -X POST https://app.sabibooks.com/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348012345678"
}'

Response:

{
"success": true,
"message": "OTP sent to +2348012345678",
"data": {
"phone": "+2348012345678",
"otp_expires_at": "2026-02-20T15:02:08Z"
},
"timestamp": "2026-02-20T14:52:08Z"
}

Submit the OTP to receive your tokens:

Terminal window
curl -X POST https://app.sabibooks.com/api/v1/auth/verify-otp \
-H "Content-Type: application/json" \
-d '{
"phone": "+2348012345678",
"otp": "654321"
}'

Response:

{
"success": true,
"message": "Login successful",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600
},
"timestamp": "2026-02-20T14:53:22Z"
}

Include the access token in the Authorization header of every API request:

Terminal window
curl -X GET https://app.sabibooks.com/api/v1/products \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiJ9..." \
-H "Content-Type: application/json"

The token contains encoded claims including your user_id, business_id, and roles. The API uses these claims to scope all data to your business automatically.

Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without re-authenticating:

Terminal window
curl -X POST https://app.sabibooks.com/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiJ9..."
}'

Response:

{
"success": true,
"message": "Token refreshed successfully",
"data": {
"access_token": "eyJhbGciOiJIUzI1NiJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiJ9...",
"token_type": "Bearer",
"expires_in": 3600
},
"timestamp": "2026-02-20T15:22:08Z"
}
TokenLifetimePurpose
Access Token1 hourAuthenticates API requests
Refresh Token30 daysObtains new access tokens
OTP Code10 minutesVerifies phone ownership

The access token payload includes:

{
"sub": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"business_id": "b1c2d3e4-f5a6-7890-bcde-f12345678901",
"roles": ["BUSINESS_OWNER"],
"iat": 1740057728,
"exp": 1740061328
}
ClaimDescription
subUser ID (UUID)
business_idThe business this user belongs to — all API responses are scoped to this business
rolesUser roles (e.g., BUSINESS_OWNER, STAFF)
iatToken issue time (Unix timestamp)
expToken expiry time (Unix timestamp)

These endpoints do not require authentication:

EndpointMethodPurpose
/auth/registerPOSTCreate new account
/auth/loginPOSTRequest login OTP
/auth/verify-otpPOSTVerify OTP and get tokens
/auth/refreshPOSTRefresh access token
/actuator/healthGETService health check
/swagger-ui/**GETInteractive API docs
/api-docs/**GETOpenAPI specification
{
"success": false,
"message": "Access token has expired",
"error": {
"type": "https://api.sabibooks.com/errors/authentication",
"title": "Unauthorized",
"status": 401,
"detail": "The provided access token has expired. Use the refresh endpoint to obtain a new token."
},
"timestamp": "2026-02-20T15:22:08Z"
}
{
"success": false,
"message": "Invalid OTP",
"error": {
"type": "https://api.sabibooks.com/errors/validation",
"title": "Bad Request",
"status": 400,
"detail": "The OTP code provided is invalid or has expired. Request a new OTP."
},
"timestamp": "2026-02-20T14:25:00Z"
}