---
title: "Exchange CDP Auth Token for Grove API Key"
method: POST
path: "/v1/auth/exchange-cdp-token"
tags: ["auth"]
---

# Exchange CDP Auth Token for Grove API Key

`POST /v1/auth/exchange-cdp-token`

Exchange a CDP Auth Token for a Grove API Key.
This endpoint supports both first-time signup and returning user login.

**This is the primary signup/login endpoint.** The identity used here becomes the
account's PRIMARY identity, which is used as the JWT subject and cannot be changed.

To add additional (secondary) identities after signup, use `POST /v1/account/identities/verify`.

## What this endpoint does

Given a valid CDP Auth Token, the server:

- Verifies the token with CDP
- Resolves a user identity (email or phone)
- Finds or creates the corresponding Grove account (identity becomes PRIMARY)
- Returns a Grove API key (deterministic, long-lived JWT)

This endpoint is idempotent. Repeating the request returns the same account and API key.

## Possible outcomes

| Case                   | Result                                                 | is_new_account |
| ---------------------- | ------------------------------------------------------ | -------------- |
| New user               | Creates account and server wallet, returns new API key | true           |
| Returning user         | Finds existing account, returns existing API key       | false          |
| Invalid token          | 401 Unauthorized                                       | —              |
| Token missing identity | 400 Bad Request                                        | —              |

## Request flow

1. User authenticates on the client via the CDP SDK (email, SMS, or social)
2. Client sends the CDP Auth Token to this endpoint
3. Server validates the token using the CDP SDK
4. Server extracts a stable identity from the token
5. Server maps the identity to a Grove account
   - Creates one if it does not exist
   - Reuses it if it does
6. Server returns the Grove API key

## Identity normalization

- **Email**: lowercased and trimmed
  - `User@Example.com` → `user@example.com`
- **SMS**: spaces and dashes removed
  - `+1 555-123-4567` → `+15551234567`

## Notes

- The CDP SDK creates an EOA wallet, which is stored as the earning wallet
- Grove creates a developer-managed server wallet for agent and automation use cases
- The returned API key is deterministic and long-lived

## Request body

- CDPTokenExchangeRequest — Request model for exchanging a CDP Auth Token for a Grove API Key.
  - `token` string, required
  - `network` string, nullable
  - `earning_address` string, nullable — Legacy compatibility field for caller-provided earning/EOA address. Canonical earning address is the Smart Account address. Server-side extraction from CDP token takes priority over this field.
  - `evm_eoa_address` string, nullable — EOA owner of the CDP Smart Account (has exportable private key). Server-side extraction from CDP token takes priority over this field.
  - `referral_code` string, nullable — Referral code from an existing user. Only applied on new account creation.

## Response `200`

Successful Response

- CDPTokenExchangeResponse — Response model for successful CDP token exchange.
  - `account_id` string, required
  - `api_key` string, required
  - `identity_type` string, required
  - `identity_value` string, required
  - `tipping_address` string, nullable, required
  - `earning_address` string, nullable
  - `eoa_owner_address` string, nullable
  - `smart_account_address` string, nullable — ERC-4337 Smart Account address (for gas sponsorship)
  - `is_new_account` boolean, required
  - `wallet_setup_status` 'ok' | 'server_failed' | 'unknown' — Outcome of server-side tipping Smart Account deployment during this login. - `ok`: deployed or nothing to do - `server_failed`: deploy attempted but failed - `unknown`: deploy not attempted (non-SA/non-EVM) Earnings Smart Account deploy status is reported separately by GET /wallets/deployment-status.
  - `referral_code` string, nullable
  - `referred_by_account_id` string, nullable
  - `can_add_referral` boolean
  - `onchain_address` string, nullable, required
  - `client_address` string, nullable, required
  - `earnings_wallet` EarningsWallet, required — Dual earnings-wallet representation (owner EOA + Smart Account).
    - `eoa_address` string, nullable — Owner EOA address (non-earning key)
    - `smart_account_address` string, nullable — Smart Account address used as canonical earning wallet
    - `earnings_address` string, nullable, required — Canonical earnings address for sender-path use.
  - `earnings_address` string, nullable, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/grove/apis/grove-api.md) · [All operations](https://skmtc.net/grove/apis/grove-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/grove/grove-api/versions/f286b48a8105/schema)
