MiniApp SDK

Learn how to register and use custom functions from the Nana host app within your mini applications using the MiniApp SDK.

MiniApp SDK - Custom Function Registration

Introduction

The MiniApp SDK provides a powerful mechanism for registering and using custom functions from the Nana host app within your mini applications. This feature allows your mini app to access host app functionalities through a standardized API interface, enabling seamless integration between your mini app and the Nana platform.

Custom function registration creates a bridge between your mini app and the host application, allowing you to:

  • Access host app services and data
  • Leverage existing host app functionalities
  • Maintain consistent user experiences across the platform
  • Implement custom business logic specific to your mini app needs

Setting Up Custom Functions

Step 1: Access the Host App Configuration

  1. Navigate to apps.nana.sa
  2. Go to your Host App section
  3. Navigate to APIs and Menus
  4. Select Configure Custom API

In this section, you'll see all available registered functions from the host app. These functions are categorized as:

  • Public functions: Available to all mini apps
  • Private functions: Restricted access based on permissions

Step 2: Create the Configuration File

In your mini app's root directory, create a new file called NanaConf.js. This file will contain the configuration for all the registered functions you want to use in your mini app.

module.exports = {
    extApi: [
        {
            name: 'getUserMobile',
            sync: false,
            params: {}
        },
        {
            name: 'getUserName',
            sync: false,
            params: {}
        },
        // Add more registered functions as needed
    ]
}

Once configured, you can use the registered functions in your code:

const userID = ft.getUserName({
    success: (res) => {
        console.log('User name retrieved successfully:', res);
        // Handle successful response
    },
    fail: (res) => {
        console.log('Failed to get user name:', res);
        // Handle error response
    }
});

Function Parameters Explanation

User Information Functions

getUserId

Retrieves the current user's ID.

NanaConf.js Configuration:

{
    name: 'getUserId',
    sync: false,
    params: {},
}

Usage Example:

const userID = ft.getUserId({
    success: (res) => {
        console.log('User ID:', res);
        // res contains: {'userId': 'userid'}
    },
    fail: (res) => {
        console.log('Error getting user ID:', res);
    }
});

Response Format:

{'userId': 'userid'}

getUserMobile

Gets the user's mobile number.

NanaConf.js Configuration:

{
    name: 'getUserMobile',
    sync: false,
    params: {}
}

Usage Example:

const userMobile = ft.getUserMobile({
    success: (res) => {
        console.log('User Mobile:', res);
        // res contains: {'userMobile': '0555555555'}
    },
    fail: (res) => {
        console.log('Error getting user mobile:', res);
    }
});

Response Format:

{'userMobile': '0555555555'}

getUserName

Fetches the user's name.

NanaConf.js Configuration:

{
    name: 'getUserName',
    sync: false,
    params: {}
}

Usage Example:

const userName = ft.getUserName({
    success: (res) => {
        console.log('User Name:', res);
        // res contains: {'userName': 'nawaf dallah'}
    },
    fail: (res) => {
        console.log('Error getting user name:', res);
    }
});

Response Format:

{'userName': 'nawaf dallah'}

getAppLang

Returns the current app language.

NanaConf.js Configuration:

{
    name: 'getAppLang',
    sync: false,
    params: {}
}

Usage Example:

const appLang = ft.getAppLang({
    success: (res) => {
        console.log('App Language:', res);
        // res contains: {'language': 'ar'}
    },
    fail: (res) => {
        console.log('Error getting app language:', res);
    }
});

Response Format:

{'language': 'ar'}

userLoggedIn

Checks if user is logged in.

NanaConf.js Configuration:

{
    name: 'userLoggedIn',
    sync: false,
    params: {}
}

Usage Example:

const loginStatus = ft.userLoggedIn({
    success: (res) => {
        console.log('User logged in status:', res);
        // res contains: {'isLoggedIn': true}
        if (res.isLoggedIn) {
            // User is logged in
        } else {
            // User is not logged in
        }
    },
    fail: (res) => {
        console.log('Error checking login status:', res);
    }
});

Response Format:

{'isLoggedIn': true}

getUserToken

Retrieves the user's authentication token.

NanaConf.js Configuration:

{
    name: 'getUserToken',
    sync: false,
    params: {}
}

Usage Example:

const userToken = ft.getUserToken({
    success: (res) => {
        console.log('User Token:', res);
        // res contains: {'token': 'hjgds8726382ddshc87@879...'}
        // Use this token for authenticated API calls
    },
    fail: (res) => {
        console.log('Error getting user token:', res);
    }
});

Response Format:

{'token': 'hjgds8726382ddshc87@879...'}

getUserAddress

Gets the user's address information.

NanaConf.js Configuration:

{
    name: 'getUserAddress',
    sync: false,
    params: {}
}

Usage Example:

const userAddress = ft.getUserAddress({
    success: (res) => {
        console.log('User Address:', res);
        // res contains complete address object
    },
    fail: (res) => {
        console.log('Error getting user address:', res);
    }
});

Response Format:

