---
title: "Sign messages and EIP-712 typed data"
description: "Message and EIP-712 typed-data signing."
---

> Documentation Index
> Fetch the complete documentation index at: https://tee.hypetrade.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Sign messages and EIP-712 typed data

**Auth: workspace token. Scope: `sign` on both routes.**

Both address a public key directly. Resolution is scoped to the session's own
workspace, so one tenant can never sign with another's key — and an address that
exists elsewhere returns the same `404` as one that does not exist at all.

## `POST /v1/sign/message`

Returns `200`.

### Request

```json
{
  "address": "0xabc…",
  "message": "hello from tee-docker",
  "encoding": "personal_sign"
}
```

| Field | Type | Required | Notes |
|---|---|---|---|
| `address` | string | yes | Public key, 1–128 characters |
| `message` | string | yes | The message to sign |
| `encoding` | enum | no | `personal_sign`, `raw`, or `ed25519` |

Omit `encoding` and the address signs with its VM's natural default.

### Response

```json
{ "address": "0xabc…", "signature": "0x…" }
```

With an explicit `encoding`, the response may also carry `messageHash`:

```json
{ "address": "0xabc…", "signature": "0x…", "messageHash": "0x…" }
```

> **raw applies no framing**
>
> `raw` signs exactly the bytes you send — no prefix, no domain separation. A
> signature over attacker-chosen raw bytes can be replayed as something else.
> Prefer `personal_sign` for anything human-originated.

## `POST /v1/sign/typed-data`

EIP-712 typed data. **EVM only.** Returns `200`.

### Request

```json
{
  "address": "0xabc…",
  "typedData": {
"domain": { "name": "MyDapp", "version": "1", "chainId": 1, "verifyingContract": "0xdef…" },
"types": { "Order": [ { "name": "maker", "type": "address" } ] },
"primaryType": "Order",
"message": { "maker": "0xabc…" }
  },
  "chainId": 1
}
```

| Field | Type | Required | Notes |
|---|---|---|---|
| `address` | string | yes | Public key, 1–128 characters |
| `typedData` | object | yes | The EIP-712 payload |
| `chainId` | integer | no | Positive. Defaults to the address's own network |

### Response

```json
{
  "address": "0xabc…",
  "signature": "0x…",
  "domainSeparator": "0x…",
  "structHash": "0x…"
}
```

Both intermediate hashes are returned so you can verify the domain binding
independently.

> **chainId is never guessed**
>
> When omitted, the signature binds to the address's own network — not to a
> default chain. An earlier release defaulted to mainnet; that was removed because
> a signed payload is a bearer instrument and a silent default let a
> testnet-intended signature carry mainnet weight.

A non-EVM address returns `422` with `unsupported_for_kind`.

## Errors

| Status | Code |
|---|---|
| 400 | `invalid_body` |
| 401 | `session_expired` |
| 403 | `scope_denied` |
| 404 | `account_not_found` |
| 422 | `unsupported_for_kind` |
| 423 | `account_locked` |

## Related

- [Sign messages](/guides/sign-messages/) — the task walkthrough

Source: https://tee.hypetrade.xyz/api/sign/index.mdx
