Python SDK for trading on Native Core via the public gateway (testnet only for now).
Project description
native-core-python-sdk
Testnet only. This release connects to the Native Core testnet (the UAT gateway) and nothing else. Mainnet is not supported yet: approving an API wallet is currently open on the testnet site only, so a mainnet key cannot be created or used through the SDK. Treat this as an early, pre-1.0 release whose surface may still change; mainnet support will land in a later version.
A Python SDK for trading on Native Core. It reads market data, places and cancels orders, and runs trading bots against the public gateway.
There are two classes. Info handles reads, Exchange handles writes. Calls are synchronous (built on requests) and return the gateway's JSON as plain dicts, annotated with TypedDict.
The SDK trades with an API wallet: a key scoped to placing and cancelling orders, never to moving funds (section 2 covers why that makes it safe in a bot). Deposits and withdrawals stay in the web app with your main wallet.
You need Python 3.10 or newer. The runtime dependencies are requests, eth-account, and eth-utils.
Scope. Spot order-book markets only (no perpetual futures). Testnet only for now. Calls are synchronous and blocking: a /trade write returns its settled outcome inline (no polling to learn whether it landed), and there is no async API and no websocket or streaming feed (wrap calls in your own executor if you need concurrency). Deposits and withdrawals are done in the web app, not through the SDK.
1. Install
pip install native-core-python-sdk
While the SDK is pre-1.0, any release may change the API. Pin an exact version and review the changes before upgrading:
pip install native-core-python-sdk==0.2.0
2. Get an API wallet
Before the SDK can trade, you need a funded account and an API wallet (your bot's key). You set this up once in the Native web app. The SDK never handles funds itself.
- Open the Native app and connect your main wallet.
- Fund the account by depositing through the app. There is no faucet: bring your own Arbitrum Sepolia testnet assets and deposit them from your main wallet. Your trading account is created on the first deposit.
- Open the API wallets panel and click Create API wallet. Your main wallet signs one approval, and the app shows you a connection bundle that contains the private key. It shows the key once, so copy it now.
The bundle is a small JSON object. Save the whole thing to a file (e.g. bundle.json — that is what the quickstart loads), and hand it to the SDK as a file path, a dict, or a JSON string:
{
"network": "testnet", // which gateway to use
"accountAddress": "0x…", // your main wallet, the account the bot trades on
"agentPrivateKey": "0x…", // the API wallet key the SDK signs with
"…": "…"
}
A leaked API wallet key can trade your balance, but it can never withdraw or move funds off Native, so it is safe to run in a bot. Revoke it in the app any time to rotate it.
3. Quickstart
Load the bundle, place a resting limit order, confirm it rests, then cancel it. This runs on testnet:
from decimal import Decimal
from native_core import Exchange, is_accepted, order_state
BUNDLE = "bundle.json" # the file you saved, or the dict / JSON string itself
MARKET = "ETH/USDT"
exchange = Exchange.from_bundle(BUNDLE) # picks the gateway, loads the key, sets owner
info = exchange.info
# Check the API wallet is approved before you trade.
print(exchange.agent_info()) # {"approved": True, "slot_id": 0, "epoch": 10}
# Price a bid well below the market so it rests instead of filling.
book = info.l2_book(MARKET, depth=1)
reference = book["asks"] or book["bids"] # whichever side has liquidity
px = info.snap_price(MARKET, Decimal(reference[0]["price"]) / 2)
sz = info.min_order_size(MARKET, px)
# place() submits the order and waits for it to rest. It returns the handle and the state.
order = exchange.place(MARKET, is_buy=True, sz=sz, limit_px=px, tif="gtc")
print(order["cloid"], order["state"]) # 0x… open
# Cancel it, then confirm it left the book.
cancel = exchange.cancel_by_cloid(MARKET, order["cloid"])
assert is_accepted(cancel)
final = info.wait_for_order(exchange.effective_account, MARKET, order["cloid"])
print(order_state(final)) # cancelled
Two ideas this quickstart leans on — a write returns its settled outcome directly, and every order carries a reconcilable cloid — are the heart of the next section.
4. Core concepts
Reads versus writes. Info wraps POST /info (market data, balances, order status). Exchange wraps POST /trade (orders). Both return the gateway's raw JSON.
The write returns the settled outcome. The gateway is synchronous: a write's submission_status is exactly one of three values — accepted (the tx landed and executed, which INCLUDES a benign no-fill/no-rest cancel like ioccancel or marketordernoliquidity), rejected (an admission reject or a genuine execution failure, with the reason on error.code), or timeout (indeterminate). You do not poll to learn whether the write landed. What the response does not carry is the oid, the fill amount, or the fill/rest/cancel lifecycle — those live only on /info order status, so read the order once when you need them:
wait_for_open(user, market, cloid)for an order you expect to rest (gtc / alo). It returns the resting snapshot (with theoid).wait_for_order(user, market, cloid)for one you expect to finish (ioc / fok / market, or after a cancel). It returns the terminal snapshot (withfilled_qty).exchange.place(...)submits and does that one enrichment read for you, returning{cloid, submission, status, state}.
Do not call wait_for_order on a resting order. A resting order has no terminal state, so the call just times out. That is what wait_for_open is for.
Every order is reconcilable. order() and market_order() return the cloid and the nonce they used; batch() returns cloids (one per order leg) plus the shared nonce. Pass your own cloid or let the SDK generate one; either way the response carries it. If a write times out on the wire, the SDK raises SubmissionUncertain with the cloid attached. Reconcile it with wait_for_order. Do not resubmit under a fresh nonce, or the order may land twice.
One Exchange per API wallet. The nonce is a per-instance monotonic counter and is lock-guarded, so a single Exchange is safe to share across threads. But two instances — or two processes — signing with the same key hand out colliding nonces and draw seemingly random rejections. Construct one and share it, rather than one per worker.
Numbers are strings, never floats. Pass sz and limit_px as str or Decimal: "0.01", not 0.01. Each market has a fixed precision (decimal places, significant figures, a minimum notional). info.snap_price(market, price) and info.min_order_size(market, price) round a value to what the market accepts. The SDK validates before signing and raises LocalValidationError rather than round your number down without telling you.
Errors live in the response body. A business rejection is data, not an exception: {"submission_status": "rejected", "error": {"code": …}}. Read it with the helpers is_accepted, is_rejected, is_timeout, error_code, retry_after_ms, and is_retryable. The SDK raises only for a transport failure (NetworkError), a response that is not a trade response (ClientError / ServerError), or a problem it catches before signing (LocalValidationError).
Markets by symbol or id. Anywhere a market argument appears, pass "ETH/USDT" or its integer id. Symbols and precision are fetched once when you construct Info.
Testnet only, for now. This release runs on testnet. The bundle's network must be testnet, and from_bundle picks the gateway. Building by hand against constants.MAINNET_API_URL (or a bundle with network: "mainnet") raises LocalValidationError — mainnet is not usable through the SDK yet, because an API wallet can only be approved on the testnet site. An API wallet is bound to one network.
5. Running the examples
The examples ship in the source distribution (the .tar.gz on PyPI), under examples/. They read examples/config.json; copy the template and fill in your key:
cp examples/config.json.example examples/config.json
{ "secret_key": "0x<agentPrivateKey>", "account_address": "0x<accountAddress>" }
Read-only tours live under examples/info/. They place no orders, but still read your key from config.json (the account address is derived from the key when account_address is blank), so a valid secret_key must be present:
python examples/info/query_markets_info.py # tradable markets and their precision
python examples/info/query_orderbook_info.py # the L2 order book for a market
python examples/info/query_balances_info.py # your spot balances
python examples/info/query_open_order_info.py # your open orders in a market
The trading examples sit at the top level. They place real orders on testnet:
python examples/basic_order.py # resting limit order: place, confirm it rested, cancel
python examples/basic_market_order.py # market order with an explicit protection price
python examples/basic_batch.py # several orders and cancels under one nonce
They default to testnet and ETH/USDT. Edit the MARKET constant to trade a different market.
6. Using it from an AI agent
The SDK is built to be driven by an AI agent, not just a person. If you are wiring an agent (or an autonomous bot) to trade, start here: one safety contract, two integration paths.
Pointing an agent at mainnet raises LocalValidationError at construction (testnet only for now — see the top of this README).
The safety contract
An agent that places money-moving orders must hold to a few rules. The SDK returns each outcome as structured fields, so the agent branches on a field instead of parsing prose or remembering the rule. (Section 4 explains each rule; this is the agent-facing summary.)
- Read the settled status; a fill is not implied. A successful write's
submission_statusisaccepted— the tx landed, butacceptedINCLUDES a benign no-fill/no-rest cancel, so it does not mean the order rested or filled. The response carries nooid, fill amount, or lifecycle — callreconcile_by_cloid(orwait_for_openfor a resting order) once to read them. - Never resubmit an uncertain write. A wire timeout —
SubmissionUncertain, orsubmission_status: "timeout"— means the order MAY still be live. Reconcile bycloidand act on the result; resubmitting under a fresh nonce risks a double-fill. The response says so directly:next_actionisRECONCILE_BY_CLOID, with the cloid attached. - Rejections are data. A business rejection comes back in the body with an
error.code; fix the cause. OnlyRateLimitedis safe to resend (is_retryable). - Numbers are strings. Size with
min_order_sizeand validate withbuild_order(a dry run that sends nothing) to avoid a precision or minimum-notional rejection. - Survive a restart. Generate the
cloidyourself withrandom_cloid(), persist{intent, cloid}durably before callingorder(..., cloid=cloid), and on restart reconcile every persisted cloid withreconcile_by_cloidbefore placing anything new. An agent that crashes after sending but before recording an SDK-generated cloid cannot reconcile and may double-fill — this is the idempotency-key pattern.
next_action(response) collapses any trade response into one verdict to branch on (it returns None for a non-trade response):
next_action |
Situation | What the agent does |
|---|---|---|
READ_ORDER_STATUS |
accepted — landed & executed |
Read order_status once for the oid / fill amount (the outcome itself is already settled — a single read, not a poll) |
RECONCILE_BY_CLOID |
timeout — indeterminate |
reconcile_by_cloid; never resubmit |
BACKOFF_AND_RETRY |
RateLimited — never admitted |
Sleep retry_after_ms, then resend the same order |
FIX_AND_RESUBMIT |
rejected — admission or execution failure |
Read error.code, fix the input or account state, submit fresh |
None |
not a trade response | — |
as_problem_details(failure) renders any exception or rejected/timeout body into one flat {type, title, retryable, next_action, cloids, …} envelope (see the response helpers in section 7).
Option A — the MCP server (no glue code)
An optional MCP server lets an AI assistant that speaks the Model Context Protocol (such as Claude Desktop) read the market and place orders through the SDK, without you writing any glue code. Install it with the mcp extra:
pip install "native-core-python-sdk[mcp]"
Or, from a clone: pip install -e ".[mcp]".
The server reads its configuration from the environment, never from the assistant. Reads are always available; the order-placing and cancelling tools are registered only when you explicitly turn trading on, so a read-only setup physically cannot place an order.
| Variable | Purpose |
|---|---|
NATIVE_CORE_BUNDLE |
Path to a connection bundle JSON ({network, accountAddress, agentPrivateKey}). Supplies everything on its own. |
NATIVE_CORE_NETWORK |
testnet (default) when not using a bundle. Mainnet is not supported yet. |
NATIVE_CORE_ACCOUNT |
Your account address, for account-scoped reads. |
NATIVE_CORE_AGENT_KEY |
The API wallet's private key, required for trading. |
NATIVE_CORE_ENABLE_TRADING |
Set to 1 to register the write tools. Off by default: without it the server is read-only even if a key is present. |
Run it over stdio with native-core-mcp (or python -m native_core.mcp). To connect it to Claude Desktop, add this to its MCP config, pointing NATIVE_CORE_BUNDLE at your bundle file:
{
"mcpServers": {
"native-core": {
"command": "native-core-mcp",
"env": {
"NATIVE_CORE_BUNDLE": "/path/to/your/bundle.json",
"NATIVE_CORE_ENABLE_TRADING": "1"
}
}
}
}
The read tools are always available: whoami, list_markets, get_orderbook, get_balances, list_open_orders, get_order (poll one order by cloid), get_fills (recent executions), get_min_order_size, and reconcile_order (the uncertain/timeout recovery). The write tools are registered only when trading is enabled: preview_order (a dry run that places nothing), place_limit_order, place_market_order, cancel_order, and cancel_all_orders. Every result is normalized so the assistant sees the order's state and what to do next; a timed-out or uncertain order comes back telling it to reconcile by cloid, never to resubmit.
Use a dedicated, limited API wallet here, never your main wallet. These tools are convenience, not a security boundary: the real protection is that the API wallet is scoped and revocable in the app.
Option B — drive the SDK from your agent code
If your agent does its own tool-calling (not MCP), call the SDK directly and hand the model the same decision-ready fields. A minimal place-then-reconcile loop:
from native_core import Exchange
exchange = Exchange.from_bundle(BUNDLE) # a testnet bundle
order = exchange.place(MARKET, is_buy=True, sz=sz, limit_px=px, tif="gtc")
# Resolve the real outcome by cloid — never resubmit on an uncertain one.
verdict = exchange.info.reconcile_by_cloid(exchange.effective_account, MARKET, order["cloid"])
if verdict["undetermined"]:
... # not confirmed yet: keep reconciling by cloid, do not re-place
elif verdict["is_filled"]:
... # fully filled
elif verdict["filled_qty"] != "0":
... # partially filled and still resting — verdict["filled_qty"] is how much
else:
... # resting, unfilled (verdict["state"], e.g. "open")
The response helpers and reconcile_by_cloid (section 7) are the agent-facing surface. The MCP tools above are thin wrappers over exactly these SDK calls: get_order ≈ reconcile_by_cloid, get_min_order_size ≈ min_order_size, preview_order ≈ build_order.
7. API reference
Info (reads)
Build with Info(base_url) or Info.from_bundle(bundle). Any market argument takes a "BASE/QUOTE" symbol or an integer market id.
| Method | Returns |
|---|---|
markets() / assets() / quote_assets() |
Tradable markets and their assets, with precision |
resolve_market_id(market) |
Resolve a "BASE/QUOTE" symbol to its integer market id |
l2_book(market, depth=20) |
Order book, up to 100 levels |
mark_prices(asset_ids=None) / oracle_status() |
Mark prices; oracle health |
query_status() |
Current query height and the available block-height window |
user_balances(address) |
Spot balances |
open_orders(address, market) |
Resting orders in one market |
open_orders_all(address, markets=None) |
Open orders across markets, each tagged with its market id |
order_status(oid=None, user=None, market=None, cloid=None) |
One order, by oid or by (user, market, cloid) |
batch_order_status(orders) |
Up to 20 orders at once |
user_fills(address, from_height, to_height, limit) |
Fills in a raw block-height window (≤10,000 blocks) |
recent_fills(address, blocks=10000) |
Every fill in roughly the last N blocks, window resolved for you |
iter_user_fills(address, start_height=None, …) |
Iterate all fills since a height, paged and deduped |
tx_status(user, cloid) |
Status of a deposit / withdraw / settle / repay by cloid |
account_status(address) |
Whether an account exists and its state |
spot_credit_account(address) / spot_credit_positions(address) |
Credit-account details |
user_agents(address) / agent_status(owner, agent_address) |
Approved API wallets; whether one is approved |
snap_price(market, price) / min_order_size(market, price) |
Round a price or size to what the market accepts |
protection_price(market, is_buy, slippage_bps, ref_price=None) |
Worst acceptable price for a market order, derived from the book |
wait_for_open(user, market, cloid, timeout=5.0) |
Poll until the order is resting or terminal |
wait_for_order(user, market, cloid, timeout=5.0) |
Poll until the order is terminal |
reconcile_by_cloid(user, market, cloid, timeout=5.0) |
Did an order land? A one-call verdict (state, undetermined, is_filled, filled_qty) for the uncertain/timeout recovery path |
Exchange (writes)
Build with Exchange.from_bundle(bundle), or Exchange(wallet, base_url, owner=<account_address>) where wallet is an eth_account account made from your API wallet key.
| Method | Description |
|---|---|
place(market, is_buy, sz, limit_px, tif, cloid=None, *, confirm=True, timeout=5.0) |
Submit an order and wait for the outcome that matches its tif; returns {cloid, submission, status, state}. confirm and timeout are keyword-only |
order(market, is_buy, sz, limit_px, tif, cloid=None) |
Limit order. tif is gtc / ioc / fok / alo |
market_order(market, is_buy, sz, protection_px=None, tif="ioc", cloid=None, *, slippage_bps=None) |
Market order (ioc / fok). Pass protection_px (worst acceptable price) or slippage_bps to derive it from the book |
build_order(market, is_buy, sz, limit_px, tif, cloid=None, order_type="limit") |
Dry run: validate and build an order without signing or sending it |
cancel(market, oid) / cancel_by_cloid(market, cloid) |
Cancel one order |
cancel_all(market) |
Cancel every open order in a market |
cancel_open(markets=None) |
Cancel every open order across markets (only where orders rest) |
modify(market, oid_or_cloid, replacement) |
Atomically cancel and replace one order |
batch(items) |
Up to 10 mixed order / cancel / cancelAll / modify actions under one nonce |
set_expires_after(expires_after_ms) |
Attach an expiry to every signed action |
agent_info() |
Whether this API wallet is approved on the owner: {approved, slot_id, epoch} |
Each write returns the raw gateway response with the client handle echoed in: submission_status, tx_hash, error, cloid (or cloids for a batch), and nonce.
Also on Exchange: the agent_address property (the signing wallet), effective_account (the account orders act on: the owner in agent mode, otherwise the wallet), and the static Exchange.random_cloid().
Response helpers
is_accepted, is_rejected, is_timeout, error_code, retry_after_ms, and is_retryable classify a trade response, and next_action turns one into a single verdict (READ_ORDER_STATUS, BACKOFF_AND_RETRY, RECONCILE_BY_CLOID, or FIX_AND_RESUBMIT). order_state pulls the status string out of an order_status response; is_terminal and is_undetermined classify it, and is_filled / filled_quantity read the fill. as_problem_details renders any failure — an exception or a rejected/timeout body — into one flat envelope, and retry_on_rate_limit(action) wraps a write to resend only on RateLimited, honoring retry_after_ms. random_cloid returns a fresh client order id.
Exceptions
Everything inherits from native_core.Error. Business rejections are not exceptions; they arrive in the response body (see above).
| Exception | Raised when |
|---|---|
LocalValidationError |
Before signing: bad precision, below the minimum notional, an unknown tif or market, or (at construction) an API wallet that is not an approved agent |
NetworkError |
A transport failure (timeout, connection, DNS) before any response arrived |
SubmissionUncertain |
A write was signed and sent, then timed out. Carries cloid and nonce to reconcile with wait_for_order |
ClientError |
An HTTP 4xx whose body is not a trade response. Has status_code, error_code, error_message |
ServerError |
An HTTP 5xx whose body is not a trade response. Has status_code |
ErrorCode is a convenience enum of known codes. Admission-layer codes are CamelCase — RateLimited, ExpiredTx, WrongChainId, DirectSignerIsActiveAgent, AgentEpochMismatch; execution-stage codes are lowercased — e.g. insufficientspotbalance, badalopx, tick, lotsize, marketclosed. An execution code lands on error.code of a rejected body when the transaction fails outright. But an order rejected purely at the order level — most notably a post-only (alo) order that would cross — comes back accepted (the transaction itself succeeded) with the code on its orderStatus lifecycle instead; the order did not rest. This is the sharpest case of accepted ≠ rested: read orderStatus for the real outcome. The code set is open-ended, so error_code(resp) returns unknown codes as raw strings.
Rate limits and retries
The SDK surfaces rate limiting but does not throttle or retry on its own. A RateLimited rejection comes back in the body with error.retry_after_ms. Use is_retryable(resp) (true only for RateLimited, which is never admitted, so resending the same order is safe) and retry_after_ms(resp) to back off. A timeout is never retryable. A read that hits an HTTP 429 or 503 with no trade body raises ClientError / ServerError, so pace your own requests. The gateway's real limits are not exposed here; get them from the platform.
Under load the gateway can return two other write-plane families. PlaceOrderSuspended (HTTP 503, with retry_after_ms) is a clean rejected body emitted before the order reaches the node when the chain is degraded (only cancels are allowed); it is not is_retryable, so back off with retry_after_ms(resp) and resubmit yourself once it clears — the order did not land. A submit-routing failure (HandoffTimeout, HandoffBufferFull:*, HandoffMultipleActive at 503; node_unreachable at 504) instead arrives as a timeout body — indeterminate, so next_action is RECONCILE_BY_CLOID: reconcile by cloid, never resubmit.
Transport controls
Info and Exchange (and their from_bundle) both accept timeout (per-request deadline in seconds, default 30; pass None for no deadline), pool_maxsize (connection pool size, default 100), and hooks for logging, latency capture, and tracing:
on_request(url_path, body, trace_id)— called before each request;trace_idis the id sent with it (see below), orNone.on_response(url_path, status, body, elapsed_ms, trace_id)— called after each response;trace_idis thex-trace-idthe gateway returned, orNone.
The gateway accepts an x-trace-id request header and echoes it back, so you can line up a request with the gateway's own logs. You supply the id — the SDK never generates one:
trace_id_factory(constructor) — called once per request for the id to send; e.g.lambda: str(uuid.uuid4())for a unique id, or a fixed value to group requests. Omit it to send no header.trace_id=(per call topost) — overrides the factory for one request.
To only capture the id the gateway itself generates, send none and read the trace_id argument of on_response.
import uuid
exchange = Exchange.from_bundle(
bundle,
trace_id_factory=lambda: str(uuid.uuid4()),
on_response=lambda path, status, body, ms, trace_id: log(path, trace_id),
)
Constants
constants.TESTNET_API_URL, constants.MAINNET_API_URL, and constants.NETWORK_URLS (network name to gateway URL). The chain id is derived from the URL. The mainnet values are defined but not usable yet: constructing Info or Exchange against the mainnet gateway raises LocalValidationError (testnet only for now).
8. Troubleshooting
| You see | Meaning and fix |
|---|---|
LocalValidationError: … is not an active agent for owner (at construction) |
The API wallet is not approved on that account. Check the owner, or create a fresh API wallet: the old key may have been revoked or replaced in the app. Call info.agent_status(owner, agent) to see the current slots. |
SubmissionUncertain |
A write timed out on the wire. Reconcile with wait_for_order(user, market, e.cloid). Do not resubmit under a new nonce. |
NetworkError |
A transport failure (timeout, connection, DNS) on a read. Retry the read. |
DirectSignerIsActiveAgent |
You built Exchange with an API wallet key but no owner. Pass owner=<accountAddress>, or use from_bundle. |
WrongChainId |
The key's network does not match the gateway. from_bundle avoids this; if you build by hand, match the endpoint to the bundle's network. |
LocalValidationError: … decimal places / significant figures |
sz or limit_px exceed the market's precision. Snap them with info.snap_price / info.min_order_size. |
insufficientspotbalance (rejected) |
The account is not funded for that market's quote asset. |
submission_status: "rejected" |
A hard write failure — an admission reject OR a genuine execution failure. Read error_code(resp). It is data, not an exception. |
submission_status: "timeout" |
Indeterminate: the order may still land. Reconcile with wait_for_order; never resubmit with a new nonce. |
AgentEpochMismatch |
The SDK refreshes and retries once on its own. If it persists, the API wallet was revoked or re-approved; create a new one. |
9. Development
make install # uv sync
make lint # ruff + mypy --strict
make test # pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file native_core_python_sdk-0.2.0.tar.gz.
File metadata
- Download URL: native_core_python_sdk-0.2.0.tar.gz
- Upload date:
- Size: 88.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
11423357977cf1d45cddb1d5313e55d3c11fc21dbd15ff57ba5fb2989b42de65
|
|
| MD5 |
13d63445bff1df2e2424ed1d0a6f69e9
|
|
| BLAKE2b-256 |
c25acf51d89e448d0b73daeaad27c2793cd9432a42087e75fdc72f1cdb0df12b
|
File details
Details for the file native_core_python_sdk-0.2.0-py3-none-any.whl.
File metadata
- Download URL: native_core_python_sdk-0.2.0-py3-none-any.whl
- Upload date:
- Size: 60.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.27 {"installer":{"name":"uv","version":"0.9.27","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec8bdc0d5fc50997fafe59ea5501b3c6a75ea42be391c532962f1b0f508a81d4
|
|
| MD5 |
0b1b8b20916fc1abf6926209530a97a1
|
|
| BLAKE2b-256 |
8ee019c3e1e23cf9c134aaf8276e2f81159cab248b64c0e70d5e29d492c17e9c
|