Installment Purchase

Flexible payment plans with 7+ frequencies, custom intervals, and 2-4 plans per product. Features transparent amortization schedules, 75% early payoff interest discount, and two fulfillment options (immediate or after payment). Includes configurable 0-60 day grace periods, automated payment processing via JobRunr, up to 5 retry attempts for failed payments, real-time tracking of payment history and agreement status, and full admin control for plan management.

Installment Purchase - Customer Endpoints

Author: Josh S. Sakweli, Backend Lead Team
Last Updated: 2025-10-18
Version: v1.0

Base URL: https://api.nextgate.com/api/v1/installments

Short Description: This API provides endpoints for customers to manage their installment purchase agreements. Customers can view their agreements, track payment schedules, make manual payments, retry failed payments, calculate and process early payoffs, and cancel agreements. All endpoints require authentication and operate on the principle that customers can only access their own agreement data.

Hints:


Standard Response Format

All API responses follow a consistent structure using our Globe Response Builder pattern:

Success Response Structure

{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    // Actual response data goes here
  }
}

Error Response Structure

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2025-10-18T10:30:45",
  "data": "Error description"
}

Standard Response Fields

Field Type Description
success boolean Always true for successful operations, false for errors
httpStatus string HTTP status name (OK, BAD_REQUEST, NOT_FOUND, etc.)
message string Human-readable message describing the operation result
action_time string ISO 8601 timestamp of when the response was generated
data object/string Response payload for success, error details for failures

HTTP Method Badge Standards

For better visual clarity, all endpoints use colored badges for HTTP methods with the following standard colors:


Endpoints

1. Get My Agreements

Purpose: Retrieve all installment agreements for the authenticated customer, optionally filtered by status

Endpoint: GET {base_url}/my-agreements

Access Level: 🔒 Protected (Requires Authentication)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Query Parameters:

Parameter Type Required Description Validation Default
status string No Filter by agreement status enum: PENDING_FIRST_PAYMENT, ACTIVE, COMPLETED, DEFAULTED, CANCELLED null (all statuses)

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Agreements retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "agreementNumber": "INST-2025-12345",
      "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "productName": "Samsung Galaxy S24 Ultra",
      "productImage": "https://cdn.example.com/products/samsung-s24.jpg",
      "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
      "shopName": "Tech World Store",
      "totalAmount": 2500000.00,
      "amountPaid": 500000.00,
      "amountRemaining": 2000000.00,
      "currency": "TZS",
      "paymentsCompleted": 1,
      "paymentsRemaining": 11,
      "totalPayments": 12,
      "progressPercentage": 20.0,
      "nextPaymentDate": "2025-11-18T00:00:00",
      "nextPaymentAmount": 166666.67,
      "agreementStatus": "ACTIVE",
      "agreementStatusDisplay": "ACTIVE",
      "createdAt": "2025-10-18T09:00:00",
      "completedAt": null,
      "canMakeEarlyPayment": true,
      "canCancel": false
    }
  ]
}

Success Response Fields:

Field Description
agreementId Unique identifier for the agreement
agreementNumber Human-readable agreement number (format: INST-YYYY-NNNNN)
productId ID of the product being purchased
productName Name of the product
productImage URL to product image
shopId ID of the shop selling the product
shopName Name of the shop
totalAmount Total amount to be paid including interest
amountPaid Amount paid so far
amountRemaining Amount still owed
currency Currency code (TZS)
paymentsCompleted Number of payments made
paymentsRemaining Number of payments left
totalPayments Total number of scheduled payments
progressPercentage Percentage of payments completed
nextPaymentDate Date when next payment is due
nextPaymentAmount Amount of next payment
agreementStatus Current status of the agreement
agreementStatusDisplay Human-readable status
createdAt When agreement was created
completedAt When agreement was completed (null if not completed)
canMakeEarlyPayment Whether early payoff is allowed
canCancel Whether agreement can be cancelled

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "UNAUTHORIZED",
  "message": "Token has expired",
  "action_time": "2025-10-18T10:30:45",
  "data": "Token has expired"
}

Standard Error Types:

Application-Level Exceptions (400-499)

Error Response Examples:

Unauthorized - Token Issues (401):

{
  "success": false,
  "httpStatus": "UNAUTHORIZED",
  "message": "Token has expired",
  "action_time": "2025-10-18T10:30:45",
  "data": "Token has expired"
}

Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "User not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "User not found"
}

2. Get My Active Agreements

Purpose: Retrieve only active installment agreements for the authenticated customer

Endpoint: GET {base_url}/my-agreements/active

Access Level: 🔒 Protected (Requires Authentication)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Active agreements retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "agreementNumber": "INST-2025-12345",
      "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "productName": "Samsung Galaxy S24 Ultra",
      "productImage": "https://cdn.example.com/products/samsung-s24.jpg",
      "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
      "shopName": "Tech World Store",
      "totalAmount": 2500000.00,
      "amountPaid": 500000.00,
      "amountRemaining": 2000000.00,
      "currency": "TZS",
      "paymentsCompleted": 1,
      "paymentsRemaining": 11,
      "totalPayments": 12,
      "progressPercentage": 20.0,
      "nextPaymentDate": "2025-11-18T00:00:00",
      "nextPaymentAmount": 166666.67,
      "agreementStatus": "ACTIVE",
      "agreementStatusDisplay": "ACTIVE",
      "createdAt": "2025-10-18T09:00:00",
      "completedAt": null,
      "canMakeEarlyPayment": true,
      "canCancel": false
    }
  ]
}

Success Response Fields: Same as Get My Agreements endpoint

Error Response Examples: Same error types as Get My Agreements endpoint


3. Get Agreement By ID

Purpose: Retrieve detailed information about a specific installment agreement by its ID

Endpoint: GET {base_url}/agreements/{agreementId}

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Agreement details retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agreementNumber": "INST-2025-12345",
    "customerId": "9b2e4d56-7c8a-4f9b-a3d1-5e6f7a8b9c0d",
    "customerName": "John Doe",
    "customerEmail": "john.doe@example.com",
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "productImage": "https://cdn.example.com/products/samsung-s24.jpg",
    "productPrice": 2000000.00,
    "quantity": 1,
    "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
    "shopName": "Tech World Store",
    "selectedPlanId": "4b5c6d7e-8f9a-4b1c-9d2e-3f4a5b6c7d8e",
    "planName": "12 Month Standard Plan",
    "paymentFrequency": "MONTHLY",
    "paymentFrequencyDisplay": "Monthly",
    "customFrequencyDays": null,
    "numberOfPayments": 12,
    "duration": "12 months",
    "apr": 15.00,
    "gracePeriodDays": 30,
    "downPaymentAmount": 400000.00,
    "financedAmount": 1600000.00,
    "monthlyPaymentAmount": 166666.67,
    "totalInterestAmount": 400000.00,
    "totalAmount": 2400000.00,
    "currency": "TZS",
    "paymentsCompleted": 1,
    "paymentsRemaining": 11,
    "amountPaid": 566666.67,
    "amountRemaining": 1833333.33,
    "progressPercentage": 8.33,
    "nextPaymentDate": "2025-11-18T00:00:00",
    "nextPaymentAmount": 166666.67,
    "agreementStatus": "ACTIVE",
    "defaultCount": 0,
    "createdAt": "2025-10-18T09:00:00",
    "firstPaymentDate": "2025-11-18T00:00:00",
    "lastPaymentDate": "2026-10-18T00:00:00",
    "completedAt": null,
    "fulfillmentTiming": "IMMEDIATE",
    "shippedAt": "2025-10-18T14:00:00",
    "deliveredAt": null,
    "orderId": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
    "shippingAddress": {
      "fullName": "John Doe",
      "phoneNumber": "+255712345678",
      "street": "123 Main Street",
      "city": "Dar es Salaam",
      "state": "Dar es Salaam",
      "postalCode": "12345",
      "country": "Tanzania"
    },
    "billingAddress": {
      "fullName": "John Doe",
      "phoneNumber": "+255712345678",
      "street": "123 Main Street",
      "city": "Dar es Salaam",
      "state": "Dar es Salaam",
      "postalCode": "12345",
      "country": "Tanzania"
    },
    "payments": [
      {
        "paymentId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
        "paymentNumber": 1,
        "scheduledAmount": 166666.67,
        "paidAmount": 166666.67,
        "principalPortion": 146666.67,
        "interestPortion": 20000.00,
        "remainingBalance": 1453333.33,
        "lateFee": null,
        "currency": "TZS",
        "paymentStatus": "COMPLETED",
        "paymentStatusDisplay": "COMPLETED",
        "dueDate": "2025-11-18T00:00:00",
        "paidAt": "2025-11-18T10:30:00",
        "attemptedAt": "2025-11-18T10:29:45",
        "paymentMethod": "WALLET",
        "transactionId": "TXN-2025-67890",
        "failureReason": null,
        "retryCount": 0,
        "daysUntilDue": null,
        "daysOverdue": null,
        "canPay": false,
        "canRetry": false
      }
    ],
    "canMakeEarlyPayment": true,
    "canCancel": false,
    "canUpdatePaymentMethod": false
  }
}

