PersonaHub Automation API

Use PersonaHub's local HTTP API to manage profiles, proxies, fingerprints, and website credentials, then launch browsers and connect over CDP for web automation.

The PersonaHub automation API lets you create and manage profiles, configure proxies and fingerprints, manage saved website credentials, and launch or close profile browsers.

Reading pages, clicking, typing, and taking screenshots require CDP or a compatible automation tool after the browser starts.

1. Before you start

  1. Open the PersonaHub desktop app and sign in.
  2. Enable the API in the app's automation settings, copy the API key, and check the port.
  3. Make sure the browser engine is ready before launching a profile.
  4. Keep the app running, signed in, and connected to the internet while using the API.

The API can only access the signed-in account's profiles. Profile creation is subject to the account's quota.

SettingDefault
HTTP base URLhttp://127.0.0.1:43110
Automation serverDisabled
Listen address127.0.0.1; changes to 0.0.0.0 when remote access is enabled
Port range1–65535, configurable in settings

For remote access, replace 127.0.0.1 with the address of the computer running PersonaHub. Browsers, debugging ports, and returned file paths belong to that computer.

2. Conventions

2.1 Authentication

Every request except GET /health requires:

Authorization: Bearer <API_KEY>

For requests with a body, also send:

Content-Type: application/json

The API key does not replace account sign-in or grant additional account permissions.

2.2 Requests and responses

  • Request bodies must be JSON objects, not arrays, strings, or null.
  • Request bodies are limited to 256 KiB. An oversized request may have its connection closed directly.
  • All successful endpoints listed here return 200, including creation and deletion.
  • Responses use JSON and include Cache-Control: no-store.
  • Profile and credential path IDs are UUIDs. Invalid path IDs return 404.
  • Replace :id, :passwordId, :otpId, and :passkeyId with actual IDs.
  • List endpoints do not support pagination parameters.
  • PATCH preserves omitted fields; nested-field rules are described below. Do not use null in place of an omitted field.

Error response:

{
  "error": "Error description",
  "code": "not_found"
}

Handle errors using the HTTP status and code, not the wording or language of error.

3. Quick start

These commands use Bash/zsh syntax. Replace the API key and the UUID of an existing profile before running them.

export PERSONA_API_BASE='http://127.0.0.1:43110'
export PERSONA_API_KEY='<API_KEY>'

curl -sS "$PERSONA_API_BASE/health"

curl -sS "$PERSONA_API_BASE/v1/engine" \
  -H "Authorization: Bearer $PERSONA_API_KEY"

curl -sS "$PERSONA_API_BASE/v1/profiles" \
  -H "Authorization: Bearer $PERSONA_API_KEY"

export PROFILE_ID='<PROFILE_UUID>'

curl -sS -X POST "$PERSONA_API_BASE/v1/profiles/$PROFILE_ID/launch" \
  -H "Authorization: Bearer $PERSONA_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"startupUrl":"https://example.com","extraArgs":["--remote-debugging-port=9222"]}'

A successful launch returns:

{"ok": true}

This confirms browser startup, not that a page, website login, or CDP endpoint is ready. Once the debugging port is available, query it with:

curl -sS http://127.0.0.1:9222/json/version

Connect using the returned webSocketDebuggerUrl, or the CDP HTTP address if your automation tool supports it. Port 43110 is the automation API port; 9222 is the example browser debugging port. Assign different debugging ports when enabling CDP for multiple profiles at once.

Close the browser started through the API:

curl -sS -X POST "$PERSONA_API_BASE/v1/profiles/$PROFILE_ID/close" \
  -H "Authorization: Bearer $PERSONA_API_KEY"

4. Service status and account entitlements

MethodPathPurposeSuccess response
GET/healthServer health; no authentication required{ "ok": true }
GET/v1/engineBrowser engine status{ "ready": true, "version": "..." }
GET/v1/account/entitlementsCurrent account entitlements{ "entitlements": {...} }

A successful /health response does not confirm account sign-in or engine readiness. The version returned by /v1/engine is the browser engine version, not the app version, and is an empty string when unavailable. ready does not indicate that a profile has launched or that CDP is available.

The entitlements object contains:

FieldTypeDescription
tierstringPlan identifier
maxProfilesnumberProfile limit
usedProfilesnumberProfiles currently counted toward the limit
renewsAtstring or nullRenewal time
cancelAtstring or nullCancellation time
statusstring or nullSubscription status

5. Profiles

MethodPathPurposeSuccess response
GET/v1/profilesList profiles{ "profiles": [...] }
POST/v1/profilesCreate a profile{ "profile": {...} }
GET/v1/profiles/:idGet profile details{ "profile": {...} }
PATCH/v1/profiles/:idUpdate a profile{ "profile": {...} }
DELETE/v1/profiles/:idDelete a profile and its corresponding local data and cache{ "ok": true }

5.1 Create and update fields

FieldTypeRequired on creationDescription
namestringYesNonempty after trimming; up to 120 characters
startupUrlstringNoDefault startup URL; HTTP/HTTPS, up to 2048 characters; an empty string leaves it unset
extraArgsstringNoSaved launch arguments, separated by whitespace; up to 4096 characters; defaults to an empty string
proxyobjectNoProfile proxy settings, described below
fingerprintobjectNoFingerprint settings, described below
proxyIpInfoobjectNoKnown proxy exit information; skips automatic detection
acceptProxyChainbooleanNoWhether to accept the app's configured proxy chain; defaults to true
appearanceLabelstringNoBrowser appearance label
appearanceBackgroundColorstringNoAppearance background color, such as #2563EB
appearanceForegroundColorstringNoAppearance foreground color, such as #FFFFFF

Minimal creation body:

{"name": "Automation profile"}

Omitted settings use defaults on creation. Updates to proxy and fingerprint change only the supplied subfields. Proxy detection may affect the timezone, as described in section 5.4.

Example partial update:

PATCH /v1/profiles/:id
{
  "name": "Automation profile A",
  "startupUrl": "https://example.com",
  "extraArgs": "--remote-debugging-port=9222"
}

Here, extraArgs is a string, unlike the string array used by the launch endpoints. Saved arguments do not support shell-style quoting; pass an argument containing spaces as one item in the launch endpoint's extraArgs array. Set startupUrl or extraArgs to an empty string in an update to clear its saved value.

5.2 Proxy settings

Configure the proxy in the profile's proxy field.

FieldTypeCreation defaultDescription
protocolstringsocks5http, https, or socks5
hoststring""Proxy hostname or IP; an empty string means no profile-specific proxy
portnumber1080Integer from 1 to 65535
usernamestring""Proxy authentication username
passwordstring""Proxy authentication password
bypassListstringlocalhost;127.0.0.1Proxy bypass rules separated by semicolons
{
  "name": "US profile",
  "proxy": {
    "protocol": "socks5",
    "host": "proxy.example.com",
    "port": 1080,
    "username": "<PROXY_USERNAME>",
    "password": "<PROXY_PASSWORD>"
  }
}

Leaving the profile-specific proxy unset does not force a direct connection. App proxy-chain or system proxy settings may still affect the connection.

5.3 Fingerprint settings

FieldTypeCreation defaultDescription
browserVersionstring""Reported version, up to 32 characters; empty or auto selects the highest available version matching the engine's major version
hardwareConcurrencynumberRandomCPU thread count; integer from 1 to 256
cpuPerformancenumberFrom random presetCPU performance tier; integer from 0 to 4
deviceMemorynumberRandomReported memory: 2, 4, 8, 16, or 32 GB; does not allocate physical memory
speechVoicesModestringoverridenone: no override; override: full override; append_google: append Google voices only
fontAllowlistOverridebooleantrueApply the preset font allowlist for the host system
disableCanvasNoisebooleanfalseDisable pixel noise in Canvas 2D readback and image exports; noise stays enabled by default. Does not affect WebGL, WebGPU, or other noise. Relaunch after changes
webrtcIpPolicystringdisable_non_proxied_udpWebRTC IP policy
timezonestringAmerica/New_YorkIANA timezone; proxy detection may supply a default timezone
acceptLanguagesstringen-US,enComma-separated language list

Each creation randomly selects 8/12/16/20/24/32 CPU threads and 16/32 GB of memory. The random preset uses performance tier 3 for 8 threads and 4 otherwise. Explicit fields override the corresponding preset values. Updates preserve omitted fields, and launches do not randomize them again.