{
    'address': {
        "address_id": "cb175f5e29",
        "manual_location": null,
        "type_second_info": "",
        "state": "الرياض",
        "city": "الرياض",
        "title": "Office",
        "is_supported": 1,
        "latitude": "24.764998609744307",
        "type_first_info": "",
        "type": null,
        "zip_code": null,
        "kind": "first",
        "country": "Saudi Arabia",
        "longitude": "46.71348897092447",
        "manually_update_title": null,
        "isManual": null,
        "food_city_id": 1
    }
}

Commerce Functions

addToCart

Adds an item to the shopping cart.

NanaConf.js Configuration:

{
    name: 'addToCart',
    sync: false,
    params: {
        retailer_id: '',
        pid: '',
        quantity: 0,
        image: '',
        price: 0.0,
        promotionId: '',
        name: '',
        addedFrom: '',
        resolvedBidId: '',
        pricingStyle: '',
    }
}

Usage Example:

const addItemResult = ft.addToCart({
    retailer_id: 'retailer_123',     // (string) The retailer identifier
    pid: 'product_456',              // (string) Product identifier
    quantity: 2,                     // (number) Quantity of items to add
    image: 'https://example.com/product-image.jpg',  // (string) Product image URL
    price: 29.99,                    // (number) Product price
    promotionId: 'promo_789',        // (string) Promotion identifier if applicable
    name: 'Sample Product',          // (string) Product name
    addedFrom: 'miniapp',            // (string) Source where item was added from
    resolvedBidId: 'bid_101',        // (string) Resolved bid identifier
    pricingStyle: 'standard',        // (string) Pricing style information
    success: (res) => {
        console.log('Item added to cart successfully:', res);
        // res contains: {'success': true, 'message': 'Product added to cart!'}
    },
    fail: (res) => {
        console.log('Failed to add item to cart:', res);
        // Handle error response
    }
});

Response Format:

{'success': true, 'message': 'Product added to cart!'}

orderPayment

Processes order payment by showing a payment bottom sheet with available payment methods (Apple Pay, Mada, etc.). Important: You must first create a payment session using the API before calling this function.

NanaConf.js Configuration:

{
    name: 'orderPayment',
    sync: false,
    params: {
        data: {},
    }
}

Step 1: Get User Token

First, you need to get the user's authentication token:

ft.getUserToken({
    success: (userTokenRes) => {
        console.log('User Token:', userTokenRes.token);
        // Use this token to create payment session
        createPaymentSession(userTokenRes.token);
    },
    fail: (res) => {
        console.log('Error getting user token:', res);
    }
});

Step 2: Create Payment Session

Create a payment session using the API:

async function createPaymentSession(userToken) {
    const miniAppApiKey = 'your_miniapp_api_key'; // Your mini app API key
    
    try {
        const response = await new Promise((resolve, reject) => {
            wx.request({
                url: 'https://miniapps.nana.sa/api/v2/mobile-user-activities/create-payment-session',
                method: 'POST',
                header: {
                    'Content-Type': 'application/json',
                    'miniapp-api-key': miniAppApiKey,
                    'miniapp-user-token': `Bearer ${userToken}` 
                },
                data: {
                    amount: 10,           // (number) Payment amount
                    reference: 'order_ref_12345'  // (string) Unique payment reference
                },
                success: (res) => {
                    resolve(res.data);
                },
                fail: (err) => {
                    reject(new Error(`Network Error: ${err.errMsg}`));
                }
            });
        });

        if (response.success) {
            // Get the mini app ID
            const appInfo = wx.getAccountInfoSync();
            const appId = appInfo.miniProgram.appId;
            
            // Add mini app ID to the response data
            response.data.mini_app_id = appId;
            
            // Now call orderPayment with the session data
            processPayment(response.data);
        } else {
            console.error('Failed to create payment session:', response);
        }
    } catch (error) {
        console.error('Error creating payment session:', error);
    }
}

Step 3: Process Payment

Use the payment session data with orderPayment:

function processPayment(paymentSessionData) {
    ft.orderPayment({
        data: paymentSessionData,  // (object) The complete payment session data from API response
        success: (res) => {
            console.log('Payment processed successfully:', res);
            // Handle successful payment
            // The payment bottom sheet will be shown with available methods
        },
        fail: (res) => {
            console.log('Payment failed:', res);
            // Handle payment failure
        }
    });
}

Complete Payment Workflow Example:

