Start a session without an account
Proves with App Attest that the request comes from the switchfile app on a real device. A new key sends its attestation once; later tokens need an assertion of the same key. The token converts files with the free files of the day of this device. Buying credits needs an account.
POST
https://api.switchfile.io/v1/app/guestExample
Request
curl "https://api.switchfile.io/v1/app/guest" \
-H "Content-Type: application/json" \
-d '{
"key_id": "kWQ0m6p1y4s3Vb2n8c7x5z9A0Bq1Cw2Dv3Eu4Ft5Gs8=",
"challenge": "1763116800.q8Jx2v3mQ0yS6nB1kR9tLw.Wm9vYmFyYmF6cXV4",
"attestation": "o2NmbXRvYXBwbGUtYXBwYXR0ZXN0…"
}'const res = await fetch("https://api.switchfile.io/v1/app/guest", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
key_id: "kWQ0m6p1y4s3Vb2n8c7x5z9A0Bq1Cw2Dv3Eu4Ft5Gs8=",
challenge: "1763116800.q8Jx2v3mQ0yS6nB1kR9tLw.Wm9vYmFyYmF6cXV4",
attestation: "o2NmbXRvYXBwbGUtYXBwYXR0ZXN0…"
}),
});
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
console.log(await res.json());<?php
$ch = curl_init('https://api.switchfile.io/v1/app/guest');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode([
'key_id' => 'kWQ0m6p1y4s3Vb2n8c7x5z9A0Bq1Cw2Dv3Eu4Ft5Gs8=',
'challenge' => '1763116800.q8Jx2v3mQ0yS6nB1kR9tLw.Wm9vYmFyYmF6cXV4',
'attestation' => 'o2NmbXRvYXBwbGUtYXBwYXR0ZXN0…',
]),
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
],
CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($status >= 400) {
throw new RuntimeException("HTTP $status: $response");
}
print_r(json_decode($response, true));import requests
res = requests.post(
"https://api.switchfile.io/v1/app/guest",
json={
"key_id": "kWQ0m6p1y4s3Vb2n8c7x5z9A0Bq1Cw2Dv3Eu4Ft5Gs8=",
"challenge": "1763116800.q8Jx2v3mQ0yS6nB1kR9tLw.Wm9vYmFyYmF6cXV4",
"attestation": "o2NmbXRvYXBwbGUtYXBwYXR0ZXN0…",
},
)
res.raise_for_status()
print(res.json())Request body
assertionstringAssertion of a key that was attested before (base64)
1 to 6000 characters
attestationstringAttestation object for a new key (base64). Send it once per key.
1 to 22000 characters
challengestringrequired1 to 200 characters
key_idstringrequiredKey identifier from DCAppAttestService (base64)
40 to 64 characters
Responses
200OK
access_tokenstringrequiredBearer token for conversions without an account. The free files of the day count per device.
expires_instring (integer) | integerrequiredSeconds until the token expires. Ask for a new one with an assertion.
token_typestringrequiredone of "Bearer"
200 application/json{ "access_token": "sfgt_6f1c0b2e-8d4a-4c7b-9e3f-2a1d5c8b7e60.1763721600.c2lnbmF0dXJl", "token_type": "Bearer", "expires_in": 604800 }400The challenge has expired or was not issued by us
INVALID_CHALLENGE400 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-invalid-challenge", "title": "Invalid challenge", "status": 400, "code": "INVALID_CHALLENGE", "detail": "The challenge has expired. Request a new one." }401App Attest could not verify the device, or the key is not registered
ATTESTATION_FAILED401 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-attestation-failed", "title": "Attestation failed", "status": 401, "code": "ATTESTATION_FAILED", "detail": "We couldn't verify this device. Try again or sign in." }403This device can only use the app with an account
DEVICE_BLOCKED403 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-device-blocked", "title": "Device blocked", "status": 403, "code": "DEVICE_BLOCKED", "detail": "This device can't use the app without an account. Sign in to continue." }409The key was attested before; send an assertion
DEVICE_ALREADY_ATTESTED409 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-device-already-attested", "title": "Device already attested", "status": 409, "code": "DEVICE_ALREADY_ATTESTED", "detail": "This key is already registered. Send an assertion instead." }422Invalid data. errors names the fields
INVALID_DATA422 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-invalid-data", "title": "Invalid data", "status": 422, "code": "INVALID_DATA", "detail": "The request contains invalid data.", "errors": { "to": [ "Expected string" ] } }429Too many requests, or too many new devices from one network on one day
TOO_MANY_DEVICES429 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-too-many-devices", "title": "Too many devices", "status": 429, "code": "TOO_MANY_DEVICES", "detail": "Too many new devices from this network today. Sign in to continue." }503Not available right now or busy. See Retry-After
GUEST_UNAVAILABLE503 application/problem+json{ "type": "https://switchfile.io/docs/api/v1#errors-guest-unavailable", "title": "Guest unavailable", "status": 503, "code": "GUEST_UNAVAILABLE", "detail": "Using the app without an account isn't available yet. Sign in to continue." }