Skip to main content

Internal Transfer Workflow

This guide shows you how to create transfer recommendations, approve them, and execute the transfers.

Prerequisites

  • API Key: Valid API key with appropriate permissions:
    • transfers.read for viewing recommendations
    • transfers.write for generating recommendations
    • transfers.approve for approving recommendations
    • transfers.execute for executing transfers
  • Organization Access: Access to your organization’s transfer features
  • Location IDs: Source and destination location IDs

Step-by-Step Guide

Step 1: Generate Transfer Recommendations

Generate transfer recommendations based on stock imbalances. Request:
curl -X POST "https://app.betterdata.co/api/transfers/recommendations" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "locationId": "loc_123",
    "minStockDifferencePct": 0.2,
    "requirePositiveROI": true,
    "unitMargin": 10.00
  }'
Response:
{
  "success": true,
  "created": 5,
  "recommendations": [
    {
      "id": "rec_123",
      "productMasterId": "prod_123",
      "sourceLocationId": "loc_123",
      "destLocationId": "loc_456",
      "quantity": 50,
      "priority": "HIGH",
      "status": "PENDING",
      "reason": "High stock at source (200 units), low stock at destination (20 units)",
      "estimatedROI": 0.15,
      "createdAt": "2024-03-01T00:00:00Z"
    }
  ]
}
Notes:
  • Min Stock Difference: Minimum percentage difference to trigger recommendation (0-1)
  • Positive ROI: Only generate recommendations with positive return on investment
  • Unit Margin: Profit margin per unit for ROI calculation
  • Priority: Automatically calculated based on stock levels and urgency

Step 2: List Pending Recommendations

Retrieve pending recommendations that need approval. Request:
curl -X GET "https://app.betterdata.co/api/transfers/recommendations/pending" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"
Response:
{
  "recommendations": [
    {
      "id": "rec_123",
      "productMasterId": "prod_123",
      "sourceLocationId": "loc_123",
      "destLocationId": "loc_456",
      "quantity": 50,
      "priority": "HIGH",
      "status": "PENDING",
      "reason": "High stock at source, low stock at destination",
      "estimatedROI": 0.15,
      "createdAt": "2024-03-01T00:00:00Z"
    }
  ],
  "total": 5,
  "limit": 50,
  "offset": 0
}
Alternative: Filter by Status
curl -X GET "https://app.betterdata.co/api/transfers/recommendations?status=PENDING&priority=URGENT" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"

Step 3: Get Recommendation Details

Get detailed information about a specific recommendation. Request:
curl -X GET "https://app.betterdata.co/api/transfers/recommendations/rec_123" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json"
Response:
{
  "id": "rec_123",
  "productMasterId": "prod_123",
  "productName": "Product Name",
  "sourceLocationId": "loc_123",
  "sourceLocationName": "Main Warehouse",
  "destLocationId": "loc_456",
  "destLocationName": "Store Front",
  "quantity": 50,
  "priority": "HIGH",
  "status": "PENDING",
  "reason": "High stock at source (200 units), low stock at destination (20 units)",
  "estimatedROI": 0.15,
  "sourceStock": 200,
  "destStock": 20,
  "createdAt": "2024-03-01T00:00:00Z"
}

Step 4: Approve Recommendation

Approve a transfer recommendation. Request:
curl -X POST "https://app.betterdata.co/api/transfers/recommendations/rec_123/approve" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "Approved for immediate transfer"
  }'
Response:
{
  "success": true,
  "recommendation": {
    "id": "rec_123",
    "status": "APPROVED",
    "approvedAt": "2024-03-01T12:00:00Z",
    "approvedBy": "user_123",
    "comment": "Approved for immediate transfer"
  }
}
Notes:
  • Approval Required: Recommendations must be approved before execution
  • Comment Optional: Include a comment explaining approval decision
  • Role Required: Requires ADMIN or MANAGER role

Step 5: Execute Transfer

Execute an approved transfer recommendation. Request:
curl -X POST "https://app.betterdata.co/api/transfers/recommendations/rec_123/execute" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "shipmentDate": "2024-03-02T00:00:00Z",
    "expectedDeliveryDate": "2024-03-03T00:00:00Z",
    "carrier": "Internal Transfer",
    "trackingNumber": "TRANSFER-123"
  }'
Response:
{
  "success": true,
  "transfer": {
    "id": "transfer_123",
    "recommendationId": "rec_123",
    "status": "EXECUTED",
    "shipmentId": "ship_123",
    "executedAt": "2024-03-01T12:30:00Z",
    "executedBy": "user_123"
  }
}
Notes:
  • Status Check: Only APPROVED recommendations can be executed
  • Shipment Creation: Execution creates a shipment record
  • Inventory Update: Inventory is updated when shipment is received

