--- title: Partner panel description: Signing in, managing API keys, and reading your own order and referral history. --- import { PANEL_URL, LOGIN_CODE_TTL_MINUTES, LOGIN_CODE_MAX_ATTEMPTS, SESSION_DAYS_DEFAULT, SESSION_DAYS_KEEP, SESSION_REVOKE_MIN_AGE_HOURS, } from "/snippets/vars.mdx"; `PartnerApi` backs the panel at {PANEL_URL}. Everything it exposes is scoped to one partner: your keys, your orders, your referral earnings. It is a separate service from `HularApi` and uses session tokens rather than API keys. ## Signing in There is no password. Request a code by email, then exchange it for a session. Requesting a code requires a Cloudflare Turnstile token, minted by the widget on the panel's sign-in form. ```ts const { partner } = createHularClient({ token: () => session }); await partner.requestLoginCode({ email, captchaToken }); const created = await partner.verifyLoginCode({ email, code: "123456", keepSignedIn: false, }); created.token; // send as: authorization: Bearer created.expiresAt; // when it stops working ``` | Rule | Value | | --- | --- | | Code lifetime | {LOGIN_CODE_TTL_MINUTES} minutes | | Wrong attempts before the code is discarded | {LOGIN_CODE_MAX_ATTEMPTS} | | Session lifetime | {SESSION_DAYS_DEFAULT} day | | Session lifetime with `keep_signed_in` | {SESSION_DAYS_KEEP} days | Requesting codes in quick succession is throttled: a second request inside a minute is rejected rather than sending another email. Turnstile tokens are single-use and short-lived, so each request needs a fresh one; deployments without a configured Turnstile secret skip the check. Every other `PartnerApi` call needs the token in an `authorization: Bearer` header. An expired or unknown token returns `UNAUTHENTICATED`. `Logout` invalidates the session immediately. ## API keys ```ts const me = await partner.getPartner({}); me.email; me.keys; // existing keys me.maxKeys; // cap on active keys ``` | RPC | Effect | | --- | --- | | `CreatePartnerApiKey` | Creates a named key and returns it, including the secret. | | `RevokePartnerApiKey` | Revokes by id. Requests using it then fail as disabled. | The key value is returned on the key objects, so a partner can retrieve an existing key rather than rotating when it is misplaced. Treat it as a secret regardless: it carries your rate limit and your attribution. Key changes are cached briefly on the API side, so a new or revoked key takes a few seconds to take effect. See [API keys](/integration/api-keys). ## Usage The Usage tab charts your API traffic per key: requests over time split by status (ok, rate limited, error), rate limit points consumed, and a per-method breakdown of calls and errors. Use it to see which methods are eating your budget and whether you are hitting the limit. The same data is available programmatically: ```ts const stats = await partner.getPartnerApiStats({ rangeSecs: 86400n, stepSecs: 300n, }); stats.requests; // per key, method, and status stats.points; // rate limit points consumed per key ``` See [GetPartnerApiStats](/api-reference/partner) for the bounds on range and step, and [API keys](/integration/api-keys) for how points and costs work. ## Sessions The Sessions tab lists every live sign-in on the account: the device it came from, every IP it has been used from with a best-effort location, when it was created, when it was last active, and when it expires. ```ts const page = await partner.listPartnerSessions({}); for (const session of page.sessions) { session.userAgent; session.ips; // every address the session was used from session.lastUsedAt; session.current; // the session making this call } await partner.revokePartnerSession({ id: page.sessions[1].id }); ``` A session can revoke the account's other sessions only once it is at least {SESSION_REVOKE_MIN_AGE_HOURS} hours old, so a freshly stolen token cannot immediately evict you; `can_revoke` on the listing says whether yours qualifies. Revoking your own current session is `Logout`. ## Your orders `ListPartnerOrders` returns orders attributed to your keys, newest first, cursor-paginated. ```ts const page = await partner.listPartnerOrders({ limit: 50n }); for (const order of page.items) { order.quoteHash; order.state; order.srcChain; order.dstChain; order.depositAmount; order.depositSymbol; order.referrerFee; order.apiKeyName; // which key originated it } ``` `api_key_name` is what makes this useful across surfaces: issue one key per application and the attribution comes back for free. ## Referrals and vouchers | RPC | Returns | | --- | --- | | `GetPartnerReferrals` | Claimable balances grouped by referrer, chain, and token. | | `ClaimPartnerReferrer` | A signed voucher for one balance, marking its orders claimed. | | `ListPartnerVouchers` | Every voucher issued to you, with redemption status. | | `BuildVoucherRedemption` | A prepared redemption transaction for a voucher and payer. | See [Referral program](/integration/referrals) for what the voucher is and how redemption works on each chain. Do not embed a partner session token in a client application. It grants key management and claiming. Sessions belong in the panel or in a backend you control.