Login request
Call this from your backend when a user wants to log in. Touchque sends a push notification to their device.
POST/login/request
Body parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
externalUsername | string | — | User ID Required |
type | string | "LOGIN" | e.g. "LOGIN", "TRANSFER", "PAYMENT": an action type your workspace has defined (see Action types), or the answer is 400 unknown_action. Sent to AI Risk Engine for semantic analysis. Optional |
referenceId | string | null | Your tracking number Optional |
browserProof | string | null | Silent sign-ins: the browser's X-Touchque-Browser proof, passed through untouched. Once this request is approved on the phone, Touchque knows the browser. Optional |
Login request is valid for 30 seconds. After expiry it becomes
EXPIRED."Why?" case code. Every answer carries
caseCode (e.g. K7P-2QX): the 200 and each refusal (403 blocked and device_keys_lost, 423 frozen, 429 rate_limited). When a request is refused or asks for number matching, show it to the user ("Tell your support team: K7P-2QX"). Your team opens the decision in this dashboard under Logs → Look up a case: the reasons, each check and what would have let it through. A number-matching or passkey answer also carries plain reasons [{ code, text }].Request
const { Touchque } = require('@touchque/node');
const tq = new Touchque({
apiKey: 'tq_abc123',
apiSecret: 'YOUR_API_SECRET'
});
async function loginUser() {
// If you only want to send a request (using Callbacks):
const request = await tq.login.request({
externalUsername: 'user@yourcompany.com',
type: 'LOGIN'
});
console.log('Request ID:', request.requestId);
// ALTERNATIVE: Send request and wait for approval in one line (Polling):
/*
try {
const result = await tq.login.verify({
externalUsername: 'user@yourcompany.com',
type: 'LOGIN',
timeout: 30000,
// Number matching: show the number now; the phone asks for it
onChallenge: ({ challengeCode }) => { if (challengeCode) console.log('Pick', challengeCode, 'on your phone'); }
});
console.log('User approved!');
} catch (err) {
console.log('User rejected or timeout:', err.message);
}
*/
}
loginUser();<?php
require_once 'vendor/autoload.php';
use Touchque\Touchque;
use Touchque\Config;
$tq = new Touchque(new Config('tq_abc123', 'YOUR_API_SECRET'));
// If you only want to send a request (using Callbacks):
$request = $tq->login->request('user@yourcompany.com', 'LOGIN');
echo "Request ID: " . $request['requestId'] . "\n";
// ALTERNATIVE: Send request and wait for approval in one line (Polling):
/*
try {
// Number matching: show the number now; the phone asks for it
$result = $tq->login->verify('user@yourcompany.com', 'LOGIN', null, 30000, null, null, false, false, null, null,
function (array $c) { if (isset($c['challengeCode'])) echo "Pick {$c['challengeCode']} on your phone\n"; });
echo "User approved!";
} catch (\Exception $e) {
echo "User rejected or timeout: " . $e->getMessage();
}
*/package main
import (
"fmt"
"log"
"github.com/Touchque/touchque-go/v5/touchque"
)
func main() {
tq, err := touchque.New(touchque.DefaultConfig("tq_abc123", "YOUR_API_SECRET"))
if err != nil {
log.Fatal(err)
}
// If you only want to send a request (using Callbacks):
request, err := tq.Login.RequestWithOptions(touchque.LoginRequestOptions{
ExternalUsername: "user@yourcompany.com",
Type: "LOGIN",
})
if err != nil {
log.Fatal(err)
}
fmt.Println("Request ID:", request.RequestID)
// ALTERNATIVE: Send request and wait for approval in one line (Polling):
/*
// Number matching: show the number now; the phone asks for it
result, err := tq.Login.VerifyWithOptions(touchque.LoginRequestOptions{
ExternalUsername: "user@yourcompany.com", Type: "LOGIN",
OnChallenge: func(c touchque.VerifyChallenge) {
if c.ChallengeCode != "" { fmt.Println("Pick", c.ChallengeCode, "on your phone") }
},
}, 30000)
if err != nil {
log.Println("User rejected or timeout:", err)
} else {
fmt.Println("User approved!")
}
*/
}from touchque import Touchque, Config
tq = Touchque(Config(api_key="tq_abc123", api_secret="YOUR_API_SECRET"))
# If you only want to send a request (using Callbacks):
request = tq.login.request("user@yourcompany.com", "LOGIN")
print("Request ID:", request["requestId"])
# ALTERNATIVE: Send request and wait for approval in one line (Polling):
# try:
# # Number matching: show the number now; the phone asks for it
# result = tq.login.verify("user@yourcompany.com", "LOGIN",
# on_challenge=lambda c: c.get("challengeCode") and print("Pick", c["challengeCode"], "on your phone"))
# print("User approved!")
# except Exception as e:
# print(f"User rejected or timeout: {e}")using Touchque;
var tq = new TouchqueClient(new TouchqueOptions { ApiKey = "tq_abc123", ApiSecret = "YOUR_API_SECRET" });
// If you only want to send a request (using Callbacks):
var request = await tq.Login.RequestAsync("user@yourcompany.com", "LOGIN");
Console.WriteLine($"Request ID: {request.RequestId}");var tq = new TouchqueClient(new TouchqueOptions().apiKey("tq_abc123").apiSecret("YOUR_API_SECRET"));
// If you only want to send a request (using Callbacks):
Login.RequestResult request = tq.login().request("user@yourcompany.com");
System.out.println("Request ID: " + request.requestId());tq = Touchque::Client.new(api_key: "tq_abc123", api_secret: "YOUR_API_SECRET")
# If you only want to send a request (using Callbacks):
request = tq.login.request("user@yourcompany.com", type: "LOGIN")
puts "Request ID: #{request["requestId"]}"# 1) Generate signature
BODY='{"externalUsername": "user@yourcompany.com", "type": "LOGIN"}'
BODY_HASH=$(echo -n "$BODY" | openssl dgst -sha256 | awk '{print $2}')
TS=$(date +%s000)
NONCE=$(openssl rand -hex 16)
MSG="POST:/login/request:$TS:$NONCE:$BODY_HASH"
SIG=$(echo -n "$MSG" | openssl dgst -sha256 -hmac "YOUR_API_SECRET" | awk '{print $2}')
# 2) Send request
curl -X POST https://api.touchque.com/login/request \
-H "x-api-key: tq_abc123" \
-H "x-signature: $SIG" \
-H "x-timestamp: $TS" \
-H "x-nonce: $NONCE" \
-H "Content-Type: application/json" \
-d "$BODY"Response 200
{
"message": "Request sent",
"requestId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"caseCode": "K7P-2QX"
}