Step 6: Reject Recommendation (Alternative)

If a recommendation shouldn’t be executed, reject it. Request:
curl -X POST "https://app.betterdata.co/api/transfers/recommendations/rec_123/reject" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "comment": "Stock levels acceptable, no transfer needed"
  }'
Response:
{
  "success": true,
  "recommendation": {
    "id": "rec_123",
    "status": "REJECTED",
    "rejectedAt": "2024-03-01T12:00:00Z",
    "rejectedBy": "user_123",
    "comment": "Stock levels acceptable, no transfer needed"
  }
}

Complete Example

Here’s a complete workflow example:
#!/bin/bash

API_KEY="YOUR_API_KEY"
BASE_URL="https://app.betterdata.co/api"

# Step 1: Generate recommendations
echo "Generating transfer recommendations..."
RECOMMENDATIONS_RESPONSE=$(curl -s -X POST "${BASE_URL}/transfers/recommendations" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{
    "minStockDifferencePct": 0.2,
    "requirePositiveROI": true
  }')

CREATED=$(echo $RECOMMENDATIONS_RESPONSE | jq -r '.created')
echo "Created ${CREATED} recommendations"

# Step 2: Get pending recommendations
echo "Fetching pending recommendations..."
PENDING_RESPONSE=$(curl -s -X GET "${BASE_URL}/transfers/recommendations/pending" \
  -H "Authorization: Bearer ${API_KEY}" \
  -H "Content-Type: application/json")

# Step 3: Process each recommendation
echo $PENDING_RESPONSE | jq -r '.recommendations[] | @json' | while read rec; do
  REC_ID=$(echo $rec | jq -r '.id')
  PRIORITY=$(echo $rec | jq -r '.priority')
  QUANTITY=$(echo $rec | jq -r '.quantity')
  
  echo "Processing recommendation ${REC_ID} (Priority: ${PRIORITY}, Qty: ${QUANTITY})"
  
  # Step 4: Approve if high priority
  if [ "$PRIORITY" = "URGENT" ] || [ "$PRIORITY" = "HIGH" ]; then
    echo "  Approving recommendation..."
    APPROVE_RESPONSE=$(curl -s -X POST "${BASE_URL}/transfers/recommendations/${REC_ID}/approve" \
      -H "Authorization: Bearer ${API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "comment": "Auto-approved high priority transfer"
      }')
    
    # Step 5: Execute immediately
    echo "  Executing transfer..."
    EXECUTE_RESPONSE=$(curl -s -X POST "${BASE_URL}/transfers/recommendations/${REC_ID}/execute" \
      -H "Authorization: Bearer ${API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "carrier": "Internal Transfer"
      }')
    
    TRANSFER_ID=$(echo $EXECUTE_RESPONSE | jq -r '.transfer.id')
    echo "  Transfer executed: ${TRANSFER_ID}"
  else
    echo "  Skipping - not high priority"
  fi
done

Idempotency Notes

  • Generate Recommendations: Generating recommendations multiple times may create duplicates. Check for existing recommendations before generating.
  • Approve/Reject: Approving or rejecting a recommendation is idempotent - subsequent calls return the same result.
  • Execute: Executing a recommendation creates a transfer/shipment. Multiple executions will create multiple transfers (not idempotent). Check status before executing.

Pagination Notes

  • List Recommendations: Supports pagination with limit and offset (default: 50, max: 100).
  • Pending Recommendations: Returns all pending recommendations (may require pagination for large datasets).

Common Issues

Recommendations Not Generated

Symptom: No recommendations returned despite stock imbalances. Solutions:
  1. Verify minStockDifferencePct threshold is appropriate
  2. Check that requirePositiveROI isn’t filtering out valid recommendations
  3. Ensure source and destination locations have sufficient stock difference
  4. Verify locations are active and accessible

Cannot Approve Recommendation

Symptom: Error when trying to approve recommendation. Solutions:
  1. Verify recommendation status is PENDING
  2. Check user has ADMIN or MANAGER role
  3. Ensure API key has transfers.approve permission
  4. Verify recommendation hasn’t expired

Execution Fails

Symptom: Error when executing transfer. Solutions:
  1. Verify recommendation status is APPROVED (not PENDING or REJECTED)
  2. Check source location has sufficient stock
  3. Ensure destination location is active
  4. Verify shipment date is in the future


Permissions & Roles

Transfer workflow requires different permissions for each step:
  • Generate: ADMIN, MANAGER, or PLANNER role
  • Approve: ADMIN or MANAGER role
  • Execute: ADMIN or MANAGER role