Skip to main content

Overview

What this integration doesWhen Privy is configured as your wallet provider:
  • Authentication — users sign in to AGG with their Privy access token.
  • Execution — AGG signs trades with the wallets in your Privy app.
Your users keep the same wallet addresses and balances.

Authentication

Privy access tokens

Wallets

Your existing Privy wallets

Chains

Ethereum + Solana
Both effects come from one setup in one Privy app. Privy sign-in is not available on its own, because AGG finds a user’s Privy wallets through the Privy identity that sign-in records.

Quick start

1

Prepare wallets

Make sure every trading user has an Ethereum and a Solana wallet that AGG can sign with. See Wallet ownership.
2

Configure AGG

Save your Privy credentials under Settings → Wallet Provider and click Validate. See Configure Privy in AGG.
3

Authenticate the user

Exchange the user’s Privy access token for an AGG session. See Authentication & sessions and Authenticate users.
4

Deposit addresses

Request them from Funding & withdrawals. That page owns the poll. For a Privy wallet-provider app, evmAddress is the authorized Privy wallet.
5

Fund and trade

Send USDC to the addresses Funding returns, and place orders as usual.

Prerequisites

Before you start, you need:
  • Your Privy App ID
  • Your Privy App Secret
  • Your Privy Authorization Private Key
  • A Privy Signer ID — only if AGG should create missing wallets
  • An Ethereum and a Solana wallet for every trading user
Privy shows the authorization private key only once. Store your own copy before you leave the Privy dashboard. If you lose it, create a new authorization key in Privy and save it in AGG again.
The key is accepted in any of the shapes Privy hands out: the wallet-auth:MIGH... form, a bare base64 PKCS#8 body, or a full -----BEGIN PRIVATE KEY----- PEM block.

How it works

  1. Sign-in. Your frontend gets an access token from Privy and posts it to AGG. AGG verifies it against your Privy app’s public keys and returns an AGG session. There is no callback URL: Privy never redirects.
  2. Wallet setup. The first time a user’s deposit addresses are requested, AGG finds that user’s Ethereum and Solana wallets in your Privy app and links them. If you opted in, it creates any that are missing.
  3. Execution. Every trade, bridge and transfer is signed through Privy with the authorization key you saved, with no user present.

Wallet ownership

AGG can only use a wallet it can sign with on its own: A user-owned wallet with your server signer looks like this in Privy:
Important — AGG must sign without the user being present. Limit-order fills, settlement webhooks, and managed balance refills run after the original user request has ended, some of them minutes or hours later.
If some existing wallets do not have your server signer yet, the user has to add it from your app — see Existing wallets without your signer. Also check that no Privy policy blocks your authorization key.

Wallet discovery

AGG looks for a user’s wallets in two places, so either ownership model works without extra configuration: Of the wallets found, AGG uses the first one per chain that it can actually sign with, proven by signing a harmless message.
Entity is immutable once set. A server-owned wallet created without one can never be attributed to a user.

Wallet creation

By default AGG never creates a wallet — it uses the ones your onboarding already made. If your users can reach trading before a wallet exists, turn on Create wallets for users who have none and enter your Signer ID. AGG then creates the missing wallet as a user-owned wallet with your signer attached:
Use the key quorum your backend already attaches to your users’ wallets, so your signer policies and key rotation also cover wallets AGG creates. AGG never creates an app-owned wallet, and the setting cannot be saved without a Signer ID.
AGG does not replace existing wallets. Creation only fills a chain where the user has no wallet. If AGG cannot sign with an existing wallet, it reports that instead of creating a second one, because your user’s funds may be in the wallet it skipped.
Avoid duplicate wallets. If your onboarding already creates wallets — possibly after the user has signed in to AGG — leave Create wallets for users who have none disabled. Otherwise both sides can create a wallet for the same chain.
Unlike the wallet provider itself, this setting can be changed at any time. A change applies the next time a user’s wallets are set up.

Existing wallets without your signer

Embedded wallets that Privy created at signup are owned by the user. If your key quorum was never added to them, AGG cannot sign with them, and GET /execution/deposit-addresses answers 409 with code: "PRIVY_WALLET_NOT_SIGNABLE". Create wallets for users who have none does not help here — it only fills a chain with no wallet, and never replaces one your user may already have funded. Only the wallet’s owner can change its signers, so your server key cannot add the signer on its own. Add it from your frontend, with the user’s Privy session, using Privy’s useSigners hook:
Call it after sign-in, before you request deposit addresses, or when that request returns PRIVY_WALLET_NOT_SIGNABLE. Deposit address hooks surface the same code as error. The request itself is on Funding & withdrawals.

What to expect

On older versions of Privy’s React SDK without useSigners, use useSessionSigners().addSessionSigners — it takes the same arguments.
Users who have no wallet yet do not need this: with Create wallets for users who have none turned on, AGG creates their wallets with your signer already attached.

Configure Privy in AGG

1

Open Wallet Provider settings

In the AGG dashboard, go to Settings → Wallet Provider.
2

Choose Privy

Change the provider from Portal (default) to Privy.
3

Enter credentials

Enter the App ID, App Secret, and Authorization Private Key. To let AGG create missing wallets, also turn on Create wallets for users who have none and enter your Signer ID.
4

Save

Secrets are encrypted before storage and never returned to the dashboard — the form only shows whether they are set.
5

Validate

Checks your credentials against Privy from the service that signs trades, so a typo fails here instead of during a trade.
6

Allow your domains

Under Domains, add every origin your frontend calls AGG from. Browser requests from other origins are rejected with 403 Origin not allowed for this app. Server-to-server calls are not affected.

Authenticate users

Get the user’s access token from Privy’s client SDK, then exchange it for an AGG session with POST /auth/verify and { "kind": "privy", "privyToken" }. There is no Privy setting on the Auth tab — saving Privy as the wallet provider enables it, and there is no callback URL. See Authentication & sessions. AGG verifies the token with Privy’s published public keys at https://auth.privy.io/api/v1/apps/{appId}/jwks.json. The Privy DID (sub) becomes the user’s identity, so the same person signing in to two of your apps gets one identity across both.
Signing in does not set up the user’s wallets. Deposit addresses are on Funding & withdrawals. For a Privy wallet-provider app, evmAddress is the authorized Privy wallet.

Sign-in errors

Every failure is a 401:

Initialize user wallets

For a Privy wallet-provider app, the deposit address is the authorized Privy wallet: evmAddress on EVM and svmAddress on Solana. Other apps get a managed deposit address. Follow the polling example in Funding & withdrawals until provisioning is ready. A 409 means the Privy wallet does not grant Agg’s authorization key signing rights. Add your signer, then request addresses from Funding. See Existing wallets without your signer. The wallets.ready webhook fires once a user’s wallets are set up.

Provider lock

The wallet provider cannot be migrated. Once any wallet exists for one of your app’s users, the provider is permanently locked. To change providers, create a new AGG app.The two custodians hold key material in different systems and neither exports it, so switching would strand every existing wallet and the funds in it. The rule is enforced by the API, not just the dashboard.

Errors & troubleshooting