Success Response Fields:

Field Description
agreementId Unique identifier for the agreement
agreementNumber Human-readable agreement number
customerId ID of the customer
customerName Customer's full name
customerEmail Customer's email address
productId ID of the product
productName Name of the product
productImage URL to product image
productPrice Original product price
quantity Quantity purchased
shopId ID of the shop
shopName Name of the shop
selectedPlanId ID of the selected installment plan
planName Name of the installment plan
paymentFrequency Payment frequency enum value
paymentFrequencyDisplay Human-readable payment frequency
customFrequencyDays Custom frequency in days (if applicable)
numberOfPayments Total number of payments
duration Human-readable duration
apr Annual Percentage Rate
gracePeriodDays Grace period before first payment
downPaymentAmount Down payment amount
financedAmount Amount being financed
monthlyPaymentAmount Amount per payment
totalInterestAmount Total interest to be paid
totalAmount Grand total (product + interest)
currency Currency code
paymentsCompleted Number of completed payments
paymentsRemaining Number of remaining payments
amountPaid Total amount paid so far
amountRemaining Total amount remaining
progressPercentage Percentage of completion
nextPaymentDate Next payment due date
nextPaymentAmount Next payment amount
agreementStatus Current agreement status
defaultCount Number of missed payments
createdAt Agreement creation timestamp
firstPaymentDate First payment due date
lastPaymentDate Last payment due date
completedAt Completion timestamp (null if not completed)
fulfillmentTiming When product is shipped (IMMEDIATE or AFTER_PAYMENT)
shippedAt Shipment timestamp
deliveredAt Delivery timestamp
orderId Associated order ID
shippingAddress Shipping address object
billingAddress Billing address object
payments Array of payment objects with full details
canMakeEarlyPayment Whether early payoff is allowed
canCancel Whether agreement can be cancelled
canUpdatePaymentMethod Whether payment method can be updated

Error Response Examples:

Bad Request (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "You do not have access to this agreement",
  "action_time": "2025-10-18T10:30:45",
  "data": "You do not have access to this agreement"
}

Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Agreement not found with ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "action_time": "2025-10-18T10:30:45",
  "data": "Agreement not found with ID: 3fa85f64-5717-4562-b3fc-2c963f66afa6"
}

4. Get Agreement By Number

Purpose: Retrieve detailed information about a specific installment agreement by its agreement number

Endpoint: GET {base_url}/agreements/number/{agreementNumber}

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementNumber string Yes Agreement number (format: INST-YYYY-NNNNN) Pattern: INST-\d{4}-\d{5}

Success Response JSON Sample: Same as Get Agreement By ID endpoint

Success Response Fields: Same as Get Agreement By ID endpoint

Error Response Examples: Same as Get Agreement By ID endpoint, with agreement number in error messages instead of ID


5. Get Agreement Payments

Purpose: Retrieve all payment records for a specific installment agreement

Endpoint: GET {base_url}/agreements/{agreementId}/payments

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Payment history retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "paymentId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
      "paymentNumber": 1,
      "scheduledAmount": 166666.67,
      "paidAmount": 166666.67,
      "principalPortion": 146666.67,
      "interestPortion": 20000.00,
      "remainingBalance": 1453333.33,
      "lateFee": null,
      "currency": "TZS",
      "paymentStatus": "COMPLETED",
      "paymentStatusDisplay": "COMPLETED",
      "dueDate": "2025-11-18T00:00:00",
      "paidAt": "2025-11-18T10:30:00",
      "attemptedAt": "2025-11-18T10:29:45",
      "paymentMethod": "WALLET",
      "transactionId": "TXN-2025-67890",
      "failureReason": null,
      "retryCount": 0,
      "daysUntilDue": null,
      "daysOverdue": null,
      "canPay": false,
      "canRetry": false
    },
    {
      "paymentId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
      "paymentNumber": 2,
      "scheduledAmount": 166666.67,
      "paidAmount": null,
      "principalPortion": 148533.33,
      "interestPortion": 18133.34,
      "remainingBalance": 1304800.00,
      "lateFee": null,
      "currency": "TZS",
      "paymentStatus": "SCHEDULED",
      "paymentStatusDisplay": "SCHEDULED",
      "dueDate": "2025-12-18T00:00:00",
      "paidAt": null,
      "attemptedAt": null,
      "paymentMethod": null,
      "transactionId": null,
      "failureReason": null,
      "retryCount": 0,
      "daysUntilDue": 61,
      "daysOverdue": null,
      "canPay": false,
      "canRetry": false
    }
  ]
}

Success Response Fields:

Field Description
paymentId Unique identifier for the payment
paymentNumber Sequential payment number (1, 2, 3...)
scheduledAmount Amount scheduled to be paid
paidAmount Amount actually paid (null if not paid)
principalPortion Amount going toward principal
interestPortion Amount going toward interest
remainingBalance Balance after this payment
lateFee Late fee if applicable
currency Currency code
paymentStatus Current payment status
paymentStatusDisplay Human-readable status
dueDate When payment is due
paidAt When payment was made (null if not paid)
attemptedAt Last payment attempt timestamp
paymentMethod Payment method used
transactionId Transaction reference ID
status Payment status after processing
processedAt When payment was processed
message Success message
agreementUpdate Updated agreement information
agreementUpdate.paymentsCompleted Updated number of completed payments
agreementUpdate.paymentsRemaining Updated number of remaining payments
agreementUpdate.amountPaid Updated total amount paid
agreementUpdate.amountRemaining Updated remaining amount
agreementUpdate.nextPaymentDate Next payment due date
agreementUpdate.nextPaymentAmount Next payment amount
agreementUpdate.agreementStatus Updated agreement status
agreementUpdate.isCompleted Whether agreement is now completed

Error Response Examples:

Bad Request - Insufficient Balance (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Insufficient wallet balance. Required: 166666.67 TZS, Available: 50000.00 TZS. Please top up your wallet before the next payment attempt.",
  "action_time": "2025-10-18T10:30:45",
  "data": "Insufficient wallet balance. Required: 166666.67 TZS, Available: 50000.00 TZS. Please top up your wallet before the next payment attempt."
}

Bad Request - Payment Already Completed (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Payment is already completed",
  "action_time": "2025-10-18T10:30:45",
  "data": "Payment is already completed"
}

Bad Request - Payment Not Due (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Payment is not due yet. Due date: 2025-12-18T00:00:00",
  "action_time": "2025-10-18T10:30:45",
  "data": "Payment is not due yet. Due date: 2025-12-18T00:00:00"
}

6. Get Upcoming Payments

Purpose: Retrieve all upcoming payments across all active agreements for the authenticated customer

Endpoint: GET {base_url}/upcoming-payments

Access Level: 🔒 Protected (Requires Authentication)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Upcoming payments retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "paymentId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
      "paymentNumber": 2,
      "scheduledAmount": 166666.67,
      "paidAmount": null,
      "principalPortion": 148533.33,
      "interestPortion": 18133.34,
      "remainingBalance": 1304800.00,
      "lateFee": null,
      "currency": "TZS",
      "paymentStatus": "SCHEDULED",
      "paymentStatusDisplay": "SCHEDULED",
      "dueDate": "2025-12-18T00:00:00",
      "paidAt": null,
      "attemptedAt": null,
      "paymentMethod": null,
      "transactionId": null,
      "failureReason": null,
      "retryCount": 0,
      "daysUntilDue": 61,
      "daysOverdue": null,
      "canPay": false,
      "canRetry": false
    }
  ]
}

Success Response Fields: Same as Get Agreement Payments endpoint

Error Response Examples: Standard authentication errors only


7. Make Manual Payment

Purpose: Process a manual payment for a specific scheduled installment

Endpoint: POST {base_url}/agreements/{agreementId}/payments/{paymentId}/pay

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format
paymentId UUID Yes Unique identifier of the payment Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Payment processed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "paymentId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
    "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agreementNumber": "INST-2025-12345",
    "amount": 166666.67,
    "currency": "TZS",
    "paymentMethod": "WALLET",
    "transactionId": "TXN-2025-67891",
    "status": "COMPLETED",
    "processedAt": "2025-10-18T10:30:45",
    "message": "Payment processed successfully",
    "agreementUpdate": {
      "paymentsCompleted": 2,
      "paymentsRemaining": 10,
      "amountPaid": 733333.34,
      "amountRemaining": 1666666.66,
      "nextPaymentDate": "2026-01-18T00:00:00",
      "nextPaymentAmount": 166666.67,
      "agreementStatus": "ACTIVE",
      "isCompleted": false
    }
  }
}

Success Response Fields:

