# Batches API Quickstart

Use this guide to submit an address CSV, review the quote, start a Batches v1 job, and retrieve its results.

Batches v1 processes a CSV through the Addresses v2 geocoder, reverse geocoder, or MailPoint. Submission validates the configuration and starts quoting. Processing starts after you accept the quote or enable automatic start.

## Before you begin

You need:

- A [Geoscape Hub](https://hub.geoscape.com.au) application with Batches API access and access to the address products you will use
- The application's Consumer Key and sufficient credits for the quoted job
- A UTF-8 CSV at an HTTP, HTTPS, or FTP URL the service can read
- A terminal with `curl` and `jq` installed

MailPoint and premium additional properties require paid-plan access. Follow [Authentication](/guides/authentication) for application setup.

## 1. Set your Consumer Key

```shell
export GEOSCAPE_API_KEY="YOUR_CONSUMER_KEY"
```

The header name is `Authorization`. Its value is the Consumer Key directly, without a `Bearer` prefix. The Consumer Secret is not used. The base URL is `https://api.psma.com.au/v1/batches`.

## 2. Prepare your input

Save the following as a CSV and host it at a URL the service can access:

```csv
customerAddressId,address
1,113 Canberra Ave Griffith ACT 2603
2,1 Martin Place Sydney NSW 2000
```

The `address` column will be mapped to the geocoder's `address` parameter. The customer ID is retained in the output unless you exclude it. See [Files and Mappings](/guides/batches/files-and-mappings) for structured addresses, coordinates, credentials, and JSONPath examples.

## 3. Submit the job for quoting

Create `batch-request.json`, replacing the example input URL with your hosted CSV. Omit `output.file` to receive a download link instead of writing results to your server:

```json
{
  "type": "addressGeocoder",
  "parameters": {"matchType": "Address"},
  "input": {
    "file": "https://example.com/input.csv",
    "format": [{"name": "address", "apiParameter": "address"}]
  },
  "output": {
    "format": [
      {"name": "Matched Address", "source": "$.features[0].properties.formattedAddress"},
      {"name": "Address ID", "source": "$.features[0].properties.addressId"},
      {"name": "Match Quality", "source": "$.features[0].matchQuality"}
    ]
  }
}
```

Submit the JSON and save the returned job ID:

```shell
BATCH_RESULT=$(curl --fail-with-body \
  "https://api.psma.com.au/v1/batches/batch" \
  -H "Authorization: $GEOSCAPE_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  --data @batch-request.json)

printf '%s\n' "$BATCH_RESULT" | jq .
BATCH_ID=$(printf '%s\n' "$BATCH_RESULT" | jq -r '.batchInfo.batchId // empty')
```

An accepted submission returns `200` with `status: "Quoting"`. The ID is in `batchInfo.batchId`, not at the top level. The service checks file access, CSV headers, required input mappings, and output expressions before accepting the job.

## 4. Review the quote

If `BATCH_ID` is present, retrieve the job until its status is `Quoted`:

```shell
curl --fail-with-body \
  "https://api.psma.com.au/v1/batches/batch/$BATCH_ID" \
  -H "Authorization: $GEOSCAPE_API_KEY" \
  -H "Accept: application/json"
```

Check:

- `status`, including `Failed` if quoting could not complete
- `batchInfo.totalRows`, the number of rows counted for processing
- `batchInfo.estimatedCreditCost`, the quoted cost in credits
- `batchInfo.estimatedRunTime`, an estimated duration

Use [Managing Jobs](/guides/batches/managing-jobs) to understand status transitions and how to change a quoted job.

## 5. Start the job

Once you have reviewed the quote and have sufficient credits, send an empty POST:

```shell
curl --fail-with-body --request POST \
  "https://api.psma.com.au/v1/batches/batch/$BATCH_ID/start" \
  -H "Authorization: $GEOSCAPE_API_KEY" \
  -H "Accept: application/json"
```

The job enters `Queued`, then `Running`. Retrieve the job with GET to check `batchInfo.progress`. This field is descriptive text, not a numeric percentage.

## 6. Download the results

Retrieve the job again when processing completes:

```shell
BATCH_STATUS=$(curl --fail-with-body \
  "https://api.psma.com.au/v1/batches/batch/$BATCH_ID" \
  -H "Authorization: $GEOSCAPE_API_KEY" \
  -H "Accept: application/json")

printf '%s\n' "$BATCH_STATUS" | jq .

if [ "$(printf '%s\n' "$BATCH_STATUS" | jq -r '.status')" = "Completed" ]; then
  DOWNLOAD_URL=$(printf '%s\n' "$BATCH_STATUS" | jq -r '.batchInfo.downloadPath // empty')
  if [ -n "$DOWNLOAD_URL" ]; then
    curl --fail-with-body "$DOWNLOAD_URL" --output batch-results.csv
  fi
fi
```

Use the returned download URL directly. It does not need your Consumer Key. Check `messages` if a completed job has no download link, as premium-data access can restrict downloads.

## If the request fails

| Status | What to check |
| --- | --- |
| `400` | JSON fields, file access, CSV mappings, JSONPath syntax, or whether the job's status permits the action |
| `401` | The application's Consumer Key and API access |
| `403` | Job ownership, product access, or sufficient credits to start |
| `404` | The job ID and whether the job is available |
| `429` or `500` | Follow [Error Handling](/guides/errors) for rate-limit and transient-failure handling |

Service errors contain `messages`. Gateway authentication errors can contain `fault`. A job can also fail asynchronously after an HTTP request succeeds, so always inspect `status`.

The endpoint reference provides language-specific request examples. Choose the language in the request example panel. Do not repeatedly resubmit POST requests to poll a job. Use GET with a suitable polling interval and observe [Rate Limiting](/guides/rate-limiting).

## Next steps

- [Configure files and mappings](/guides/batches/files-and-mappings)
- [Manage batch jobs](/guides/batches/managing-jobs)
- [Assess address matches](/guides/addresses/assessing-matches)
