Verify SMS PIN

Verify the SMS PIN to authorize a transfer. This endpoint validates the PIN sent to the player's phone and, upon success, generates a claim code that can be shared with the intended recipient.

POST

/api/transfers/verify-sms

Verifies the SMS PIN and authorizes the transfer

Authentication Required

Must include the same game secret key used to initiate the transfer:

X-Game-Secret-Key: your_game_secret_key_here

Request Body Parameters

ParameterTypeRequiredDescription
transaction_idstringYesTransaction ID returned from initiate-transfer
sms_pinstringYes6-digit PIN received via SMS

SMS PIN Requirements

PIN Format

  • • 6-digit numeric code
  • • Case-sensitive (numbers only)
  • • Unique per transfer attempt
  • • One-time use only

Time Limits

  • • PIN expires in 10 minutes
  • • Maximum 3 verification attempts
  • • Failed attempts count toward rate limits
  • • Expired PINs cannot be reused

Implementation Examples

UnityUnity C# SMS Verification

// This function MUST be called on your secure server, NOT the client.
public IEnumerator VerifySMSPin(string transactionId, string smsPin, 
    Action<string> onSuccess, Action<string> onError)
{
    string url = "https://invo.network/api/transfers/verify-sms";
    
    var requestData = new {
        transaction_id = transactionId,
        sms_pin = smsPin
    };
    string jsonBody = JsonUtility.ToJson(requestData);

    using (UnityWebRequest request = new UnityWebRequest(url, "POST"))
    {
        byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(jsonBody);
        request.uploadHandler = new UploadHandlerRaw(bodyRaw);
        request.downloadHandler = new DownloadHandlerBuffer();
        
        request.SetRequestHeader("X-Game-Secret-Key", "your_game_secret_key_here");
        request.SetRequestHeader("Content-Type", "application/json");

        yield return request.SendWebRequest();

        if (request.result == UnityWebRequest.Result.Success)
        {
            onSuccess?.Invoke(request.downloadHandler.text);
        }
        else
        {
            onError?.Invoke(request.error + ": " + request.downloadHandler.text);
        }
    }
}

UnrealUnreal C++ SMS Verification

// This function MUST be called on your secure server.
void AYourGameMode::VerifySMSPin(const FString& TransactionId, const FString& SMSPin)
{
    TSharedPtr<FJsonObject> RequestObj = MakeShareable(new FJsonObject);
    RequestObj->SetStringField("transaction_id", TransactionId);
    RequestObj->SetStringField("sms_pin", SMSPin);

    FString RequestBody;
    TSharedRef<TJsonWriter<>> Writer = TJsonWriterFactory<>::Create(&RequestBody);
    FJsonSerializer::Serialize(RequestObj.ToSharedRef(), Writer);

    TSharedRef<IHttpRequest> Request = FHttpModule::Get().CreateRequest();
    Request->SetURL("https://invo.network/api/transfers/verify-sms");
    Request->SetVerb("POST");
    Request->SetHeader("X-Game-Secret-Key", "your_game_secret_key_here");
    Request->SetHeader("Content-Type", "application/json");
    Request->SetContentAsString(RequestBody);
    
    Request->OnProcessRequestComplete().BindUObject(this, &AYourGameMode::OnSMSVerified);
    Request->ProcessRequest();
}

GodotGodot GDScript SMS Verification

# This function MUST be called on your secure server.
func verify_sms_pin(transaction_id: String, sms_pin: String):
    var url = "https://invo.network/api/transfers/verify-sms"
    var headers = [
        "X-Game-Secret-Key: your_game_secret_key_here",
        "Content-Type: application/json"
    ]
    var body = {
        "transaction_id": transaction_id,
        "sms_pin": sms_pin
    }
    
    http_request.request(url, headers, HTTPClient.METHOD_POST, JSON.stringify(body))

Request & Response Examples

Example Request

POST /api/transfers/verify-sms
Content-Type: application/json
X-Game-Secret-Key: your_game_secret_key_here

{
  "transaction_id": "txn_abc123def456",
  "sms_pin": "123456"
}

Guardian-approval-aware responses

If the original transaction was initiated by a minor account, this endpoint may return:

  • 202 GUARDIAN_APPROVAL_PENDING — guardian hasn't replied yet. The same call succeeds normally once approval lands; just keep polling.
  • 410 GUARDIAN_APPROVAL_REJECTED or GUARDIAN_APPROVAL_EXPIRED — terminal. Show a clear message; user must re-initiate.

Full state machine: Guardian Approval.