Field Description
paymentId ID of the processed payment
agreementId ID of the agreement
agreementNumber Agreement number
amount Amount paid
currency Currency code
paymentMethod Payment method used
transaction

8. Retry Failed Payment

Purpose: Retry a failed payment that has not exceeded maximum retry attempts

Endpoint: POST {base_url}/payments/{paymentId}/retry

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
paymentId UUID Yes Unique identifier of the payment to retry Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Payment retry processed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "paymentId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
    "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agreementNumber": "INST-2025-12345",
    "amount": 166666.67,
    "currency": "TZS",
    "paymentMethod": "WALLET",
    "transactionId": "TXN-2025-67892",
    "status": "COMPLETED",
    "processedAt": "2025-10-18T10:30:45",
    "message": "Payment retry successful",
    "agreementUpdate": {
      "paymentsCompleted": 2,
      "paymentsRemaining": 10,
      "amountPaid": 733333.34,
      "amountRemaining": 1666666.66,
      "nextPaymentDate": "2026-01-18T00:00:00",
      "nextPaymentAmount": 166666.67,
      "agreementStatus": "ACTIVE",
      "isCompleted": false
    }
  }
}

Success Response Fields: Same as Make Manual Payment endpoint

Error Response Examples:

Bad Request - Cannot Retry (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Payment cannot be retried",
  "action_time": "2025-10-18T10:30:45",
  "data": "Payment cannot be retried"
}

Bad Request - Max Retries Exceeded (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Maximum retry attempts (5) exceeded",
  "action_time": "2025-10-18T10:30:45",
  "data": "Maximum retry attempts (5) exceeded"
}

9. Preview Flexible Payment

Purpose: Calculate and preview how a flexible payment amount will be distributed across installment payments before processing

Endpoint: POST {base_url}/installments/agreements/{agreementId}/early-flexible-payment/preview

Access Level: 🔒 Protected (Requires Authentication)

Authentication: Bearer Token (JWT)

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication
Content-Type string Yes Must be application/json

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes The ID of the installment agreement Must be a valid UUID, agreement must belong to authenticated user

Request JSON Sample:

{
  "amount": 500000.00
}

Request Body Parameters:

Parameter Type Required Description Validation
amount decimal Yes Amount the customer wants to pay Must be > 0, cannot exceed remaining balance

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Flexible payment preview calculated successfully",
  "action_time": "2025-11-06T10:30:45",
  "data": {
    "requestedAmount": 500000.00,
    "minimumRequired": 150000.00,
    "maximumAllowed": 1200000.00,
    "isValid": true,
    "validationMessage": null,
    "impactedPayments": [
      {
        "paymentNumber": 3,
        "dueDate": "2025-12-01T00:00:00",
        "scheduledAmount": 200000.00,
        "currentPaid": 50000.00,
        "willApply": 150000.00,
        "willRemain": 0.00,
        "resultStatus": "Will be COMPLETED"
      },
      {
        "paymentNumber": 4,
        "dueDate": "2026-01-01T00:00:00",
        "scheduledAmount": 200000.00,
        "currentPaid": 0.00,
        "willApply": 200000.00,
        "willRemain": 0.00,
        "resultStatus": "Will be COMPLETED"
      },
      {
        "paymentNumber": 5,
        "dueDate": "2026-02-01T00:00:00",
        "scheduledAmount": 200000.00,
        "currentPaid": 0.00,
        "willApply": 150000.00,
        "willRemain": 50000.00,
        "resultStatus": "Will be PARTIALLY_PAID"
      }
    ],
    "paymentsWillComplete": 2,
    "paymentsWillBePartial": 1,
    "remainingAfter": 700000.00
  }
}

Success Response Fields:

Field Description
requestedAmount The amount customer wants to pay
minimumRequired Minimum payment required (next incomplete payment amount)
maximumAllowed Maximum payment allowed (total remaining balance)
isValid Whether the requested amount is valid
validationMessage Error message if amount is invalid, null if valid
impactedPayments Array of payments that will be affected by this payment
impactedPayments[].paymentNumber Sequential payment number
impactedPayments[].dueDate When this payment is due
impactedPayments[].scheduledAmount Original scheduled amount for this payment
impactedPayments[].currentPaid Amount already paid towards this payment
impactedPayments[].willApply How much of the flexible payment will apply here
impactedPayments[].willRemain How much will remain unpaid after applying
impactedPayments[].resultStatus Final status: "Will be COMPLETED" or "Will be PARTIALLY_PAID"
paymentsWillComplete Number of payments that will be fully completed
paymentsWillBePartial Number of payments that will be partially paid
remainingAfter Total remaining balance after this payment

Error Response Examples:

Bad Request - Amount Too Low (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Minimum payment required: 150000.00 TZS",
  "action_time": "2025-11-06T10:30:45",
  "data": "Minimum payment required: 150000.00 TZS"
}

Bad Request - Amount Too High (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Payment amount exceeds remaining balance. Use early payoff endpoint if paying off completely.",
  "action_time": "2025-11-06T10:30:45",
  "data": "Payment amount exceeds remaining balance. Use early payoff endpoint if paying off completely."
}

Forbidden - Not Agreement Owner (403):

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "You do not have access to this agreement",
  "action_time": "2025-11-06T10:30:45",
  "data": "You do not have access to this agreement"
}

Not Found - Agreement Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Agreement not found",
  "action_time": "2025-11-06T10:30:45",
  "data": "Agreement not found"
}

Validation Error - Invalid Amount (422):

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-11-06T10:30:45",
  "data": {
    "amount": "must be greater than 0"
  }
}

10. Process Flexible Payment

Purpose: Process a flexible payment that can pay multiple installments or partially pay upcoming installments

Endpoint: POST {base_url}/installments/agreements/{agreementId}/early-flexible-payment

Access Level: 🔒 Protected (Requires Authentication, Sufficient Wallet Balance)

Authentication: Bearer Token (JWT)

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication
Content-Type string Yes Must be application/json

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes The ID of the installment agreement Must be a valid UUID, agreement must belong to authenticated user

Request JSON Sample:

{
  "amount": 500000.00,
  "note": "Paying 3 months ahead"
}

Request Body Parameters:

Parameter Type Required Description Validation
amount decimal Yes Amount to pay Must be > 0, between minimumRequired and maximumAllowed
note string No Optional note about the payment Max 500 characters

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Successfully paid 2 installments and partially paid 1 more",
  "action_time": "2025-11-06T10:30:45",
  "data": {
    "agreementId": "a8b3c4d5-e6f7-8901-2345-6789abcdef01",
    "agreementNumber": "INST-2025-12345",
    "totalAmountPaid": 500000.00,
    "currency": "TZS",
    "transactionId": "TXN-2025-67890",
    "processedAt": "2025-11-06T10:30:45",
    "paymentsAffected": [
      {
        "paymentId": "p1a2b3c4-d5e6-f789-0123-456789abcdef",
        "paymentNumber": 3,
        "dueDate": "2025-12-01T00:00:00",
        "scheduledAmount": 200000.00,
        "amountApplied": 150000.00,
        "previouslyPaid": 50000.00,
        "newPaidAmount": 200000.00,
        "remaining": 0.00,
        "status": "COMPLETED",
        "wasCompleted": true
      },
      {
        "paymentId": "p2a3b4c5-d6e7-f890-1234-56789abcdef0",
        "paymentNumber": 4,
        "dueDate": "2026-01-01T00:00:00",
        "scheduledAmount": 200000.00,
        "amountApplied": 200000.00,
        "previouslyPaid": 0.00,
        "newPaidAmount": 200000.00,
        "remaining": 0.00,
        "status": "COMPLETED",
        "wasCompleted": true
      },
      {
        "paymentId": "p3a4b5c6-d7e8-f901-2345-6789abcdef01",
        "paymentNumber": 5,
        "dueDate": "2026-02-01T00:00:00",
        "scheduledAmount": 200000.00,
        "amountApplied": 150000.00,
        "previouslyPaid": 0.00,
        "newPaidAmount": 150000.00,
        "remaining": 50000.00,
        "status": "PARTIALLY_PAID",
        "wasCompleted": false
      }
    ],
    "agreementUpdate": {
      "paymentsCompleted": 4,
      "paymentsPartial": 1,
      "paymentsRemaining": 8,
      "amountPaid": 1300000.00,
      "amountRemaining": 700000.00,
      "nextPaymentDate": "2026-02-01T00:00:00",
      "nextPaymentAmount": 50000.00,
      "agreementStatus": "ACTIVE",
      "isCompleted": false
    },
    "message": "Successfully paid 2 installments and partially paid 1 more"
  }
}

Success Response Fields:

Field Description
agreementId ID of the installment agreement
agreementNumber Human-readable agreement number
totalAmountPaid Total amount paid in this transaction
currency Currency code (TZS)
transactionId Unique transaction identifier from ledger system
processedAt Timestamp when payment was processed
paymentsAffected Array of payments that were affected
paymentsAffected[].paymentId ID of the affected payment
paymentsAffected[].paymentNumber Sequential payment number
paymentsAffected[].dueDate When this payment is due
paymentsAffected[].scheduledAmount Original scheduled amount
paymentsAffected[].amountApplied How much of flexible payment was applied here
paymentsAffected[].previouslyPaid Amount that was previously paid
paymentsAffected[].newPaidAmount Total amount now paid for this payment
paymentsAffected[].remaining Amount still remaining for this payment
paymentsAffected[].status New payment status (COMPLETED or PARTIALLY_PAID)
paymentsAffected[].wasCompleted Whether this payment became fully completed
agreementUpdate Updated agreement summary
agreementUpdate.paymentsCompleted Total number of completed payments
agreementUpdate.paymentsPartial Number of partially paid payments
agreementUpdate.paymentsRemaining Number of payments still remaining
agreementUpdate.amountPaid Total amount paid on agreement
agreementUpdate.amountRemaining Total amount still remaining
agreementUpdate.nextPaymentDate When next payment is due
agreementUpdate.nextPaymentAmount Amount of next payment (remaining amount)
agreementUpdate.agreementStatus Current agreement status
agreementUpdate.isCompleted Whether agreement is fully completed
message Human-readable success message

Error Response Examples:

Bad Request - Insufficient Balance (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Insufficient wallet balance. Required: 500000.00 TZS, Available: 300000.00 TZS",
  "action_time": "2025-11-06T10:30:45",
  "data": "Insufficient wallet balance. Required: 500000.00 TZS, Available: 300000.00 TZS"
}

Bad Request - Agreement Not Active (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Cannot make payment on inactive agreement. Status: COMPLETED",
  "action_time": "2025-11-06T10:30:45",
  "data": "Cannot make payment on inactive agreement. Status: COMPLETED"
}

Bad Request - Wallet Not Active (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Wallet is not active",
  "action_time": "2025-11-06T10:30:45",
  "data": "Wallet is not active"
}

Validation Error (422):

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-11-06T10:30:45",
  "data": {
    "amount": "must be greater than 0",
    "note": "size must be between 0 and 500"
  }
}

11. Calculate Early Payoff

Purpose: Calculate the amount required to pay off the entire agreement early with interest discount

Endpoint: GET {base_url}/agreements/{agreementId}/early-payoff

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Early payoff calculation completed",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "paymentsCompleted": 2,
    "paymentsRemaining": 10,
    "amountPaid": 733333.34,
    "remainingPrincipal": 1320000.00,
    "unaccruedInterest": 346666.66,
    "interestRebate": 260000.00,
    "payoffWithRebate": 1406666.66,
    "payoffWithoutRebate": 1666666.66,
    "savingsVsScheduled": 260000.00,
    "rebatePolicy": "75% discount on remaining interest for early payoff",
    "calculatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
agreementId ID of the agreement
paymentsCompleted Number of payments already made
paymentsRemaining Number of payments left
amountPaid Total amount paid so far
remainingPrincipal Principal amount remaining
unaccruedInterest Interest not yet charged
interestRebate Interest discount amount (75% of remaining interest)
payoffWithRebate Early payoff amount with discount applied
payoffWithoutRebate Full remaining amount if paid on schedule
savingsVsScheduled Amount saved by paying off early
rebatePolicy Description of rebate policy
calculatedAt When calculation was performed

Error Response Examples:

Bad Request - Not Eligible (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Early payoff not available for this agreement",
  "action_time": "2025-10-18T10:30:45",
  "data": "Early payoff not available for this agreement"
}

Bad Request - Agreement Not Active (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Agreement is not active. Status: COMPLETED",
  "action_time": "2025-10-18T10:30:45",
  "data": "Agreement is not active. Status: COMPLETED"
}

12. Process Early Payoff

Purpose: Process full early payment of the agreement with interest discount applied

Endpoint: POST {base_url}/agreements/{agreementId}/early-payoff

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Early payoff processed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "paymentId": null,
    "agreementId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "agreementNumber": "INST-2025-12345",
    "amount": 1406666.66,
    "currency": "TZS",
    "paymentMethod": "WALLET",
    "transactionId": null,
    "status": "COMPLETED",
    "processedAt": "2025-10-18T10:30:45",
    "message": "Early payoff processed successfully",
    "agreementUpdate": {
      "paymentsCompleted": 12,
      "paymentsRemaining": 0,
      "amountPaid": 2400000.00,
      "amountRemaining": 0.00,
      "nextPaymentDate": null,
      "nextPaymentAmount": null,
      "agreementStatus": "COMPLETED",
      "isCompleted": true
    }
  }
}

Success Response Fields:

Field Description
paymentId Payment ID (null for early payoff)
agreementId ID of the agreement
agreementNumber Agreement number
amount Total early payoff amount paid
currency Currency code
paymentMethod Payment method used
transactionId Transaction reference (null for early payoff)
status Payment status (COMPLETED)
processedAt When payoff was processed
message Success message
agreementUpdate Updated agreement information
agreementUpdate.paymentsCompleted Updated to total number of payments
agreementUpdate.paymentsRemaining Set to 0
agreementUpdate.amountPaid Updated to total amount
agreementUpdate.amountRemaining Set to 0
agreementUpdate.nextPaymentDate Set to null
agreementUpdate.nextPaymentAmount Set to null
agreementUpdate.agreementStatus Set to COMPLETED
agreementUpdate.isCompleted Set to true

Error Response Examples:

Bad Request - Insufficient Balance (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Insufficient wallet balance for early payoff. Required: 1406666.66 TZS, Available: 500000.00 TZS",
  "action_time": "2025-10-18T10:30:45",
  "data": "Insufficient wallet balance for early payoff. Required: 1406666.66 TZS, Available: 500000.00 TZS"
}

Bad Request - Not Eligible (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Agreement is not active. Status: DEFAULTED",
  "action_time": "2025-10-18T10:30:45",
  "data": "Agreement is not active. Status: DEFAULTED"
}

13. Cancel Agreement

Purpose: Cancel an installment agreement before any payments have been completed

Endpoint: POST {base_url}/agreements/{agreementId}/cancel

Access Level: 🔒 Protected (Requires Authentication, Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication
Content-Type string Yes application/json

Path Parameters:

Parameter Type Required Description Validation
agreementId UUID Yes Unique identifier of the agreement Valid UUID format

Request JSON Sample:

{
  "reason": "Changed my mind about the purchase. Found a better deal elsewhere."
}

Request Body Parameters:

Parameter Type Required Description Validation
reason string Yes Reason for cancellation Min: 1, Max: 500 characters

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Agreement cancelled successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": null
}

Success Response Fields: No data returned on successful cancellation

Error Response Examples:

Bad Request - Cannot Cancel (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Agreement cannot be cancelled. Only agreements with no completed payments can be cancelled.",
  "action_time": "2025-10-18T10:30:45",
  "data": "Agreement cannot be cancelled. Only agreements with no completed payments can be cancelled."
}

Validation Error (422):

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "reason": "Cancellation reason is required"
  }
}

Quick Reference Guide

HTTP Method Badge Code Templates

GET Badge:

<span style="background-color: #28a745; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span>

POST Badge:

<span style="background-color: #007bff; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">POST</span>

Common HTTP Status Codes

Authentication

Agreement Status Flow

  1. PENDING_FIRST_PAYMENT: Down payment made, waiting for grace period
  2. ACTIVE: Currently paying installments
  3. COMPLETED: Fully paid off
  4. DEFAULTED: Missed 2+ payments, in collections
  5. CANCELLED: User cancelled before first payment

Payment Status Types

Business Rules

Common Error Scenarios

  1. Insufficient Wallet Balance: Top up wallet before payment
  2. Payment Not Due: Wait until due date or make early payoff
  3. Agreement Defaulted: Contact support for resolution
  4. Max Retries Exceeded: Contact support
  5. Ownership Validation Failed: Can only access own agreements

Notes for Developers

Idempotency

Rate Limiting

Webhooks

Testing

Support


Installment Purchase - Public & Plan Endpoints

Author: Josh S. Sakweli, Backend Lead Team
Last Updated: 2025-10-18
Version: v1.0

Base URL: https://api.nextgate.com/api/v1/installments

Short Description: This API provides public endpoints for browsing installment plans and calculating installment previews before checkout. These endpoints do not require authentication and are designed to help customers explore installment options, understand payment breakdowns, and make informed purchase decisions. The endpoints return detailed financial calculations including amortization schedules, interest breakdowns, and payment timelines.

Hints:


Standard Response Format

All API responses follow a consistent structure using our Globe Response Builder pattern:

Success Response Structure

{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    // Actual response data goes here
  }
}

Error Response Structure

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2025-10-18T10:30:45",
  "data": "Error description"
}

