# Sign and store arbitrary payloads

You can use the following two API intent types for payload signature and storage:

- Sign a manifest: An intent that signs an arbitrary payload.
- Notarize data: An intent that securely stores a payload.


## Sign a manifest

There are three types of manifests you can sign:

- EIP-191: Payload signature based on the Ethereum EIP-191 standard.
- JSON Web Token (JWT): Signature of a constructed JWT.
- Unsafe: Signature of any arbitrary payload, including a message that represents a real transaction. To use this type, you need to enable it first by setting environment variable `HMZ_NOTARY_ENABLE_UNSAFE_SIGN_MANIFESTS = TRUE` in the notary container.


The primary purpose of this feature is to enable signature of any arbitrary message. Transactions broadcast on ledgers using Ripple Custody with the `SignManifest` route may result in unexpected product behavior.
For more information, contact the Ripple support team.

### Prerequisites

| Prerequisite | Additional information |
|  --- | --- |
| The ID of the source account whose private key will produce the signature.For EIP-191 manifests, this must be an Ethereum account. | [View account details](/pt-br/products/custody/accounts-and-assets/accounts/manage-accounts-api#view-account-details) |
| A new intent ID, in a standard UUID format |  |
| To sign with a specific address on a Bitcoin-family ledger: an address that Ripple Custody recorded for the source account on that ledger | [Sign with a specific Bitcoin-family address](#sign-with-a-specific-bitcoin-family-address) |


### Sign the manifest

System change process
All new requests to change the system state follow the same process. To familiarize yourself with this process first, see [Manage intents and approvals](/pt-br/products/custody/governance/intents/manage-intents-and-approvals).

To sign a manifest, follow the steps in [Submit an intent with the API](/pt-br/products/custody/governance/intents/manage-intents-and-approvals#submit-an-intent-with-the-api), with a payload similar to one of the following examples.

#### Payload examples

##### Sign a payload with a EIP-191 signature

```json
{
    "payload":{
        "id": "b4446c6b-448c-48c6-b0c5-27fb2af441cd",
        "accountId": "d259d90a-9050-4849-ad8a-4072ac509d9a",
        "content": {
            "value": "0x19457468657265756d205369676e6564204d6573736167653a0a33333957656c636f6d6520746f204f70656e536561210a0a436c69636b20746f207369676e20696e20616e642061636365707420746865204f70656e536561205465726d73206f6620536572766963653a2068747470733a2f2f6f70656e7365612e696f2f746f730a0a5468697320726571756573742077696c6c206e6f742074726967676572206120626c6f636b636861696e207472616e73616374696f6e206f7220636f737420616e792067617320666565732e0a0a596f75722061757468656e7469636174696f6e207374617475732077696c6c20726573657420616674657220323420686f7572732e0a0a57616c6c657420616464726573733a0a3078333662353163666135303637356661636332393038336362326330393361363237346230346639330a0a4e6f6e63653a0a63336561316363662d653032302d343430652d613935302d623462326139383862653433",
            "type": "EIP-191"
        },
        "customProperties": {},
        "type": "v0_SignManifest"
    }
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `type` | Type of intent, in this case `v0_SignManifest` |
| `content.type` | Type of signature |
| `content.value` | A hexidecimal string in format `0x19 <1 byte version> <version specific data> <data to sign>`, where `<1 byte version>` is `00`, `01`, or `45`, depending on the formatting the bytes must use. For example, `01` means you can also sign messages in the EIP-712 standard format. You must check the formatting carefully, as no additional validation is performed by Ripple Custody. |


##### Sign a payload with a JWT

```json
"payload": {
    "id": "b4446c6b-448c-48c6-b0c5-27fb2af441cd",
    "accountId": "777067ee-741b-4536-bbd0-4a11c04bcbd1",
    "content": {
        "header": {
            "type": "at+jwt",
            "algorithm": "RS256",
            "additionalParameters": {
                "custom_field": "custom value"
            }
        },
        "payload": {
            "issuer": "https://oauth-harmonize-qa-v4-1-7.m3t4c0.tech",
            "subject": "MFkwEwYHKoZAQcDQgAE0h3vZHgWEw3JPK2J/a+ffK4cRwgGdHwzU2jfAC6X+LnDOEFeVA==",
            "audience": "metaco",
            "expiration": 1668604952,
            "notBefore": 1668590552,
            "issuedAt": 1668590552,
            "jwtId": "Bkgw2n4gLO4SNMbbceY9e",
            "additionalClaims": {
                "custom_field": "custom value"
            }
        },
        "type": "JWT"
    },
    "customProperties": {
        "custom_property": "0x57656c636f6d6520746f204f70656e536561210a0a436c69636b20746f207369676e20696e20616e642061636365707420746865204f70656e536561205465726d73206f6620536572766963653a2068747470733a2f2f6f70656e7365612e696f2f746f730a0a5468697320726571756573742077696c6c206e6f742074726967676572206120626c6f636b636861696e207472616e73616374696f6e206f7220636f737420616e792067617320666565732e0a0a596f75722061757468656e7469636174696f6e207374617475732077696c6c20726573657420616674657220323420686f7572732e0a0a57616c6c657420616464726573733a0a3078333662353163666135303637356661636332393038336362326330393361363237346230346639330a0a4e6f6e63653a0a63336561316363662d653032302d343430652d613935302d623462326139383862653433"
       },
       "type": "v0_SignManifest"
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `type` | Type of intent, in this case `v0_SignManifest` |
| `content.type` | Type of signature |
| `content.header` | Header details of the payload to sign |
| `content.payload` | Content details of the payload to sign |


##### Sign an unsafe payload

```json

{
    "id": "a50f8c73-26b6-4198-9cda-a557ae3a3040",
    "accountId": "54f87389-71f2-4e11-8dd4-427f876c96a1",
    "description": "An unsafe type of signature",
    "customProperties": {},
    "content": {
        "type": "Unsafe",
        "value": "dGhpcyBpcyBmaW5lIQ=="
    },
    "type": "v0_SignManifest"
}
```

Fields of the `payload` block to note are as follows:

| Field | Description |
|  --- | --- |
| `type` | Type of intent, in this case `v0_SignManifest` |
| `content.type` | Type of signature |
| `content.value` | Base64-encoded payload to sign. For a transaction object, this is the unsigned raw transaction. |


### Sign with a specific Bitcoin-family address

On account-based ledgers such as Ethereum, an account has a single address. On Bitcoin-family ledgers — Bitcoin, Bitcoin Cash, Litecoin, Dogecoin, and Dash — an account can have several addresses, each with its own key, so to prove ownership of a specific address, you need to choose which address's key signs the manifest.

To prove that you control a specific address — for example, for a Travel Rule check by a counterparty — set the optional `address` field. The manifest is then signed with the key of that address, and the counterparty can recover the address's public key from the signature.

- The address must be one that Ripple Custody recorded for the source account on that ledger. You can't sign with an address that you derived yourself from the account's extended public key (xpub).
- The manifest must be of type `Unsafe`. The `address` field isn't supported for `EIP-191` or `JWT` manifests. The `Unsafe` type must be enabled first, as described in [Sign a manifest](#sign-a-manifest).
- If the account has addresses on more than one ledger, also set `ledgerId`.
- If you omit `address`, the manifest is signed as it was before version 1.43.
- Address-level signing is available through the API only, and only for Bitcoin-family ledgers. It isn't available for other ledgers, including Cardano.


The signature uses ECDSA over secp256k1 on SHA-256(SHA-256(payload)) and returns `r`, `s`, and a recovery ID, so a verifier can recover the public key.

#### Payload example

The following example signs an unsafe payload with the key of a Bitcoin testnet address:

```json
{
    "id": "a50f8c73-26b6-4198-9cda-a557ae3a3040",
    "accountId": "54f87389-71f2-4e11-8dd4-427f876c96a1",
    "ledgerId": "bitcoin-testnet",
    "address": "tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx",
    "description": "Proof of address ownership",
    "customProperties": {},
    "content": {
        "type": "Unsafe",
        "value": "dGhpcyBpcyBmaW5lIQ=="
    },
    "type": "v0_SignManifest"
}
```

| Field | Description |
|  --- | --- |
| `address` | Optional. The address whose key signs the manifest. Must be an address that Ripple Custody recorded for the account on a Bitcoin-family ledger. Supported only when `content.type` is `Unsafe`. |
| `ledgerId` | Optional. The ledger of the address. Required if the account has addresses on more than one ledger. |


Ripple Custody rejects the intent with a message that describes the reason, if the address isn't a recorded address of the account on that ledger, or if the account's key can't be used for address-level signing.

### Retrieve the manifest signature

To retrieve the signature generated for the manifest, call the [Get manifest details](/pt-br/products/custody/reference/api/openapi/accounts/getmanifest) API operation. For a manifest signed with a specific address, the response includes that `address`; otherwise, `address` is `null`.

The `additionalDetails.processing.type` field of the response gives the manifest's processing status:

| Status | Meaning |
|  --- | --- |
| `Pending` | The notary has validated the `v0_SignManifest` intent, and ledger accounting has acknowledged the manifest. |
| `Preparing` | Ledger accounting has acknowledged the manifest signature that the vault returned. |
| `Completed` | The notary has completed the manifest request. |
| `Failed` | The manifest request failed. |


## Store a payload

The `v0_NotarizeData` intent type is a generic intent that you can use to securely store a data payload. Once validated, it does not trigger any specific action other than to save the data contained in the payload in a secure state.
You can use this intent to trigger external effects to extend the capabilities of the system, such as to initiate fiat payment orders or trading orders.

To securely store a payload, follow the steps in [Submit an intent with the API](/pt-br/products/custody/governance/intents/manage-intents-and-approvals#submit-an-intent-with-the-api), with a payload similar to the following example.

### Payload example

```json
{
    "payload": {
        "data": " ... ",
        "type": "v0_NotarizeData"
    }
}
```

There is no specific constraint on how to format the `data` field.