Wallets

Add organisation wallets and prove you own them, add beneficiary wallets, and know which wallet a transaction can send from or pay to

There are two kinds of wallet, created through different endpoints:

Organisation walletBeneficiary wallet
Belongs toYour organisationA receiver
Used asThe wallet you send crypto from, and where on-ramp tokens arriveThe wallet you pay crypto to
CreatePOST /organisations/{organisationId}/add-walletPOST /wallets
ScreeningYes. The result is stored on the walletYes. The wallet is refused unless it passes
Ownership proofRequiredNot required
ReadGET /organisations/{id}, in walletsGET /receivers/{id}, in wallets
RemoveDELETE /organisations/{organisationId}/delete-wallet/{walletId}DELETE /wallets/{id}

Get network ids from GET /networks/client-visible. Wallets are supported on EVM networks and Solana.

Organisation wallets

Requirements

  • organisationId must be the user's selected organisation. Read it from selectedOrganisation._id in GET /users/me.
  • The user must be a member of the organisation who is not view-only.
  • The address must not already belong to another organisation.

Add the wallet

POST /organisations/{organisationId}/add-wallet

FieldRequiredNotes
addressYesEVM: 0x followed by 40 hex characters. Solana: a base58 address
networkYesNetwork _id. The address format must match the network
typeNoEOA (default) or SAFE. SAFE is for Safe multisig wallets on EVM networks only
ownershipMessageNoThe text you will sign to prove ownership. If you leave it out, the server generates a 6-digit number
{
  "address": "0x2f4e1b7c9a0d3e5f6a8b1c2d3e4f5a6b7c8d9e0f",
  "network": "6650a1b2c3d4e5f607182930",
  "type": "EOA",
  "ownershipMessage": "Skyline wallet verification 2026-09-28"
}

The response is the organisation, not the wallet. The new wallet is the last element of its wallets array. Keep its _id and ownership.message.

StatusMessage
400No selected organisation
400User selected organisation different from provided organisation Id
401Your user does not have enough permission to perform this action
400The address <address> is already linked to an existing organization
400An address that is not valid for the network, or an unknown network

Screening result

Every wallet is screened when you add it. The result is in walletAnalysisStatus on the wallet:

StatusMeaning
APPROVEDPassed. The wallet can be used
REQUIRES_MANUAL_CHECKSkyline compliance must review it. It cannot be used until approved
BLOCKEDRefused. It cannot be used
ERRORScreening could not complete. Contact Skyline
PENDINGNot screened yet

Screening finishes during the add request. REQUIRES_MANUAL_CHECK, BLOCKED and ERROR change only after a Skyline review, so re-read the organisation later instead of polling quickly.

Prove ownership

A new organisation wallet starts with ownership.status = PENDING. To approve it:

  1. Take the exact ownership.message string from the wallet.
  2. Sign it with the wallet's key:
    • EVM (EOA): EIP-191 personal_sign, which is what signMessage does in ethers, viem and web3.js. Send the 0x hex signature. Contract wallets that implement EIP-1271 are also accepted.
    • Solana: an ed25519 signature over the UTF-8 bytes of the message, encoded in base58.
  3. Send it to POST /wallets/{id}/verify-wallet, where {id} is the wallet _id:
{
  "message": "Skyline wallet verification 2026-09-28",
  "signedMessage": "0x5b1c…"
}

On success the response is the wallet with ownership.status = APPROVED.

StatusMessageCause
400Invalid messagemessage is not exactly ownership.message
400Invalid signature: signed by 0xabc…, expected 0xdef…An EVM signature from a different address
400Invalid signatureThe signature does not verify
400Wallet network is not configuredThe wallet has no network
403User <id> does not have permission to access this wallet.The wallet is not in your organisation
404Wallet not foundWrong id

Safe multisig wallets

A Safe approves the message once enough owners have signed it.

  1. In the Safe app or with the Safe SDK, have an owner sign ownership.message as a Safe message. This creates a message proposal that other owners confirm.

  2. Call POST /wallets/{id}/verify-wallet with the message and the owner's signature.

  3. While the proposal has fewer confirmations than the Safe's threshold, the call returns 400 with "code": "SAFE_SIGNATURES_PENDING". If the Safe service cannot be reached, it returns 503 with "code": "SAFE_SERVICE_UNAVAILABLE".

  4. Poll POST /wallets/{id}/verify-wallet/recheck (no body) about every 10 seconds while the other owners confirm. It returns { "status": …, "confirmations": …, "confirmationsRequired": … }:

    statusMeaning
    PENDING_SIGNATURESBelow the threshold. Keep polling
    APPROVEDThreshold met. The wallet now has ownership.status = APPROVED. Stop
    NOT_FOUNDNo proposal for ownership.message yet. Check step 1
    SERVICE_ERRORThe Safe service could not be reached. Retry later
    NOT_APPLICABLENot a Safe wallet on an EVM network, or ownership is already decided

Beneficiary wallets

POST /wallets

FieldRequiredNotes
receiverYesThe receiver's _id
addressYesThe wallet address
networkYesNetwork _id
typeNoEOA (default) or SAFE
{
  "receiver": "665f1c2e9b1e8a0012a3b4c5",
  "address": "0x8a3b9c2d1e0f4a5b6c7d8e9f0a1b2c3d4e5f6a7b",
  "network": "6650a1b2c3d4e5f607182930"
}
  • The wallet is screened during the request. If it does not pass, the call returns 403 Wallet with address <address> is not approved and nothing is saved.
  • If screening cannot complete, the wallet is saved with walletAnalysisStatus = ERROR and cannot be used until Skyline reviews it.
  • The server does not check that the address format matches the network. Check it yourself: a wrong pair cannot be paid.
  • No ownership proof is needed for a third party's wallet.
  • The response is the wallet.

PATCH /wallets/{id} changes only network. DELETE /wallets/{id} removes a beneficiary wallet. Do not use it for organisation wallets.

Which wallet a transaction can use

Role in a transactionWalletMust have
Sender in crypto-to-fiat and crypto-to-crypto (walletAddress)An organisation wallet of the selected organisationwalletAnalysisStatus = APPROVED
Destination of an on-rampAn organisation walletwalletAnalysisStatus = APPROVED and ownership.status = APPROVED
Destination of a crypto paymentA beneficiary walletwalletAnalysisStatus = APPROVED. A wallet on your organisation's own receiver also needs ownership.status = APPROVED

Errors you may see at submit, accept or payout:

  • 403 Wallet not found: the sender address is not an organisation wallet of your selected organisation.
  • 403 with "code": "WALLET_NOT_WHITELISTED": the destination has not passed screening, or its ownership is not approved where required. The body includes walletAnalysisStatus, ownershipStatus and ownershipRequired.

Prove ownership of every organisation wallet as soon as you add it.

What's next

With receivers, bank accounts and wallets in place, create a transaction.

On this page