Authentication

Two layers, always together: the token proves the credential is yours; the signature proves the request left the server that holds the private key. One without the other does not move money.

Token

curl -X POST "https://auth.api.corpx.com/oauth2/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials" \
-d "client_id=$CLIENT_ID" \
-d "client_secret=$CLIENT_SECRET"
{
"access_token": "eyJraWQiOiJ…",
"expires_in": 300,
"token_type": "Bearer"
}

The same access_token is valid on every call until it expires. Store it and only request another when about 60 seconds remain, or when the API refuses the token. Read expires_in from the response — do not hard-code 300 on the client.

scope is optional. Omitting it returns a token with every scope the credential has. Sending a subset (space-separated) restricts that token.

Headers on every API call

Host: https://client.api.corpx.com.

HeaderWhenValue
AuthorizationAlwaysBearer {access_token}
X-Tenant-IdAlwaysThe identifier the bank showed
X-Request-TimestampAlwaysUnix seconds; 300s skew
X-Content-SHA256AlwaysSHA-256 of the body, lowercase hex
X-Request-SignatureAlwaysDetached JWS — Signing
Idempotency-KeyPOST/PUT/PATCH that create or moveUUID of the attempt. Repeating returns the original

How to build the three signing headers is in the signing guide. GET /v1/me also needs those headers (it is /v1/** on the signed host) but does not need X-Tenant-Id.

Check the token: GET /v1/me

curl -X GET "https://client.api.corpx.com/v1/me" \
-H "Authorization: Bearer $TOKEN" \
-H "X-Request-Timestamp: $TS" \
-H "X-Content-SHA256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" \
-H "X-Request-Signature: $SIG"

The response has clientId, scopes and tenantRoles[] with the contexts the token is valid for. For an internet-banking credential, sub and clientId are the same value.

What this credential reaches

It was issued for one account. Calls to another account return 403 forbidden.

You canStays with the bank / holder
Read balance, statement, bank detailsIssue another credential
Send and receive PIX, TED, boleto, internal transferSet or reset an operator PIN
Create a webhook for this account (accountId required)Subscribe to webhooks for every account at the bank
Rotate your keys and your IP allowlistOpen accounts, backoffice, bank-wide policies
Read the locks in forceChange the holder’s locks (PUT on locks)

PIN and hour / source-IP locks belong to the internet-banking UI. On payment routes you do not send X-Transaction-Pin or X-Acting-Document: possession is already in the private key and the credential IP.

18-hour grace

Issuance returns activeFrom 18h ahead. Until then: 403 credential_not_yet_active. Adding a public key or an IP uses the same grace; removing a key or IP is immediate. Detail in Keys and IPs.