Action types
An action type names what a person is asked to approve: LOGIN for a sign-in, SEND_MONEY for a transfer, or any name you choose. The phone shows its name and description. Every login request and every SDK guard names one, and Touchque refuses a type your workspace has not defined.
Define it first. A new workspace has no action types, not even
LOGIN. Until a type is defined, every request that names it, and every guard such as requireTouchque('SEND_MONEY'), gets 400 unknown_action.Where to define them
- In the dashboard: Developers → Action types. You can also turn a type off there; a define call from code never turns it back on.
- From your server at start-up:
actionTypes.definein every SDK, orPOST /action-types. It is safe to call on every start: it never turns on a type an admin turned off, and changescritical,descriptionandsecondThoughtonly when you send them. - From an AI coding assistant: the Touchque MCP's
touchque_define_action_type, which asks you before it creates one.
Fields
| Field | Meaning |
|---|---|
type | The ID you pass as type: 1 to 64 letters, digits and _ . : - (e.g. LOGIN, SEND_MONEY). Required. |
name | Shown on the phone and in the dashboard. Required. |
description | A line under the name on the phone. |
critical | The phone asks for number matching on every approval. Time-based codes are refused, and offline sign needs its own opt-in in App user policy. |
secondThought | Up to two yes/no questions the phone asks before Approve, for actions people get talked into ("Is someone on a call telling you to do this?"). A risky answer does not refuse: the approval comes back provisional. |
active | Dashboard only. A request with an inactive type gets 403 action_disabled. |
Guards use the type you name.
requireTouchque('SEND_MONEY') (Node), @require_touchque('SEND_MONEY') (Python), ->middleware('touchque:SEND_MONEY') (Laravel) and touchque.Require(tq, "SEND_MONEY", …) (Go) all send SEND_MONEY as the type.const { Touchque } = require('@touchque/node');
const tq = new Touchque(); // TQ_API_KEY / TQ_API_SECRET from the environment
// At start-up: creates or updates (never turns on one an admin turned off)
await tq.actionTypes.define('LOGIN', { name: 'Sign in' });
await tq.actionTypes.define('SEND_MONEY', { name: 'Send money', description: 'A transfer from your account', critical: true });
const types = await tq.actionTypes.list();from touchque import Touchque
tq = Touchque() # TQ_API_KEY / TQ_API_SECRET from the environment
# At start-up: creates or updates (never turns on one an admin turned off)
tq.action_types.define("LOGIN", name="Sign in")
tq.action_types.define("SEND_MONEY", name="Send money", description="A transfer from your account", critical=True)
types = tq.action_types.list()$tq = new \Touchque\Touchque(); // TQ_API_KEY / TQ_API_SECRET from the environment
// At start-up: creates or updates (never turns on one an admin turned off)
$tq->actionTypes->define('LOGIN', 'Sign in');
$tq->actionTypes->define('SEND_MONEY', 'Send money', 'A transfer from your account', true);
$types = $tq->actionTypes->list();tq, err := touchque.New() // TQ_API_KEY / TQ_API_SECRET from the environment
if err != nil {
log.Fatal(err)
}
// At start-up: creates or updates (never turns on one an admin turned off)
_, err = tq.ActionTypes.Define("LOGIN", touchque.DefineOptions{Name: "Sign in"})
critical := true
_, err = tq.ActionTypes.Define("SEND_MONEY", touchque.DefineOptions{Name: "Send money", Description: "A transfer from your account", Critical: &critical})
types, err := tq.ActionTypes.List()var tq = new TouchqueClient(); // TQ_API_KEY / TQ_API_SECRET from the environment
// At start-up: creates or updates (never turns on one an admin turned off)
await tq.ActionTypes.DefineAsync("LOGIN", "Sign in");
await tq.ActionTypes.DefineAsync("SEND_MONEY", "Send money", "A transfer from your account", critical: true);
var types = await tq.ActionTypes.ListAsync();var tq = new TouchqueClient(); // TQ_API_KEY / TQ_API_SECRET from the environment
// At start-up: creates or updates (never turns on one an admin turned off)
tq.actionTypes().define("LOGIN", "Sign in", false);
tq.actionTypes().define("SEND_MONEY", "Send money", "A transfer from your account", true, null);
JsonNode types = tq.actionTypes().list();tq = Touchque::Client.new # TQ_API_KEY / TQ_API_SECRET from the environment
# At start-up: creates or updates (never turns on one an admin turned off)
tq.action_types.define("LOGIN", name: "Sign in")
tq.action_types.define("SEND_MONEY", name: "Send money", description: "A transfer from your account", critical: true)
types = tq.action_types.list# Signed requests (HMAC), see Authentication
POST /action-types
{ "type": "SEND_MONEY", "name": "Send money", "description": "A transfer from your account", "critical": true }
→ { "id": "…", "type": "SEND_MONEY", "name": "Send money", "description": "A transfer from your account", "critical": true, "active": true, "secondThought": null }
GET /action-types
→ [ { "type": "LOGIN", … }, { "type": "SEND_MONEY", … } ]