Standard Response Fields

Field Type Description
success boolean Always true for successful operations, false for errors
httpStatus string HTTP status name (OK, BAD_REQUEST, NOT_FOUND, etc.)
message string Human-readable message describing the operation result
action_time string ISO 8601 timestamp of when the response was generated
data object/string Response payload for success, error details for failures

HTTP Method Badge Standards

For better visual clarity, all endpoints use colored badges for HTTP methods with the following standard colors:


Endpoints

1. Get Available Plans for Product

Purpose: Retrieve all active installment plans available for a specific product

Endpoint: GET {base_url}/products/{productId}/plans

Access Level: 🌐 Public (No Authentication Required)

Authentication: None

Path Parameters:

Parameter Type Required Description Validation
productId UUID Yes Unique identifier of the product Valid UUID format

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Available installment plans retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "planId": "4b5c6d7e-8f9a-4b1c-9d2e-3f4a5b6c7d8e",
      "planName": "Quick Payment Plan",
      "paymentFrequency": "WEEKLY",
      "paymentFrequencyDisplay": "Weekly",
      "customFrequencyDays": null,
      "numberOfPayments": 8,
      "duration": "8 weeks",
      "apr": 10.00,
      "minDownPaymentPercent": 20,
      "gracePeriodDays": 7,
      "fulfillmentTiming": "IMMEDIATE",
      "isActive": true,
      "isFeatured": false,
      "displayOrder": 1,
      "preview": {
        "productPrice": 2000000.00,
        "minDownPaymentAmount": 400000.00,
        "maxDownPaymentAmount": 1000000.00,
        "financedAmountExample": 1600000.00,
        "paymentAmountExample": 210000.00,
        "totalInterestExample": 80000.00,
        "totalCostExample": 2080000.00,
        "firstPaymentDateExample": "2025-10-25T00:00:00",
        "lastPaymentDateExample": "2025-12-13T00:00:00"
      }
    },
    {
      "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
      "planName": "Standard Monthly Plan",
      "paymentFrequency": "MONTHLY",
      "paymentFrequencyDisplay": "Monthly",
      "customFrequencyDays": null,
      "numberOfPayments": 12,
      "duration": "12 months",
      "apr": 15.00,
      "minDownPaymentPercent": 15,
      "gracePeriodDays": 30,
      "fulfillmentTiming": "IMMEDIATE",
      "isActive": true,
      "isFeatured": true,
      "displayOrder": 2,
      "preview": {
        "productPrice": 2000000.00,
        "minDownPaymentAmount": 300000.00,
        "maxDownPaymentAmount": 1000000.00,
        "financedAmountExample": 1700000.00,
        "paymentAmountExample": 156250.00,
        "totalInterestExample": 175000.00,
        "totalCostExample": 2175000.00,
        "firstPaymentDateExample": "2025-11-17T00:00:00",
        "lastPaymentDateExample": "2026-10-17T00:00:00"
      }
    },
    {
      "planId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
      "planName": "Budget Friendly Plan",
      "paymentFrequency": "MONTHLY",
      "paymentFrequencyDisplay": "Monthly",
      "customFrequencyDays": null,
      "numberOfPayments": 24,
      "duration": "24 months",
      "apr": 18.00,
      "minDownPaymentPercent": 10,
      "gracePeriodDays": 30,
      "fulfillmentTiming": "AFTER_PAYMENT",
      "isActive": true,
      "isFeatured": false,
      "displayOrder": 3,
      "preview": {
        "productPrice": 2000000.00,
        "minDownPaymentAmount": 200000.00,
        "maxDownPaymentAmount": 1000000.00,
        "financedAmountExample": 1800000.00,
        "paymentAmountExample": 87500.00,
        "totalInterestExample": 300000.00,
        "totalCostExample": 2300000.00,
        "firstPaymentDateExample": "2025-11-17T00:00:00",
        "lastPaymentDateExample": "2027-10-17T00:00:00"
      }
    }
  ]
}

Success Response Fields:

Field Description
planId Unique identifier for the plan
planName Display name of the plan
paymentFrequency Payment frequency enum (DAILY, WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY, QUARTERLY, CUSTOM_DAYS)
paymentFrequencyDisplay Human-readable payment frequency
customFrequencyDays Custom frequency in days (only for CUSTOM_DAYS type)
numberOfPayments Total number of payments in the plan
duration Human-readable duration (e.g., "12 months", "8 weeks")
apr Annual Percentage Rate
minDownPaymentPercent Minimum down payment percentage required by this plan
gracePeriodDays Days before first payment is due
fulfillmentTiming When product ships (IMMEDIATE = after down payment, AFTER_PAYMENT = after final payment)
isActive Whether plan is currently active
isFeatured Whether plan is featured/recommended (shows "Most Popular" badge)
displayOrder Order for display on product page
preview Preview calculations object
preview.productPrice Product price used for calculations
preview.minDownPaymentAmount Minimum down payment amount
preview.maxDownPaymentAmount Maximum down payment amount (platform limit: 50%)
preview.financedAmountExample Amount being financed (at minimum down payment)
preview.paymentAmountExample Each installment amount (at minimum down payment)
preview.totalInterestExample Total interest to be paid (at minimum down payment)
preview.totalCostExample Grand total cost including interest (at minimum down payment)
preview.firstPaymentDateExample When first payment would be due
preview.lastPaymentDateExample When last payment would be due

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found with ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "action_time": "2025-10-18T10:30:45",
  "data": "Product not found with ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Standard Error Types:

Application-Level Exceptions (400-499)

Error Response Examples:

Not Found - Product (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found with ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7",
  "action_time": "2025-10-18T10:30:45",
  "data": "Product not found with ID: 7c9e6679-7425-40de-944b-e07fc1f90ae7"
}

Special Cases:


2. Calculate Installment Preview

Purpose: Calculate detailed payment breakdown and schedule for a specific plan with customer's chosen down payment percentage

Endpoint: POST {base_url}/calculate-preview

Access Level: 🌐 Public (No Authentication Required)

Authentication: None

Request Headers:

Header Type Required Description
Content-Type string Yes application/json

Request JSON Sample:

{
  "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
  "productPrice": 2000000.00,
  "quantity": 1,
  "downPaymentPercent": 20
}

Request Body Parameters:

Parameter Type Required Description Validation
planId UUID Yes ID of the installment plan to calculate Valid UUID format, plan must exist and be active
productPrice decimal Yes Price of the product Min: 0.01, Max: 999999999.99
quantity integer Yes Quantity of product Min: 1, Max: 1 (installment limited to 1 item)
downPaymentPercent integer Yes Down payment percentage customer chooses Min: 10, Max: 50, must be >= plan's minDownPaymentPercent

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment preview calculated successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "planName": "Standard Monthly Plan",
    "planDescription": "Pay in 12 monthly installments at 15.0% APR",
    "paymentFrequency": "Monthly",
    "numberOfPayments": 12,
    "durationDisplay": "12 months",
    "apr": 15.00,
    "gracePeriodDays": 30,
    "productPrice": 2000000.00,
    "quantity": 1,
    "totalProductCost": 2000000.00,
    "downPaymentPercent": 20,
    "downPaymentAmount": 400000.00,
    "minDownPaymentPercent": 15,
    "maxDownPaymentPercent": 50,
    "minDownPaymentAmount": 300000.00,
    "maxDownPaymentAmount": 1000000.00,
    "financedAmount": 1600000.00,
    "monthlyPaymentAmount": 146666.67,
    "totalInterestAmount": 160000.00,
    "totalAmount": 2160000.00,
    "currency": "TZS",
    "firstPaymentDate": "2025-11-17T00:00:00",
    "lastPaymentDate": "2026-10-17T00:00:00",
    "schedule": [
      {
        "paymentNumber": 1,
        "dueDate": "2025-11-17T00:00:00",
        "amount": 146666.67,
        "principalPortion": 126666.67,
        "interestPortion": 20000.00,
        "remainingBalance": 1473333.33,
        "description": "Month 1 payment"
      },
      {
        "paymentNumber": 2,
        "dueDate": "2025-12-17T00:00:00",
        "amount": 146666.67,
        "principalPortion": 128250.00,
        "interestPortion": 18416.67,
        "remainingBalance": 1345083.33,
        "description": "Month 2 payment"
      },
      {
        "paymentNumber": 3,
        "dueDate": "2026-01-17T00:00:00",
        "amount": 146666.67,
        "principalPortion": 129853.13,
        "interestPortion": 16813.54,
        "remainingBalance": 1215230.20,
        "description": "Month 3 payment"
      },
      {
        "paymentNumber": 12,
        "dueDate": "2026-10-17T00:00:00",
        "amount": 146666.67,
        "principalPortion": 144833.33,
        "interestPortion": 1833.34,
        "remainingBalance": 0.00,
        "description": "Final payment"
      }
    ],
    "comparison": {
      "payingUpfront": 2000000.00,
      "payingWithInstallment": 2160000.00,
      "additionalCost": 160000.00,
      "additionalCostPercent": 8.00
    },
    "fulfillmentTiming": "IMMEDIATE",
    "fulfillmentDescription": "Product ships immediately after down payment"
  }
}

