POST
/v1/me/passkeysSend the attestation the platform returned, together with a name for it. The name is what the account will see in its own list of devices, so use something a person recognises months later.
The ceremony has to be the one this device started: the challenge is kept against the token, and it is gone after this call either way.
Request
curl -X POST https://api.proppertrading.com/v1/me/passkeys \
-H "Authorization: Bearer ptat_9f2c1a44_3b8e7d2f5c9a1b4e6d8f0a2c4e6b8d1f" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 1b8a6f0e-3c5d-4f7a-9e2b-0d4c6a8e1f30" \
-d '{
"name": "iPhone",
"id": "AQIDBA",
"rawId": "AQIDBA",
"type": "public-key",
"response": {
"clientDataJSON": "eyJ0eXBlIjoid2ViYX...",
"attestationObject": "o2NmbXRkbm9uZWdh..."
}
}'
| Field | Type | Description |
|---|---|---|
name | string | Up to 64 characters. Required |
id, rawId, type | string | From the platform, unchanged. Required |
response.clientDataJSON | string | From the platform, unchanged. Required |
response.attestationObject | string | From the platform, unchanged. Required |
Response
The passkey as the list shows it. Status is 201.
{
"data": {
"id": "890ad7f8-de78-4b88-b4b2-fc52715671e8",
"object": "passkey",
"name": "iPhone",
"is_enabled": true,
"created_at": "2026-08-20T09:12:44.000000Z",
"last_used_at": "2026-08-20T09:12:44.000000Z"
},
"meta": { "request_id": "req_01kz4bkr1aj1gv63d8fv3133ey" }
}
Errors
| Status | Code | Meaning |
|---|---|---|
| 400 | invalid_passkey | The attestation did not verify, or answered a challenge that is no longer live. Ask for options again |
| 403 | insufficient_scope | This device does not hold me:write |
| 422 | validation_failed | A field is missing or malformed |
One reason for every failure inside the ceremony
invalid_passkey covers a wrong origin, a spent challenge, a bad signature and
several other things. The distinctions are in our logs, because out here they
only help somebody who is guessing.