Success Response (200 OK)

{
  "status": "success",
  "message": "SMS verification successful. Transfer is now pending claim by receiver.",
  "transaction_id": "txn_abc123def456",
  "claim_code": "KJMRS-47281",
  "claim_instructions": {
    "message": "Provide this claim code to the intended receiver.",
    "target_game_id": "42",
    "target_game_name": "Space Warriors",
    "claim_code_expires_at": "2024-06-25T14:30:00Z"
  },
  "transfer_summary": {
    "amount_initiated": "500.00",
    "net_amount_for_claim": "450.00",
    "fees_deducted": "50.00",
    "source_player_current_available_balance": "750.00"
  },
  "order_id": "TFRO_1719235200_A1B2C3D4"
}

Error Response - Invalid PIN (400 Bad Request)

{
  "status": "error",
  "message": "Invalid SMS PIN.",
  "attempts_remaining": 2
}

Error Response - Expired PIN (400 Bad Request)

{
  "status": "error",
  "message": "SMS PIN is not valid: PIN expired."
}

Error Response - Rate Limited (429 Too Many Requests)

{
  "error": "sms_verification_blocked",
  "message": "Too many SMS verification attempts. Please try again in 1 hour.",
  "retry_after": 3600
}

What Happens After Successful Verification

Claim Code Generated

A unique claim code is generated and included in the response. This code is also sent via SMS to the sender for easy sharing.

"Your Invo transfer to Space Warriors claim code is KJMRS-47281. Valid for 24 hours. Our employees will never ask you for this code."

Transfer Status Updated

The transfer status changes from "pending_pin_verification" to "pending_claim". The funds remain reserved in the sender's account until the transfer is either claimed or expires.

24-Hour Claim Window

The recipient has 24 hours to claim the transfer using the claim code. If not claimed within this time, the transfer expires and the net amount (minus fees) is automatically returned to the sender's balance.

Security Features

PIN Protection

  • • Hashed storage - PINs never stored in plain text
  • • Limited attempts - Maximum 3 verification tries
  • • Time-based expiry - 10 minute validity window
  • • One-time use - PIN becomes invalid after successful verification

Rate Limiting

  • • 40 verification attempts per hour per player
  • • 20 attempts per minute per transaction
  • • 200 attempts per hour per IP address
  • • Failed attempts trigger progressive blocking

Fraud Detection

  • • SMS verification spam detection
  • • Invalid PIN attempt tracking
  • • IP-based suspicious activity monitoring
  • • Automatic blocking for repeated failures

Transaction Integrity

  • • Funds remain reserved during verification
  • • Automatic cleanup of expired transactions
  • • Comprehensive audit trail
  • • Circuit breaker for service protection

Common Error Scenarios

HTTP 400 - Bad Request

  • Invalid SMS PIN: PIN doesn't match or has wrong format
  • PIN expired: More than 10 minutes have passed since initiation
  • Max attempts reached: 3 incorrect PIN attempts used up
  • Missing parameters: transaction_id or sms_pin not provided
  • Wrong transfer state: Transfer not in pending_pin_verification status

HTTP 404 - Not Found

  • Transaction not found: Invalid transaction_id or wrong game
  • Unauthorized access: Game secret key doesn't match transfer source

HTTP 429 - Too Many Requests

  • SMS verification spam: Too many verification attempts from player
  • Transaction rate limit: Too many attempts for specific transaction
  • IP rate limit: Too many requests from the same network
  • Invalid PIN blocking: Player blocked due to repeated invalid PINs

HTTP 500 - Server Error

  • Database connectivity: Temporary database issues
  • SMS service error: Unable to send claim code SMS
  • Circuit breaker open: Service temporarily unavailable

Implementation Best Practices

User Experience

  • • Display remaining attempts when PIN verification fails
  • • Show countdown timer for PIN expiration
  • • Provide clear error messages for different failure scenarios
  • • Allow users to request a new transfer if PIN expires

Error Handling

  • • Parse error responses to show appropriate user messages
  • • Handle rate limiting with retry logic and user feedback
  • • Implement exponential backoff for server errors
  • • Log all API responses for debugging and monitoring

Security

  • • Never log or store SMS PINs in your application
  • • Validate PIN format on client side before sending
  • • Clear PIN input fields after submission
  • • Use HTTPS for all API communications

Claim Code Sharing

  • • Display claim code prominently after successful verification
  • • Provide easy copy-to-clipboard functionality
  • • Show target game name and expiration time clearly
  • • Consider QR code generation for mobile sharing