Skip to main content
The Content Ingestion API allows you to populate and update the ISO 3166 subdivision database, which is used for address component standardization.

What is ISO 3166?

ISO 3166 is an international standard for country codes and their subdivisions (states, provinces, regions, etc.). The Address API uses this data to standardize address components when Google’s Geocoding API returns local variants or subdivision names instead of ISO 3166 codes.

Why is this needed?

Google’s Geocoding API sometimes returns state information in different formats:
  • ISO 3166 code (e.g., “CA” for California)
  • Full subdivision name (e.g., “California”)
  • Local language variant (e.g., “Québec” instead of “QC”)
This content database allows the Address API to normalize these variations back to standard ISO 3166 codes, ensuring consistent address data across all responses.

Endpoint

POST /api/v1/internal/iso_3166/ingest/json
Required role: MANAGE_CONTENT

Request

Headers

HeaderRequiredDescription
x-commenda-keyYesYour API key with MANAGE_CONTENT role
Content-TypeYesMust be application/json

Body

{
  "items": [
    {
      "country_code": "US",
      "subdivision_code": "CA",
      "subdivision_name": "California",
      "subdivision_local_variant": null
    },
    {
      "country_code": "US",
      "subdivision_code": "NY",
      "subdivision_name": "New York",
      "subdivision_local_variant": null
    }
  ]
}
FieldTypeRequiredDescription
itemsarrayYesArray of subdivision records to ingest (minimum 1 item)
items[].country_codestringYesISO 3166-1 alpha-2 country code (exactly 2 characters)
items[].subdivision_codestringYesISO 3166-2 subdivision code (maximum 3 characters)
items[].subdivision_namestring | nullYesFull name of the subdivision (can be null)
items[].subdivision_local_variantstring | nullYesLocal language variant of the name (can be null)

Response

Success response (200 OK)

{
  "data": {
    "upserted": 2
  }
}
FieldTypeDescription
upsertednumberNumber of records inserted or updated

How ingestion works

The ingestion process uses an upsert strategy:
  1. Uniqueness: Each record is identified by the combination of country_code and subdivision_code
  2. Insert or update: If a record with the same country/subdivision combination exists, it’s updated. Otherwise, a new record is created
  3. Duplicate detection: The API validates that no duplicates exist within a single request
  4. Batch processing: All items in the request are processed in a single transaction
  5. Validation: Each item is validated for required fields and format constraints

Example requests

Ingest US states

curl -X POST https://address-api.in.commenda.io/api/v1/internal/iso_3166/ingest/json \\\n  -H "x-commenda-key: your-api-key" \\\n  -H "Content-Type: application/json" \\\n  -d '{\n    "items": [\n      {\n        "country_code": "US",\n        "subdivision_code": "CA",\n        "subdivision_name": "California",\n        "subdivision_local_variant": null\n      },\n      {\n        "country_code": "US",\n        "subdivision_code": "TX",\n        "subdivision_name": "Texas",\n        "subdivision_local_variant": null\n      }\n    ]\n  }'

Ingest Canadian provinces

curl -X POST https://address-api.in.commenda.io/api/v1/internal/iso_3166/ingest/json \\\n  -H "x-commenda-key: your-api-key" \\\n  -H "Content-Type: application/json" \\\n  -d '{\n    "items": [\n      {\n        "country_code": "CA",\n        "subdivision_code": "ON",\n        "subdivision_name": "Ontario",\n        "subdivision_local_variant": null\n      },\n      {\n        "country_code": "CA",\n        "subdivision_code": "QC",\n        "subdivision_name": "Quebec",\n        "subdivision_local_variant": "Québec"\n      }\n    ]\n  }'

Error responses

Invalid request body (400)

{
  "error": {
    "type": "CLIENT_BAD_REQUEST",
    "title": "Invalid request body.",
    "status": 400,
    "instance": "/api/v1/internal/iso_3166/ingest/json",
    "detail": {
      "description": "The request body is invalid or missing required fields."
    }
  }
}

Duplicate records (400)

{
  "error": {
    "type": "CLIENT_BAD_REQUEST",
    "title": "ISO 3166 ingestion validation failed.",
    "status": 400,
    "instance": "/api/v1/internal/iso_3166/ingest/json",
    "detail": {
      "description": "Validation errors occurred during ISO 3166 ingestion."
    },
    "errors": [
      {
        "pointer": "items[1]",
        "details": "Duplicate (country_code, subdivision_code) within the same request."
      }
    ]
  }
}

Missing API key (401)

{
  "error": {
    "type": "CLIENT_UNAUTHORIZED",
    "title": "Missing API key.",
    "status": 401,
    "instance": "/api/v1/internal/iso_3166/ingest/json",
    "detail": {
      "description": "The x-commenda-key header is required for authentication."
    }
  }
}

Missing role (403)

{
  "error": {
    "type": "CLIENT_FORBIDDEN",
    "title": "Missing required role.",
    "status": 403,
    "instance": "/api/v1/internal/iso_3166/ingest/json",
    "detail": {
      "description": "Your API key does not have the MANAGE_CONTENT role."
    }
  }
}

Database schema

The ISO 3166 data is stored in the iso_3166 table:
CREATE TABLE "iso_3166" (
  "id" serial NOT NULL,
  "country_code" character varying(2) NOT NULL,
  "subdivision_code" character varying(3) NOT NULL,
  "subdivision_name" text NULL,
  "subdivision_local_variant" text NULL,
  PRIMARY KEY ("id"),
  CONSTRAINT "iso_3166_country_subdivision_unique"
    UNIQUE ("country_code", "subdivision_code")
);

Best practices

  • Batch your requests: Send multiple items in a single request to reduce API calls
  • Validate data: Ensure country codes are valid ISO 3166-1 alpha-2 codes
  • Handle errors: Check for duplicate records and validation errors in your ingestion pipeline
  • Update regularly: Re-run ingestion when subdivision data changes (new states, name changes, etc.)
  • Use upsert behavior: Don’t worry about duplicates - the API will update existing records