Account endpoints reference · Base URL https://2fast.ng/api/
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.
Creates a new user account.
{
"fname": "Usman",
"lname": "Halal",
"email": "usman@example.com",
"phone": "08012345678",
"password": "mypassword1",
"transpin": "5532",
"state": "Lagos",
"account": "subscriber"
}
email normalized to lowercase; valid format required.phone normalized to 11-digit Nigerian format (accepts 080…, 234…, or 10-digit).password at least 6 characters.transpin exactly 4 digits; weak PINs (0000, 1234, …) rejected.{ "status": "success", "msg": "Registration Successfull" }
| msg | Reason |
|---|---|
Phone Number Already Exist | Phone already registered |
Email Already Exist | Email already registered |
Phone Number Must Be 11 Digits | Invalid phone format |
Transaction PIN Must Be 4 Digits | PIN length wrong |
Please Set A More Secured Transaction PIN | Weak PIN |
Invalid Email Format | Email malformed |
Password Must Be At Least 6 Characters | Password too short |
Authenticates by phone + password.
{ "phone": "08012345678", "accesspass": "mypassword1" }
{
"status": "success",
"msg": "Login Successful",
"name": "Usman Halal",
"phone": "08012345678"
}
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.
| msg | Reason |
|---|---|
Incorrect credentials. Attempt 1 of 5 | Wrong 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:00 | Locked for 5 minutes |
Account Blocked, Please Contact Customer Support | account_status not active |
Sends a 4-digit recovery code to the user's email via Resend (from support@2fast.ng).
{ "email": "usman@example.com" }
{ "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).
| msg | Reason |
|---|---|
Invalid Email Format | Email malformed |
Email Not Found | No user with that email |
Failed to send recovery email | Resend delivery failed |
Verifies a recovery code without changing the password.
{ "email": "usman@example.com", "code": "5678" }
{ "status": "success", "msg": "Code Verified Successfully" }
| msg | Reason |
|---|---|
Invalid Email Format | Email malformed |
Invalid Code | Code wrong / used / not found |
Code Expired | OTP older than 10 minutes |
Email Not Found | No user with that email |
Sets a new password using a valid recovery code (pending or already-verified).
{
"email": "usman@example.com",
"code": "5678",
"password": "mynewpassword1"
}
{ "status": "success", "msg": "Password Updated Successfully" }
The OTP row is marked used after the password update.
| msg | Reason |
|---|---|
Invalid Email Format | Email malformed |
Invalid Code | Code wrong / used / not found |
Code Expired | OTP older than 10 minutes |
Password Must Be At Least 6 Characters | Password too short |
Email Not Found | No user with that email |
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" }.
Generates a 4-digit email-verification code, sends it via Resend, and invalidates any previous pending code.
{}
{ "status": "success", "msg": "Verification code sent to u***@gmail.com" }
| msg | Reason |
|---|---|
Your email is already verified | No need to resend |
Failed to send email. Please try again | Mail server error |
User not found | Invalid API key |
Verifies the 4-digit code and marks the user's email as verified.
{ "code": "4821" }
{
"status": "success",
"msg": "Email verified successfully",
"email": "user@example.com"
}
| msg | Reason |
|---|---|
Verification code is required | Missing code field |
Invalid verification code | Code is not numeric |
Incorrect verification code. Please check your email and try again | Code doesn't match / expired |
Your email is already verified | Already verified |
Returns the authenticated user's profile.
{}
{
"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..."
}
Paginated list of the user's transactions, newest first.
{ "limit": 20, "offset": 0 }
{
"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"
}
]
}
Details for a single transaction by reference.
{ "ref": "DATA20260303001" }
{
"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.
Double-duty endpoint. Empty JSON body returns the current picture. Multipart body uploads a new one and deletes the previous file.
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.
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"
}
| msg | Reason |
|---|---|
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 |
Removes the current profile picture. Safe to call when none exists.
{}
{ "status": "success", "msg": "Profile picture removed successfully" }
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.