Skip to content
TDACorpIDENTITYSign in

Using an access token

Call the account API at /v1/me with a personal access token to read or update your own profile from a script.

On this page

A personal access token lets a script call the account API as you. This page shows the one place a token is accepted, what it returns and how it fails. To create a token, see Access tokens.

Using a token with the account API is behind the pat_bearer_api feature flag, which defaults OFF, and it is available only where your organization allows it (an organization above yours can also switch tokens off). Where it is not available, calls with a token are refused in the same way as an invalid token.

Where a token works#

A token works on one address only: /v1/me, on the identity host. Nothing else under /v1/me accepts a token. The rest of the account API, such as sessions, security settings and data export, needs you to be signed in with a session or with a first-party sign-in, and refuses a token as invalid.

MethodScope the token needsWhat it does
GET /v1/meidentity.self.profile.read or identity.self.readReads your own profile.
PATCH /v1/meidentity.self.profile.write or identity.self.writeUpdates your own profile and returns the result.

The other scopes you can tick when you create a token are not accepted anywhere yet. The token must also be unexpired (a token created with Never has no expiry), not revoked, used from an allowed address if you set a list, and its organization must still be one you are an active member of.

Send the token#

Present the token as a bearer credential. Its secret starts with tdaid_pat_.

curl https://identity.tdacorp.in/v1/me \  -H "Authorization: Bearer $TDAID_TOKEN"

Keep the secret in an environment variable or a secret store, never in the command history or in source code.

Read your profile#

A successful GET answers 200 with a JSON object:

{  "email": "ada@example.com",  "email_verified": true,  "picture": "https://example.com/avatar.webp",  "created_at": "2026-09-01T09:30:00.000Z",  "sub": "01J...",  "display_name": "Ada Lovelace",  "username": "ada",  "bio": null,  "locale": "en-GB",  "tz": "Europe/London",  "updated_at": "2026-09-20T12:00:00.000Z"}
FieldMeaning
subYour account identifier. An application registered for pairwise identifiers is given a different one for you.
display_nameYour display name.
username, bio, locale, tzYour optional username, short bio, language tag and time zone. null when unset.
email, email_verifiedYour email address and whether it is verified. Present when you have one.
pictureThe address of your profile picture. Present only when you have uploaded one.
created_at, updated_atWhen the account was created and when the profile last changed.

Update your profile#

A token with identity.self.profile.write or identity.self.write can change these fields:

curl -X PATCH https://identity.tdacorp.in/v1/me \  -H "Authorization: Bearer $TDAID_TOKEN" \  -H "Content-Type: application/json" \  -d '{ "display_name": "Ada L.", "tz": "Europe/London" }'

The body is a JSON object with any of display_name, username, bio, locale and tz. A field you leave out is left alone. Any other field is refused.

  • display_name is required to be non-blank when present and is never cleared.
  • username, bio, locale and tz are cleared by sending null or an empty string.
  • A username must pass the same checks as the one you set on your Profile page, and a username someone else holds is refused with 409 and the error username_unavailable.

The response is the updated profile, in the same shape as GET.

Updating through the API is recorded in your activity like any other profile change.

Failures#

StatusBody errorWhat it means
400invalid_requestThe body is not valid: a field that is not allowed, a blank display name, or a value that fails its check. The description says which.
401invalid_tokenThe token is not accepted. The response carries WWW-Authenticate: Bearer error="invalid_token".
409username_unavailableAnother account holds that username.
429rate_limitedThe token has used its allowance for now. The Retry-After header says how many seconds to wait.

Every reason a token can be refused gives the same 401, whether it is wrong, expired, revoked, outside its address list or short of scope. This is deliberate: someone holding a stolen token learns nothing about its limits. If a token you expect to work is refused, open the Access tokens tab and check its status, expiry, scopes and Allowed IPs.

A refused attempt with a real token is also recorded as a security event in your feed.

Good practice#

  • Create one token per script, with a name that says which.
  • Give each the shortest expiry that works and only the scopes it needs.
  • Use an address list when the script runs from a fixed place.
  • Revoke a token when the script is retired, and replace it before it expires.
  • If a token may have leaked, revoke it at once from the Access tokens tab.

Verified against commit c5ef357