Device profiles
A device profile (archetype in the API) is the exact iPhone model, iOS
version, and browser version that a session or saved profile is created with. Do not
hard-code a copied catalog: use this endpoint to populate selectors and
validate configuration. It is the same list the desktop app and dashboard
use.
List available device profiles
GET /v1/archetypes
No API key is required. Responses are cacheable for five minutes:
Cache-Control: public, max-age=300.
curl https://api.driftstack.dev/v1/archetypes
Response (200):
{
"default_archetype_id": "iphone15_ios18_7_safari26_5",
"data": [
{
"id": "iphone15_ios18_7_safari26_5",
"display_label": "iPhone 15 / iOS 18.7 / Safari 26.5",
"device": "iPhone 15",
"ios_version": "18.7",
"safari_version": "26.5",
"browser": "safari",
"browser_version": "26.5",
"status": "available",
"new_profiles": "open",
"is_default": false
}
]
}
Only customer-selectable entries are returned:
launch— selectable (the original launch device)available— selectable
Each entry says whether new profiles may use it:
new_profiles—openorclosed. A new profile (POST /v1/profiles, a copy, an import, a restore from a snapshot) or a session without a profile may name only anopendevice. Acloseddevice stays in the list because the profiles already on it keep it and keep running; naming it for a new one is refused with400(code: "device_closed_for_new_profiles"; see Errors). An entry withoutnew_profilesis from an older server: treat it asopen.
Each entry says which browser it runs:
browser— currentlysafariorchrome(Chrome for iPhone). Every entry today issafari. It is an open string: later versions may add values, andothermeans a browser this server cannot name yet. Treat a value you do not know as another browser, not as an error.browser_version— the version of that browser. On asafarientry it is the same value assafari_version("26.4"). On achromeentry it is the Chrome version (for example"149"). Anotherentry has none.safari_version— always a Safari release, on every entry. On achromeentry it is the Safari release that device’s iOS ships, which Chrome for iPhone is built on (for example"26.6"); it is never the Chrome version.
browser and browser_version were added after safari_version. A client
that does not read them keeps working. An entry without browser is from an
older server: treat an entry without browser as safari.
There is no default device. default_archetype_id and is_default are
deprecated: they stay in the response for clients that read them,
is_default is false on every entry, and default_archetype_id names one
model open for new profiles (null when none is open) but is not what a
create gets; ignore it. New profiles and sessions started without a device get a randomly chosen iPhone model from those your plan includes that are open for new profiles; you can also pick a model yourself. Open
means new_profiles is open in the list above.
A profile created without archetype keeps the model it gets, drawn
once. A session created without a profile or archetype runs as a
fresh visitor, a different model from session to session, weighted toward the
newest iOS; pass archetype to pin a device, or profile_id to keep an
identity between runs. The session’s
archetype and archetype_source (explicit, profile or random) say
what it got.
Every paid plan includes every device. The free trial includes the iPhone 13
and iPhone 13 mini only; any other device is refused with 403.
Direct session creation, profile creation, and profile import accept only an
id present in the current response. Any other id returns
400 ValidationFailed on the archetype field before anything is created.
Which devices can start right now
GET /v1/archetypes/availability
Requires an API key; it answers for the key’s own account. Never cached:
Cache-Control: private, no-store.
The list above says which devices you may choose; this says, right now,
whether a machine that runs sessions is running each one.
curl https://api.driftstack.dev/v1/archetypes/availability \
-H "Authorization: Bearer $DRIFTSTACK_API_KEY"
Response (200):
{
"data": [{ "id": "iphone15_ios18_7_safari26_5", "available_now": true }]
}
One row per entry of GET /v1/archetypes, in the same order:
available_now: true— a machine is running this device now.available_now: false— no machine is running it right now. A profile create (POST /v1/profiles,POST /v1/profiles/import) or a session create on it (POST /v1/sessions,POST /v1/profiles/{id}/launch,POST /v1/agent-sessions) is refused (after any device, plan or closed-device refusal) with409 device-unavailable,code: "archetype_not_served",retryable: true, and nothing is created. Choose another device, or try again later.available_now: null— not known right now (no machine is connected, one has not reported yet, or this check is not on for your account). A create goes ahead as usual.
A create that names no device is not given one whose available_now is
false while another device on your plan can start.
Generate a create payload from the live catalog
Resolve capabilities to an id at runtime instead of constructing or guessing a
slug. Match on browser as well as the versions: a chrome entry carries the
Safari release it is built on in safari_version, so a filter on
safari_version alone can match a Chrome entry. This helper can generate the body for either POST /v1/sessions or
POST /v1/profiles:
type ArchetypeFilter = {
id?: string;
device?: string;
ios_version?: string;
safari_version?: string;
// 'safari' unless you ask for another browser.
browser?: string;
};
async function archetypeCreatePayload(filter: ArchetypeFilter = {}) {
const requested = Object.entries(filter).filter(([, value]) => value !== undefined);
if (requested.length === 0) return {};
const response = await fetch('https://api.driftstack.dev/v1/archetypes');
if (!response.ok) throw new Error(`Catalog request failed: ${response.status}`);
const catalog = (await response.json()) as {
default_archetype_id: string | null; // deprecated: there is no default device
data: Array<{
id: string;
device: string;
ios_version: string;
safari_version: string;
browser?: string;
}>;
};
const matches = catalog.data.filter(
(entry) =>
(filter.id === undefined || entry.id === filter.id) &&
(filter.device === undefined || entry.device === filter.device) &&
(filter.ios_version === undefined || entry.ios_version === filter.ios_version) &&
(filter.safari_version === undefined || entry.safari_version === filter.safari_version) &&
// An entry without `browser` is from an older server: Safari.
(entry.browser ?? 'safari') === (filter.browser ?? 'safari'),
);
if (matches.length === 0) {
throw new Error('No currently selectable archetype matches those capabilities.');
}
if (matches.length > 1) {
throw new Error(
'More than one archetype matches. Add another capability or use an exact catalog id.',
);
}
return { archetype: matches[0]!.id };
}
const sessionBody = await archetypeCreatePayload({
device: 'iPhone 15',
ios_version: '18.7',
safari_version: '26.5',
});
If no capability filter is needed, omit archetype. New profiles and sessions started without a device get a randomly chosen iPhone model from those your plan includes that are open for new profiles; you can also pick a model yourself.
Existing stored profiles keep their pinned device profile
even if it later leaves the selectable catalog; compatibility operations on
those profiles remain available, but new direct creates and imports must choose
from the live response.
The route and its inline response schema are also published in
/openapi.json. Do not copy returned
IDs into a separate application constant; refresh the catalog after its
five-minute response lifetime.