cpuPerformance tiers: 0 = Unknown, 1 = Low, 2 = Mid, 3 = High, 4 = Ultra.

Supported webrtcIpPolicy values:

  • disable_non_proxied_udp
  • default_public_interface_only
  • default_public_and_private_interfaces
  • default

UDP-enabled modes may expose direct IP addresses instead of the node IP. Close and relaunch the browser after changes.

5.4 Proxy exit information

When a proxy is configured without exit information, the API detects it automatically. A failed check returns proxy_probe_failed.

If you already have detection results, provide proxyIpInfo:

FieldTypeRequiredDescription
ipstringYesNonempty proxy exit IP
countrystringNoTwo-letter country or region code, such as US
region, citystringNoRegion and city
timezonestringNoIANA timezone
latitude, longitudenumberNoCoordinates
asn, orgstringNoASN and network organization
  • If the request does not explicitly provide a nonempty fingerprint.timezone and the detected or supplied exit information includes a timezone, that timezone is used.
  • Automatic detection does not change acceptLanguages. Supply it explicitly to change the language list.

5.5 Profile responses

Each list entry contains id, name, startupUrl, extraArgs, createdAt, updatedAt, and optional lastLaunchedAt.

Detail, creation, and update responses also contain:

  • proxy: proxy connection settings, including the authentication password.
  • fingerprint: fingerprint settings.
  • acceptProxyChain: whether the profile accepts the app's proxy chain.
  • appearanceLabel, appearanceBackgroundColor, and appearanceForegroundColor: appearance settings.

6. Browser lifecycle

MethodPathPurposeSuccess response
POST/v1/profiles/:id/launchLaunch the profile browser{ "ok": true }
POST/v1/profiles/:id/commandGet a launch command without starting the browser{ "executable": "...", "args": [...] }
POST/v1/profiles/:id/closeClose a browser started through launch{ "ok": true }

6.1 Launch options

launch and command accept the same body. Send {} if no temporary options are needed.

FieldTypeRequiredDescription
startupUrlstringNoURL for this launch; omitted or empty uses the profile's saved URL
extraArgsstring[]NoArguments for this launch, appended after saved launch arguments
{
  "startupUrl": "https://example.com",
  "extraArgs": ["--remote-debugging-port=9222"]
}

Launch arguments include the profile's saved arguments, the app's global launch arguments, and this call's extraArgs, in that order. Clearing the profile's saved arguments does not clear the app's global arguments.

These options apply only to this call and do not change the profile's saved values. extraArgs cannot override the data directory or browser lifecycle arguments managed by PersonaHub.

A successful launch only confirms browser startup. Calling it again may close and restart that profile. Do not use it to poll browser status.

6.2 Launch command

The command response contains:

FieldTypeDescription
executablestringPath to the browser executable
argsstring[]Complete launch arguments

Pass the returned values directly to a process-spawning API on the computer running PersonaHub. Do not concatenate them into a shell command or override the data directory.

For --remote-debugging-pipe, use command and have the caller start the process with the debugging pipes connected. launch does not return debugging pipes.

6.3 Usage limits

  • Keep the PersonaHub desktop app running while using the browser.
  • close does not manage browsers launched from the app UI or processes started by the caller using command.
  • If no API launch is available to close, the API returns 404 with code not_running. The first close request can still succeed after the browser has exited on its own, so do not use this endpoint to check whether it is running.
  • A successful close means closure was requested, not that the browser has exited.
  • Do not launch multiple instances of the same profile concurrently.

7. Saved website credentials

7.1 Website passwords

MethodPathPurposeSuccess response
GET/v1/profiles/:id/passwordsList summaries without passwords{ "credentials": [...] }
POST/v1/profiles/:id/passwordsSave a website password{ "ok": true }
GET/v1/profiles/:id/passwords/:passwordIdGet a credential, including its password{ "credential": {...} }
PATCH/v1/profiles/:id/passwords/:passwordIdUpdate a website password{ "ok": true }
DELETE/v1/profiles/:id/passwords/:passwordIdDelete a website password{ "ok": true }

Save request:

{
  "origin": "https://example.com",
  "username": "user@example.com",
  "password": "<WEBSITE_PASSWORD>"
}
FieldRules
originRequired HTTP/HTTPS URL; up to 2048 characters
usernameRequired and nonempty; up to 512 characters
passwordRequired and nonempty; up to 2048 characters

