Create a link
Completes a link for a member who has just authorized you through
Bilt’s IdP. Bilt validates the idToken (signature against the
environment’s JWKS, iss, aud, exp, single-use jti), reads the
Bilt member id from sub, and links it to your partnerUserId.
partnerUserId must be stable for the lifetime of the account. It
is the only handle you have on the link afterwards: status lookups are
keyed by it, and unlinks name it. Do not send an email address, a
phone number, or any other personal data in this field.
Idempotent only for a byte-identical retry. Resending the same
idToken with the same partnerUserId returns 200 with the
existing link while it is still active — the sanctioned path after a
timeout or a lost response. The same token with a different
partnerUserId, or after the link was broken, is
409 ID_TOKEN_REPLAYED: the token is spent, mint a fresh one.
Keep the linkId from the response or fetch it later from the status
read — POST /unlink requires it.
Authorizations
Preferred. A partner access token minted by your partner
client with the client-credentials grant — the client you
authenticate as, with no member involved. Send it as
Authorization: Bearer <access_token> and on no other header. It is
a different client from the IdP one that mints member id_tokens,
and it is not the member access_token the code exchange returns —
see the guide's
§5 Authentication.
Headers
Optional but strongly recommended: a unique id per request (a UUID is
fine). Echoed back as error.requestId so your logs and Bilt's line
up. Quote it in every support ticket.
"6f6b1afd-22e0-4137-a096-b15e41cdc890"
Body
The id_token Bilt's IdP returned from the authorization-code
exchange, passed through exactly as the compact JWS string. Its
sub identifies the Bilt member; its aud must be your IdP
client id; its jti is single-use.
1 - 8192Your opaque, stable identifier for the account being linked. The only handle you have on the link afterwards. Never an email address, phone number, or name.
1 - 256"acme_customer_sandbox_123"
Response
Link created — or, on an idempotent retry of the identical request,
the existing active link. partnerDetails is not part of this
response; read it from the status endpoint.
Partner-facing view of a link. Returned by oauth-link (without
partnerDetails) and by the status read.
The id of this link episode, and the value POST /unlink
requires. One account legitimately owns several historical links,
so ending one means naming which. Published on both the create
response and the status read, so you can always recover it rather
than having to store it.
"9f1c2e4a-7b30-4d55-8e21-6c0b9a3f5d78"
Your opaque user id, echoed back.
"acme_customer_sandbox_123"
The states you can observe on the oauth-link response and the
status read. LINKED is the only usable state. UNLINKED and
LINK_REVOKED are terminal for that link; the next successful
oauth-link creates a fresh one. UNLINKING_IN_PROGRESS is only
reachable for integrations where Bilt calls you on unlink — unusable
but not terminal; re-read later. Do not code against values outside
this list.
LINKED, UNLINKED, LINK_REVOKED, UNLINKING_IN_PROGRESS "LINKED"
When the link became LINKED, ISO-8601 UTC.
"2026-07-31T13:45:00Z"
Non-sensitive metadata Bilt holds about the link. Present on the
status read only; empty ({}) for this integration model —
reserved for future use.