Skip to main content
GET
/
v2
/
onboard
/
{refNo}
/
status
Retrieve Onboarding Status
curl --request GET \
  --url https://kyc.sbx.moduluslabs.io/v2/onboard/{refNo}/status \
  --header 'Authorization: Bearer <token>'
{
  "onboardingStatus": "NEW",
  "onboardingReferenceNumber": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "merchantName": "<string>",
  "dateCreated": "2023-11-07T05:31:56Z",
  "dateUpdated": "2023-11-07T05:31:56Z",
  "declinedReason": "<string>"
}

Overview

Retrieves the current onboarding status for a merchant using the onboarding reference number. This is a lightweight endpoint that returns only essential status information without the full onboarding data.
Ideal for: Polling the onboarding status, quick status checks in dashboards, or determining if full onboarding data needs to be fetched.
Lightweight Alternative: Use this endpoint instead of Retrieve Onboarding Data when you only need to check the approval status.

Authentication

This endpoint requires JWT Bearer Token authentication.
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Authorization Required: The authenticated user must be the owner of the onboarding record. Only the user who created the onboarding record can retrieve its status.

Path Parameters

refNo
string
required
The onboarding reference number (UUID v4 format)Format: Valid UUID v4Example: "550e8400-e29b-41d4-a716-446655440000"
This is the referenceNumber returned when you successfully submit an onboarding request via the Onboard Merchant endpoint.

Response

Success Response

Status Code: 200 OK
onboardingStatus
string
required
Current status of the merchant’s onboarding applicationValues:
  • NEW: Merchant completed onboarding, awaiting initial approval
  • PENDING: Merchant updated form after decline, awaiting re-approval
  • APPROVED: Merchant has been approved
  • DECLINED: Merchant was declined and needs to update their form
Example: "NEW"
onboardingReferenceNumber
string
required
Unique identifier for the onboarding record (same as path parameter)Format: UUID v4Example: "550e8400-e29b-41d4-a716-446655440000"
merchantName
string
required
Trading name or DBA (Doing Business As) name of the merchantExample: "Acme Store"
dateCreated
string
required
Timestamp when the onboarding record was initially createdFormat: ISO 8601Example: "2024-01-15T10:30:00Z"
dateUpdated
string
Timestamp of the most recent status changeFormat: ISO 8601Example: "2024-01-20T14:45:00Z"
This is the latest date among ApprovedAt, DeclinedAt, or PendingAt. Returns null if no status change has occurred (still in NEW status).
declinedReason
string
Reason provided by admin when declining the applicationExample: "Missing required documents: SEC Registration Certificate"
Visibility: Present only when onboardingStatus is DECLINED. Set to null for other statuses.

Response Examples

{
  "onboardingStatus": "NEW",
  "onboardingReferenceNumber": "550e8400-e29b-41d4-a716-446655440000",
  "merchantName": "Acme Store",
  "dateCreated": "2024-01-15T10:30:00Z",
  "dateUpdated": null,
  "declinedReason": null
}

Error Responses

Status Code: 400
{
  "statusCode": 400,
  "message": "Invalid onboarding reference number format",
  "error": "Bad Request",
  "details": {
    "refNumReceived": "invalid-uuid"
  }
}
Cause: The reference number provided is not a valid UUID v4 formatSolution: Ensure the reference number is a valid UUID v4 string
Status Code: 400
{
  "statusCode": 400,
  "message": "Onboarding record does not exist",
  "error": "Bad Request"
}
Cause: No onboarding record found for the authenticated userPossible Reasons:
  • The authenticated user has no associated business account
  • The business account has no associated business record
  • The onboarding record was deleted
Solution: Verify the user has completed the onboarding process
Status Code: 400
{
  "statusCode": 400,
  "message": "Onboarding reference number mismatch",
  "error": "Bad Request",
  "details": {
    "refNumReceived": "550e8400-e29b-41d4-a716-446655440000"
  }
}
Cause: The provided reference number does not match the authenticated user’s business recordSolution: Ensure you’re using the correct JWT token for the account that owns this onboarding record
Status Code: 401
{
  "statusCode": 401,
  "message": "Account not found",
  "error": "Unauthorized"
}
Cause: Invalid or missing JWT Bearer token, or account doesn’t existSolution:
  • Verify the Authorization header contains a valid JWT token
  • Ensure the token hasn’t expired
  • Confirm the account exists in the system

Status Flow Diagram

The onboarding status follows this flow:
NEW → APPROVED (direct approval)
NEW → DECLINED → PENDING → APPROVED (decline then resubmit flow)
NEW → DECLINED → PENDING → DECLINED (multiple decline cycles possible)
1

NEW

Merchant has completed the onboarding form and submitted it for initial review. Awaiting admin approval.
2

DECLINED (Optional)

Admin reviewed the application and declined it. The declinedReason field contains the reason for rejection. Merchant needs to update their information.
3

PENDING (Optional)

Merchant has updated their form after being declined and resubmitted for review. Awaiting admin re-approval.
4

APPROVED

Admin has approved the merchant’s onboarding application. Merchant can now process transactions.

Code Examples

# Set your Bearer token and reference number
TOKEN="your_jwt_bearer_token_here"
REF_NO="550e8400-e29b-41d4-a716-446655440000"

