# Write DataSignals data Use `patch_data()` to update selected metric keys and `put_data()` to insert or replace complete rows. Both methods are available on the synchronous `API` and asynchronous `AsyncAPI` facades. :::{warning} `put_data(..., on_conflict="replace")` replaces the complete metrics document for an existing timestamp, site, and location. Metric keys omitted from the request are removed. Prefer `patch_data()` for ordinary partial updates. ::: ## Conflict behavior | Method | `on_conflict` | Existing row behavior | | --- | --- | --- | | PUT | `replace` | Replace the complete metrics document | | PUT | `nothing` | Leave the existing row unchanged | | PATCH | `replace` | Merge keys, with incoming values winning | | PATCH | `nothing` | Add only keys that do not exist | Both methods insert the row when its timestamp, site, and location combination does not exist. ## Write one or more rows Each row must contain `timestamp`, `site`, `location`, and at least one metric: ```python from api_24sea.datasignals.core import API api = API() api.authenticate("username", "password") result = api.patch_data( [ { "timestamp": "2026-07-23T10:00:00Z", "site": "windfarm", "location": "WFA01", "mean_WFA01_windspeed": 10.5, }, { "timestamp": "2026-07-23T10:00:00Z", "site": "windfarm", "location": "WFA02", "mean_WFA02_windspeed": 10.8, }, ], on_conflict="replace", ) ``` The result includes `processed_rows`, `affected_rows`, `skipped_rows`, and `projects`. ## Write a DataFrame `site` and `location` can be supplied once when they are not columns: ```python result = api.patch_data( frame, site="windfarm", location="WFA01", ) ``` A timestamp column or an index named `timestamp` is required. Sparse PATCH frames omit pandas missing values. PUT rejects missing metric values to avoid silently replacing a complete metrics document with a sparse row. Use a mapping with an explicit `None` value to write JSON `null`. The synchronous pandas accessor provides the same convenience: ```python result = frame.datasignals.patch_data( site="windfarm", location="WFA01", ) ``` ## Write asynchronously ```python from api_24sea.datasignals.core import AsyncAPI api = AsyncAPI() api.authenticate("username", "password") result = await api.patch_data( payload, on_conflict="replace", ) ``` The async facade uses the same validation and response contract. Write retries are disabled by default; set `max_retries` explicitly when retrying an HTTP 502 is appropriate. ## Permissions Writes require a staff or superuser account with a DataSignals write permission covering the requested project, location, timestamp, and every metric. For local Sample testing, configure the client before authentication: ```python api = API() api.base_url = "https://api.24sea.localhost/routes/v1" api.authenticate("admin", "password") ``` Use generated test timestamps and ensure exact cleanup of every written row. Do not use Sample write examples against production.