GuidesAPI Reference
Guides

How to run a full batch job

The following example presents a full lifecycle of a job using cURL and bash, illustrating how to create a job, poll for its status until processing completes, and then download the results and potential errors.

Prerequisite

Before you begin, make sure to have a HERE platform account and an App with OAuth credentials in ~/.here.

A file input.csv with input data.

Install the following tools:

Script

#!/bin/bash

# config
pollTimeout="30s"   # 10s is good for small jobs (<10k records). For lager use 30-60s.

# Get OAuth token form olp cli. This will be passed as 'Authorization' header.
# As alternative an ApiKey can be passed as query parameter.
YOUR_BEARER_TOKEN=$(olp api token get --json | jq -r .accessToken)

# Submit job
resp=$(curl --request 'POST' \
  'https://batch.search.hereapi.com/v7/batch/jobs?serviceHrn=hrn%3Ahere%3Aservice%3A%3Aolp-here%3Asearch-geocode-7&inputDelimiter=%7C&outputDelimiter=%7C&outputColumns=position%7Ctitle%7Cid' \
  --header "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
  --header 'accept: application/json' \
  --header 'Content-Type: text/plain' \
  --data-binary @input.csv \
  2>/dev/null)

# Print response and jobId 
echo ${resp} | jq
jobId=$(echo $resp | jq -r '.id') && echo Job Id is: ${jobId}
# Extract 'status'
status=$(echo $resp | jq -r '.status')

# Poll metadata until 'completed' 'failure' or 'deleted'
while [[ "completed failure deleted" != *${status}* ]]; do
  # Sleep for configured time
  sleep ${pollTimeout}
  # Fetch metadata
  resp=$(curl --request 'GET' \
    "https://batch.search.hereapi.com/v7/batch/jobs/${jobId}" \
    --header "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
    --header 'accept: application/json' \
    2>/dev/null)
  # Extract status
  status=$(echo $resp | jq -r '.status')
  # Print timestamp, status and progress
  # Sample output: 2025-08-12 13:25:32+02:00 inProgress - 12000/127050 processed.
  echo "$(date --rfc-3339=seconds) ${status} - $(echo ${resp} | jq -r '.records.processed')/$(echo ${resp} | jq -r '.records.total') processed."
done

# Job is completed.
# Print some statistics
echo Job is completed. Statistics:
echo $resp | jq '.records'

echo Downloading output.

# Download results
# Extract URL to results from metadata 'resultsHref'
resultsHref=$(echo $resp | jq -r '.resultsHref')
# If resultHref is empty, there are no results. All records caused an error.
if [ "${resultsHref}" ]; then
  curl --request 'GET' \
      "${resultsHref}" \
      --header "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
      --header 'accept: text/plain' \
      -o "${jobId}_results.csv" \
      2>/dev/null
  echo Results saved at ${jobId}_results.csv
else
  echo No results provided.
fi

# Download errors
# Extract URL to errors from metadata 'errorsHref'
errorsHref=$(echo $resp | jq -r '.errorsHref')
# If errorsHref is empty, there are no errors. Great!
if [ "${errorsHref}" ]; then
  curl --request 'GET' \
      "${errorsHref}" \
      --header "Authorization: Bearer ${YOUR_BEARER_TOKEN}" \
      --header 'accept: text/plain' \
      -o "${jobId}_errors.csv" \
      2>/dev/null
  echo Results saved at ${jobId}_errors.csv
else
  echo No errors provided.
fi

echo Job done.

Description

  1. Get an OAuth token form OLP CLI
  2. Submit a job and save response.
  3. Extract the jobId and status for later use.
  4. Poll metadata until status is completed failure or deleted.
  5. Print the processed records vs. total while polling.
  6. Print some statistics about the job.
  7. Download the results based on metadata resultsHref. If empty, there are no results. All records failed.
  8. Download errors based on metadata errorsHref. If empty, there are no errors.

Input

The input is similar to this:

recId|q|country
0001|Invalidenstraße 116 10115 Berlin|DEU
0002|Am Kronberger Hang 8 65824 Schwalbach|DEU
0003|425 W Randolph St Chicago IL 60606|USA
0004|One Main Street Cambridge MA 02142|USA
...

Output

The script output will look like this:

{
  "id": "<jobId>",
  "serviceHrn": "hrn:here:service::olp-here:search-geocode-7",
  "billingTags": [],
  "status": "queued",
  "href": "https://batch.search.hereapi.com/v7/batch/jobs/<jobId>"
}
Job Id is: <jobId>
2025-08-14 11:23:00+02:00 inProgress - 0/127050 processed.
2025-08-14 11:23:30+02:00 inProgress - 8000/127050 processed.
2025-08-14 11:24:00+02:00 inProgress - 17000/127050 processed.
2025-08-14 11:24:30+02:00 inProgress - 26000/127050 processed.
2025-08-14 11:25:00+02:00 inProgress - 34000/127050 processed.
2025-08-14 11:25:31+02:00 inProgress - 44000/127050 processed.
2025-08-14 11:26:01+02:00 inProgress - 54000/127050 processed.
2025-08-14 11:26:31+02:00 inProgress - 65000/127050 processed.
2025-08-14 11:27:01+02:00 inProgress - 76000/127050 processed.
2025-08-14 11:27:31+02:00 inProgress - 87000/127050 processed.
2025-08-14 11:28:02+02:00 inProgress - 100000/127050 processed.
2025-08-14 11:28:32+02:00 inProgress - 112000/127050 processed.
2025-08-14 11:29:02+02:00 inProgress - 125050/127050 processed.
2025-08-14 11:29:32+02:00 completed - 127050/127050 processed.
Job is completed. Statistics:
{
  "total": 127050,
  "valid": 127050,
  "invalid": 0,
  "processed": 127050,
  "pending": 0,
  "succeeded": 127050,
  "failed": 0
}
Downloading output.
Results saved at <jobId>_results.csv
No errors provided.
Job done.

Result

The Result is similar to this:

recId|seqNumber|seqLength|position|title|id
1|1|1|(52.53086,13.38469)|Invalidenstraße 116, 10115 Berlin, Deutschland|here:af:streetsection:tVuvjJYhO86yd5jk1cmzNB:CgcIBCCE59BeEAEaAzExNg
2|1|1|(50.16193,8.53361)|Am Kronberger Hang 8, Hillsite, 65824 Schwalbach am Taunus, Deutschland|here:af:streetsection:6cjWtEIO2t07E.pKRVV5bA:CgcIBCCa46pZEAEaATgiCEhpbGxzaXRl
3|1|1|(41.88432,-87.63877)|425 W Randolph St, Chicago, IL 60606-1515, United States|here:af:streetsection:hdZ6xBRUraY46IQZCqZidD:CgcIBCDMlOElEAEaAzQyNQ
4|1|1|(42.36225,-71.0803)|1 Main St, Cambridge, MA 02142-1517, United States|here:af:streetsection:k-3ojKsslOuU0B1PF4J4HD:CgcIBCCq3cJGEAEaATE
...