curl -X GET "https://kyc.sbx.moduluslabs.io/v2/onboard/$REF_NO/status" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Accept: application/json"

Polling Best Practices

Use this lightweight endpoint for efficient status polling:
async function pollOnboardingStatus(refNo, maxAttempts = 30) {
  let attempts = 0;
  const pollInterval = 30000; // 30 seconds

  const poll = async () => {
    if (attempts >= maxAttempts) {
      console.log('  Polling timeout reached');
      return;
    }

    attempts++;
    console.log(`Checking status (attempt ${attempts}/${maxAttempts})...`);

    try {
      const status = await getOnboardingStatus(refNo);

      if (status.onboardingStatus === 'APPROVED') {
        console.log(' Onboarding approved!');
        return status;
      } else if (status.onboardingStatus === 'DECLINED') {
        console.log(' Onboarding declined');
        return status;
      }

      // Continue polling if NEW or PENDING
      setTimeout(poll, pollInterval);
    } catch (error) {
      console.error('Polling error:', error.message);
      setTimeout(poll, pollInterval);
    }
  };

  await poll();
}
Implement exponential backoff to reduce server load:
async function pollWithBackoff(refNo, maxAttempts = 20) {
  let attempts = 0;
  let delay = 10000; // Start with 10 seconds
  const maxDelay = 300000; // Max 5 minutes

  const poll = async () => {
    if (attempts >= maxAttempts) return;

    attempts++;
    const status = await getOnboardingStatus(refNo);

    if (['APPROVED', 'DECLINED'].includes(status.onboardingStatus)) {
      return status;
    }

    // Exponential backoff with max delay cap
    delay = Math.min(delay * 1.5, maxDelay);
    setTimeout(poll, delay);
  };

  await poll();
}
Cache the status response to reduce unnecessary API calls:
const statusCache = new Map();
const CACHE_TTL = 30000; // 30 seconds

async function getCachedStatus(refNo) {
  const cached = statusCache.get(refNo);

  if (cached && (Date.now() - cached.timestamp) < CACHE_TTL) {
    return cached.data;
  }

  const status = await getOnboardingStatus(refNo);
  statusCache.set(refNo, {
    data: status,
    timestamp: Date.now()
  });

  return status;
}
Automatically stop polling when reaching a terminal status:
const TERMINAL_STATUSES = ['APPROVED', 'DECLINED'];

async function pollUntilTerminal(refNo) {
  const interval = setInterval(async () => {
    const status = await getOnboardingStatus(refNo);

    if (TERMINAL_STATUSES.includes(status.onboardingStatus)) {
      clearInterval(interval);
      console.log(`Terminal status reached: ${status.onboardingStatus}`);

      // Trigger appropriate action
      if (status.onboardingStatus === 'APPROVED') {
        onApproved(status);
      } else {
        onDeclined(status);
      }
    }
  }, 30000);

  return interval;
}

Use Cases

Dashboard Status Widget

Display real-time onboarding status in merchant dashboards

Automated Polling

Poll for status changes without fetching full onboarding data

Conditional UI Updates

Show/hide UI elements based on approval status

Notification Triggers

Trigger notifications when status changes to APPROVED or DECLINED

Status Comparison Table

StatusIs Approved?Is Declined?Is Pending?Description
NEWMerchant completed onboarding, awaiting initial review
PENDING✅ (was)Merchant updated form after decline, awaiting re-approval
APPROVEDMerchant has been approved
DECLINEDMerchant was declined, needs to update form

When to Use This Endpoint

  • Polling for status changes
  • Dashboard status displays
  • Quick status checks
  • Determining if full data fetch is needed
  • Triggering status-based workflows
  • Mobile applications (reduced bandwidth)

Troubleshooting

Error: Onboarding reference number mismatchCause: Trying to access an onboarding record that doesn’t belong to your accountSolution:
  • Verify you’re using the correct JWT token
  • Each onboarding record can only be accessed by the account that created it
  • Ensure you’re not mixing sandbox and production reference numbers
Issue: Status remains in NEW or PENDING indefinitelyPossible Causes:
  • Onboarding awaiting manual admin approval
  • Application is in review queue
  • Additional documentation may be required
Solution:
  • Implement maximum polling attempts (recommended: 30-60 minutes)
  • Contact support if status hasn’t changed after reasonable time
  • Check for any notifications or emails from the approval team
Issue: declinedReason is null even though status is DECLINEDPossible Causes:
  • Admin declined without providing a reason (rare)
  • Data synchronization issue
Solution:

Next Steps

Authorizations

Authorization
string
header
required

JWT Bearer token authentication

Path Parameters

refNo
string<uuid>
required

The onboarding reference number (UUID v4 format)

Response

Onboarding status retrieved successfully

onboardingStatus
enum<string>

Current status of the merchant's onboarding application

Available options:
NEW,
PENDING,
APPROVED,
DECLINED
onboardingReferenceNumber
string<uuid>

Unique identifier for the onboarding record

merchantName
string

Trading name or DBA name of the merchant

dateCreated
string<date-time>

Timestamp when the onboarding record was created

dateUpdated
string<date-time> | null

Timestamp of the most recent status change

declinedReason
string | null

Reason provided when declining the application (only present when status is DECLINED)