> ## Documentation Index
> Fetch the complete documentation index at: https://docs.countrystatecity.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Postcode by Code

> Look up every postcode record that matches an exact code within a country

Look up a postcode / ZIP code within a country and get back every matching record. Use this to confirm that a user-supplied postcode appears in the dataset.

<Note>
  **Free on every plan**, including Community. Exact lookup counts against your normal daily/monthly quota like any other request. Paginated listing and search use [Get Postcodes by Country](/api/endpoints/get-postcodes-by-country) and require a Starter+ plan — exact lookup has no such gate.
</Note>

<Warning>
  This is informational postcode data, not an address verification or mail-deliverability service. A match confirms the code exists in the dataset — it does not confirm a delivery point, standardize an address, or guarantee mail will arrive.
</Warning>

## Why the response is an array

A postcode is not always unique to one place. The same code can legitimately cover more than one locality, so this endpoint returns **every** matching record instead of picking one — an empty result is a `404`, never an empty success.

<Info>
  Fields above **Basic** are stripped for lower plans, not just hidden — a Community or Starter key never receives `country_id`, `state_id`, `city_id`, `latitude`, or `longitude` in the response body. See **Tier-based field availability** below. `id` and every foreign-key field are returned as numeric strings rather than JSON numbers — parse them as strings in your client.
</Info>

```json 200 - Duplicate exact match, Basic tier (Community, Starter, Legacy) theme={null}
{
  "data": [
    {
      "id": "670115",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Mabola",
      "type": "full"
    },
    {
      "id": "670116",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Watinapaha",
      "type": "full"
    },
    {
      "id": "670117",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Wattala",
      "type": "full"
    }
  ],
  "meta": {
    "country_code": "LK",
    "query": "11104",
    "match_count": 3
  }
}
```

```json 200 - Duplicate exact match, Full tier (Supporter, Professional, Business) theme={null}
{
  "data": [
    {
      "id": "670115",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Mabola",
      "type": "full",
      "country_id": "208",
      "state_id": "2804",
      "city_id": null,
      "latitude": 7.0062833,
      "longitude": 79.8924828,
      "source": "geonames",
      "wikiDataId": null
    },
    {
      "id": "670116",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Watinapaha",
      "type": "full",
      "country_id": "208",
      "state_id": "2804",
      "city_id": null,
      "latitude": 7.1853118,
      "longitude": 80.0003875,
      "source": "geonames",
      "wikiDataId": null
    },
    {
      "id": "670117",
      "code": "11104",
      "country_code": "LK",
      "state_code": "12",
      "locality_name": "Wattala",
      "type": "full",
      "country_id": "208",
      "state_id": "2804",
      "city_id": null,
      "latitude": 6.9906677,
      "longitude": 79.8931709,
      "source": "geonames",
      "wikiDataId": null
    }
  ],
  "meta": {
    "country_code": "LK",
    "query": "11104",
    "match_count": 3
  }
}
```

## Tier-based field availability

| Tier | Plans | Fields |
| - | - | - |
| **Basic** | Community, Starter, Legacy | `id`, `code`, `country_code`, `state_code`, `locality_name`, `type` |
| **Full** | Supporter, Professional, Business | All Basic **+** `country_id`, `state_id`, `city_id`, `latitude`, `longitude`, `source`, `wikiDataId` |