Success Response Fields:

Field Description
planId ID of the plan used
planName Name of the plan
planDescription Description of the plan
paymentFrequency Human-readable payment frequency
numberOfPayments Total number of payments
durationDisplay Human-readable duration
apr Annual Percentage Rate
gracePeriodDays Grace period before first payment
productPrice Per-unit product price
quantity Quantity purchased
totalProductCost Total product cost (price × quantity)
downPaymentPercent Chosen down payment percentage
downPaymentAmount Calculated down payment amount
minDownPaymentPercent Minimum allowed down payment %
maxDownPaymentPercent Maximum allowed down payment % (50%)
minDownPaymentAmount Minimum down payment amount
maxDownPaymentAmount Maximum down payment amount
financedAmount Amount being financed (after down payment)
monthlyPaymentAmount Each installment payment amount
totalInterestAmount Total interest to be paid
totalAmount Grand total (product + interest)
currency Currency code (TZS)
firstPaymentDate When first payment is due
lastPaymentDate When last payment is due
schedule Array of payment schedule items
schedule[].paymentNumber Payment number (1, 2, 3...)
schedule[].dueDate When payment is due
schedule[].amount Payment amount
schedule[].principalPortion Amount going to principal
schedule[].interestPortion Amount going to interest
schedule[].remainingBalance Balance after this payment
schedule[].description Payment description
comparison Comparison information object
comparison.payingUpfront Cost if paying full price now
comparison.payingWithInstallment Total cost with installment
comparison.additionalCost Extra cost (interest)
comparison.additionalCostPercent Interest as % of product price
fulfillmentTiming When product ships
fulfillmentDescription Description of fulfillment timing

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Down payment must be at least 15% for this plan",
  "action_time": "2025-10-18T10:30:45",
  "data": "Down payment must be at least 15% for this plan"
}

Standard Error Types:

Application-Level Exceptions (400-499)

Error Response Examples:

Bad Request - Down Payment Too Low (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Down payment must be at least 15% for this plan",
  "action_time": "2025-10-18T10:30:45",
  "data": "Down payment must be at least 15% for this plan"
}

Bad Request - Down Payment Too High (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Down payment cannot exceed 50%",
  "action_time": "2025-10-18T10:30:45",
  "data": "Down payment cannot exceed 50%"
}

Bad Request - Plan Not Active (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "This installment plan is not currently available",
  "action_time": "2025-10-18T10:30:45",
  "data": "This installment plan is not currently available"
}

Not Found - Plan (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Installment plan not found with ID: 5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
  "action_time": "2025-10-18T10:30:45",
  "data": "Installment plan not found with ID: 5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f"
}

Validation Error (422):

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "Plan ID is required",
    "productPrice": "Product price must be greater than 0",
    "downPaymentPercent": "must be between 10 and 50"
  }
}

Quick Reference Guide

HTTP Method Badge Code Templates

GET Badge:

<span style="background-color: #28a745; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">GET</span>

POST Badge:

<span style="background-color: #007bff; color: white; padding: 4px 8px; border-radius: 4px; font-family: monospace; font-size: 12px; font-weight: bold;">POST</span>

Common HTTP Status Codes

Payment Frequency Types

Fulfillment Timing Options

Down Payment Rules

APR (Annual Percentage Rate)

Financial Calculations

Amortization Formula

Monthly Payment = P × [r(1+r)^n] / [(1+r)^n - 1]

Where:

Period Rate Calculation

Payment Breakdown

Each payment consists of:

  1. Interest Portion: Remaining balance × period rate
  2. Principal Portion: Payment amount - interest portion
  3. Remaining Balance: Previous balance - principal portion

Schedule Generation

Comparison Information

Shows cost difference between:

Common Use Cases

1. Display Plans on Product Page

GET /api/v1/installments/products/{productId}/plans

2. Calculate Custom Preview

POST /api/v1/installments/calculate-preview
{
  "planId": "...",
  "productPrice": 2000000.00,
  "quantity": 1,
  "downPaymentPercent": 25
}

3. Pre-Checkout Validation

POST /api/v1/installments/calculate-preview

Integration Examples

Frontend Flow

  1. Product page loads → Call GET /products/{id}/plans
  2. Display plan options with previews
  3. User selects plan and adjusts down payment
  4. Call POST /calculate-preview on down payment change
  5. Show detailed breakdown and schedule
  6. User proceeds to checkout with selected configuration

Mobile App Flow

  1. Fetch plans when user taps "Installment Options"
  2. Show plan cards with key metrics
  3. Tapped plan shows full preview
  4. Slider for down payment percentage
  5. Real-time preview updates
  6. "Continue to Checkout" with configuration

Error Handling Best Practices

Client-Side Validation

Server-Side Errors

Performance Considerations

Testing Scenarios

Happy Path

  1. Get plans for valid product with installment enabled
  2. Calculate preview with valid parameters
  3. Verify calculations match expected values

Edge Cases

  1. Product with no active plans → empty array
  2. Product with installment disabled → empty array
  3. Down payment at minimum boundary
  4. Down payment at maximum boundary (50%)
  5. Inactive plan in preview request → error

Error Cases

  1. Invalid product ID → 404
  2. Invalid plan ID → 404
  3. Down payment too low → 400
  4. Down payment too high → 400
  5. Missing required fields → 422
  6. Invalid data types → 422

Data Format Standards

Business Rules Summary

  1. One Item Per Agreement: Installment limited to single product
  2. Active Plans Only: Only active plans returned in public endpoints
  3. Down Payment Range: 10-50% (plan minimum to platform maximum)
  4. APR Limits: 0-36% (platform enforced)
  5. Grace Period: 0-60 days (plan-specific)
  6. Payment Frequency: All standard frequencies supported
  7. Fulfillment Options: IMMEDIATE or AFTER_PAYMENT
  8. Currency: TZS only (Tanzania market)
  9. Rounding: All calculations rounded to 2 decimal places
  10. Early Payoff: 75% discount on remaining interest (not shown in preview)

Notes for Developers

Calculation Accuracy

Caching Strategy

Mobile Optimization

Security Considerations

Support & Resources

Documentation Checklist

Before using this API, ensure you understand:


Installment Plan Management - Admin/Shop Endpoints

Author: Josh S. Sakweli, Backend Lead Team
Last Updated: 2025-10-18
Version: v1.0

Base URL: https://api.nextgate.com/api/v1/products/{shopId}/{productId}/installment-plans

Short Description: This API provides comprehensive endpoints for shop owners and administrators to create, manage, and configure installment plans for their products. Shop owners can define flexible payment terms including payment frequencies, interest rates, down payment requirements, grace periods, and fulfillment options. The API supports full CRUD operations, plan activation/deactivation, featured plan selection, and product-level installment enablement. All endpoints require authentication and validate shop ownership.

Hints:


Standard Response Format

All API responses follow a consistent structure using our Globe Response Builder pattern:

Success Response Structure

{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    // Actual response data goes here
  }
}

Error Response Structure

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2025-10-18T10:30:45",
  "data": "Error description"
}

Standard Response Fields

Field Type Description
success boolean Always true for successful operations, false for errors
httpStatus string HTTP status name (OK, BAD_REQUEST, NOT_FOUND, etc.)
message string Human-readable message describing the operation result
action_time string ISO 8601 timestamp of when the response was generated
data object/string Response payload for success, error details for failures

HTTP Method Badge Standards

For better visual clarity, all endpoints use colored badges for HTTP methods with the following standard colors:


Endpoints

1. Create Installment Plan

Purpose: Create a new installment plan for a specific product

Endpoint: POST {base_url}

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan to deactivate Valid UUID format, must belong to specified product

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan deactivated successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
    "planName": "Budget Friendly Plan",
    "isActive": false,
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
planId ID of the deactivated plan
planName Name of the plan
isActive Active status (false)
updatedAt Update timestamp

Error Response Examples: Same as Activate Installment Plan endpoint

Important Notes:


2. Get Product Installment Plans

Purpose: Retrieve all installment plans for a specific product (including inactive plans for admin view)

