Merchant Registration (v2)

To register as a merchant with Paylink, the following steps need to be completed:

Partner Onboarding API Documentation

Overview

The Partner Onboarding API provides endpoints for partners to register and authenticate with the Paylink platform. This documentation covers the key endpoints required for partner registration, identity verification through Nafath, and authentication.

Table of Contents

  1. Authentication
  2. API Endpoints
  3. Integration Flow
  4. Error Handling
  5. Examples

Authentication

Most partner registration endpoints require authentication with the MERCHANT_API_ACCOUNT role. The authentication flow is:

  1. First, obtain a JWT token using the /api/partner/auth endpoint
  2. Include the JWT token in the Authorization header for subsequent requests

Authentication Header Format

Authorization: Bearer <JWT_TOKEN>

API Endpoints

Partner Authentication

Authenticate a partner and receive a JWT token for subsequent API calls.

Endpoint: POST /api/partner/auth

Authentication Required: No (This is a public endpoint)

Request Body

FieldTypeRequiredDescriptionExample
profileNoStringYesPartner profile number"12312312"
apiKeyStringYesPartner API key"your-api-key"
persistTokenBooleanNoWhether to persist token (30 hours) or not (30 minutes)true

Request Example

{
  "profileNo": "12312312",
  "apiKey": "your-api-key-here",
  "persistToken": true
}

Response

Success Response (200 OK)

{
  "id_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response Headers:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

cURL Example

curl -X POST https://api.paylink.sa/api/partner/auth \
  -H "Content-Type: application/json" \
  -d '{
    "profileNo": "12312312",
    "apiKey": "your-api-key",
    "persistToken": true
  }'

Create Merchant Account

Creates a new merchant with merchant registration details.

Endpoint: POST /api/partner/register/create-account

Authentication Required: Yes

Request Body

FieldTypeRequiredDescriptionExample
sessionUuidStringYesSession UUID (any UUID)"12345678-1234-1234-1234-123456789012"
registrationTypeStringYesType of registration (cr/freelancer)"cr"
licenseNumberStringYesCommercial Registration unified number or Freelancer license number"7041231231"
mobileNumberStringYesMobile number with country code"0501234567"
hijriYearStringYesHijri birth year"1401"
hijriMonthStringYesHijri birth month"12"
hijriDayStringYesHijri birth day"15"
partnerProfileNoStringYesPartner profile number"12312312"
ibanStringYesSaudi IBAN"SA1234567890123456789012"
bankSwiftNameStringYesBank SWIFT code"RJHISARI"
monthlySalesVolumeDoubleYesExpected monthly sales volume10000.0
categoryDescriptionStringYesBusiness category"Grocery"
sellingScopeStringYesSelling scope (domestic/global)"domestic"
nationalIdStringYesNational ID number"1234567890"
emailStringYesEmail address"[email protected]"
firstNameStringYesFirst name"Ahmed"
lastNameStringYesLast name"Ali"
passwordStringYesAccount password"SecurePassword123!"
nafathCallbackUrlStringYesURL for Nafath callbacks (Webhook for Nafath Status Change)"https://partner.example.com/nafath-callback"
nafathCallbackHeader1NameStringNoCustom header name for callback"X-Partner-Auth"
nafathCallbackHeader1ValueStringNoCustom header value for callback"partner-secret"
nafathCallbackHeader2NameStringNoSecond custom header name"X-Request-ID"
nafathCallbackHeader2ValueStringNoSecond custom header value"unique-request-id"
socialMedia1-7StringNoSocial media URLs"https://twitter.com/merchant"
globalReasonStringNoReason for global selling (if applicable)"International customers"
isDigitalBooleanNoWhether business is digitaltrue
monthlySalesDoubleNoCurrent monthly sales5000.0
avgTicketSizeDoubleNoAverage transaction amount150.0

Request Example

