Skip to main content

Documentation Index

Fetch the complete documentation index at: https://code.dcycle.io/llms.txt

Use this file to discover all available pages before exploring further.

Imports

The Imports API is our new in-house replacement for the Nuvo-style import flow. It is designed for structured tabular uploads where a client needs to:
  • upload a source file
  • map source columns to a Dcycle template
  • inspect distinct raw values for category fields
  • validate rows before ingestion
  • patch a subset of rows when validation fails
  • submit the cleaned dataset into downstream processing
This API is especially useful for automation, partner integrations, and eventually dcy.
The Imports API is a session-based workflow. You do not send one big “import everything” request. Instead, you create an import session, validate it, optionally correct rows, and only then submit it.

End-to-End Flow

1

1. Create session

Call POST /v2/imports/sessions with a template_id and the source file as multipart form data.Required form fields:
  • template_id — backend template identifier (e.g. logistics_requests)
  • upload_file — the source CSV/XLSX file
Optional form fields:
  • numeric_locale — locale for decimal parsing (e.g. es_ES)
  • date_localeDateLocaleEnum value for date parsing when the source uses a non-ISO format
  • sheet_name — sheet to read for multi-sheet XLSX uploads
  • project_id / folder_id — UUIDs scoping the import to a project or folder
  • raw_file_id — UUID of a previously uploaded raw file to link the session to
The backend parses the file and returns:
  • import_id
  • detected source columns
  • sample rows
  • sheet/header metadata
2

2. Suggest mapping

Call POST /v2/imports/{import_id}/mapping/suggest.This returns a best-effort mapping suggestion from source columns to template columns. Each suggestion includes a column_confidence, a value_confidence (category targets only), and a restored_from_history flag indicating when the match was lifted from a prior import rather than re-scored. Clients can accept these suggestions as-is or adjust them before validation.
3

3. Confirm mapping (optional but recommended)

Call POST /v2/imports/{import_id}/mapping with the mapping the user accepted.This persists the mapping on the session and transitions its status from parsed to mapped. It is optional because validate also accepts a mapping in the body, but confirming has two benefits:
  • GET /v2/imports/sessions surfaces the chosen mapping so a user can resume the session later
  • downstream calls (unique-values, validate) behave consistently with what the user saw
4

4. Inspect category values

Call POST /v2/imports/{import_id}/unique-values with the current mapping.The backend returns distinct raw values for mapped category columns only, each annotated with an auto-resolved canonical value and a matched / unmatched status. This is the right moment to build a value-mapping UI before row-level validation starts.
5

5. Validate rows

Call POST /v2/imports/{import_id}/validate with the chosen mapping. Optionally include value_mappings to pre-resolve category values the user remapped by hand.Query parameters:
  • page, page_size — paginate the returned rows
  • errors_only=true — return only rows that still have validation issues
The response includes:
  • valid_rows
  • error_rows
  • errors_by_column
  • paginated row-level validation output
6

6. Review rows

Call GET /v2/imports/{import_id}/rows to page through the processed rows.Use errors_only=true when you only want rows that still need action.Sort by any column with sort_by=<column_key> and sort_direction=asc|desc. When sort_by is omitted rows come back in original row_index order.Filter rows server-side with filters, a JSON-encoded object mapping column keys to allowed values:
GET /v2/imports/{import_id}/rows?filters=%7B%22country%22%3A%5B%22Spain%22%2C%22France%22%5D%2C%22fuel%22%3A%5B%22diesel%22%5D%7D
Decoded: {"country": ["Spain", "France"], "fuel": ["diesel"]}.Semantics:
  • AND across columns, IN within a column. A row is returned when every listed column matches any of its listed values.
  • Whitespace-insensitive. Values are compared after trimming, matching what the dropdown surfaces.
  • Empty value list = no filter on that column. Sending {"country": []} is equivalent to omitting country. To get zero rows, omit the request — there is no “match nothing” sentinel.
  • Caps: at most 20 filter keys per request, 500 values per key. Beyond either cap returns 422.
  • Allowed key characters: [a-zA-Z0-9_]+.
To populate filter dropdowns with cascading constraints (Excel-style), call GET /v2/imports/{import_id}/rows/column-values?column=<column_key>&filters=<json>. The endpoint returns the distinct values present in column under the other columns’ filters (the filter for column itself is automatically excluded so the user keeps seeing the full list available for that column):
{
  "column": "country",
  "values": ["France", "Spain"],
  "total_unique": 2,
  "truncated": false
}
truncated is true when the unique-value count exceeds the server cap (currently 1000); total_unique always reports the real count of the filtered dataset.
7

7. Patch corrections

If some rows are invalid, call PATCH /v2/imports/{import_id}/rows with row-level corrections (max 500 per request).The backend revalidates the corrected rows and returns updated row data plus the remaining error count.
8

8. Submit import

