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

# Company Wallets quickstart

> From API key to a signed or custodially sent transaction with the 0xkey server SDK.

This guide assumes you have a 0xkey organization and an API keypair (create them in the [Dashboard](https://app.0xkey.io) under **Users → API keys**, or via `createApiOnlyUsers`). It uses the TypeScript server SDK. For Go, see [sdk-go examples](/sdks/go/landing).

## Installation

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
npm install @0xkey-io/sdk-server
```

## Sign or send your first transaction

<Steps>
  <Step title="Initialize the server client">
    Add credentials to `.env`:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    OXKEY_API_BASE_URL=https://api.0xkey.io
    OXKEY_ORGANIZATION_ID=<your-organization-id>
    OXKEY_API_PRIVATE_KEY=<your-api-private-key>
    OXKEY_API_PUBLIC_KEY=<your-api-public-key>
    ```

    ```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    import { ZeroXKey } from "@0xkey-io/sdk-server";

    const client = new ZeroXKey({
      apiBaseUrl: process.env.OXKEY_API_BASE_URL!,
      defaultOrganizationId: process.env.OXKEY_ORGANIZATION_ID!,
      apiPrivateKey: process.env.OXKEY_API_PRIVATE_KEY!,
      apiPublicKey: process.env.OXKEY_API_PUBLIC_KEY!,
    }).apiClient();
    ```
  </Step>

  <Step title="Create a wallet">
    ```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const { walletId, addresses } = await client.createWallet({
      walletName: "treasury",
      accounts: [
        {
          curve: "CURVE_SECP256K1",
          pathFormat: "PATH_FORMAT_BIP32",
          path: "m/44'/60'/0'/0/0",
          addressFormat: "ADDRESS_FORMAT_ETHEREUM",
        },
      ],
    });

    const ethereumAddress = addresses[0];
    console.log("Ethereum address:", ethereumAddress, "walletId:", walletId);
    ```

    For Solana, use `CURVE_ED25519` + `ADDRESS_FORMAT_SOLANA` + path `m/44'/501'/0'/0'`. For Tron, see [Tron](/networks/tron).
  </Step>

  <Step title="Add a deny-by-default allowlist policy (recommended)">
    Without an allow policy, signing is denied. Create a narrow policy for your automation user (replace tags / addresses as needed):

    ```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    await client.createPolicy({
      policyName: "treasury-eth-transfer-allowlist",
      effect: "EFFECT_ALLOW",
      condition:
        "activity.type == 'ACTIVITY_TYPE_SIGN_TRANSACTION_V2' && eth.tx.to == '0xApprovedRecipient'",
      consensus: "approvers.count() >= 1",
      notes: "Company Wallets quickstart sample",
    });
    ```

    See [Policy templates](/company-wallets/policy-templates) for treasury 2-of-N and agent deny patterns.
  </Step>

  <Step title="Sign a raw payload or custodially send">
    **Sign only** (you broadcast yourself):

    ```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const { r, s, v } = await client.signRawPayload({
      signWith: ethereumAddress,
      payload: "0xdeadbeef",
      encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
      hashFunction: "HASH_FUNCTION_KECCAK256",
    });
    ```

    **Custodial send** (0xkey builds, policy-checks, signs, broadcasts — EVM example):

    ```ts theme={"theme":{"light":"github-light","dark":"github-dark"}}
    const { sendTransactionStatusId } = await client.ethSendTransaction({
      from: ethereumAddress,
      to: "0xApprovedRecipient",
      caip2: "eip155:84532", // Base Sepolia — use a funded testnet address
      value: "0",
      data: "0x",
      sponsor: false,
    });

    const status = await client.getSendTransactionStatus({
      sendTransactionStatusId,
    });
    console.log(status);
    ```

    <Note>
      `sponsor: true` (gas sponsorship) requires an **Enterprise** plan. Free / PAYG / Pro receive an entitlement error. See [Gas Station](/reference/gas-station) and billing entitlements.
    </Note>
  </Step>
</Steps>

## When an activity needs consensus

If a policy sets `consensus` (e.g. `approvers.count() >= 2`), the activity stays in `ACTIVITY_STATUS_CONSENSUS_NEEDED` until enough approvers call `approveActivity` (or reject). Operators can approve in the [Dashboard → Activities](https://app.0xkey.io) or via the API. Approvals expire after **24 hours**.

## Next steps

* [Integration guide](/company-wallets/integration-guide) — tags, webhooks, import/export
* [Remote attestation](/products/company-wallets/features/security/remote-attestation) — verify TEE proofs in production
* [demo-company-wallet](https://github.com/0xkey-io) — local/staging sandbox (org → policy → consensus → send)