{
  "sessionUuid": "12345678-1234-1234-1234-123456789012",
  "registrationType": "cr",
  "licenseNumber": "2041231231",
  "mobileNumber": "0501234567",
  "hijriYear": "1443",
  "hijriMonth": "12",
  "hijriDay": "15",
  "partnerProfileNo": "12312312",
  "iban": "SA1234567890123456789012",
  "bankSwiftName": "RJHISARI",
  "monthlySalesVolume": 10000.0,
  "categoryDescription": "Grocery",
  "sellingScope": "domestic",
  "nationalId": "1234567890",
  "email": "[email protected]",
  "firstName": "Ahmed",
  "lastName": "Ali",
  "password": "SecurePassword123!",
  "nafathCallbackUrl": "https://partner.example.com/nafath-callback",
  "isDigital": true
}

Response

Success Response (200 OK)

{
  "mobile": "0501234567",
  "sessionUuid": "12345678-1234-1234-1234-123456789012",
  "signature": "9874ffff8710904aecb139f0f9f7f3e35bdad3ae99d26a93c94fb74c208e828a",
  "success": true,
  "note": "Account created successfully, proceed with Nafath verification",
  "nafathRandomNo": "42"
}

cURL Example

curl -X POST https://api.paylink.sa/api/partner/register/create-account \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "sessionUuid": "12345678-1234-1234-1234-123456789012",
    "registrationType": "cr",
    "licenseNumber": "2041231231",
    "mobileNumber": "0501234567",
    "hijriYear": "1443",
    "hijriMonth": "12",
    "hijriDay": "15",
    "partnerProfileNo": "12312312",
    "iban": "SA1234567890123456789012",
    "bankSwiftName": "RJHISARI",
    "monthlySalesVolume": 10000.0,
    "categoryDescription": "Grocery",
    "sellingScope": "domestic",
    "nationalId": "1234567890",
    "email": "[email protected]",
    "firstName": "Ahmed",
    "lastName": "Ali",
    "password": "SecurePassword123!",
    "nafathCallbackUrl": "https://partner.example.com/nafath-callback"
  }'

Check Nafath Status

Check the status of Nafath identity verification for a registration session.

Endpoint: POST /api/partner/register/check-nafath

Authentication Required: Yes (MERCHANT_API_ACCOUNT role)

Request Body

FieldTypeRequiredDescriptionExample
sessionUuidStringYesSession UUID from registration"12345678-1234-1234-1234-123456789012"
mobileNumberStringYesMobile number of the user"966501234567"
partnerProfileNoStringYesPartner profile number"12312312"

Request Example

{
  "sessionUuid": "12345678-1234-1234-1234-123456789012",
  "mobileNumber": "0501234567",
  "partnerProfileNo": "12312312"
}

Response

Success Response (200 OK)

{
  "signature": "1234567890abcdef",
  "mobile": "0501234567",
  "sessionUuid": "12345678-1234-1234-1234-123456789012",
  "nafathNumber": "42",
  "status": "ACCEPTED",
  "email": "[email protected]",
  "errorMessage": null,
  "activatingAccountResponse": {
    "merchantId": 12345,
    "apiKey": "newly-generated-api-key",
    "success": true
  }
}

Nafath Status Values

  • PENDING - Nafath verification is pending
  • ACCEPTED - Nafath verification successful
  • REJECTED - Nafath verification failed
  • EXPIRED - Nafath session expired

cURL Example

curl -X POST https://api.paylink.sa/api/partner/register/check-nafath \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -d '{
    "sessionUuid": "12345678-1234-1234-1234-123456789012",
    "mobileNumber": "0501234567",
    "partnerProfileNo": "12312312"
  }'

Integration Flow

The typical partner onboarding flow follows these steps:

sequenceDiagram
    participant Partner
    participant PayLink API
    participant Nafath
    
    Partner->>PayLink API: 1. POST /api/partner/auth
    PayLink API-->>Partner: JWT Token
    
    Partner->>PayLink API: 2. POST /api/partner/register/create-account
    PayLink API-->>Partner: Session UUID & Nafath Number
    
    Partner->>Nafath: 3. User completes Nafath verification
    Nafath-->>PayLink API: Verification result
    
    Partner->>PayLink API: 4. POST /api/partner/register/check-nafath
    PayLink API-->>Partner: Verification status & API credentials

