> ## Documentation Index
> Fetch the complete documentation index at: https://docs.limitless.exchange/llms.txt
> Use this file to discover all available pages before exploring further.

# Partner Accounts

> Create and manage sub-accounts with the Go SDK

The `PartnerAccountService` creates sub-account profiles linked to the authenticated partner. Requires HMAC authentication with the `account_creation` scope.

## Access

```go theme={null}
import "github.com/limitless-labs-group/limitless-exchange-go-sdk/limitless"

client := limitless.NewClient(
    limitless.WithHMACCredentials(limitless.HMACCredentials{
        TokenID: tokenID,
        Secret:  secret,
    }),
)

// Use client.PartnerAccounts.*
```

## Server wallet mode

Creates a managed Privy wallet for the sub-account. Enables [delegated signing](/developers/programmatic-api#sub-account-modes) — the partner submits unsigned orders and the server signs them.

```go theme={null}
createServerWallet := true
account, err := client.PartnerAccounts.CreateAccount(ctx, limitless.CreatePartnerAccountInput{
    DisplayName:        "user-alice",
    CreateServerWallet: &createServerWallet,
}, nil)
if err != nil {
    log.Fatal(err)
}

fmt.Println(account.ProfileID)
fmt.Println(account.Account)
```

<Note>
  New server wallets should be checked with `CheckAllowances` before the first delegated trade. If retryable targets are missing or failed, call `RetryAllowances` and poll again.
</Note>

## List and recover sub-accounts

Use `ListAccounts` to list partner-owned sub-accounts or recover a specific child profile by wallet address. This calls `GET /profiles/partner-accounts` and requires HMAC credentials with the `account_creation` scope.

```go theme={null}
accounts, err := client.PartnerAccounts.ListAccounts(ctx, limitless.ListPartnerAccountsParams{
    Limit: 25,
    Page:  1,
})
if err != nil {
    log.Fatal(err)
}

for _, account := range accounts.Data {
    fmt.Println(account.ProfileID, account.Account, account.DisplayName)
}

recovered, err := client.PartnerAccounts.ListAccounts(ctx, limitless.ListPartnerAccountsParams{
    Account: "0x1676716Ef7F19B5C5d690631CB57cf0bFD900A3d",
    Limit:   25,
    Page:    1,
})
if err != nil {
    log.Fatal(err)
}

if len(recovered.Data) > 0 {
    fmt.Println("profile ID:", recovered.Data[0].ProfileID)
}
```

| Parameter | Description                                                            |
| --------- | ---------------------------------------------------------------------- |
| `Account` | Optional exact EVM address filter for recovering a known child account |
| `Limit`   | Optional page size. The API caps values above `25` to `25`             |
| `Page`    | Optional 1-indexed page number                                         |

<Warning>
  Do not send `x-on-behalf-of` to this endpoint. Results are always scoped to the authenticated partner behind the HMAC token.
</Warning>

## Allowance recovery

Server-wallet sub-accounts need delegated-trading approvals before they can trade. The partner allowance helpers use the Partner API only:

* `CheckAllowances(ctx, profileID)` calls `GET /profiles/partner-accounts/:profileId/allowances`
* `RetryAllowances(ctx, profileID)` calls `POST /profiles/partner-accounts/:profileId/allowances/retry`
* both methods require HMAC credentials with `account_creation` and `delegated_signing`
* `profileID` is the child/server-wallet profile id

```go theme={null}
allowances, err := client.PartnerAccounts.CheckAllowances(ctx, account.ProfileID)
if err != nil {
    log.Fatal(err)
}

if !allowances.Ready {
    retryable := false
    for _, target := range allowances.Targets {
        if target.Retryable &&
            (target.Status == limitless.PartnerAccountAllowanceStatusMissing ||
                target.Status == limitless.PartnerAccountAllowanceStatusFailed) {
            retryable = true
            break
        }
    }

    if retryable {
        allowances, err = client.PartnerAccounts.RetryAllowances(ctx, account.ProfileID)
        if err != nil {
            var rateLimitErr *limitless.RateLimitError
            var conflictErr *limitless.ConflictError
            switch {
            case errors.As(err, &rateLimitErr):
                fmt.Println("retryAfterSeconds is in rateLimitErr.Data")
            case errors.As(err, &conflictErr):
                fmt.Println("Retry already running; poll CheckAllowances again shortly.")
            default:
                log.Fatal(err)
            }
        }
    }
}

for _, target := range allowances.Targets {
    if target.Status == limitless.PartnerAccountAllowanceStatusSubmitted {
        // A sponsored tx/user operation was submitted by this retry request.
        // Poll CheckAllowances again after a short delay to observe confirmed chain state.
    }
}
```

Recommended partner flow:

1. Poll `CheckAllowances(ctx, profileID)`.
2. If `Ready == true`, continue.
3. If targets are `missing` or `failed` with `Retryable == true`, call `RetryAllowances(ctx, profileID)`.
4. If retry returns `submitted` targets, poll `CheckAllowances` again after a short delay.
5. If retry returns `429`, wait `retryAfterSeconds`.
6. If retry returns `409`, wait briefly and call `CheckAllowances` again.

## Withdrawal address allowlist

Explicit treasury destinations for server-wallet withdrawals must be allowlisted on the authenticated partner profile unless the destination is already the partner account or partner smart wallet. Allowlist management uses a Privy identity token, not API-token/HMAC auth.

```go theme={null}
identityToken := os.Getenv("PRIVY_IDENTITY_TOKEN")
treasuryAddress := "0x0F3262730c909408042F9Da345a916dc0e1F9787"

entry, err := client.PartnerAccounts.AddWithdrawalAddress(ctx, identityToken, limitless.PartnerWithdrawalAddressInput{
    Address: treasuryAddress,
    Label:   "treasury",
})
if err != nil {
    log.Fatal(err)
}

fmt.Println(entry.DestinationAddress)

if err := client.PartnerAccounts.DeleteWithdrawalAddress(ctx, identityToken, treasuryAddress); err != nil {
    log.Fatal(err)
}
```

<Note>
  `AddWithdrawalAddress` and `DeleteWithdrawalAddress` call `POST /portfolio/withdrawal-addresses` and `DELETE /portfolio/withdrawal-addresses/:address` with the `identity: Bearer <token>` header. `POST /portfolio/withdraw` still uses HMAC auth with the `withdrawal` scope.
</Note>

## EOA mode

Creates a profile for an externally-owned address. The end user manages their own keys and signs orders themselves.

EOA mode requires wallet ownership verification headers:

```go theme={null}
account, err := client.PartnerAccounts.CreateAccount(ctx, limitless.CreatePartnerAccountInput{
    DisplayName: "user-bob",
}, &limitless.CreatePartnerAccountEOAHeaders{
    Account:        "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
    SigningMessage: "0x...",
    Signature:      "0x...",
})
```

## Validation

* `DisplayName` is optional, max 44 characters. Defaults to the wallet address if omitted.
* Returns `409 Conflict` if a profile already exists for the target address.
* Cannot create a sub-account for the partner's own address.
* The SDK validates `DisplayName` length locally before sending the request.