PATCH requires at least one of these fields. Omitted fields keep their current values; empty strings are not allowed. signon_realm is generated automatically and is not accepted as a request field.

Summaries contain id, origin, signon_realm, and username; single-credential responses also include password. Saving the same sign-on realm and username updates the existing entry. Saving returns no ID; query the list afterward to obtain it.

Changes are provided to the browser on a subsequent launch. Deletion does not change the website account or remove credentials already loaded by a running browser. Later browser sync may overwrite changes or recreate deleted entries.

7.2 TOTP codes

MethodPathPurposeSuccess response
GET/v1/profiles/:id/otpList entry metadata{ "entries": [...] }
POST/v1/profiles/:id/otpSave or update a TOTP entry{ "entry": {...} }
DELETE/v1/profiles/:id/otp/:otpIdRemove an entry{ "ok": true }
GET/v1/profiles/:id/otp/:otpId/codeGenerate the current code{ "id": "...", "code": "...", "expiresAt": "..." }

Save fields:

FieldTypeRequiredDescription
secretstringYesBase32 secret; up to 256 characters after removing whitespace and uppercasing; not an otpauth:// URL
labelstringNoUp to 120 characters; derived from issuer and account when omitted, or Authenticator if both are empty
issuerstringNoUp to 120 characters; defaults to an empty string
accountNamestringNoUp to 180 characters; defaults to an empty string
algorithmstringNoSHA1, SHA256, or SHA512; defaults to SHA1
digitsnumberNo6 or 8; defaults to 6
periodnumberNoPeriod in seconds; integer from 15 to 120; defaults to 30

List and save responses include id, label, issuer, accountName, algorithm, digits, and period. They do not return the secret.

Within the same profile, the same normalized secret updates or restores the existing entry. A different secret creates a new entry. Omitted metadata and settings use defaults on each save; they do not preserve existing values.

Example code response:

{
  "id": "<OTP_UUID>",
  "code": "012345",
  "expiresAt": "2026-09-17T08:00:30.000Z"
}

code is a string; preserve leading zeroes. Codes use the clock on the computer running PersonaHub. expiresAt is a UTC ISO timestamp. The API does not submit the code. Saving or deleting an entry does not enable or disable two-step verification on the website.

7.3 Passkeys

MethodPathPurposeSuccess response
GET/v1/profiles/:id/passkeysList passkey metadata{ "entries": [...] }
DELETE/v1/profiles/:id/passkeys/:passkeyIdRemove a saved entry{ "ok": true }

Each entry contains id, rpId, userName, and userDisplayName. Private keys are not returned. The automation API has no endpoint for creating or importing passkeys.

Deletion affects subsequent launches. It does not unregister the credential on the website or remove copies already loaded by a running browser. See the passkey guide for plan requirements when using passkeys in the browser.

8. Common errors

HTTP statuscodeMeaning
400body_invalidInvalid JSON
400body_not_objectThe top-level request value is not an object
400input_invalidFingerprint, website password, or TOTP fields are invalid
400profile_name_required / profile_name_too_longMissing or oversized profile name
400startup_url_invalid / startup_url_too_longInvalid startup URL type, format, or length
400launch_args_too_longSaved launch arguments are too long
400extra_args_invalidTemporary arguments are not a string array or include a protected argument
400proxy_invalidProxy settings are not an object
400protocol_invalidUnsupported proxy protocol
400proxy_port_invalidInvalid proxy port
400proxy_ip_info_invalidInvalid proxy exit information or missing IP
400proxy_probe_failedProxy check failed
400password_account_takenUpdated sign-on realm and username conflict with another credential
400otp_code_failedFailed to generate a TOTP code
401unauthorizedMissing or incorrect API key
401not_authenticatedDesktop account is signed out or its session has expired
403profile_quota_exceededAccount profile limit reached
404not_foundResource or route not found, or invalid path ID
404not_runningNo API launch available to close
405method_not_allowedUnsupported HTTP method
413body_too_largeRequest body exceeds the limit; the connection may close directly
500automation_api_errorRequest processing failed
503console_session_not_readyThe desktop session is not ready
503browser_engine_not_readyThe browser engine is not ready

Related guides