See [Pricing](https://countrystatecity.in/pricing?source=docs\&campaign=postcode_lookup) for plan details.

## Caching and conditional requests

Every response sets `ETag`, `Cache-Control`, and `X-Cache` (`HIT`/`MISS`), cached for 24 hours. Send the last `ETag` back as `If-None-Match` to get a bodyless `304` when nothing changed instead of re-downloading the result:

```javascript theme={null}
const response = await fetch(url, {
  headers: {
    'X-CSCAPI-KEY': 'YOUR_API_KEY',
    'If-None-Match': savedEtag
  }
});

if (response.status === 304) {
  // Nothing changed — reuse your cached copy.
} else {
  savedEtag = response.headers.get('ETag');
}
```

<RequestExample>
  ```bash cURL theme={null}
  curl 'https://api.countrystatecity.in/v1/countries/LK/postcodes/11104' \
    -H 'X-CSCAPI-KEY: YOUR_API_KEY'
  ```

  ```python Python theme={null}
  import requests

  def get_postcode(country_code, code):
      response = requests.get(
          f'https://api.countrystatecity.in/v1/countries/{country_code}/postcodes/{code}',
          headers={'X-CSCAPI-KEY': 'YOUR_API_KEY'}
      )
      response.raise_for_status()
      return response.json()

  result = get_postcode('LK', '11104')
  print(f"{result['meta']['match_count']} match(es) for {result['meta']['query']}")
  ```

  ```javascript JavaScript theme={null}
  const getPostcode = async (countryCode, code) => {
    const response = await fetch(
      `https://api.countrystatecity.in/v1/countries/${countryCode}/postcodes/${encodeURIComponent(code)}`,
      { headers: { 'X-CSCAPI-KEY': 'YOUR_API_KEY' } }
    );

    if (!response.ok) throw new Error(await response.text());
    return response.json();
  };

  const result = await getPostcode('LK', '11104');
  console.log(`${result.meta.match_count} match(es) for ${result.meta.query}`);
  ```
</RequestExample>

## Errors

<ResponseField name="details.reason" type="string">
  Distinguishes the three `404` cases below. Check this instead of parsing `message`.
</ResponseField>

```json 404 - Unknown country theme={null}
{
  "status": "error",
  "message": "Country not found.",
  "details": { "reason": "country_not_found" }
}
```

```json 404 - No coverage for this country theme={null}
{
  "status": "error",
  "message": "No postcode coverage is available for this country.",
  "details": { "reason": "postcode_coverage_unavailable" }
}
```

```json 404 - Code has no match theme={null}
{
  "status": "error",
  "message": "No postcode matches the given code.",
  "details": { "reason": "postcode_not_found" }
}
```

```json 400 - Invalid code theme={null}
{
  "status": "error",
  "message": "postcode must be at most 20 characters"
}
```

`code` is also rejected as empty, or for containing a `/`, `\`, or control character.

See [Errors & Rate Limits](/api/errors) for the `401`/`429` shapes and usage headers common to every endpoint.

## Related

<CardGroup cols={2}>
  <Card title="Get Postcodes by Country" icon="magnifying-glass" href="/api/endpoints/get-postcodes-by-country">
    Page through or search a country's postcodes. Requires Starter+.
  </Card>

  <Card title="Postcodes Reference" icon="mailbox" href="/database/postcodes">
    Coverage stats, postcode types, and self-hosted query examples.
  </Card>
</CardGroup>


## OpenAPI

````yaml GET /countries/{ciso}/postcodes/{code}
openapi: 3.0.3
info:
  title: Country State City API
  description: >-
    Geographic data API providing countries, states, cities, timezones,
    currencies, and phone dial codes with tiered access levels.


    ## Authentication

    All endpoints require an API key passed via the `X-CSCAPI-KEY` header. Get
    your free key at [app.countrystatecity.in](https://app.countrystatecity.in).


    ## Pricing & Limits

    The fields returned, endpoints available, and request quotas depend on your
    plan. See current tiers and limits at:


    **[countrystatecity.in/pricing](https://countrystatecity.in/pricing)**


    ## Data Access Levels

    Each plan includes a data access level that controls which fields are
    returned:


    - **Basic** — Core fields: id, name, iso2, iso3, phonecode, capital,
    currency, coordinates, region, timezones, emoji

    - **Coordinates** — Basic + extended metadata (population, tld, nationality,
    currency details, postal codes, etc.)

    - **Full** — All fields including translations (18+ languages) and
    wikiDataId


    Fields restricted to higher tiers are marked in each schema below.


    ## Feature Gating

    Some endpoints require a minimum tier. Restricted endpoints return `403`
    with an `upgradeUrl` when accessed on a lower plan. Check the [pricing
    page](https://countrystatecity.in/pricing) for current feature availability.


    ## Rate Limiting

    Requests exceeding your daily or monthly quota receive a `429` response with
    your current limit, period, tier, and an upgrade URL.


    ## Caching

    Cacheable geographic responses include `Cache-Control`, `ETag`, and
    `X-Cache` (HIT/MISS) headers; send `If-None-Match` on them to receive `304
    Not Modified`. Phone number parsing is never cached (`Cache-Control:
    no-store`, no `ETag`); see each endpoint for exceptions.


    ## Usage Headers

    All `/v1/*` responses include usage and plan headers:

    - `X-CSC-Plan` — your current tier

    - `X-CSC-Daily-Used` / `X-CSC-Daily-Limit` — today's usage vs limit

    - `X-CSC-Monthly-Used` / `X-CSC-Monthly-Limit` — this month's usage vs limit


    Use these to monitor consumption without a separate API call.
  contact:
    name: Darshan Gada (dr5hn)
    email: gadadarshan@gmail.com
    url: https://countrystatecity.in
  license:
    name: Creative Commons Attribution 4.0
    url: https://creativecommons.org/licenses/by/4.0/
  version: 2.4.1
servers:
  - url: https://api.countrystatecity.in/v1
    description: Production API
security: []
tags:
  - name: Countries
    description: Country data — 250+ countries with metadata, coordinates, and translations
  - name: States
    description: State/province/region data — 5,000+ subdivisions
  - name: Cities
    description: City data — 150,000+ cities worldwide
  - name: Postcodes
    description: >-
      Postcode and ZIP code lookup and search. Informational data, not address
      verification.
  - name: Regions
    description: Geographic regions and subregions — continental groupings of countries
  - name: Timezones
    description: >-
      IANA timezone lookup by country, state, or city — includes UTC offset and
      DST status
  - name: Currencies
    description: ISO 4217 currency data — list all currencies or look up by country
  - name: Phone
    description: >-
      International dial codes — list, lookup by country, and E.164 phone number
      parsing
  - name: ISO
    description: >-
      ISO 3166 code lookup and conversion — country (alpha-2/3/numeric) and
      state (ISO 3166-2)
  - name: Search
    description: Typo-tolerant fuzzy search across cities, states, and countries
  - name: Changes
    description: >-
      Data change feed — track additions, removals, and updates to place records
      over time. **Professional and Business plans only.**
  - name: Meta
    description: Information about the dataset release currently served
paths:
  /countries/{ciso}/postcodes/{code}:
    get:
      tags:
        - Postcodes
      summary: Get postcode by code
      description: >-
        Exact postcode lookup within a country. Returns **every** matching
        record, because one code can cover several localities.


        Informational data only: this is not an address verification or
        mail-deliverability service.


        **Availability:** All tiers.
      operationId: getPostcodeByCode
      parameters:
        - name: ciso
          in: path
          required: true
          description: >-
            ISO 3166-1 alpha-2 country code, case-insensitive (e.g. `LK`).
            Numeric IDs and ISO3 codes are not accepted on postcode endpoints.
          schema:
            type: string
            minLength: 2
            maxLength: 2
            example: LK
        - name: code
          in: path
          required: true
          description: >-
            Postcode to look up, 1 to 20 characters. Case-insensitive and
            tolerant of repeated internal spaces (`gy1  1aa` matches `GY1 1AA`).
            URL-encode spaces.
          schema:
            type: string
            minLength: 1
            maxLength: 20
            example: '11104'
      responses:
        '200':
          description: All records matching the code
          headers:
            Cache-Control:
              $ref: '#/components/headers/CacheControl'
            ETag:
              $ref: '#/components/headers/ETag'
            X-Cache:
              $ref: '#/components/headers/XCache'
            X-CSC-Plan:
              $ref: '#/components/headers/XCSCPlan'
            X-CSC-Daily-Used:
              $ref: '#/components/headers/XCSCDailyUsed'
            X-CSC-Daily-Limit:
              $ref: '#/components/headers/XCSCDailyLimit'
            X-CSC-Monthly-Used:
              $ref: '#/components/headers/XCSCMonthlyUsed'
            X-CSC-Monthly-Limit:
              $ref: '#/components/headers/XCSCMonthlyLimit'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostcodeLookupResponse'
        '304':
          description: Not modified (sent `If-None-Match` matched the current `ETag`)
        '400':
          description: >-
            Invalid code (empty, over 20 characters, or containing `/`, `\\` or
            control characters)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusError'
              example:
                status: error
                message: postcode must be at most 20 characters
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          description: >-
            Unknown country (`country_not_found`), no postcode coverage
            (`postcode_coverage_unavailable`), or no match
            (`postcode_not_found`). See `details.reason`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StatusError'
              example:
                status: error
                message: No postcode matches the given code.
                details:
                  reason: postcode_not_found
        '429':
          $ref: '#/components/responses/RateLimited'
      security:
        - ApiKeyAuth: []
components:
  headers:
    CacheControl:
      description: Cache directive
      schema:
        type: string
        example: public, max-age=3600
    ETag:
      description: Entity tag for conditional requests (use with `If-None-Match`)
      schema:
        type: string
        example: '"a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5"'
    XCache:
      description: Whether the response was served from cache
      schema:
        type: string
        enum:
          - HIT
          - MISS
        example: HIT
    XCSCPlan:
      description: Your current pricing tier
      schema:
        type: string
        enum:
          - community
          - starter
          - supporter
          - professional
          - business
          - legacy
          - custom
        example: supporter
    XCSCDailyUsed:
      description: Number of requests used today
      schema:
        type: integer
        example: 42
    XCSCDailyLimit:
      description: Your daily request limit (or 'unlimited' for custom plans)
      schema:
        type: string
        example: '1000'
    XCSCMonthlyUsed:
      description: Number of requests used this month
      schema:
        type: integer
        example: 850
    XCSCMonthlyLimit:
      description: Your monthly request limit (or 'unlimited' for custom plans)
      schema:
        type: string
        example: '30000'
  schemas:
    PostcodeLookupResponse:
      type: object
      properties:
        data:
          type: array
          description: >-
            Every record matching the code, ascending `id`. Never empty (no
            match is a `404`).
          items:
            $ref: '#/components/schemas/Postcode'
        meta:
          type: object
          properties:
            country_code:
              type: string
              example: LK
            query:
              type: string
              description: >-
                Normalised code used for matching (trimmed, uppercased, repeated
                spaces collapsed)
              example: '11104'
            match_count:
              type: integer
              example: 3
      required:
        - data
        - meta
    StatusError:
      type: object
      description: Error envelope used by the postcode and meta endpoints.
      properties:
        status:
          type: string
          example: error
        message:
          type: string
        details:
          type: object
          nullable: true
          properties:
            reason:
              type: string
              description: >-
                Machine-readable reason. Check this instead of parsing
                `message`.
          additionalProperties: true
      required:
        - status
        - message
    Postcode:
      type: object
      description: >-
        A postcode record. `id` and foreign keys are numeric strings for 64-bit
        safety. Fields above the Basic tier are stripped, not nulled, for lower
        plans.
      properties:
        id:
          type: string
          pattern: ^[0-9]+$
          description: Unique identifier, as a numeric string
          example: '670115'
        code:
          type: string
          description: Postcode as stored, original spacing and casing preserved
          example: '11104'
        country_code:
          type: string
          description: ISO2 country code
          example: LK
        state_code:
          type: string
          nullable: true
          description: State/province code, when linked
          example: '12'
        locality_name:
          type: string
          nullable: true
          description: Place name associated with the postcode
          example: Wattala
        type:
          type: string
          nullable: true
          description: >-
            Source-provided classification (not a fixed enum), e.g. `full`,
            `area`, `fsa`, `po_box`, `street`
          example: full
        country_id:
          type: string
          pattern: ^[0-9]+$
          description: Country ID. **Coordinates tier and above.**
          example: '208'
        state_id:
          type: string
          pattern: ^[0-9]+$
          description: State ID. **Coordinates tier and above.**
          nullable: true
          example: '2804'
        city_id:
          type: string
          pattern: ^[0-9]+$
          description: City ID, when linked to a city. **Coordinates tier and above.**
          nullable: true
        latitude:
          type: number
          nullable: true
          description: Latitude. **Coordinates tier and above.**
          example: 6.9906677
        longitude:
          type: number
          nullable: true
          description: Longitude. **Coordinates tier and above.**
          example: 79.8931709
        source:
          type: string
          nullable: true
          description: Originating data source. **Full tier only.**
        wikiDataId:
          type: string
          nullable: true
          description: Wikidata Q-ID. **Full tier only.**
      required:
        - id
        - code
        - country_code
    Error:
      type: object
      properties:
        error:
          type: string
          description: Error message
      required:
        - error
    RateLimitError:
      type: object
      properties:
        error:
          type: string
          example: >-
            Daily usage limit exceeded. Please try again tomorrow or contact
            support for higher limits.
        limit:
          type: integer
          description: Your plan's limit for the exceeded period
          example: 100
        period:
          type: string
          enum:
            - daily
            - monthly
          example: daily
        tier:
          type: string
          description: Your current tier
          example: community
        upgradeUrl:
          type: string
          description: URL to upgrade your plan
          example: https://countrystatecity.in/pricing
      required:
        - error
  responses:
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
          example:
            error: Unauthorized. You shouldn't be here.
    RateLimited:
      description: Daily or monthly usage limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/RateLimitError'
          example:
            error: >-
              Daily usage limit exceeded. Please try again tomorrow or contact
              support for higher limits.
            limit: 100
            period: daily
            tier: community
            upgradeUrl: https://countrystatecity.in/pricing
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      description: >-
        API key for authentication. Get your free key at
        [app.countrystatecity.in](https://app.countrystatecity.in).
      name: X-CSCAPI-KEY
      in: header

````

## Related topics

- [Postcodes](/database/postcodes.md)
- [Get Postcodes by Country](/api/endpoints/get-postcodes-by-country.md)
- [Database Schema](/database/schema.md)
- [Get Dial Code by Country](/api/endpoints/get-dial-code-by-country.md)
- [Changelog](/changelog.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.