---
title: "Push a file or directory from the node to a write-enabled connection"
method: POST
path: "/preview/nodes/{name}/data-exports"
tags: ["nodes"]
---

# Push a file or directory from the node to a write-enabled connection

`POST /preview/nodes/{name}/data-exports`

## Request

- Base URL: `https://autoresearch.sfcompute.com`
- URL: `https://autoresearch.sfcompute.com/preview/nodes/{name}/data-exports`
- Auth: HTTP bearer

Push a file or directory from a RUNNING node to your own storage through a stored org connection with the "write" verb (list_connections shows verbs): the platform exercises the access on the host - never in this chat, never inside the node. `dest` must sit inside the connection's scope. S3 family (kind "s3-keys"): dest is an object key (e.g. "s3://acme-ml/results/run7/model.tar") and lands as ONE object (a directory is tarred; extract with tar -xf). Your org's own storage (auto-minted storage/<bucket>, kind "gmn-storage"): dest is an object key like s3, OR a '/'-terminated PREFIX - a directory then lands as a mirrored TREE of objects, one per file, committed as they land (get_export shows files_done/files_total). The connection names the bucket, so a dest here may be bucket-relative or full: "corpus-v3/" = "s3://datasets/corpus-v3/". Tree re-runs RESUME: objects already landed with matching size are skipped, never re-sent. Landed bytes count against your storage quota and bill as stored bytes. Hugging Face (kind "huggingface"): dest is "owner/name[@revision][:path/in/repo]" (e.g. "acme/ckpts@main:runs/run7/"; "datasets/owner/name" for dataset repos) and a directory lands as individual files under the path in ONE commit - model checkpoints stay loadable, never a tar; the repo must already exist on the Hub. Returns {export_id} immediately; poll get_export(node, export_id). A stopped node is a refusal, never a wake. Export time is node time: you're billed while it streams, and the transfer holds the node out of grace. Size is bounded (the refusal names the numbers; s3 and platform-storage exports STREAM as multipart, so big checkpoints fit - the Hub arm bounds any single FILE at one PUT, so shard big checkpoints or push them to s3; tree members too are single-PUT bounded). Every call is recorded to your org's audit log (connection, node, source, dest - never any credential). For a download link instead of a push, use export_file.

## Path parameters

- `name` string, required: Node name (from `list_nodes`).

## Query parameters

- `workspace` string

## Request body

- object
  - `connection` string, required: Connection name (from `list_connections`; needs the "write" verb).
  - `dest` string, required: The destination, inside the connection's scope: an object key for s3 kinds (e.g. "s3://acme-ml/results/run7/model.tar"), or "owner/name[@revision][:path/in/repo]" for huggingface (e.g. "acme/ckpts@main:runs/run7/").
  - `mission` string, nullable: Attribute this work to a mission (from open_mission). Omit and it joins the node's own mission, which is usually what you want.
  - `source` string, required: Path in the node's volume, absolute or ~-relative (e.g. "~/out/model"). To an s3 dest a directory exports as ONE tar object and a file streams as-is; to a huggingface dest a directory lands as individual files (one commit) and a file as one file.

## Response `200`

The capability's JSON result.

- Result: The capability's result: the same object the MCP tool returns as structuredContent. Resources carry an `object` type discriminator and an immutable id; money is integer micro-dollars in `*_usd_micros` fields.
  - `object` string: The resource type, when the result is one resource.

## Other responses

- `400`: Malformed request: bad JSON, a parameter that does not parse, or a value outside its range. Code `invalid`.
- `401`: No bearer token, or one this API cannot verify. Code `unauthenticated`.
- `403`: Authenticated, but the token's scopes or the account's role do not reach this operation. The message names the scope word to request. Code `forbidden`.
- `404`: No such route. Code `not_found`; the body names the OpenAPI document.
- `409`: The node is not in a state this export can read: stopped, still coming up, lost, or changing state mid-call. Code `NODE_NOT_RUNNING`.
- `413`: The path is over the export size cap. `export_file` stops at the object store's single-PUT bound and no raise exceeds it; send a larger path with `export_data`. Code `TOO_LARGE`.
- `422`: A well-formed request the platform declined: no such node, a cap reached, a state that forbids the move. The message says which, and what to do instead. Code `refused`.
- `429`: Over this door's per-customer budget. Wait `Retry-After` seconds. Code `rate_limited`.
- `500`: Our fault. Retry; if it persists, quote the request-id. Code `internal`.
- `503`: The node's host did not answer, went away mid-export, or export is not configured here. Ours, not yours: retry. Codes `HOST_UNAVAILABLE`, `NOT_ENABLED`.
- `504`: copy_file's export leg did not finish inside the call's wait. It is still running and may land: read the artifact by id before copying again. Code `TIMEOUT`. (export_file answers a wait that ends with 200 and `state: pending` instead.)

---

[API](https://skmtc.dev/givemeanode/apis/autoresearch-customer-api.md) · [All operations](https://skmtc.dev/givemeanode/apis/autoresearch-customer-api/llms.txt) · [OpenAPI document](https://skmtc.dev/givemeanode/apis/autoresearch-customer-api/revisions/f88dcb70ac6c?raw)