Endpoint: GET {base_url}

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plans retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": [
    {
      "planId": "4b5c6d7e-8f9a-4b1c-9d2e-3f4a5b6c7d8e",
      "planName": "Quick Payment Plan",
      "paymentFrequency": "WEEKLY",
      "paymentFrequencyDisplay": "Weekly",
      "customFrequencyDays": null,
      "numberOfPayments": 8,
      "calculatedDurationDays": 56,
      "calculatedDurationDisplay": "8 weeks",
      "apr": 10.00,
      "minDownPaymentPercent": 20,
      "gracePeriodDays": 7,
      "fulfillmentTiming": "IMMEDIATE",
      "isActive": true,
      "isFeatured": false,
      "displayOrder": 1,
      "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "productName": "Samsung Galaxy S24 Ultra",
      "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
      "shopName": "Tech World Store",
      "createdAt": "2025-10-15T09:00:00",
      "updatedAt": "2025-10-15T09:00:00"
    },
    {
      "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
      "planName": "12 Month Standard Plan",
      "paymentFrequency": "MONTHLY",
      "paymentFrequencyDisplay": "Monthly",
      "customFrequencyDays": null,
      "numberOfPayments": 12,
      "calculatedDurationDays": 360,
      "calculatedDurationDisplay": "12 months",
      "apr": 15.00,
      "minDownPaymentPercent": 20,
      "gracePeriodDays": 30,
      "fulfillmentTiming": "IMMEDIATE",
      "isActive": true,
      "isFeatured": true,
      "displayOrder": 2,
      "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "productName": "Samsung Galaxy S24 Ultra",
      "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
      "shopName": "Tech World Store",
      "createdAt": "2025-10-16T10:30:00",
      "updatedAt": "2025-10-16T10:30:00"
    },
    {
      "planId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
      "planName": "Budget Friendly Plan",
      "paymentFrequency": "MONTHLY",
      "paymentFrequencyDisplay": "Monthly",
      "customFrequencyDays": null,
      "numberOfPayments": 24,
      "calculatedDurationDays": 720,
      "calculatedDurationDisplay": "24 months",
      "apr": 18.00,
      "minDownPaymentPercent": 10,
      "gracePeriodDays": 30,
      "fulfillmentTiming": "AFTER_PAYMENT",
      "isActive": false,
      "isFeatured": false,
      "displayOrder": 3,
      "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "productName": "Samsung Galaxy S24 Ultra",
      "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
      "shopName": "Tech World Store",
      "createdAt": "2025-10-17T14:00:00",
      "updatedAt": "2025-10-18T08:00:00"
    }
  ]
}

Success Response Fields: Same as Create Installment Plan endpoint, returned as array

Error Response Examples:

Forbidden (403):

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "You do not have permission to view this shop's products",
  "action_time": "2025-10-18T10:30:45",
  "data": "You do not have permission to view this shop's products"
}

Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "Product not found"
}

3. Get Installment Plan By ID

Purpose: Retrieve detailed information about a specific installment plan

Endpoint: GET {base_url}/{planId}

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan Valid UUID format, must belong to specified product

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan retrieved successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "planName": "12 Month Standard Plan",
    "paymentFrequency": "MONTHLY",
    "paymentFrequencyDisplay": "Monthly",
    "customFrequencyDays": null,
    "numberOfPayments": 12,
    "calculatedDurationDays": 360,
    "calculatedDurationDisplay": "12 months",
    "apr": 15.00,
    "minDownPaymentPercent": 20,
    "gracePeriodDays": 30,
    "fulfillmentTiming": "IMMEDIATE",
    "isActive": true,
    "isFeatured": true,
    "displayOrder": 2,
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
    "shopName": "Tech World Store",
    "createdAt": "2025-10-16T10:30:00",
    "updatedAt": "2025-10-16T10:30:00",
    "metadata": {}
  }
}

Success Response Fields: Same as Create Installment Plan endpoint

Error Response Examples: Same as Get Product Installment Plans endpoint, plus:

Not Found - Plan (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Installment plan not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "Installment plan not found"
}

4. Update Installment Plan

Purpose: Update an existing installment plan's configuration

Endpoint: PUT {base_url}/{planId}

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication
Content-Type string Yes application/json

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan to update Valid UUID format, must belong to specified product

Request JSON Sample:

{
  "planName": "12 Month Premium Plan",
  "paymentFrequency": "MONTHLY",
  "customFrequencyDays": null,
  "numberOfPayments": 12,
  "apr": 12.00,
  "minDownPaymentPercent": 25,
  "gracePeriodDays": 45,
  "fulfillmentTiming": "IMMEDIATE",
  "displayOrder": 1
}

Request Body Parameters:

Parameter Type Required Description Validation
planName string No Updated display name Min: 3, Max: 100 characters
paymentFrequency string No Updated payment frequency enum: DAILY, WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY, QUARTERLY, CUSTOM_DAYS
customFrequencyDays integer Conditional Updated custom frequency Required if paymentFrequency is CUSTOM_DAYS, Min: 1, Max: 365
numberOfPayments integer No Updated number of payments Min: 2, Max: 120
apr decimal No Updated APR Min: 0.00, Max: 36.00
minDownPaymentPercent integer No Updated minimum down payment Min: 10, Max: 50
gracePeriodDays integer No Updated grace period Min: 0, Max: 60
fulfillmentTiming string No Updated fulfillment option enum: IMMEDIATE, AFTER_PAYMENT
displayOrder integer No Updated display order Min: 0

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan updated successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "planName": "12 Month Premium Plan",
    "paymentFrequency": "MONTHLY",
    "paymentFrequencyDisplay": "Monthly",
    "customFrequencyDays": null,
    "numberOfPayments": 12,
    "calculatedDurationDays": 360,
    "calculatedDurationDisplay": "12 months",
    "apr": 12.00,
    "minDownPaymentPercent": 25,
    "gracePeriodDays": 45,
    "fulfillmentTiming": "IMMEDIATE",
    "isActive": true,
    "isFeatured": true,
    "displayOrder": 1,
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
    "shopName": "Tech World Store",
    "createdAt": "2025-10-16T10:30:00",
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields: Same as Create Installment Plan endpoint

Error Response Examples: Same as Create Installment Plan endpoint

Important Notes:


5. Delete Installment Plan

Purpose: Permanently delete an installment plan (only if no active agreements exist)

Endpoint: DELETE {base_url}/{planId}

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan to delete Valid UUID format, must belong to specified product

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan deleted successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": null
}

Success Response Fields: No data returned on successful deletion

Error Response Examples:

Bad Request - Has Active Agreements (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Cannot delete plan with active agreements. Deactivate the plan instead.",
  "action_time": "2025-10-18T10:30:45",
  "data": "Cannot delete plan with active agreements. Deactivate the plan instead."
}

Forbidden (403):

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "You do not have permission to delete this plan",
  "action_time": "2025-10-18T10:30:45",
  "data": "You do not have permission to delete this plan"
}

Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Installment plan not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "Installment plan not found"
}

6. Activate Installment Plan

Purpose: Activate an installment plan to make it available to customers

Endpoint: PATCH {base_url}/{planId}/activate

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan to activate Valid UUID format, must belong to specified product

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan activated successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "6d7e8f9a-0b1c-4d2e-9f3a-4b5c6d7e8f9a",
    "planName": "Budget Friendly Plan",
    "isActive": true,
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
planId ID of the activated plan
planName Name of the plan
isActive Active status (true)
updatedAt Update timestamp

Error Response Examples: Same as Delete Installment Plan endpoint


7. Deactivate Installment Plan

Purpose: Deactivate an installment plan to hide it from customers (preserves data for existing agreements)

Endpoint: PATCH {base_url}/{planId}/deactivate

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token

Purpose: Mark a plan as featured (recommended/most popular) - only one plan per product can be featured

Endpoint: PATCH {base_url}/{planId}/set-featured

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop
planId UUID Yes Unique identifier of the plan to feature Valid UUID format, must belong to specified product

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Featured plan set successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "planName": "12 Month Premium Plan",
    "isFeatured": true,
    "previousFeaturedPlanId": "4b5c6d7e-8f9a-4b1c-9d2e-3f4a5b6c7d8e",
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
planId ID of the newly featured plan
planName Name of the plan
isFeatured Featured status (true)
previousFeaturedPlanId ID of previously featured plan (null if none)
updatedAt Update timestamp

Error Response Examples: Same as Activate Installment Plan endpoint

Important Notes:


9. Enable Installments for Product

Purpose: Enable installment payment option for a product (makes all active plans available)

Endpoint: PATCH {base_url}/enable-installments

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installments enabled successfully for product",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "installmentAvailable": true,
    "activePlansCount": 2,
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
productId ID of the product
productName Name of the product
installmentAvailable Installment availability status (true)
activePlansCount Number of active plans for this product
updatedAt Update timestamp

Error Response Examples:

Bad Request - No Plans (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Cannot enable installments: No installment plans created for this product",
  "action_time": "2025-10-18T10:30:45",
  "data": "Cannot enable installments: No installment plans created for this product"
}

Forbidden (403):

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "You do not have permission to modify this product",
  "action_time": "2025-10-18T10:30:45",
  "data": "You do not have permission to modify this product"
}

Not Found (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "Product not found"
}

10. Disable Installments for Product

Purpose: Disable installment payment option for a product (hides all plans from customers)

Endpoint: PATCH {base_url}/disable-installments

