bitpro가 원문에서 글자만 모은 내용이에요. 표·그림·수식은 빠지거나 깨질 수 있어요. 전체 75쪽 중 19쪽
*` | 20 |
| `POST` | `/v1/exchange/stablefx/fund` | 20 |
| `GET` | `/v1/exchange/stablefx/fees/{tradeId}` | 30 |
| `POST` | `/v1/exchange/stablefx/notifications` | 50 |
# How-to: Verify webhook signatures
Source: https://developers.circle.com/api-reference/verify-webhook-signatures
Confirm that a webhook notification was sent by Circle by verifying its digital signature.
Every
[v2 webhook notification](/api-reference/webhooks#notification-api-versions)
sent by Circle (Circle Wallets, Circle Contracts, CPN payments, Digital Asset
Accounts, Gateway, StableFX) is signed with an asymmetric key. By verifying the
signature on each notification, you confirm the payload came from Circle and
wasn't tampered with in transit. The verification flow is the same across these
products. Only the public key endpoint differs per product.
<Note>
v1 notifications (Circle Mint, CPN Managed Payments) use a different signature
scheme. Contact your [Circle representative](mailto:sales@circle.com) for
details.
</Note>
## Signature scheme
Circle signs each v2 webhook notification with the `ECDSA_SHA_256` algorithm.
Every notification includes two headers your endpoint uses to verify the
signature:
* `X-Circle-Signature`: the digital signature of the notification body,
base64-encoded.
* `X-Circle-Key-Id`: the UUID of the public key that signed the notification.
Each signature is unique to the notification it accompanies, so run the
verification flow below for every webhook you receive.
## Verify a signature
<Steps>
<Step title="Read the signature and key ID from the headers">
Extract `X-Circle-Signature` and `X-Circle-Key-Id` from the incoming webhook
request's headers.
```text theme={null}
X-Circle-Key-Id: 879dc113-5ca4-4ff7-a6b7-54652083fcf8
X-Circle-Signature: MEYCIQCA9EvPbdEJiy7Cw0eY+KQZA/oFi5ZEInPs8CYpyaJexgIhAKtRNnDz9QRQmFKx8QFrvawp+8b9Bs2dQ03xD+XaWVDE
```
</Step>
<Step title="Fetch the public key">
Using the value of `X-Circle-Key-Id`, call your product's public key endpoint to
retrieve the public key and algorithm. Replace `<public_key_endpoint>` with the
endpoint for your product:
* [Wallets](/api-reference/wallets/common/get-notification-signature),
[Contracts](/api-reference/contracts/common/get-notification-signature),
[Gateway](/api-reference/gateway/all/get-permissionless-notification-signature),
and Digital Asset Accounts: `/v2/notifications/publicKey/{keyId}`
* [CPN](/api-reference/cpn/common/get-notification-signature):
`/v2/cpn/notifications/publicKey/{keyId}`
* [StableFX](/api-reference/stablefx/all/get-notification-signature):
`/v2/stablefx/notifications/publicKey/{id}`
```bash theme={null}
curl --request GET \
--url 'https://api.circle.com/<public_key_endpoint>/879dc113-5ca4-4ff7-a6b7-54652083fcf8' \
--header 'Authorization: Bearer $CIRCLE_API_KEY'
```
A successful response returns the base64-encoded public key:
```json theme={null}
{
"data": {
"id": "879dc113-5ca4-4ff7-a6b7-54652083fcf8",
"algorithm": "ECDSA_SHA_256",
"publicKey": "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAESl76SZPBJemW0mJNN4KTvYkLT8bOT4UGhFhzNk3fJqf6iuPlLQLq533FelXwczJbjg2U1PHTvQTK7qOQnDL2Tg==",
"createDate": "2026-01-15T21:47:35.107250Z"
}
}
```
<Tip>
The public key for a given `keyId` is static, so cache the result to avoid
fetching it on every webhook.
</Tip>
</Step>
<Step title="Verify the signature against the raw body">
Use the public key to verify the signature against the **raw** request body.
Parsing the JSON and re-serializing it changes the byte order, so the signature
no longer matches.
<CodeGroup>
```typescript Node.js theme={null}
import { createVerify, createPublicKey, KeyObject } from "crypto";
// Cache the public key by keyId to avoid refetching on every webhook.
const publicKeyCache = new Map<string, KeyObject>();
async function getPublicKey(keyId: string): Promise<KeyObject> {
const cached = publicKeyCache.get(keyId);
if (cached) return cached;
// Replace <public_key_endpoint> with your product's endpoint.
const response = await fetch(
`https://api.circle.com/<public_key_endpoint>/${keyId}`,
{ headers: { Authorization: `Bearer ${process.env.CIRCLE_API_KEY}` } },
);
const { data } = await response.json();
const publicKey = createPublicKey({
key: Buffer.from(data.publicKey, "base64"),
format: "der",
type: "spki",
});
publicKeyCache.set(keyId, publicKey);
return publicKey;
}
export async function verifyWebhook(
rawBody: string,
signature: string,
keyId: string,
): Promise<boolean> {
const publicKey = await getPublicKey(keyId);
const verifier = createVerify("SHA256");
verifier.update(rawBody);
return verifier.verify(publicKey, signature, "base64");
}
```
```python Python theme={null}
import base64
import os
import requests
from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec
# Cache the public key by keyId to avoid refetching on every webhook.
public_key_cache: dict = {}
def get_public_key(key_id: str):
if key_id in public_key_cache:
return public_key_cache[key_id]
# Replace <public_key_endpoint> with your product's endpoint.
response = requests.get(
f"https://api.circle.com/<public_key_endpoint>/{key_id}",
headers={"Authorization": f"Bearer {os.environ['CIRCLE_API_KEY']}"},
)
data = response.json()["data"]
public_key_bytes = base64.b64decode(data["publicKey"])
public_key = serialization.load_der_public_key(public_key_bytes)
public_key_cache[key_id] = public_key
return public_key
def verify_webhook(raw_body: bytes, signature_b64: str, key_id: str) -> bool:
public_key = get_public_key(key_id)
signature_bytes = base64.b64decode(signature_b64)
try:
public_key.verify(
signature_bytes,
raw_body,
ec.ECDSA(hashes.SHA256()),
)
return True
except InvalidSignature:
return False
```
</CodeGroup>
If verification succeeds, the notification is authentic. If it fails, reject the
request.
</Step>
</Steps>
# Wallets API
Source: https://developers.circle.com/api-reference/wallets
Create and manage developer-controlled and user-controlled wallets, execute transactions, and sign messages across supported blockchains.
Programmable Wallets is Circle's embedded MPC wallet platform. Use it when you
need secure key management without running your own custody stack.
## Get started
<CardGroup>
<Card title="API keys" icon="key" href="/api-reference/keys">
Authenticate your requests with an API key.
</Card>
<Card title="Postman collection" icon="rocket" href="/api-reference/wallets/postman">
Try the Wallets API with Circle's Postman collection.
</Card>
<Card title="Webhooks" icon="bell" href="/api-reference/wallets/common/get-subscriptions">
Set up webhook subscriptions for wallet events.
</Card>
</CardGroup>
## Endpoint categories
<CardGroup>
<Card title="Developer-Controlled" icon="server" href="/api-reference/wallets/developer-controlled-wallets/get-wallet-sets">
Manage wallet sets and wallets that your backend signs for.
</Card>
<Card title="User-Controlled" icon="user" href="/api-reference/wallets/user-controlled-wallets/list-users">
Manage wallets where your end users hold the signing key with a PIN.
</Card>
<Card title="Modular Wallets" icon="cubes" href="/api-reference/wallets/buidl/list-transfers">
Read transfers, user operations, and balances for Modular Wallets.
</Card>
<Card title="Configurations" icon="sliders" href="/api-reference/wallets/programmable-wallets/list-monitored-tokens">
Manage monitored tokens, developer account keys, and the faucet.
</Card>
<Card title="Compliance Engine" icon="shield-check" href="/api-reference/wallets/compliance/screen-address">
Screen addresses against compliance rules.
</Card>
</CardGroup>
## OpenAPI specifications
The Wallets API reference is generated from these OpenAPI specifications:
* `https://developers.circle.com/openapi/configurations_1.yaml`
* `https://developers.circle.com/openapi/configurations_2.yaml`
* `https://developers.circle.com/openapi/developer-controlled-wallets.yaml`
* `https://developers.circle.com/openapi/user-controlled-wallets.yaml`
* `https://developers.circle.com/openapi/buidl-wallets.yaml`
* `https://developers.circle.com/openapi/compliance.yaml`
See [OpenAPI Specifications](/api-reference/openapi-specifications) for the full
catalog of Circle's API specs.
# Retrieve a transfer
Source: https://developers.circle.com/api-reference/wallets/buidl/get-transfer
openapi/buidl-wallets.yaml get /v1/w3s/buidl/transfers/{id}
Retrieve an existing transfer.
# Retrieve a user operation
Source: https://developers.circle.com/api-reference/wallets/buidl/get-user-op
openapi/buidl-wallets.yaml get /v1/w3s/buidl/userOps/{id}
Retrieve an existing user operation.
# List transfers
Source: https://developers.circle.com/api-reference/wallets/buidl/list-transfers
openapi/buidl-wallets.yaml get /v1/w3s/buidl/transfers
Retrieve a list of transfers that fit the specified parameters.
# List user operations
Source: https://developers.circle.com/api-reference/wallets/buidl/list-user-ops
openapi/buidl-wallets.yaml get /v1/w3s/buidl/userOps
Retrieve a list of all user operations that fit the specified parameters.
# Get wallet balances by blockchain and address
Source: https://developers.circle.com/api-reference/wallets/buidl/list-wallet-balances-by-blockchain-address
openapi/buidl-wallets.yaml get /v1/w3s/buidl/wallets/{blockchain}/{address}/balances
Retrieve wallet balances by blockchain and address.
# Get wallet balances
Source: https://developers.circle.com/api-reference/wallets/buidl/list-wallet-balances-by-id
openapi/buidl-wallets.yaml get /v1/w3s/buidl/wallets/{id}/balances
Retrieve the balances of a wallet by its ID.
# Get wallet NFTs by blockchain and address
Source: https://developers.circle.com/api-reference/wallets/buidl/list-wallet-nfts-by-blockchain-address
openapi/buidl-wallets.yaml get /v1/w3s/buidl/wallets/{blockchain}/{address}/nfts
Retrieve the NFTs of a wallet by applicable blockchain and address.
# Get wallet NFTs
Source: https://developers.circle.com/api-reference/wallets/buidl/list-wallet-nfts-by-id
openapi/buidl-wallets.yaml get /v1/w3s/buidl/wallets/{id}/nfts
Retrieve the NFTs of a wallet by its ID.
# Challenge notification
Source: https://developers.circle.com/api-reference/wallets/common/challenges-initialize
openapi/configurations_2.yaml webhook challengesInitialize
Sent when a user-controlled wallet challenge changes state. The lifecycle
state of the challenge is conveyed by the `state` field on the
`notification` object.
States covered by this notification type:
- `COMPLETE`: the end user successfully passed the challenge. The
associated operation is initiated automatically.
- `FAILED`: the challenge failed (for example, an incorrect PIN or an
expired challenge). The operation must be re-initiated.
# Create a notification subscription
Source: https://developers.circle.com/api-reference/wallets/common/create-subscription
openapi/configurations_2.yaml post /v2/notifications/subscriptions
Create a notification subscription by configuring an endpoint to receive notifications. For details, see the [Notification Flows](https://developers.circle.com/wallets/webhook-notification-flows) guide.
# Delete a notification subscription
Source: https://developers.circle.com/api-reference/wallets/common/delete-subscription
openapi/configurations_2.yaml delete /v2/notifications/subscriptions/{id}
Delete an existing subscription.
# Get a notification signature public key
Source: https://developers.circle.com/api-reference/wallets/common/get-notification-signature
openapi/configurations_2.yaml get /v2/notifications/publicKey/{id}
Get the public key and algorithm used to digitally sign webhook notifications. Verifying the digital signature ensures the notification came from Circle.
In the headers of each webhook, you can find
1. `X-Circle-Signature`: a header containing the digital signature generated by Circle.
2. `X-Circle-Key-Id`: a header containing the UUID. This value is used as the `ID` URL parameter to retrieve the relevant public key.
# Retrieve a notification subscription
Source: https://developers.circle.com/api-reference/wallets/common/get-subscription
openapi/configurations_2.yaml get /v2/notifications/subscriptions/{id}
Retrieve an existing notification subscription.
# Get all notification subscriptions
Source: https://developers.circle.com/api-reference/wallets/common/get-subscriptions
openapi/configurations_2.yaml get /v2/notifications/subscriptions
Retrieve an array of existing notification subscriptions.
# Ping
Source: https://developers.circle.com/api-reference/wallets/common/ping
openapi/configurations_2.yaml get /ping
Checks that the service is running.
# Inbound transaction notification
Source: https://developers.circle.com/api-reference/wallets/common/transactions-inbound
openapi/configurations_2.yaml webhook transactionsInbound
Sent when an inbound transaction changes state. The lifecycle state of the
transaction is conveyed by the `state` field on the `notification` object.
States covered by this notification type:
- `CONFIRMED`: the transaction has been broadcast onchain and is awaiting
the required number of confirmations.
- `COMPLETE`: the transaction has reached the required confirmations and
the funds are available in the destination account.
# Outbound transaction notification
Source: https://developers.circle.com/api-reference/wallets/common/transactions-outbound
openapi/configurations_2.yaml webhook transactionsOutbound
Sent when an outbound transaction changes state. The lifecycle state of
the transaction is conveyed by the `state` field on the `notification`
object.
States covered by this notification type:
- `QUEUED`: the transaction has been initiated but has not yet been
processed.
- `SENT`: the transaction has been processed and sent to a blockchain
node but has not yet been broadcast onchain.
- `CONFIRMED`: the transaction has been broadcast onchain and is awaiting
the required number of confirmations.
- `COMPLETE`: the transaction has reached the required confirmations and
the funds are available in the destination account.
- `CANCELED`: a cancel request for the transaction has been confirmed.
- `FAILED`: the transaction failed (for example, due to insufficient
balance or a failed challenge).
# Update a notification subscription
Source: https://developers.circle.com/api-reference/wallets/common/update-subscription
openapi/configurations_2.yaml patch /v2/notifications/subscriptions/{id}
Update subscription endpoint to receive notifications.
# Screen a blockchain address
Source: https://developers.circle.com/api-reference/wallets/compliance/screen-address
openapi/compliance.yaml post /v1/w3s/compliance/screening/addresses
Create a screening request for a specific blockchain address and chain.
# Accelerate a transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-developer-transaction-accelerate
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/transactions/{id}/accelerate
Accelerates a specified transaction from a developer-controlled wallet. Additional gas fees may be incurred.
# Cancel a transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-developer-transaction-cancel
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/transactions/{id}/cancel
Cancels a specified transaction from a developer-controlled wallet. Gas fees may still be incurred.
This is a best-effort operation, it won't be effective if the original transaction has already been processed by the blockchain.
# Create a contract execution transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-developer-transaction-contract-execution
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/transactions/contractExecution
Creates a transaction which executes a smart contract. ABI parameters must be passed in the request.
Related transactions may be submitted as a batch transaction in a single call.
To identify the wallet, you must provide either `walletId`, or both `walletAddress` and `blockchain` in the request body.
# Create a transfer transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-developer-transaction-transfer
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/transactions/transfer
Initiates an on-chain digital asset transfer from a specified developer-controlled wallet.
To identify the wallet, you must provide either `walletId`, or both `walletAddress` and `blockchain` in the request body.
# Create a wallet upgrade transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-developer-transaction-wallet-upgrade
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/transactions/walletUpgrade
Creates a transaction which upgrades a wallet.
# Estimate fee for a contract execution transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-transaction-estimate-fee
openapi/developer-controlled-wallets.yaml post /v1/w3s/transactions/contractExecution/estimateFee
Estimates gas fees that will be incurred for a contract execution transaction, given its ABI parameters and blockchain.
# Estimate fee for a transfer transaction
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-transfer-estimate-fee
openapi/developer-controlled-wallets.yaml post /v1/w3s/transactions/transfer/estimateFee
Estimates gas fees that will be incurred for a transfer transaction; given its amount, blockchain, and token.
# Validate an address
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-validate-address
openapi/developer-controlled-wallets.yaml post /v1/w3s/transactions/validateAddress
Confirms that a specified address is valid for a given token on a certain blockchain.
# Create wallets
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/wallets
Creates a new developer-controlled wallet or a batch of wallets within a wallet set, given the target blockchain and wallet name.
**Note:** Each `walletSetId` supports a maximum of 10 million wallets.
# Create a new wallet set
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/create-wallet-set
openapi/developer-controlled-wallets.yaml post /v1/w3s/developer/walletSets
Creates a new developer-controlled wallet set.
**Note:** A developer account can create up to 1,000 wallet sets, with each set supporting up to 10 million wallets.
To ensure EVM wallets are created with the same address across chains, see [Unified Wallet Addressing on EVM Chains](/w3s/unified-wallet-addressing-evm).
# Derive a wallet
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/derive-wallet
openapi/developer-controlled-wallets.yaml put /v1/w3s/developer/wallets/{id}/blockchains/{blockchain}
Derives an EOA (Externally Owned Account) or SCA (Smart Contract Account) wallet using the address of the specified wallet and blockchain. If the target wallet already exists, its metadata will be updated with the provided metadata. This operation is only supported for EVM-based blockchains.
# Derive wallet by address
Source: https://developers.circle.com/api-reference/wallets/developer-controlled-wallets/derive-wallet-by-address
openapi/developer-controlled-wallets.yaml put /v1/w3s/developer/wallets/derive
Creates a wallet on the target blockchain using the same address as the source wallet identified by source bloc프로젝트로 돌아가기