Tenants
22 API calls in this section.
List Tenants
/tenants?language=en&page=1&limit=10&status=&search=Retrieves a paginated list of tenants in the system. This endpoint supports filtering by status and searching by tenant slug. Authentication: - Requires valid authentication token - Only system administrators can access this endpoint Query Parameters: - page (optional): Page number for pagination (default: 1) - limit (optional): Number of results per page (default: 10, max: 100) - status (optional): Filter tenants by status (e.g., 'active', 'pending', 'suspended') - search (optional): Search term to filter tenants by slug - language (optional): Language code for localized response messages (e.g., 'en')
1curl --request GET "$ONDI_BASE_URL/tenants?language=en&page=1&limit=10&status=&search=" \2 --header "Authorization: Bearer {{access_token}}"Query parameters
languageOptionalen
Language code for response localization (Optional, default: en)
pageOptional1
Page number for pagination (Optional, default: 1)
limitOptional10
Number of results per page (Optional, default: 10, max: 100)
statusOptionalFilter tenants by status (Optional, e.g., 'active', 'pending', 'suspended')
searchOptionalSearch term to filter tenants by slug (Optional)
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Tenants retrieved successfully",4 "tenants": [5 {6 "id": "550e8400-e29b-41d4-a716-446655440000",7 "name": {8 "en": "Tenant Name"9 },10 "slug": "tenant-slug",11 "status": "active",12 "contact_info": {},13 "metadata": {},14 "created_at": "2023-01-01T00:00:00Z",15 "created_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",16 "updated_at": "2023-01-01T00:00:00Z",17 "updated_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",18 "tenant_users": {19 "count": 520 }21 }22 ],23 "total": 25,24 "page": 1,25 "limit": 1026}1{2 "success": false,3 "message": "Invalid pagination parameters"4}1{2 "success": false,3 "message": "Unauthorized"4}1{2 "success": false,3 "message": "Failed to fetch tenants"4}1{2 "success": false,3 "message": "Internal server error"4}1{2 "success": true,3 "message": "Tenants retrieved successfully",4 "tenants": [5 {6 "id": "uuid",7 "name": {8 "en": "Tenant Name"9 },10 "slug": "tenant-slug",11 "status": "active",12 "contact_info": {},13 "metadata": {},14 "created_at": "2023-01-01T00:00:00Z",15 "created_by": "uuid",16 "updated_at": "2023-01-01T00:00:00Z",17 "updated_by": "uuid",18 "tenant_users": {19 "count": 520 }21 }22 ],23 "total": 25,24 "page": 1,25 "limit": 1026}Create Tenant
/tenants?language=enCreates a new tenant in the system. This endpoint is restricted to system administrators only. Authentication: - Requires valid authentication token - Only system administrators can access this endpoint Important: - Tenant subscription gate fields are normalized immediately after creation via recompute_tenant_status (respects the global tenant_subscription.enabled setting). Required Fields: - name: Object containing multilingual tenant names (at least one language required) - slug: URL-friendly identifier (must be unique, lowercase alphanumeric with hyphens only) Optional Fields: - contact_info: Object containing contact information (email, phone, address, etc.) - metadata: Object containing additional tenant metadata Validations: - Slug must match pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$ - Slug must be unique across all tenants - Name must be provided in at least one language - Each language name must be a non-empty string Query Parameters: - language (optional): Language code for localized response messages (e.g., 'en')
1curl --request POST "$ONDI_BASE_URL/tenants?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "name": {7 "en": "Tenant Name",8 "fr": "Nom du Locataire"9 },10 "slug": "tenant-slug",11 "contact_info": {12 "email": "contact@example.com",13 "phone": "+1234567890",14 "address": "123 Main St"15 },16 "metadata": {17 "industry": "technology",18 "size": "enterprise"19 }20}'1{2 "name": {3 "en": "Tenant Name",4 "fr": "Nom du Locataire"5 },6 "slug": "tenant-slug",7 "contact_info": {8 "email": "contact@example.com",9 "phone": "+1234567890",10 "address": "123 Main St"11 },12 "metadata": {13 "industry": "technology",14 "size": "enterprise"15 }16}Query parameters
languageOptionalen
Language of the response
Request body fields
nameExampleExample field from the request body.
name.enExampleExample field from the request body.
name.frExampleExample field from the request body.
slugExampleExample field from the request body.
contact_infoExampleExample field from the request body.
contact_info.emailExampleExample field from the request body.
contact_info.phoneExampleExample field from the request body.
contact_info.addressExampleExample field from the request body.
metadataExampleExample field from the request body.
metadata.industryExampleExample field from the request body.
metadata.sizeExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Tenant created successfully",4 "tenant": {5 "id": "550e8400-e29b-41d4-a716-446655440000",6 "name": {7 "en": "Tenant Name",8 "fr": "Nom du Locataire"9 },10 "slug": "tenant-slug",11 "contact_info": {12 "email": "contact@example.com",13 "phone": "+1234567890",14 "address": "123 Main St"15 },16 "status": "pending",17 "metadata": {18 "industry": "technology",19 "size": "enterprise"20 },21 "subscription_status": "NONE",22 "effective_active": true,23 "effective_until": null,24 "created_at": "2023-01-01T00:00:00Z",25 "created_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",26 "created_by_user": {27 "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",28 "email": "admin@example.com"29 }30 }31}1{2 "success": false,3 "message": "Tenant name required in at least one language"4}1{2 "success": false,3 "message": "Tenant slug required"4}1{2 "success": false,3 "message": "Invalid slug format"4}1{2 "success": false,3 "message": "Slug already in use"4}1{2 "success": false,3 "message": "Unauthorized"4}1{2 "success": false,3 "message": "Failed to create tenant"4}1{2 "success": true,3 "message": "Tenant created successfully",4 "tenant": {5 "id": "uuid",6 "name": {7 "en": "Tenant Name",8 "fr": "Nom du Locataire"9 },10 "slug": "tenant-slug",11 "contact_info": {12 "email": "contact@example.com",13 "phone": "+1234567890",14 "address": "123 Main St"15 },16 "status": "pending",17 "metadata": {18 "industry": "technology",19 "size": "enterprise"20 },21 "subscription_status": "NONE",22 "effective_active": true,23 "effective_until": null,24 "created_at": "2023-01-01T00:00:00Z",25 "created_by": "uuid",26 "created_by_user": {27 "id": "uuid",28 "email": "admin@example.com"29 }30 }31}1{2 "success": false,3 "message": "Invalid name format"4}1{2 "success": false,3 "message": "Internal server error"4}Create Tenant Wizard
/tenants/wizard?language=enCreates a fully configured tenant in a single API call. If any step fails, the endpoint performs compensating rollback (best-effort) by deleting created resources (tenant + created admin user) and canceling Stripe objects when possible. Authentication: - Requires valid authentication token - Only system administrators can access this endpoint Subscription: - When system setting tenant_subscription.enabled=true: subscription is required (type: MONTHLY|ANNUAL|UNLIMITED, amount) - When tenant_subscription.enabled=false: subscription is optional and ignored; no Stripe/subscription records created Notes: - Admin user is created immediately (password required) - Email/phone are derived from tenant.contact_info - Tenant admin role is resolved automatically - Admin avatar uses brand_settings.assets.logo.light when provided, else tenant.logo_url
1curl --request POST "$ONDI_BASE_URL/tenants/wizard?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "tenant": {7 "name": {8 "en": "Acme Logistics",9 "ar": "",10 "ku": ""11 },12 "slug": "acme-logistics",13 "contact_info": {14 "email": "admin@acme.com",15 "phone": "+19876543210"16 },17 "logo_url": "https://..."18 },19 "admin_user": {20 "create": true,21 "password": "StrongPassword123!"22 },23 "modules": {24 "enabled_module_ids": [25 "uuid-1",26 "uuid-2"27 ]28 },29 "subscription": {30 "type": "MONTHLY",31 "amount": 99.99,32 "note_public": "",33 "note_internal": ""34 },35 "brand_settings": {36 "brand_name": {37 "en": "Acme",38 "ar": "",39 "ku": ""40 },41 "assets": {42 "logo": {43 "light": "url",44 "dark": "url"45 },46 "favicon": "url"47 },48 "colors": {49 "text": "#000000",50 "accent": "#FF9500",51 "primary": "#007AFF",52 "secondary": "#FFFFFF",53 "background": "#F5F5F5"54 },55 "configurations": {56 "font": "Roboto",57 "theme": "light",58 "animations": false,59 "rtl_support": false60 }61 },62 "general_config": {63 "unit_size": {64 "unit_length": 30,65 "unit_weight": 5,66 "weight_unit": "KG",67 "volumetric_divisor": 5000,68 "dimension_unit": "CM",69 "use_volumetric_weight": false70 },71 "location": {72 "latitude": 36.19,73 "longitude": 44.0174 },75 "currency": {76 "currency_code": "USD",77 "currency_name": "US Dollar",78 "currency_symbol": "$",79 "currency_mode": "code",80 "exchange_rate_to_system": 181 },82 "domestic_country": {83 "code": "CA",84 "name": "Canada",85 "dial_code": "+1"86 },87 "driver": {88 "mode": "percentage",89 "percentage": {90 "percentage_of_delivery_fee": 091 },92 "per_delivery": {93 "base_amount": 094 },95 "driver_can_self_assign": false,96 "driver_can_accept_or_reject": false97 },98 "integration": {99 "sms_channel": {100 "selected_channel": "twilio"101 }102 },103 "warehouse": {104 "handoff_required": false105 },106 "express_shipping": {107 "customer_prefix_key": ""108 },109 "user_settings": {110 "offline_threshold_seconds": 300,111 "heartbeat_interval_seconds": 30112 },113 "mobile": {114 "show_tenant_list_page": false115 },116 "storefront": {117 "review_auto_approval": {118 "enabled": false,119 "auto_approve_ratings": []120 }121 },122 "delivery": {123 "return_requests": {124 "destination_mode": "pickup_location",125 "default_delivery_service_id": "",126 "auto_approval": true127 },128 "on_demand_auto_assignment": {129 "enabled": false,130 "priority_checks": {131 "driver_online": true,132 "preferred_zone": true,133 "vehicle_capacity": true,134 "available_in_zone": true135 },136 "max_retry_attempts": 3,137 "retry_after_minutes": 1,138 "notify_admin_on_failure": true139 }140 }141 }142}'1{2 "tenant": {3 "name": {4 "en": "Acme Logistics",5 "ar": "",6 "ku": ""7 },8 "slug": "acme-logistics",9 "contact_info": {10 "email": "admin@acme.com",11 "phone": "+19876543210"12 },13 "logo_url": "https://..."14 },15 "admin_user": {16 "create": true,17 "password": "StrongPassword123!"18 },19 "modules": {20 "enabled_module_ids": [21 "uuid-1",22 "uuid-2"23 ]24 },25 "subscription": {26 "type": "MONTHLY",27 "amount": 99.99,28 "note_public": "",29 "note_internal": ""30 },31 "brand_settings": {32 "brand_name": {33 "en": "Acme",34 "ar": "",35 "ku": ""36 },37 "assets": {38 "logo": {39 "light": "url",40 "dark": "url"41 },42 "favicon": "url"43 },44 "colors": {45 "text": "#000000",46 "accent": "#FF9500",47 "primary": "#007AFF",48 "secondary": "#FFFFFF",49 "background": "#F5F5F5"50 },51 "configurations": {52 "font": "Roboto",53 "theme": "light",54 "animations": false,55 "rtl_support": false56 }57 },58 "general_config": {59 "unit_size": {60 "unit_length": 30,61 "unit_weight": 5,62 "weight_unit": "KG",63 "volumetric_divisor": 5000,64 "dimension_unit": "CM",65 "use_volumetric_weight": false66 },67 "location": {68 "latitude": 36.19,69 "longitude": 44.0170 },71 "currency": {72 "currency_code": "USD",73 "currency_name": "US Dollar",74 "currency_symbol": "$",75 "currency_mode": "code",76 "exchange_rate_to_system": 177 },78 "domestic_country": {79 "code": "CA",80 "name": "Canada",81 "dial_code": "+1"82 },83 "driver": {84 "mode": "percentage",85 "percentage": {86 "percentage_of_delivery_fee": 087 },88 "per_delivery": {89 "base_amount": 090 },91 "driver_can_self_assign": false,92 "driver_can_accept_or_reject": false93 },94 "integration": {95 "sms_channel": {96 "selected_channel": "twilio"97 }98 },99 "warehouse": {100 "handoff_required": false101 },102 "express_shipping": {103 "customer_prefix_key": ""104 },105 "user_settings": {106 "offline_threshold_seconds": 300,107 "heartbeat_interval_seconds": 30108 },109 "mobile": {110 "show_tenant_list_page": false111 },112 "storefront": {113 "review_auto_approval": {114 "enabled": false,115 "auto_approve_ratings": []116 }117 },118 "delivery": {119 "return_requests": {120 "destination_mode": "pickup_location",121 "default_delivery_service_id": "",122 "auto_approval": true123 },124 "on_demand_auto_assignment": {125 "enabled": false,126 "priority_checks": {127 "driver_online": true,128 "preferred_zone": true,129 "vehicle_capacity": true,130 "available_in_zone": true131 },132 "max_retry_attempts": 3,133 "retry_after_minutes": 1,134 "notify_admin_on_failure": true135 }136 }137 }138}Query parameters
languageOptionalen
Language code for response localization (Optional, default: en)
Request body fields
tenantExampleExample field from the request body.
tenant.nameExampleExample field from the request body.
tenant.name.enExampleExample field from the request body.
tenant.name.arExampleExample field from the request body.
tenant.name.kuExampleExample field from the request body.
tenant.slugExampleExample field from the request body.
tenant.contact_infoExampleExample field from the request body.
tenant.contact_info.emailExampleExample field from the request body.
tenant.contact_info.phoneExampleExample field from the request body.
tenant.logo_urlExampleExample field from the request body.
admin_userExampleExample field from the request body.
admin_user.createExampleExample field from the request body.
admin_user.passwordExampleExample field from the request body.
modulesExampleExample field from the request body.
modules.enabled_module_idsExampleExample field from the request body.
subscriptionExampleExample field from the request body.
subscription.typeExampleExample field from the request body.
subscription.amountExampleExample field from the request body.
subscription.note_publicExampleExample field from the request body.
subscription.note_internalExampleExample field from the request body.
brand_settingsExampleExample field from the request body.
brand_settings.brand_nameExampleExample field from the request body.
brand_settings.brand_name.enExampleExample field from the request body.
brand_settings.brand_name.arExampleExample field from the request body.
brand_settings.brand_name.kuExampleExample field from the request body.
brand_settings.assetsExampleExample field from the request body.
brand_settings.assets.logoExampleExample field from the request body.
brand_settings.assets.faviconExampleExample field from the request body.
brand_settings.colorsExampleExample field from the request body.
brand_settings.colors.textExampleExample field from the request body.
brand_settings.colors.accentExampleExample field from the request body.
brand_settings.colors.primaryExampleExample field from the request body.
brand_settings.colors.secondaryExampleExample field from the request body.
brand_settings.colors.backgroundExampleExample field from the request body.
brand_settings.configurationsExampleExample field from the request body.
brand_settings.configurations.fontExampleExample field from the request body.
brand_settings.configurations.themeExampleExample field from the request body.
brand_settings.configurations.animationsExampleExample field from the request body.
brand_settings.configurations.rtl_supportExampleExample field from the request body.
general_configExampleExample field from the request body.
general_config.unit_sizeExampleExample field from the request body.
general_config.unit_size.unit_lengthExampleExample field from the request body.
general_config.unit_size.unit_weightExampleExample field from the request body.
general_config.unit_size.weight_unitExampleExample field from the request body.
general_config.unit_size.volumetric_divisorExampleExample field from the request body.
general_config.unit_size.dimension_unitExampleExample field from the request body.
general_config.unit_size.use_volumetric_weightExampleExample field from the request body.
general_config.locationExampleExample field from the request body.
general_config.location.latitudeExampleExample field from the request body.
general_config.location.longitudeExampleExample field from the request body.
general_config.currencyExampleExample field from the request body.
general_config.currency.currency_codeExampleExample field from the request body.
general_config.currency.currency_nameExampleExample field from the request body.
general_config.currency.currency_symbolExampleExample field from the request body.
general_config.currency.currency_modeExampleExample field from the request body.
general_config.currency.exchange_rate_to_systemExampleExample field from the request body.
general_config.domestic_countryExampleExample field from the request body.
general_config.domestic_country.codeExampleExample field from the request body.
general_config.domestic_country.nameExampleExample field from the request body.
general_config.domestic_country.dial_codeExampleExample field from the request body.
general_config.driverExampleExample field from the request body.
general_config.driver.modeExampleExample field from the request body.
general_config.driver.percentageExampleExample field from the request body.
general_config.driver.per_deliveryExampleExample field from the request body.
general_config.driver.driver_can_self_assignExampleExample field from the request body.
general_config.driver.driver_can_accept_or_rejectExampleExample field from the request body.
general_config.integrationExampleExample field from the request body.
general_config.integration.sms_channelExampleExample field from the request body.
general_config.warehouseExampleExample field from the request body.
general_config.warehouse.handoff_requiredExampleExample field from the request body.
general_config.express_shippingExampleExample field from the request body.
general_config.express_shipping.customer_prefix_keyExampleExample field from the request body.
general_config.user_settingsExampleExample field from the request body.
general_config.user_settings.offline_threshold_secondsExampleExample field from the request body.
general_config.user_settings.heartbeat_interval_secondsExampleExample field from the request body.
general_config.mobileExampleExample field from the request body.
general_config.mobile.show_tenant_list_pageExampleExample field from the request body.
general_config.storefrontExampleExample field from the request body.
general_config.storefront.review_auto_approvalExampleExample field from the request body.
general_config.deliveryExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "tenant_id": "550e8400-e29b-41d4-a716-446655440000",4 "message": "Tenant created successfully"5}1{2 "success": false,3 "message": "Unauthorized"4}1{2 "success": false,3 "message": "Validation error"4}1{2 "success": false,3 "message": "Internal server error"4}1{2 "success": true,3 "tenant_id": "<uuid>",4 "message": "Tenant created successfully"5}1{2 "success": false,3 "message": "<error description>"4}Get Tenant
/tenants/:tenantId?language=enRetrieves detailed information about a specific tenant, including associated users and statistics. Authentication: - Requires valid authentication token - System administrators can access any tenant - Regular users can only access tenants they are associated with Path Parameters: - tenantId: UUID of the tenant to retrieve Query Parameters: - language (optional): Language code for localized response messages (e.g., 'en')
1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId?language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant to retrieve
Query parameters
languageOptionalen
Language of the response
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Tenant retrieved successfully",4 "tenant": {5 "id": "uuid",6 "name": {7 "en": "Example Tenant"8 },9 "slug": "example-tenant",10 "status": "active",11 "contact_info": {12 "email": "contact@example.com",13 "phone": "+1234567890"14 },15 "metadata": {},16 "created_at": "2023-01-01T00:00:00Z",17 "created_by": "uuid",18 "updated_at": "2023-01-01T00:00:00Z",19 "updated_by": "uuid",20 "tenant_users": [21 {22 "user_id": "uuid",23 "created_at": "2023-01-01T00:00:00Z",24 "user": {25 "id": "uuid",26 "email": "user@example.com"27 }28 }29 ],30 "created_by_user": {31 "id": "uuid",32 "email": "admin@example.com"33 },34 "updated_by_user": {35 "id": "uuid",36 "email": "admin@example.com"37 },38 "statistics": {39 "active_users": 540 }41 }42}1{2 "success": false,3 "message": "Tenant ID required"4}1{2 "success": false,3 "message": "Tenant not found"4}1{2 "success": false,3 "message": "Unauthorized tenant access"4}1{2 "success": false,3 "message": "Failed to fetch tenant"4}Update Tenant
/tenants/:tenantIdUpdate tenant details. Requires tenant admin or system admin access.
1curl --request PUT "$ONDI_BASE_URL/tenants/:tenantId" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "name": {7 "en": "Updated Name"8 },9 "status": "active",10 "contact_info": {11 "email": "updated@tenant.com"12 }13}'1{2 "name": {3 "en": "Updated Name"4 },5 "status": "active",6 "contact_info": {7 "email": "updated@tenant.com"8 }9}Path parameters
tenantIdRequiredID of the tenant
Request body fields
nameExampleExample field from the request body.
name.enExampleExample field from the request body.
statusExampleExample field from the request body.
contact_infoExampleExample field from the request body.
contact_info.emailExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
List Tenant Modules
/tenants/:tenantId/modules?page=1&limit=10&language=enRetrieves a list of modules associated with a specific tenant. Requires authentication - user must be either a system administrator or a member of the specified tenant.
1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId/modules?page=1&limit=10&language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredThe unique identifier of the tenant
Query parameters
pageOptional1
Page number for pagination
limitOptional10
Number of results per page
languageOptionalen
Language code for response messages
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Tenant modules retrieved successfully",4 "tenantModules": [5 {6 "id": "uuid",7 "tenant_id": "tenant-uuid",8 "system_modules": {9 "name": "module-name",10 "description": "Module description",11 "version": "1.0.0",12 "dependencies": {},13 "features": []14 },15 "created_at": "timestamp",16 "updated_at": "timestamp"17 }18 ],19 "total": 10,20 "page": 1,21 "limit": 1022}1{2 "success": false,3 "message": "Unauthorized"4}Enable Tenant Module
/tenants/:tenantId/modules/:moduleId?language=enEnable a module for a specific tenant. This endpoint allows system administrators to enable modules for any tenant, while tenant administrators can only enable modules for their own tenant if they have the 'manage:tenant' permission. Authentication: - Requires valid authentication token - User must be either a system administrator or a tenant administrator with 'manage:tenant' permission Path Parameters: - tenantId: ID of the tenant - moduleId: ID of the module to enable Query Parameters: - language (optional): Language code for localized response messages (e.g., 'en') Validations: - The module must be active at the system level - The module must be enabled at the system level
1curl --request POST "$ONDI_BASE_URL/tenants/:tenantId/modules/:moduleId?language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
moduleIdRequiredID of the module to enable
Query parameters
languageOptionalen
Language code for response localization (Optional, default: en)
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Module enabled successfully",4 "tenantModule": {5 "tenant_id": "550e8400-e29b-41d4-a716-446655440000",6 "module_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",7 "is_enabled": true,8 "enabled_at": "2023-01-01T00:00:00Z",9 "enabled_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",10 "updated_at": "2023-01-01T00:00:00Z",11 "updated_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"12 }13}1{2 "success": false,3 "message": "Insufficient permissions"4}1{2 "success": false,3 "message": "Module not active at system level"4}1{2 "success": true,3 "message": "Module enabled successfully",4 "tenantModule": {5 "tenant_id": "tenant-uuid",6 "module_id": "module-uuid",7 "is_enabled": true,8 "enabled_at": "2023-01-01T00:00:00Z",9 "enabled_by": "user-uuid",10 "updated_at": "2023-01-01T00:00:00Z",11 "updated_by": "user-uuid"12 }13}1{2 "success": false,3 "message": "Module not enabled at system level"4}1{2 "success": false,3 "message": "Module not enabled"4}1{2 "success": false,3 "message": "Internal server error"4}Disable Tenant Module
/tenants/:tenantId/modules/:moduleId?language=enDisable a module for a specific tenant. This endpoint allows system administrators to disable modules for any tenant, while tenant administrators can only disable modules for their own tenant if they have the 'manage:tenant' permission. Authentication: - Requires valid authentication token - User must be either a system administrator or a tenant administrator with 'manage:tenant' permission Path Parameters: - tenantId: ID of the tenant - moduleId: ID of the module to disable Query Parameters: - language (optional): Language code for localized response messages (e.g., 'en') Validations: - The module must be active at the system level - The module must be enabled at the system level
1curl --request DELETE "$ONDI_BASE_URL/tenants/:tenantId/modules/:moduleId?language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
moduleIdRequiredID of the module to disable
Query parameters
languageOptionalen
Language code for response localization (Optional, default: en)
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "Module enabled successfully",4 "tenantModule": {5 "tenant_id": "550e8400-e29b-41d4-a716-446655440000",6 "module_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",7 "is_enabled": false,8 "enabled_at": "2023-01-01T00:00:00Z",9 "enabled_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",10 "updated_at": "2023-01-01T00:00:00Z",11 "updated_by": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"12 }13}1{2 "success": false,3 "message": "Insufficient permissions"4}1{2 "success": false,3 "message": "Module not active at system level"4}1{2 "success": true,3 "message": "Module enabled successfully",4 "tenantModule": {5 "tenant_id": "tenant-uuid",6 "module_id": "module-uuid",7 "is_enabled": false,8 "enabled_at": "2023-01-01T00:00:00Z",9 "enabled_by": "user-uuid",10 "updated_at": "2023-01-01T00:00:00Z",11 "updated_by": "user-uuid"12 }13}1{2 "success": false,3 "message": "Module not enabled at system level"4}1{2 "success": false,3 "message": "Module not enabled"4}1{2 "success": false,3 "message": "Internal server error"4}Add User to Tenant
/tenants/:tenantId/users?language=enAdd a user to a tenant. Requires tenant admin or system admin access.
1curl --request POST "$ONDI_BASE_URL/tenants/:tenantId/users?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "user_id": "user-uuid",7 "tenant_user_type": "individual",8 "is_primary": false,9 "metadata": {},10 "invite_token": "optional-invite-token"11}'1{2 "user_id": "user-uuid",3 "tenant_user_type": "individual",4 "is_primary": false,5 "metadata": {},6 "invite_token": "optional-invite-token"7}Path parameters
tenantIdRequiredID of the tenant
Query parameters
languageOptionalen
Language of the response
Request body fields
user_idExampleExample field from the request body.
tenant_user_typeExampleExample field from the request body.
is_primaryExampleExample field from the request body.
metadataExampleExample field from the request body.
invite_tokenExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
Create API Key
/tenants/:tenantId/api-keys?language=enCreate a new API key for the tenant. Returns the API key only once.
1curl --request POST "$ONDI_BASE_URL/tenants/:tenantId/api-keys?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "name": "API Key Name",7 "user_id": "user-uuid",8 "expires_at": "2025-12-31T23:59:59Z"9}'1{2 "name": "API Key Name",3 "user_id": "user-uuid",4 "expires_at": "2025-12-31T23:59:59Z"5}Path parameters
tenantIdRequiredID of the tenant
Query parameters
languageOptionalen
Language of the response
Request body fields
nameExampleExample field from the request body.
user_idExampleExample field from the request body.
expires_atExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
List API Keys
/tenants/:tenantId/api-keys?page=1&limit=10List all API keys for the tenant with pagination
1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId/api-keys?page=1&limit=10" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
Query parameters
pageOptional1
Page number
limitOptional10
Items per page
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.
Revoke API Key
/tenants/:tenantId/api-keys/:apiKeyId?language=enRevoke an API key
1curl --request DELETE "$ONDI_BASE_URL/tenants/:tenantId/api-keys/:apiKeyId?language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
apiKeyIdRequiredID of the API key to revoke
Query parameters
languageOptionalen
Language of the response
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.
Update API Key
/tenants/:tenantId/api-keys/:apiKeyId?language=enUpdate an API key's properties
1curl --request PUT "$ONDI_BASE_URL/tenants/:tenantId/api-keys/:apiKeyId?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "name": "Updated Name",7 "expires_at": "2025-12-31T23:59:59Z",8 "is_active": true9}'1{2 "name": "Updated Name",3 "expires_at": "2025-12-31T23:59:59Z",4 "is_active": true5}Path parameters
tenantIdRequiredID of the tenant
apiKeyIdRequiredID of the API key to update
Query parameters
languageOptionalen
Language of the response
Request body fields
nameExampleExample field from the request body.
expires_atExampleExample field from the request body.
is_activeExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
List Tenant Addresses
/tenants/:tenantId/addresses?language=en&page=1&limit=10List all active addresses for a tenant
1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId/addresses?language=en&page=1&limit=10" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
Query parameters
languageOptionalen
Language of the response
pageOptional1
Page number
limitOptional10
Number of addresses per page
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.
Get Tenant Brand Settings
/tenants/:tenantId/brand-settings?language=en1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId/brand-settings?language=en" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
Query parameters
languageOptionalen
Language of the response
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.
Update Tenant Brand Settings
/tenants/:tenantId/brand-settingsUpdate tenant brand settings. Requires system admin access.
1curl --request PUT "$ONDI_BASE_URL/tenants/:tenantId/brand-settings" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "brand_name": "Updated Brand Name",7 "assets": {8 "logo": "url-to-logo"9 },10 "colors": {11 "primary": "#000000"12 },13 "configurations": {14 "theme": "dark"15 }16}'1{2 "brand_name": "Updated Brand Name",3 "assets": {4 "logo": "url-to-logo"5 },6 "colors": {7 "primary": "#000000"8 },9 "configurations": {10 "theme": "dark"11 }12}Path parameters
tenantIdRequiredID of the tenant
Request body fields
brand_nameExampleExample field from the request body.
assetsExampleExample field from the request body.
assets.logoExampleExample field from the request body.
colorsExampleExample field from the request body.
colors.primaryExampleExample field from the request body.
configurationsExampleExample field from the request body.
configurations.themeExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
Remove User from Tenant
/tenants/:tenantId/users/:userIdRemove a user from the tenant. Cannot remove the last admin.
1curl --request DELETE "$ONDI_BASE_URL/tenants/:tenantId/users/:userId" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
userIdRequiredID of the user to remove
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.
Get Tenant Settings
/tenants/:tenantId/settingsGet tenant settings. Optionally filter by specific keys. If phone_login or domestic_country is returned, the response includes options.allowed_countries sourced from the system-level tenant phone-login allowlist so tenant admins can only choose countries permitted by the system. If 'currency' is present in any group, the response includes top-level 'currencies' with system and tenant context. If delivery.assignment_change_settings.settings.default_driver_id is set, the response also includes default_driver with the driver's display information (full_name, phone, avatar_url).
1curl --request GET "$ONDI_BASE_URL/tenants/:tenantId/settings" \2 --header "Authorization: Bearer {{access_token}}"Path parameters
tenantIdRequiredID of the tenant
Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "message": "tenant_settings_retrieved_successfully",4 "tenantSettings": {5 "general": {6 "currency": {7 "settings": {8 "currency_code": "IQD",9 "currency_symbol": "د.ع",10 "currency_name": "Iraqi Dinar",11 "exchange_rate_to_system": 0.0007612 },13 "description": null14 },15 "phone_login": {16 "settings": {17 "allowed_countries": [18 {19 "code": "IN",20 "name": "India",21 "dial_code": "+91"22 }23 ],24 "default_country": {25 "code": "IN",26 "name": "India",27 "dial_code": "+91"28 }29 },30 "description": "Phone login controls (allowed countries + default country)",31 "options": {32 "allowed_countries": [33 {34 "code": "CA",35 "name": "Canada",36 "dial_code": "+1"37 },38 {39 "code": "IN",40 "name": "India",41 "dial_code": "+91"42 },43 {44 "code": "TR",45 "name": "Turkey",46 "dial_code": "+90"47 }48 ],49 "default_country": [50 {51 "code": "CA",52 "name": "Canada",53 "dial_code": "+1"54 },55 {56 "code": "IN",57 "name": "India",58 "dial_code": "+91"59 },60 {61 "code": "TR",62 "name": "Turkey",63 "dial_code": "+90"64 }65 ]66 }67 },68 "domestic_country": {69 "settings": {70 "code": "CA",71 "name": "Canada",72 "dial_code": "+1"73 },74 "description": "Domestic country configuration for tenant (default: Canada)",75 "options": {76 "allowed_countries": [77 {78 "code": "CA",79 "name": "Canada",80 "dial_code": "+1"81 },82 {83 "code": "IN",84 "name": "India",85 "dial_code": "+91"86 },87 {88 "code": "TR",89 "name": "Turkey",90 "dial_code": "+90"91 }92 ]93 }94 }95 },96 "delivery": {97 "assignment_change_settings": {98 "settings": {99 "enabled": true,100 "allow_unassign_after_pickup": false,101 "driver_can_self_unassign": false,102 "driver_can_self_unassign_after_pickup": false,103 "default_driver_id": "driver-uuid-123",104 "default_driver": {105 "full_name": "John Driver",106 "phone": "+1234567890",107 "avatar_url": "https://example.com/avatar.jpg"108 }109 },110 "description": null111 }112 }113 },114 "currencies": {115 "system": {116 "currency_code": "USD",117 "currency_symbol": "$",118 "currency_name": "US Dollar"119 },120 "tenant": {121 "currency_code": "IQD",122 "currency_symbol": "د.ع",123 "currency_name": "Iraqi Dinar",124 "exchange_rate_to_system": 0.00076125 }126 }127}Update Tenant Setting
/tenants/:tenantId/settings/:settingKeyUpdate a specific tenant setting. If settingKey='currency' and tenant currency_code differs from system currency_code, you must provide a positive 'exchange_rate_to_system'. If codes match, exchange_rate_to_system is normalized to 1. If settingKey='phone_login': - settingValue.allowed_countries can be an array of { code, name, dial_code } OR null. - When array is provided, it must be a subset of system-level phone_login.allowed_countries. - settingValue.default_country must be null or one of the allowed countries. - When allowed_countries is null, tenant falls back to system phone_login setting.
1curl --request PUT "$ONDI_BASE_URL/tenants/:tenantId/settings/:settingKey" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "settingValue": {7 "allowed_countries": [8 {9 "code": "IN",10 "name": "India",11 "dial_code": "+91"12 },13 {14 "code": "AE",15 "name": "United Arab Emirates",16 "dial_code": "+971"17 }18 ],19 "default_country": {20 "code": "IN",21 "name": "India",22 "dial_code": "+91"23 }24 }25}'1{2 "settingValue": {3 "allowed_countries": [4 {5 "code": "IN",6 "name": "India",7 "dial_code": "+91"8 },9 {10 "code": "AE",11 "name": "United Arab Emirates",12 "dial_code": "+971"13 }14 ],15 "default_country": {16 "code": "IN",17 "name": "India",18 "dial_code": "+91"19 }20 }21}Path parameters
tenantIdRequiredID of the tenant
settingKeyRequiredKey of the setting to update
Request body fields
settingValueExampleExample field from the request body.
settingValue.allowed_countriesExampleExample field from the request body.
settingValue.allowed_countries.codeExampleExample field from the request body.
settingValue.allowed_countries.nameExampleExample field from the request body.
settingValue.allowed_countries.dial_codeExampleExample field from the request body.
settingValue.default_countryExampleExample field from the request body.
settingValue.default_country.codeExampleExample field from the request body.
settingValue.default_country.nameExampleExample field from the request body.
settingValue.default_country.dial_codeExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
No response example is available for this endpoint yet.
Retry/Regenerate Label
/tenants/labels/retry?language=enRetry or regenerate a label for a delivery, inventory item, or delivery package item. This endpoint allows tenant administrators to trigger label regeneration regardless of the previous status. Authentication: - Requires valid authentication token - User must be either a system administrator or a tenant administrator with 'manage:tenant' permission At least one of the following IDs must be provided: - delivery_id (optional): UUID of the delivery to regenerate label for - item_id (optional): UUID of the inventory item to regenerate label for - delivery_package_item_id (optional): UUID of the delivery package item to regenerate label for Validations: - At least one ID must be provided - The entity must belong to the tenant (for tenant admins) - System admins can regenerate labels for any tenant Query Parameters: - language (optional): Language code for localized response messages (e.g., 'en')
1curl --request POST "$ONDI_BASE_URL/tenants/labels/retry?language=en" \2 --header "Authorization: Bearer {{access_token}}" \3 --header "Content-Type: application/json" \4 --header "Content-Type: application/json" \5 --data '{6 "delivery_id": "delivery-uuid",7 "item_id": null,8 "delivery_package_item_id": null9}'1{2 "delivery_id": "delivery-uuid",3 "item_id": null,4 "delivery_package_item_id": null5}Query parameters
languageOptionalen
Language code for response localization (Optional, default: en)
Request body fields
delivery_idExampleExample field from the request body.
item_idExampleExample field from the request body.
delivery_package_item_idExampleExample field from the request body.
Headers
AuthorizationOptionalBearer {{access_token}}
Content-TypeOptionalapplication/json
Responses
1{2 "success": true,3 "message": "Label regenerated successfully",4 "url": "https://example.supabase.co/storage/v1/object/public/documents/shipment-labels/550e8400-e29b-41d4-a716-446655440000.pdf"5}1{2 "success": false,3 "message": "At least one of delivery_id, item_id, or delivery_package_item_id is required"4}1{2 "success": false,3 "message": "Delivery not found or does not belong to your tenant"4}1{2 "success": false,3 "message": "Insufficient permissions"4}1{2 "success": false,3 "message": "Label generation failed"4}1{2 "success": true,3 "message": "Label regenerated successfully",4 "url": "https://example.supabase.co/storage/v1/object/public/documents/shipment-labels/uuid.pdf"5}1{2 "success": false,3 "message": "Item not found or does not belong to your tenant"4}1{2 "success": false,3 "message": "Package item not found or does not belong to your tenant"4}1{2 "success": false,3 "message": "Internal server error"4}Get My Subscription
/tenants/me/subscriptionReturns the authenticated tenant subscription. Response content type is always application/json. Response: - success: boolean - subscription_enabled: boolean - whether the tenant subscription model is enabled globally (system setting) - data: subscription object
1curl --request GET "$ONDI_BASE_URL/tenants/me/subscription" \2 --header "Authorization: Bearer {{access_token}}"Headers
AuthorizationOptionalBearer {{access_token}}
Responses
1{2 "success": true,3 "subscription_enabled": true,4 "data": {}5}Get My Subscription History
/tenants/me/subscription/historyReturns the authenticated tenant subscription history. Response content type is always application/json.
1curl --request GET "$ONDI_BASE_URL/tenants/me/subscription/history" \2 --header "Authorization: Bearer {{access_token}}"Headers
AuthorizationOptionalBearer {{access_token}}
Responses
No response example is available for this endpoint yet.