Detailed Integration Steps

  1. Authentication

    • Call /api/partner/auth with partner credentials
    • Store the JWT token for subsequent requests
  2. Create Account

    • Collect all required merchant information
    • Call /api/partner/register/create-account with complete details
    • Save the sessionUuid and nafathRandomNo from response
  3. Nafath Verification

    • Display the nafathRandomNo to the user
    • Direct user to complete Nafath verification in Absher app
    • The system will receive callbacks to the provided nafathCallbackUrl
  4. Check Status

    • Poll /api/partner/register/check-nafath to check verification status
    • Recommended polling interval: 5-10 seconds
    • Continue until status is ACCEPTED, REJECTED, or EXPIRED
  5. Handle Results

    • If ACCEPTED: Save the merchant credentials from activatingAccountResponse
    • If REJECTED: Display error and allow retry
    • If EXPIRED: Start new registration session

Error Handling

All endpoints return standard HTTP status codes and error responses:

Common Error Responses

401 Unauthorized

{
  "type": "https://www.jhipster.tech/problem/problem-with-message",
  "title": "Unauthorized",
  "status": 401,
  "detail": "Full authentication is required to access this resource"
}

400 Bad Request

{
  "type": "https://www.jhipster.tech/problem/constraint-violation",
  "title": "Bad Request",
  "status": 400,
  "violations": [
    {
      "field": "mobileNumber",
      "message": "must not be null"
    }
  ]
}

403 Forbidden

{
  "type": "https://www.jhipster.tech/problem/problem-with-message",
  "title": "Forbidden",
  "status": 403,
  "detail": "Access is denied"
}

500 Internal Server Error

{
  "type": "https://www.jhipster.tech/problem/problem-with-message",
  "title": "Internal Server Error",
  "status": 500,
  "detail": "An unexpected error occurred"
}

Error Handling Best Practices

  1. Implement Retry Logic

    • For 5xx errors: Implement exponential backoff
    • For 401 errors: Refresh authentication token
    • For 400 errors: Fix request data before retry
  2. Session Management

    • Store session UUID securely
    • Handle session expiration gracefully
    • Allow users to restart registration if needed
  3. User Communication

    • Display clear error messages
    • Provide actionable next steps
    • Log detailed errors for debugging

Examples

Complete Registration Flow Example

// 1. Authenticate
const authResponse = await fetch('https://rest.paylink.sa/api/partner/auth', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    profileNo: '12312312',
    apiKey: 'your-api-key',
    persistToken: true
  })
});

const { id_token } = await authResponse.json();

// 2. Create Account
const createResponse = await fetch('https://rest.paylink.sa/api/partner/register/create-account', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': `Bearer ${id_token}`
  },
  body: JSON.stringify({
    sessionUuid: generateUUID(),
    registrationType: 'cr',
    licenseNumber: '2041231231',
    mobileNumber: '0501234567',
    // ... other required fields
  })
});

const { sessionUuid, nafathRandomNo } = await createResponse.json();

// 3. Display Nafath number to user
console.log(`Please verify in Absher app using number: ${nafathRandomNo}`);

// 4. Poll for verification status
const checkStatus = async () => {
  const statusResponse = await fetch('https://rest.paylink.sa/api/partner/register/check-nafath', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${id_token}`
    },
    body: JSON.stringify({
      sessionUuid,
      mobileNumber: '0501234567',
      partnerProfileNo: '12312312'
    })
  });

  const result = await statusResponse.json();
  
  if (result.status === 'ACCEPTED') {
    console.log('Registration successful!', result.activatingAccountResponse);
  } else if (result.status === 'PENDING') {
    // Continue polling
    setTimeout(checkStatus, 5000);
  } else {
    console.error('Registration failed:', result.errorMessage);
  }
};

// Start polling
checkStatus();