Access Level: 🔒 Protected (Requires Authentication, Shop Owner Only)

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer token for authentication

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installments disabled successfully for product",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "installmentAvailable": false,
    "activePlansCount": 2,
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields: Same as Enable Installments endpoint

Error Response Examples: Same as Enable Installments endpoint

Important Notes:


Common HTTP Status Codes

Payment Frequency Options

Fulfillment Timing Options

Plan Configuration Constraints

Parameter Minimum Maximum Notes
APR 0% 36% Platform-enforced limit
Down Payment 10% 50% Minimum by plan, maximum platform-wide
Number of Payments 2 120 Typical range: 4-24 payments
Grace Period 0 days 60 days Days before first payment
Custom Frequency 1 day 365 days Only for CUSTOM_DAYS type
Plan Name 3 chars 100 chars Must be unique per product

Plan States and Lifecycle

Active Plan

Inactive Plan

Deleted Plan

Business Rules Summary

Common Workflows

Creating a New Installment Plan

  1. Ensure product exists and you own the shop
  2. POST /installment-plans with plan configuration
  3. Verify plan appears in GET /installment-plans
  4. Optionally set as featured via PATCH /set-featured
  5. Enable installments on product if not already enabled

Managing Multiple Plans

  1. Create multiple plans for different customer segments
    • Quick payment plan (8 weeks, 10% APR)
    • Standard plan (12 months, 15% APR)
    • Budget plan (24 months, 18% APR)
  2. Set most balanced plan as featured
  3. Order by display priority (displayOrder field)
  4. Monitor customer preferences and adjust

Temporarily Disabling Plans

  1. PATCH /deactivate for specific plan
  2. OR PATCH /disable-installments for all plans
  3. Existing agreements continue normally
  4. Reactivate when ready with PATCH /activate or /enable-installments

Updating Plan Terms

  1. Analyze current agreement performance
  2. PUT /installment-plans/{planId} with new terms
  3. New terms apply only to future agreements
  4. Consider creating new plan for major changes

Deleting Unused Plans

  1. Check if plan has any agreements (attempt delete will fail if so)
  2. DELETE /installment-plans/{planId}
  3. Plan permanently removed
  4. If has agreements, use deactivate instead

Client-Side Validation

Server-Side Error Handling

Testing Scenarios

Happy Path

  1. Create plan with valid parameters
  2. Retrieve plan and verify all fields
  3. Update plan configuration
  4. Set as featured plan
  5. Activate/deactivate plan
  6. Enable/disable product installments

Edge Cases

  1. Create multiple plans with same parameters
  2. Set featured when no featured plan exists
  3. Set featured when another plan is featured
  4. Update plan to use custom frequency
  5. Deactivate only active plan
  6. Enable installments with no active plans

Error Cases

  1. Invalid shop/product IDs → 404
  2. Non-owner attempting management → 403
  3. APR outside 0-36% range → 422
  4. Down payment outside 10-50% → 422
  5. Delete plan with agreements → 400
  6. Missing required fields → 422
  7. Invalid payment frequency → 422
  8. Custom days without CUSTOM_DAYS → 422

Performance Considerations

Security Considerations

Monitoring and Analytics

Track the following metrics:

Best Practices for Shop Owners

Plan Design Strategy

  1. Offer 2-3 plans for different budgets
    • Quick plan: Short term, low interest
    • Standard plan: Medium term, moderate interest
    • Budget plan: Long term, higher interest
  2. Use clear naming: "8-Week Quick Pay", "12-Month Standard"
  3. Set appropriate featured plan: Balance of affordability and profit
  4. Adjust based on data: Monitor which plans customers choose

APR Configuration

Down Payment Strategy

Grace Period Guidelines

Common Mistakes to Avoid

  1. Too many plans (confuses customers) - stick to 2-4
  2. Too high APR (customers avoid) - keep competitive
  3. Too low down payment (higher default risk) - minimum 15-20%
  4. Deleting active plans - deactivate instead
  5. Not setting featured plan - customers want guidance
  6. Inconsistent plan naming - use clear conventions
  7. Not updating based on performance - review quarterly
  8. Enabling without active plans - create plans first

Support & Resources

Version 1.0 (2025-10-18)

Path Parameters:

Parameter Type Required Description Validation
shopId UUID Yes Unique identifier of the shop Valid UUID format, must be owned by authenticated user
productId UUID Yes Unique identifier of the product Valid UUID format, must belong to specified shop

Request JSON Sample:

{
  "planName": "12 Month Standard Plan",
  "paymentFrequency": "MONTHLY",
  "customFrequencyDays": null,
  "numberOfPayments": 12,
  "apr": 15.00,
  "minDownPaymentPercent": 20,
  "gracePeriodDays": 30,
  "fulfillmentTiming": "IMMEDIATE",
  "isActive": true,
  "isFeatured": false,
  "displayOrder": 1
}

Request Body Parameters:

Parameter Type Required Description Validation
planName string Yes Display name for the plan Min: 3, Max: 100 characters
paymentFrequency string Yes Payment frequency type enum: DAILY, WEEKLY, BI_WEEKLY, SEMI_MONTHLY, MONTHLY, QUARTERLY, CUSTOM_DAYS
customFrequencyDays integer Conditional Custom frequency in days Required if paymentFrequency is CUSTOM_DAYS, Min: 1, Max: 365
numberOfPayments integer Yes Total number of payments Min: 2, Max: 120
apr decimal Yes Annual Percentage Rate Min: 0.00, Max: 36.00
minDownPaymentPercent integer Yes Minimum down payment percentage Min: 10, Max: 50
gracePeriodDays integer Yes Days before first payment due Min: 0, Max: 60
fulfillmentTiming string Yes When to ship product enum: IMMEDIATE, AFTER_PAYMENT
isActive boolean No Whether plan is active Default: true
isFeatured boolean No Whether plan is featured Default: false
displayOrder integer No Display order on product page Min: 0, Default: 0

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Installment plan created successfully",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planId": "5c6d7e8f-9a0b-4c1d-8e2f-3a4b5c6d7e8f",
    "planName": "12 Month Standard Plan",
    "paymentFrequency": "MONTHLY",
    "paymentFrequencyDisplay": "Monthly",
    "customFrequencyDays": null,
    "numberOfPayments": 12,
    "calculatedDurationDays": 360,
    "calculatedDurationDisplay": "12 months",
    "apr": 15.00,
    "minDownPaymentPercent": 20,
    "gracePeriodDays": 30,
    "fulfillmentTiming": "IMMEDIATE",
    "isActive": true,
    "isFeatured": false,
    "displayOrder": 1,
    "productId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
    "productName": "Samsung Galaxy S24 Ultra",
    "shopId": "8d3a7b12-9c4e-4f8a-b5d2-3e6f7a8b9c0d",
    "shopName": "Tech World Store",
    "createdAt": "2025-10-18T10:30:45",
    "updatedAt": "2025-10-18T10:30:45"
  }
}

Success Response Fields:

Field Description
planId Unique identifier for the created plan
planName Name of the plan
paymentFrequency Payment frequency enum value
paymentFrequencyDisplay Human-readable frequency
customFrequencyDays Custom days (if CUSTOM_DAYS type)
numberOfPayments Total number of payments
calculatedDurationDays Auto-calculated total duration in days
calculatedDurationDisplay Human-readable duration
apr Annual Percentage Rate
minDownPaymentPercent Minimum down payment percentage
gracePeriodDays Grace period in days
fulfillmentTiming Fulfillment option
isActive Active status
isFeatured Featured status
displayOrder Display order
productId Associated product ID
productName Associated product name
shopId Associated shop ID
shopName Associated shop name
createdAt Creation timestamp
updatedAt Last update timestamp

Error Response Examples:

Bad Request - Invalid APR (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "APR must be between 0% and 36%",
  "action_time": "2025-10-18T10:30:45",
  "data": "APR must be between 0% and 36%"
}

Bad Request - Invalid Payment Count (400):

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Number of payments must be between 2 and 120",
  "action_time": "2025-10-18T10:30:45",
  "data": "Number of payments must be between 2 and 120"
}

Validation Error (422):

{
  "success": false,
  "httpStatus": "UNPROCESSABLE_ENTITY",
  "message": "Validation failed",
  "action_time": "2025-10-18T10:30:45",
  "data": {
    "planName": "Plan name is required",
    "apr": "must be between 0 and 36",
    "minDownPaymentPercent": "must be between 10 and 50"
  }
}

Forbidden - Not Shop Owner (403):

{
  "success": false,
  "httpStatus": "FORBIDDEN",
  "message": "You do not have permission to manage this shop's products",
  "action_time": "2025-10-18T10:30:45",
  "data": "You do not have permission to manage this shop's products"
}

Not Found - Product (404):

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Product not found",
  "action_time": "2025-10-18T10:30:45",
  "data": "Product not found"
}