Once the session is valid, call POST /v2/imports/{import_id}/submit with the x-partner header set to your partner identifier.Submission creates the downstream processing artifact and starts the heavy processing pipeline.
9

9. Check status

Call GET /v2/imports/{import_id}/status to retrieve the session status and processing summary.
10

10. Abandon a session (optional)

If the user discards an import before submitting, call DELETE /v2/imports/sessions/{import_id} to clear the cached rows and associated data. Submitted sessions cannot be deleted.
For most clients, the safest workflow is:
  1. Create the session.
  2. Request mapping suggestions.
  3. Confirm the chosen mapping so the session is resumable.
  4. Inspect distinct values for mapped category columns.
  5. Validate with the chosen mapping (and any user-supplied value_mappings).
  6. If there are errors, fetch or display only invalid rows.
  7. Patch corrections until the session is clean.
  8. Submit the import.
  9. Poll status until downstream processing has clearly started.

Typical Session Example

1. Create the session

curl -X POST "https://api.dcycle.io/v2/imports/sessions" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -F "template_id=logistics_requests" \
  -F "numeric_locale=es_ES" \
  -F "upload_file=@./logistics.csv;type=text/csv"
Example response:
{
  "import_id": "11111111-1111-1111-1111-111111111111",
  "file_name": "logistics.csv",
  "total_rows": 240,
  "numeric_locale": "es_ES",
  "date_locale": null,
  "sheets": [],
  "selected_sheet": null,
  "detected_header_row": 0,
  "source_columns": [
    "Trip Date",
    "Client",
    "Distance",
    "Origin Country",
    "Destination Country"
  ],
  "sample_rows": [
    ["2026-03-01", "ACME", "125,4", "ES", "FR"]
  ]
}

2. Ask for mapping suggestions

curl -X POST "https://api.dcycle.io/v2/imports/11111111-1111-1111-1111-111111111111/mapping/suggest" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "Content-Type: application/json" \
  -d '{}'

3. Confirm the user-selected mapping

curl -X POST "https://api.dcycle.io/v2/imports/11111111-1111-1111-1111-111111111111/mapping" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "Content-Type: application/json" \
  -d @mapping.json

4. Validate using a chosen mapping

{
  "mapping": {
    "trip_date": "Trip Date",
    "client": "Client",
    "distance_km": "Distance",
    "origin_country": "Origin Country",
    "destination_country": "Destination Country"
  }
}
curl -X POST "https://api.dcycle.io/v2/imports/11111111-1111-1111-1111-111111111111/validate?page=1&page_size=50" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "Content-Type: application/json" \
  -d @mapping.json

5. Inspect distinct category values

curl -X POST "https://api.dcycle.io/v2/imports/11111111-1111-1111-1111-111111111111/unique-values" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "Content-Type: application/json" \
  -d @mapping.json

6. Patch one bad row

{
  "corrections": [
    {
      "row_index": 17,
      "column": "distance_km",
      "value": 128.4
    }
  ]
}

7. Submit the import

curl -X POST "https://api.dcycle.io/v2/imports/11111111-1111-1111-1111-111111111111/submit" \
  -H "x-api-key: ${DCYCLE_API_KEY}" \
  -H "x-organization-id: ${DCYCLE_ORG_ID}" \
  -H "x-partner: dcycle" \
  -H "Content-Type: application/json" \
  -d '{"ignore_errors": false}'
Example response:
{
  "status": "processing",
  "file_id": "22222222-2222-2222-2222-222222222222",
  "processing_job_id": "33333333-3333-3333-3333-333333333333",
  "rows_submitted": 240
}

Template Metadata

Use GET /v2/imports/templates/{template_id} to retrieve the target template definition before or during mapping. This is helpful when clients need to:
  • render a column picker
  • show required vs optional target fields
  • display allowed category options
  • apply defaults from the backend template definition
When a category column uses options_source instead of inline options, call GET /v2/imports/options/{source_key} to fetch the resolved list of selectable values and labels from the backend registry. When a client needs to inspect the raw values present in the uploaded file before validation, call POST /v2/imports/{import_id}/unique-values with the chosen mapping. Typical examples:
  • countries for country fields
  • logistics_tocs for logistics vehicle types
  • fuels for logistics recharge fuel selection

Status Lifecycle

created -> parsed -> mapped -> validating -> validated -> submitting -> submitted
                     |
                     +-> failed
In practice, clients will most commonly observe:
  • created briefly at session creation time before parsing metadata is persisted
  • parsed after session creation
  • validated after a successful validation pass
  • submitted after the import has been handed off for downstream processing

Best Practices

  • Persist the import_id on the client side so users can safely resume a session.
  • Use errors_only=true when rendering review tables for large imports.
  • Use the unique-values endpoint before validation if your client supports category value mapping.
  • Treat mapping suggestions as hints, not guaranteed matches.
  • Do not submit until validation is clean unless you intentionally support ignore_errors=true.
  • Use the template metadata endpoint to avoid hardcoding target columns in the client.