async function handlePayment() {
    try {
        // Step 1: Get user token
        ft.getUserToken({
            success: async (userTokenRes) => {
                try {
                    // Step 2: Create payment session
                    const miniAppApiKey = 'your_miniapp_api_key';
                    
                    const sessionResponse = await new Promise((resolve, reject) => {
                        wx.request({
                            url: 'https://miniapps.nana.sa/api/v2/mobile-user-activities/create-payment-session',
                            method: 'POST',
                            header: {
                                'Content-Type': 'application/json',
                                'miniapp-api-key': miniAppApiKey,
                                'miniapp-user-token': `Bearer ${userTokenRes.token}` 
                            },
                            data: {
                                amount: 10,
                                reference: 'order_ref_12345'
                            },
                            success: (res) => resolve(res.data),
                            fail: (err) => reject(new Error(`Network Error: ${err.errMsg}`))
                        });
                    });

                    if (sessionResponse.success) {
                        // Add mini app ID
                        const appInfo = wx.getAccountInfoSync();
                        sessionResponse.data.mini_app_id = appInfo.miniProgram.appId;
                        
                        // Step 3: Call orderPayment
                        ft.orderPayment({
                            data: sessionResponse.data,
                            success: (res) => {
                                console.log('Payment initiated successfully:', res);
                            },
                            fail: (res) => {
                                console.error('Payment failed:', res);
                            }
                        });
                    }
                } catch (error) {
                    console.error('Error in payment process:', error);
                }
            },
            fail: (res) => {
                console.log('Error getting user token:', res);
            }
        });
    } catch (error) {
        console.error('Payment process failed:', error);
    }
}

Expected Payment Session Response Structure:

{
    "status_code": 200,
    "result": "Operation Completed Successfully",
    "success": true,
    "data": {
        "payment_session_secret": "pss_4db7628a-c555-4f86-93f6-0be2a384abd6",
        "payment_session_token": "YmFzZTY0:eyJpZCI6InBzXzM0SDNPMm81VFZpNHhiblo0QVU1dFFURllrcSIs...",
        "id": "ps_34H3O2o5TVi4xbnZ4AU5tQTFYkq",
        "_links": {
            "self": {
                "href": "https://api.sandbox.checkout.com/payment-sessions/ps_34H3O2o5TVi4xbnZ4AU5tQTFYkq"
            }
        }
        // Additional payment configuration data...
    }
}

What happens after calling orderPayment:

  • A payment bottom sheet will appear in the mini app
  • Users can select from available payment methods (Apple Pay, Mada, Credit Card, etc.)
  • The payment will be processed through the selected method
  • Success/failure/cancel callbacks will be triggered based on the payment result

For more details about the create payment session API, visit: Payment API Documentation

Navigation Functions

closeMiniApp

Closes the current mini app.

NanaConf.js Configuration:

{
    name: 'closeMiniApp',
    sync: false,
    params: {
        miniAppId: ''
    }
}

Usage Example:

ft.closeMiniApp({
    miniAppId: 'your_miniapp_id',    // (string) The identifier of the mini app to close
    success: (res) => {
        console.log('Mini app closed successfully');
    },
    fail: (res) => {
        console.log('Failed to close mini app:', res);
    }
});

closeMiniAppAndOpenDeepLink

Closes mini app and opens a deep link.

NanaConf.js Configuration:

{
    name: 'closeMiniAppAndOpenDeepLink',
    sync: false,
    params: {
        miniAppId: '',
        deepLink: '',   
    }
}

Usage Example:

ft.closeMiniAppAndOpenDeepLink({
    miniAppId: 'your_miniapp_id',    // (string) The identifier of the mini app to close
    deepLink: 'https://nana.sa/profile',  // (string) The deep link URL to open
    success: (res) => {
        console.log('Mini app closed and deep link opened successfully');
    },
    fail: (res) => {
        console.log('Failed to close mini app and open deep link:', res);
    }
});

Configuration Properties

PropertyTypeRequiredDescription
namestringyesCustom API name
syncbooleannoIs it a synchronous API?
overwritebooleannoWhether to overwrite the API with the same name
pluginIdarray or stringnoThis parameter is valid only when calling loadExtApi in the applet, indicating that the plug-ins in the id list are allowed to use the custom API.
scopestringnoSupported by the basic library 3.5.6 and later. This parameter is valid only when calling loadExtApi in the plugin. The optional values are default, self, all. The default value is default
paramsobjectnoThe parameter format can only list the required attributes. If there are no restrictions, you can directly use an empty object.

Best Practices

Function Naming

  • Use clear, descriptive function names that indicate their purpose
  • Follow camelCase convention for consistency
  • Avoid special characters or spaces in function names

Error Handling

  • Always implement both success and fail callbacks
  • Provide meaningful error messages to help with debugging
  • Consider implementing retry logic for critical functions

Parameter Validation

  • Validate required parameters before calling registered functions
  • Use TypeScript for better parameter type checking
  • Document expected parameter formats and constraints

Performance Considerations

  • Use synchronous functions sparingly as they can block the UI
  • Implement loading states for asynchronous operations
  • Cache results when appropriate to reduce redundant API calls

Troubleshooting

Function Not Found

  • Verify the function name matches exactly with the host app registration
  • Check if the function is marked as public and accessible to your mini app
  • Ensure the NanaConf.js file is in the correct location

Parameter Errors

  • Validate that all required parameters are provided
  • Check parameter types match the expected format
  • Review parameter names for typos or case sensitivity issues

Callback Issues

  • Ensure both success and fail callbacks are properly defined
  • Check for syntax errors in callback functions
  • Verify callback parameters are handled correctly

This documentation provides a comprehensive guide for implementing custom function registration in your mini app, enabling powerful integration with the Nana host application.