Batch Enroll Verified Authenticators
Enroll multiple authenticators across multiple users in a single request. This endpoint is idempotent — re-enrolling the same credential for the same user is a no-op. Each item is processed independently; failures do not affect other items in the batch.
curl --request POST \
--url https://api.authsignal.com/v1/users/authenticators \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"authenticators": [
{
"userId": "user-123",
"verificationMethod": "PASSKEY",
"credentialId": "dGVzdC1jcmVkZW50aWFsLWlk",
"credentialPublicKey": "pQECAyYgASFYIPr...",
"name": "iPhone"
},
{
"userId": "user-456",
"verificationMethod": "PASSKEY",
"credentialId": "YW5vdGhlci1jcmVkZW50aWFs",
"credentialPublicKey": "pQECAyYgASFYIKm..."
}
]
}
'import requests
url = "https://api.authsignal.com/v1/users/authenticators"
payload = { "authenticators": [
{
"userId": "user-123",
"verificationMethod": "PASSKEY",
"credentialId": "dGVzdC1jcmVkZW50aWFsLWlk",
"credentialPublicKey": "pQECAyYgASFYIPr...",
"name": "iPhone"
},
{
"userId": "user-456",
"verificationMethod": "PASSKEY",
"credentialId": "YW5vdGhlci1jcmVkZW50aWFs",
"credentialPublicKey": "pQECAyYgASFYIKm..."
}
] }
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
authenticators: [
{
userId: 'user-123',
verificationMethod: 'PASSKEY',
credentialId: 'dGVzdC1jcmVkZW50aWFsLWlk',
credentialPublicKey: 'pQECAyYgASFYIPr...',
name: 'iPhone'
},
{
userId: 'user-456',
verificationMethod: 'PASSKEY',
credentialId: 'YW5vdGhlci1jcmVkZW50aWFs',
credentialPublicKey: 'pQECAyYgASFYIKm...'
}
]
})
};
fetch('https://api.authsignal.com/v1/users/authenticators', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.authsignal.com/v1/users/authenticators",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'authenticators' => [
[
'userId' => 'user-123',
'verificationMethod' => 'PASSKEY',
'credentialId' => 'dGVzdC1jcmVkZW50aWFsLWlk',
'credentialPublicKey' => 'pQECAyYgASFYIPr...',
'name' => 'iPhone'
],
[
'userId' => 'user-456',
'verificationMethod' => 'PASSKEY',
'credentialId' => 'YW5vdGhlci1jcmVkZW50aWFs',
'credentialPublicKey' => 'pQECAyYgASFYIKm...'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.authsignal.com/v1/users/authenticators"
payload := strings.NewReader("{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.authsignal.com/v1/users/authenticators")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.authsignal.com/v1/users/authenticators")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"total": 3,
"succeeded": 2,
"failed": 1,
"failures": [
{
"userId": "user-789",
"credentialId": "Y29uZmxpY3RpbmctY3JlZA",
"errorCode": "conflict",
"errorDescription": "Credential already exists for a different user."
}
]
}{
"error": "<string>",
"errorDescription": "<string>"
}{
"error": "<string>",
"errorDescription": "<string>"
}Authorizations
Use your Authsignal Server API secret key as the username and leave the password empty. The secret key can be found in the API Keys section of the Authsignal Portal settings page.
Body
An array of authenticator items to enroll. Maximum 1000 items per request.
1000Show child attributes
Show child attributes
Response
OK
The total number of items in the request.
The number of authenticators successfully enrolled.
The number of items that failed to enroll.
A list of items that failed to enroll, with per-item error details. Empty when all items succeed.
Show child attributes
Show child attributes
Was this page helpful?
curl --request POST \
--url https://api.authsignal.com/v1/users/authenticators \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"authenticators": [
{
"userId": "user-123",
"verificationMethod": "PASSKEY",
"credentialId": "dGVzdC1jcmVkZW50aWFsLWlk",
"credentialPublicKey": "pQECAyYgASFYIPr...",
"name": "iPhone"
},
{
"userId": "user-456",
"verificationMethod": "PASSKEY",
"credentialId": "YW5vdGhlci1jcmVkZW50aWFs",
"credentialPublicKey": "pQECAyYgASFYIKm..."
}
]
}
'import requests
url = "https://api.authsignal.com/v1/users/authenticators"
payload = { "authenticators": [
{
"userId": "user-123",
"verificationMethod": "PASSKEY",
"credentialId": "dGVzdC1jcmVkZW50aWFsLWlk",
"credentialPublicKey": "pQECAyYgASFYIPr...",
"name": "iPhone"
},
{
"userId": "user-456",
"verificationMethod": "PASSKEY",
"credentialId": "YW5vdGhlci1jcmVkZW50aWFs",
"credentialPublicKey": "pQECAyYgASFYIKm..."
}
] }
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
authenticators: [
{
userId: 'user-123',
verificationMethod: 'PASSKEY',
credentialId: 'dGVzdC1jcmVkZW50aWFsLWlk',
credentialPublicKey: 'pQECAyYgASFYIPr...',
name: 'iPhone'
},
{
userId: 'user-456',
verificationMethod: 'PASSKEY',
credentialId: 'YW5vdGhlci1jcmVkZW50aWFs',
credentialPublicKey: 'pQECAyYgASFYIKm...'
}
]
})
};
fetch('https://api.authsignal.com/v1/users/authenticators', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.authsignal.com/v1/users/authenticators",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'authenticators' => [
[
'userId' => 'user-123',
'verificationMethod' => 'PASSKEY',
'credentialId' => 'dGVzdC1jcmVkZW50aWFsLWlk',
'credentialPublicKey' => 'pQECAyYgASFYIPr...',
'name' => 'iPhone'
],
[
'userId' => 'user-456',
'verificationMethod' => 'PASSKEY',
'credentialId' => 'YW5vdGhlci1jcmVkZW50aWFs',
'credentialPublicKey' => 'pQECAyYgASFYIKm...'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.authsignal.com/v1/users/authenticators"
payload := strings.NewReader("{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.authsignal.com/v1/users/authenticators")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.authsignal.com/v1/users/authenticators")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"authenticators\": [\n {\n \"userId\": \"user-123\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"dGVzdC1jcmVkZW50aWFsLWlk\",\n \"credentialPublicKey\": \"pQECAyYgASFYIPr...\",\n \"name\": \"iPhone\"\n },\n {\n \"userId\": \"user-456\",\n \"verificationMethod\": \"PASSKEY\",\n \"credentialId\": \"YW5vdGhlci1jcmVkZW50aWFs\",\n \"credentialPublicKey\": \"pQECAyYgASFYIKm...\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"total": 3,
"succeeded": 2,
"failed": 1,
"failures": [
{
"userId": "user-789",
"credentialId": "Y29uZmxpY3RpbmctY3JlZA",
"errorCode": "conflict",
"errorDescription": "Credential already exists for a different user."
}
]
}{
"error": "<string>",
"errorDescription": "<string>"
}{
"error": "<string>",
"errorDescription": "<string>"
}
