TrustWixDocs

Authentication

Secret keys, environments, permissions and the short-lived tokens the browser is allowed to hold

Every request to the TrustWix API is authenticated with a secret API key sent as a bearer token.

curl https://api.trustwix.com/v1/verifications \
  -H "Authorization: Bearer TWK_..." \
  -H "Content-Type: application/json"

Two kinds of credential

A secret key identifies your account and carries the permissions attached to it. It reads TWK_ followed by one long opaque token and has no other structure. Secret keys belong on your server and nowhere else.

A client token is minted for you when you create a verification and is returned as client_token on the create response. It is scoped to that single verification, expires within minutes, and is the only credential that may be handed to a browser or a mobile client. Treat it as an opaque string, never parse it, and never cache it beyond the session it belongs to.

Where keys come from

Keys are created in your dashboard, under API keys. There is no endpoint that mints a key, so nothing in your integration ever needs a credential powerful enough to create more credentials. Creating, rotating and revoking are all owner or developer actions, and each one asks you to re-authenticate first, because each either hands out a working credential or takes one away.

The secret is shown exactly once, at the moment you create it. We keep only a hash and a short non-secret prefix, so we cannot show it to you again and neither can support. Copy it into your secret manager there and then.

Rotating mints a fresh secret on the same key and keeps its name, environment and permissions, so the key's identity in your logs survives the rotation. Deploy the new secret, confirm traffic has moved, and only then revoke what it replaced. Revocation takes effect immediately, including for requests already in flight, so doing it in the other order causes an outage.

If a key leaks

Revoke it in your dashboard straight away. A revoked key stops working for every request and can never be reactivated.

Environments

The environment is a property of the key itself, not a different host and not a header. One base URL serves both.

EnvironmentBehaviour
SandboxNo real checks run. Magic applicant values force the verdict.
LiveReal checks run against real submissions.

You pick the environment when you create the key, and it is fixed for the life of that key. Because the token carries no environment marker, there is nothing in the string to parse: read it from your dashboard, where every key is listed against the environment it belongs to, or from mode on any verification the key creates.

One wrinkle worth knowing before it surprises you. On the wire, a sandbox key's environment reads test. It is the same split your dashboard calls Sandbox and Live, under an older spelling kept so existing integrations keep parsing, and you will meet it on GET /v1/entitlements. The mode field, which is the one that appears on every verification, always says sandbox or live.

Sandbox and live data never mix. A sandbox key cannot read a live verification and a live key cannot read a sandbox one, so an accidental cross-environment call fails cleanly rather than returning the wrong record.

Permissions

Every key carries a set of scopes. Calling an endpoint your key is not scoped for returns 403 permission_error with the code INSUFFICIENT_PERMISSIONS, and you can read the scopes on the key you are currently holding from GET /v1/entitlements.

ScopeWhat it unlocks
verification:createCreate a verification, request and confirm uploads, record consent, decide an OPEN manual review, preview a flow
verification:reopenReopen a verification that already has a decision, returning it to manual review and clearing its verdict
verification:readRetrieve and list verifications, list manual reviews, read applicant records
applicant:readThe include=applicant,documents expansion: the identity read from the document, and the captured images
webhook:manageList, create and delete webhook endpoints
analytics:readThe usage summary
settings:readRead your flows, your merchant profile and your entitlements
settings:writeReserved for the surfaces you manage in the dashboard rather than over the API
verification:deleteReserved. No endpoint uses it today
console:sessionExchange the key for a back-office session acting as one of your people

What a new key gets

The default set differs by environment, deliberately. A live key starts narrower than a sandbox one, because the blast radius is not the same.

ScopeSandbox defaultLive default
verification:createyesyes
verification:readyesyes
webhook:manageyesyes
settings:readyesno
analytics:readyesno
verification:deleteyesno
applicant:readnono
verification:reopennono
settings:writenono
console:sessionnono

Two consequences are worth internalising now rather than meeting them in production.

Reading your flows, your merchant profile, your entitlements and your usage works with a sandbox key and returns 403 with a default live key, because those four need settings:read or analytics:read. If a call that works in staging fails in production, check this before anything else.

A decision we have already given you is final unless you hold verification:reopen. Approving or rejecting an OPEN case needs nothing beyond verification:create, but a case that already carries a decision will not move: the write is refused whoever sends it, including our own staff. The one way back is decision: "review" on Decide a manual review, which returns the case to the queue and clears its verdict, and that verb needs verification:reopen, which is in no default set. Ask us to put it on a specific key if you need it.

applicant:read is in no default set at all, and it is the one you are most likely to want. It is the only scope that returns a real person's name, date of birth, document number and the images of their document, so it is never inherited by a key you made for something else. You grant it yourself, when you create the key: choose Full data under "What this key can read" in the dashboard's create-key dialog, or name the scope in the permissions array on POST /v1/api-keys. An existing key cannot gain it, so this is a new key rather than a change to the one you are holding. See Applicant data.

A live key can only be created in the dashboard. POST /v1/api-keys needs settings:write, which no live key may carry, and a sandbox key holding it may only create keys in its own environment. So the endpoint is how you script sandbox keys, and a person in the console is the only way a live one comes into existence. That is deliberate.

console:session is in no default set either, and unlike applicant:read you cannot grant it to yourself. It is the only scope that mints a credential acting as one of your people rather than reading your data, and it needs a seat mapped to it before it resolves to anybody. Ask us for it on one key. See Back-office sessions.

Create narrow keys per integration rather than one key for everything, and revoke the narrow ones freely.

Read-only keys

A key is created either read and write or read only, and that is a separate question from which scopes it carries. A read-only key reads everything it is scoped for and is refused every write with 403 and the code READ_ONLY_KEY.

Choose it in the dashboard when you create the key, or send "access": "read_only" to POST /v1/api-keys. You can read it back from GET /v1/entitlements, which is the cheap way to assert in your own tests that a job is holding the credential you think it is.

It is not a permission, and that is the whole value. Scopes are additive: we add new ones over time, and a key you called read-only because it happened to hold no write scopes would quietly gain the ability to write the day somebody granted it a scope that did not exist when you made that judgement. Read-only is a property of the credential instead. Granting a write scope to a read-only key changes nothing, so a key you created read-only in January is still read-only in December without you re-auditing it.

It is fixed for the life of the key. There is no way to widen one, in the dashboard or over the API, and there will not be. A read-only key that could be flipped is a read-write key with a setting, which is not something you could hand to a contractor and stop thinking about. To widen, create a new key.

Reach for one whenever something needs to read and never to write: a nightly pull into your warehouse, an internal dashboard, a support tool your agents use, a report. The common shape is two keys, one read-only for the data and one read-write for the calls that actually create verifications.

Read-only says nothing about how much you can read. The two questions are independent, and a read-only key holding the default scopes reads only what those scopes reach. The create dialog asks both: What this key can do is read-only or read and write, What this key can read is outcomes only or full data. A credential that mirrors your account and changes none of it is the pair read-only plus full data, which is what to point a nightly sync, a warehouse pull or an internal dashboard at.

The one read scope you cannot grant yourself is console:session, because it does not read your data, it mints a credential that ACTS AS one of your people. Ask us for that one.

One deliberate exception to the shape of the rule: POST /v1/verifications/lookup is allowed on a read-only key. It uses POST because its filters outgrew a query string, but it is a search and changes nothing. We classify every endpoint by what it does rather than by its HTTP verb.

Request correlation

Every response carries an X-Request-Id header. You can also send your own X-Request-Id and it will be echoed back. Log it. It is the fastest way for support to find a specific request, and it is included in every error body as error.request_id.

On this page