2Fast API v1

Account endpoints reference · Base URL https://2fast.ng/api/

Authentication

All /account/* endpoints require a date token in the Authorization header, using today's UTC date in YYYYMMDD format:

Authorization: Token 20260824

Missing or mismatched token returns HTTP 401. All requests are POST with Content-Type: application/json.

POST/account/register

Creates a new user account.

Request body

{
  "fname": "Usman",
  "lname": "Halal",
  "email": "usman@example.com",
  "phone": "08012345678",
  "password": "mypassword1",
  "transpin": "5532",
  "state": "Lagos",
  "account": "subscriber"
}

Validation

Success

{ "status": "success", "msg": "Registration Successfull" }

Errors

msgReason
Phone Number Already ExistPhone already registered
Email Already ExistEmail already registered
Phone Number Must Be 11 DigitsInvalid phone format
Transaction PIN Must Be 4 DigitsPIN length wrong
Please Set A More Secured Transaction PINWeak PIN
Invalid Email FormatEmail malformed
Password Must Be At Least 6 CharactersPassword too short

POST/account/login

Authenticates by phone + password.

Request body

{ "phone": "08012345678", "accesspass": "mypassword1" }

Success

{
  "status": "success",
  "msg": "Login Successful",
  "name": "Usman Halal",
  "phone": "08012345678"
}

Rate limiting

Failed attempts are tracked per phone and per IP. After 5 fails in 5 minutes, the account/IP is locked for 5 minutes. Every attempt is logged with browser, OS, IP, and user-agent.

Errors

msgReason
Incorrect credentials. Attempt 1 of 5Wrong phone/password
Incorrect credentials. Attempt 4 of 5 ⚠️1–2 attempts left
Too many failed attempts. Please try again after 5 minutes at 14:30:00Locked for 5 minutes
Account Blocked, Please Contact Customer Supportaccount_status not active

POST/account/recover

Sends a 4-digit recovery code to the user's email via Resend (from support@2fast.ng).

Request body

{ "email": "usman@example.com" }

Success

{ "status": "success", "msg": "A 4-digit recovery code has been sent to your email" }

Stored in otps (otp_type=recovery, pending, expires in 10 minutes).

Errors

msgReason
Invalid Email FormatEmail malformed
Email Not FoundNo user with that email
Failed to send recovery emailResend delivery failed

POST/account/verify-code

Verifies a recovery code without changing the password.

Request body

{ "email": "usman@example.com", "code": "5678" }

Success

{ "status": "success", "msg": "Code Verified Successfully" }

Errors

msgReason
Invalid Email FormatEmail malformed
Invalid CodeCode wrong / used / not found
Code ExpiredOTP older than 10 minutes
Email Not FoundNo user with that email

POST/account/update-password

Sets a new password using a valid recovery code (pending or already-verified).

Request body

{
  "email": "usman@example.com",
  "code": "5678",
  "password": "mynewpassword1"
}

Success

{ "status": "success", "msg": "Password Updated Successfully" }

The OTP row is marked used after the password update.

Errors

msgReason
Invalid Email FormatEmail malformed
Invalid CodeCode wrong / used / not found
Code ExpiredOTP older than 10 minutes
Password Must Be At Least 6 CharactersPassword too short
Email Not FoundNo user with that email

User Endpoints — Authentication

All /user/* endpoints authenticate with the user's API key instead of the date token. Send it in the Authorization header:

Authorization: Bearer BAHCCvJ4y36...

The API key is returned by /account/login and shown on /user as api_key. Missing or unknown keys return { "status": "fail", "msg": "User not found" }.

POST/user/resend-verification

Generates a 4-digit email-verification code, sends it via Resend, and invalidates any previous pending code.

Request body

{}

Success

{ "status": "success", "msg": "Verification code sent to u***@gmail.com" }

Errors

msgReason
Your email is already verifiedNo need to resend
Failed to send email. Please try againMail server error
User not foundInvalid API key

POST/user/verify-email

Verifies the 4-digit code and marks the user's email as verified.

Request body

{ "code": "4821" }

Success

{
  "status": "success",
  "msg": "Email verified successfully",
  "email": "user@example.com"
}

Errors

msgReason
Verification code is requiredMissing code field
Invalid verification codeCode is not numeric
Incorrect verification code. Please check your email and try againCode doesn't match / expired
Your email is already verifiedAlready verified

POST/user

Returns the authenticated user's profile.

Request body

{}

Success

{
  "status": "success",
  "name": "Usman Halal",
  "fname": "Usman", "lname": "Halal",
  "email": "user@example.com",
  "phone": "08012345678",
  "state": "Lagos",
  "balance": "5000.00",
  "referral_wallet": "200.00",
  "cashback_wallet": "50.00",
  "referral_code": "08012345678",
  "account_tier": "tier1",
  "user_type": "subscriber",
  "kyc_verified": false,
  "api_key": "BAHCCvJ4y36..."
}

POST/user/transactions

Paginated list of the user's transactions, newest first.

Request body

{ "limit": 20, "offset": 0 }

Success

{
  "status": "success",
  "transactions": [
    {
      "tId": 101, "transref": "DATA20260303001",
      "servicename": "Data Bundle",
      "servicedesc": "1GB MTN data for 08012345678",
      "amount": 300.00, "status": 0,
      "oldbal": 5000.00, "newbal": 4700.00,
      "date": "2026-03-03 20:00:00"
    }
  ]
}

POST/user/transaction-details

Details for a single transaction by reference.

Request body

{ "ref": "DATA20260303001" }

Success

{
  "status": "success",
  "transaction": {
    "tId": 101, "transref": "DATA20260303001",
    "servicename": "Data Bundle",
    "servicedesc": "1GB MTN data for 08012345678",
    "amount": 300.00, "status": 0, "status_label": "Successful",
    "oldbal": 5000.00, "newbal": 4700.00,
    "date": "2026-03-03 20:00:00"
  }
}

Returns Transaction not found if the ref doesn't exist or belongs to another user — both cases look identical for security.

POST/user/profile-picture

Double-duty endpoint. Empty JSON body returns the current picture. Multipart body uploads a new one and deletes the previous file.

Get current picture

Content-Type: application/json
{}
{
  "status": "success",
  "has_picture": true,
  "image_path": "/user-uuid/profile_1234567890.jpg",
  "image_url": "https://.../signed-url"
}

When there's no picture, has_picture is false and both URL fields are null.

Upload

Content-Type: multipart/form-data
Field name: profile_picture
Allowed:    JPG, JPEG, PNG
Max size:   5MB
{
  "status": "success",
  "msg": "Profile picture updated successfully",
  "image_path": "/user-uuid/profile_1234567890.jpg",
  "image_url": "https://.../signed-url"
}

Errors

msgReason
Invalid file type. Only JPG and PNG allowed.Wrong file extension
File too large. Maximum size is 5MB.File exceeds 5MB
Uploaded file is not a valid image.File is empty or corrupt
Failed to save image. Check folder permissions.Server write error

POST/user/profile-picture/delete

Removes the current profile picture. Safe to call when none exists.

Request body

{}

Success

{ "status": "success", "msg": "Profile picture removed successfully" }

Example

curl -X POST https://2fast.ng/account/login \\
  -H "Content-Type: application/json" \\
  -H "Authorization: Token 20260824" \\
  -d '{"phone":"08012345678","accesspass":"mypassword1"}'

Replace 20260824 with today's UTC date in YYYYMMDD.