Skill Tracer
Skills › Scientific Agent Skills › pymatgen › materials_project_api.md

materials_project_api.md

474 lines · skills/pymatgen/references/materials_project_api.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Materials Project API: bounded queries, provenance, and computed-data limits
2
3This reference targets `mp-api==0.46.5` (released 2026-08-18) with
4`pymatgen==2026.9.24` and `pymatgen-core==2026.9.23`. `mp-api` requires Python
53.11+ and depends on `pymatgen>2024.2.20`.
6
7Use the separate official client:
8
9```python
10from mp_api.client import MPRester
11```
13Do not use a legacy Materials Project client import from older pymatgen
14examples.
16Verification on 2026-09-30 used current official guides, the current OpenAPI
17schema captured during this review, installed 0.46.5 SDK source and mocked
18transports. A repeat OpenAPI request returned HTTP 403; protected endpoints were
19not exercised with credentials. Network examples in
20this reference are illustrative, not authenticated end-to-end tests.

Materials Project API: bounded queries, provenance, and computed-data limits

This reference targets mp-api==0.46.5 (released 2026-08-18) with pymatgen==2026.9.24 and pymatgen-core==2026.9.23. mp-api requires Python 3.11+ and depends on pymatgen>2024.2.20.

Use the separate official client:

from mp_api.client import MPRester

Do not use a legacy Materials Project client import from older pymatgen examples.

Verification on 2026-09-30 used current official guides, the current OpenAPI schema captured during this review, installed 0.46.5 SDK source and mocked transports. A repeat OpenAPI request returned HTTP 403; protected endpoints were not exercised with credentials. Network examples in this reference are illustrative, not authenticated end-to-end tests.

Raw lines 1 to 21
22## Installation
24Pin the tested client and materials stack:
26```bash
27uv add "pymatgen==2026.9.24" "pymatgen-core==2026.9.23" "mp-api==0.46.5"
28uv lock
29uv sync --frozen
30```
32The 0.46.5 package metadata declares direct dependencies including
33`pymatgen>2024.2.20`, `monty>=2024.12.10`, `emmet-core>=0.87.1`,
34`requests>=2.23.0`, `orjson>=3.10,<4`, `pyarrow>=20`, and
35`deltalake>=1.4,<1.6`, plus boto3 and typing extensions. A lockfile is needed
36to freeze transitive artifacts.

Installation

Pin the tested client and materials stack:

uv add "pymatgen==2026.9.24" "pymatgen-core==2026.9.23" "mp-api==0.46.5"
uv lock
uv sync --frozen

The 0.46.5 package metadata declares direct dependencies including pymatgen>2024.2.20, monty>=2024.12.10, emmet-core>=0.87.1, requests>=2.23.0, orjson>=3.10,<4, pyarrow>=20, and deltalake>=1.4,<1.6, plus boto3 and typing extensions. A lockfile is needed to freeze transitive artifacts.

Raw lines 22 to 37
38## Authentication: one named secret
40An API key is required and is available from the logged-in Materials Project
41[dashboard](https://next-gen.materialsproject.org/dashboard).
43The approved pattern is:
45```python
46from mp_api.client import MPRester
48# Inject MP_API_KEY before execution; keep this workflow on the official host.
49with MPRester(endpoint="https://api.materialsproject.org/") as rester:
50 pass
51```
53Operational rules:
55- use only the environment variable `MP_API_KEY`
56- inject it through the user's shell/session secret manager
57- never accept it as a command-line argument
58- never embed it in code, notebooks, URLs, cache files, or manifests
59- never traverse dot-env files or dump the environment
60- never print the key or unredacted exceptions that might contain it
61- do not send it anywhere except the official Materials Project API endpoint
63The bundled query CLI follows these rules and reads the variable only after
64`--execute`.

Authentication: one named secret

An API key is required and is available from the logged-in Materials Project dashboard.

The approved pattern is:

from mp_api.client import MPRester

# Inject MP_API_KEY before execution; keep this workflow on the official host.
with MPRester(endpoint="https://api.materialsproject.org/") as rester:
    pass

Operational rules:

  • use only the environment variable MP_API_KEY
  • inject it through the user's shell/session secret manager
  • never accept it as a command-line argument
  • never embed it in code, notebooks, URLs, cache files, or manifests
  • never traverse dot-env files or dump the environment
  • never print the key or unredacted exceptions that might contain it
  • do not send it anywhere except the official Materials Project API endpoint

The bundled query CLI follows these rules and reads the variable only after --execute.

Raw lines 38 to 65
66## Query contract before network
68Before any request, disclose:
701. endpoint and `mp-api` version
712. all filters
723. exact response fields
734. `num_chunks`, `chunk_size`, and maximum serialized bytes
745. cache reads/writes
756. output path and no-overwrite behavior
767. API-key source by name, never value
778. data license, citation, provenance, and scientific limitations
79The dry-run planner:
81```bash
82python scripts/mp_query.py \
83 --chemsys Li-Fe-O \
84 --energy-above-hull 0 0.05 \
85 --fields formula_pretty,energy_above_hull,band_gap,origins \
86 --limit 25
87```
89Only an explicit execution permits the disclosed network workflow:
91```bash
92python scripts/mp_query.py \
93 --material-id mp-149 \
94 --fields formula_pretty,structure,origins,last_updated \
95 --limit 1 --output mp-149.json --execute
96```
98The CLI has no implicit result cache. The explicit bounded JSON output is the
99reusable artifact. `MPRester` initialization performs compatibility and
100heartbeat/database-version metadata requests before the bounded summary
101search. The CLI discloses those requests, disables the platform-detail user
102agent and local database-version notification log, and records the server's
103database version.
105The CLI pins `endpoint` explicitly so SDK endpoint configuration cannot redirect
106its credential. Initialization makes separate unauthenticated `GET /heartbeat`
107calls for server/emmet version, database version and controlled-dataset metadata.
108Those calls do not use the session retry/timeout mechanism; apply a process
109deadline for automation. If heartbeat is denied, the SDK may report an empty
110database version; retain that limitation rather than invent a release.

Query contract before network

Before any request, disclose:

  1. endpoint and mp-api version
  2. all filters
  3. exact response fields
  4. num_chunks, chunk_size, and maximum serialized bytes
  5. cache reads/writes
  6. output path and no-overwrite behavior
  7. API-key source by name, never value
  8. data license, citation, provenance, and scientific limitations

The dry-run planner:

python scripts/mp_query.py \
  --chemsys Li-Fe-O \
  --energy-above-hull 0 0.05 \
  --fields formula_pretty,energy_above_hull,band_gap,origins \
  --limit 25

Only an explicit execution permits the disclosed network workflow:

python scripts/mp_query.py \
  --material-id mp-149 \
  --fields formula_pretty,structure,origins,last_updated \
  --limit 1 --output mp-149.json --execute

The CLI has no implicit result cache. The explicit bounded JSON output is the reusable artifact. MPRester initialization performs compatibility and heartbeat/database-version metadata requests before the bounded summary search. The CLI discloses those requests, disables the platform-detail user agent and local database-version notification log, and records the server's database version.

The CLI pins endpoint explicitly so SDK endpoint configuration cannot redirect its credential. Initialization makes separate unauthenticated GET /heartbeat calls for server/emmet version, database version and controlled-dataset metadata. Those calls do not use the session retry/timeout mechanism; apply a process deadline for automation. If heartbeat is denied, the SDK may report an empty database version; retain that limitation rather than invent a release.

Raw lines 66 to 111
Runs code python scripts/mp_query.py :82
112## Summary searches
114The official docs identify summary data as the main property overview for a
115material:
117```python
118from mp_api.client import MPRester
120with MPRester() as rester:
121 docs = rester.materials.summary.search(
122 material_ids=["mp-149", "mp-13"],
123 fields=[
124 "material_id",
125 "formula_pretty",
126 "energy_above_hull",
127 "band_gap",
128 "origins",
129 "last_updated",
130 ],
131 all_fields=False,
132 num_chunks=1,
133 chunk_size=25,
134 )
135```
137`material_ids` accepts one ID or a list in the current signature. Both numeric
138IDs (`mp-149`) and alphabetical AlphaIDs (`mp-aaaaaaft`) are supported. The SDK
139normalizes them through emmet; these two examples identify the same record.
140Preserve the user's query and returned identifier instead of enforcing a
141digits-only pattern. The result is a list of Pydantic document objects based
142on `SummaryDoc`; selected-field results can use a reduced `MPDataDoc` model.

Summary searches

The official docs identify summary data as the main property overview for a material:

from mp_api.client import MPRester

with MPRester() as rester:
    docs = rester.materials.summary.search(
        material_ids=["mp-149", "mp-13"],
        fields=[
            "material_id",
            "formula_pretty",
            "energy_above_hull",
            "band_gap",
            "origins",
            "last_updated",
        ],
        all_fields=False,
        num_chunks=1,
        chunk_size=25,
    )

material_ids accepts one ID or a list in the current signature. Both numeric IDs (mp-149) and alphabetical AlphaIDs (mp-aaaaaaft) are supported. The SDK normalizes them through emmet; these two examples identify the same record. Preserve the user's query and returned identifier instead of enforcing a digits-only pattern. The result is a list of Pydantic document objects based on SummaryDoc; selected-field results can use a reduced MPDataDoc model.

Raw lines 112 to 143
144### Property filters
146Verified public `SummaryRester.search` parameters include:
148```python
149with MPRester() as rester:
150 docs = rester.materials.summary.search(
151 chemsys="Li-Fe-O",
152 elements=["Li", "O"],
153 exclude_elements=["F"],
154 energy_above_hull=(0.0, 0.05),
155 band_gap=(0.5, 3.0),
156 is_stable=None,
157 fields=["material_id", "formula_pretty", "energy_above_hull", "band_gap"],
158 all_fields=False,
159 num_chunks=1,
160 chunk_size=25,
161 )
162```
164Other current filters include formula, crystal system, density, deprecation,
165dielectric ranges, elastic ranges, metal/direct-gap flags, property
166availability, magnetic ordering, element/site counts, space group, theoretical
167status, energy ranges, volume, and surface-property ranges. Consult the exact
168installed signature instead of passing guessed keywords.
170`exclude_elements` is a list of element symbols; it is not a Boolean flag.
172`available_fields` lists fields the endpoint can return. It does not mean every
173field is a valid filter:
175```python
176with MPRester() as rester:
177 returnable_fields = rester.materials.summary.available_fields
178```
180Requesting all fields is the documented default and can be expensive. Always
181pass a short `fields` list and bound chunks.
183The REST search is a `GET /materials/summary/` with `x-api-key` authentication
184and URL query parameters, not a JSON POST. The SDK joins lists (for example
185`material_ids`, `elements`, `exclude_elements`) with commas and expands range
186tuples to endpoint-specific `_min`/`_max` parameters. Responses contain a
187`data` array and `meta.total_doc`; the SDK returns the document list.
188`num_chunks=None` retrieves all pages; `num_chunks=1, chunk_size=25` bounds this
189workflow. Pagination uses `_limit`/`_skip`; current `search()` also exposes
190`_page` and `_sort_fields`. List splitting or retries can make one SDK search
191more than one HTTP request. A full page does not prove the query is exhaustive.
192The saved-byte cap applies after receipt and serialization.
194For direct REST requests, `_limit` defaults to 100 and is capped at 1000.
195`_page`/`_per_page` take precedence over `_limit`/`_skip`; do not combine both
196pagination styles. `id_format=legacy|alpha` changes response ID formatting,
197not which input IDs are accepted. This REST parameter is not a documented
198`SummaryRester.search()` argument in 0.46.5.

Property filters

Verified public SummaryRester.search parameters include:

with MPRester() as rester:
    docs = rester.materials.summary.search(
        chemsys="Li-Fe-O",
        elements=["Li", "O"],
        exclude_elements=["F"],
        energy_above_hull=(0.0, 0.05),
        band_gap=(0.5, 3.0),
        is_stable=None,
        fields=["material_id", "formula_pretty", "energy_above_hull", "band_gap"],
        all_fields=False,
        num_chunks=1,
        chunk_size=25,
    )

Other current filters include formula, crystal system, density, deprecation, dielectric ranges, elastic ranges, metal/direct-gap flags, property availability, magnetic ordering, element/site counts, space group, theoretical status, energy ranges, volume, and surface-property ranges. Consult the exact installed signature instead of passing guessed keywords.

exclude_elements is a list of element symbols; it is not a Boolean flag.

available_fields lists fields the endpoint can return. It does not mean every field is a valid filter:

with MPRester() as rester:
    returnable_fields = rester.materials.summary.available_fields

Requesting all fields is the documented default and can be expensive. Always pass a short fields list and bound chunks.

The REST search is a GET /materials/summary/ with x-api-key authentication and URL query parameters, not a JSON POST. The SDK joins lists (for example material_ids, elements, exclude_elements) with commas and expands range tuples to endpoint-specific _min/_max parameters. Responses contain a data array and meta.total_doc; the SDK returns the document list. num_chunks=None retrieves all pages; num_chunks=1, chunk_size=25 bounds this workflow. Pagination uses _limit/_skip; current search() also exposes _page and _sort_fields. List splitting or retries can make one SDK search more than one HTTP request. A full page does not prove the query is exhaustive. The saved-byte cap applies after receipt and serialization.

For direct REST requests, _limit defaults to 100 and is capped at 1000. _page/_per_page take precedence over _limit/_skip; do not combine both pagination styles. id_format=legacy|alpha changes response ID formatting, not which input IDs are accepted. This REST parameter is not a documented SummaryRester.search() argument in 0.46.5.

Raw lines 144 to 199
200## Serialization
202Use the public Pydantic model interface:
204```python
205payload = [document.model_dump(mode="json") for document in docs]
206```
208Then write strict JSON with `allow_nan=False`, a byte bound, and a new output
209path. Include query, fields, retrieval time, endpoint, client versions, and
210license/citation. Do not use deprecated generic dictionary shims, pickle, or a
211general object decoder on untrusted cached data.

Serialization

Use the public Pydantic model interface:

payload = [document.model_dump(mode="json") for document in docs]

Then write strict JSON with allow_nan=False, a byte bound, and a new output path. Include query, fields, retrieval time, endpoint, client versions, and license/citation. Do not use deprecated generic dictionary shims, pickle, or a general object decoder on untrusted cached data.

Raw lines 200 to 212
213## Structures
215```python
216from mp_api.client import MPRester
218with MPRester() as rester:
219 structure = rester.get_structure_by_material_id(
220 "mp-149",
221 final=True,
222 conventional_unit_cell=False,
223 )
224```
226Alternatively request `structure` as an explicit summary field. Preserve:
228- material ID
229- whether the final/initial and conventional/primitive representation was
230 requested
231- `origins` and task IDs
232- retrieval and database release
233- parser/API warnings
235Validate the returned structure locally. A Materials Project structure is a
236computed relaxed representation, not necessarily the experimental setting,
237lattice parameters, disorder, temperature, or composition model.
239This convenience method searches `/materials/core/` for `structure` when
240`final=True`, or `initial_structures` when false. The former returns one
241`Structure`, the latter a list; unavailable data can return `None`.

Structures

from mp_api.client import MPRester

with MPRester() as rester:
    structure = rester.get_structure_by_material_id(
        "mp-149",
        final=True,
        conventional_unit_cell=False,
    )

Alternatively request structure as an explicit summary field. Preserve:

  • material ID
  • whether the final/initial and conventional/primitive representation was requested
  • origins and task IDs
  • retrieval and database release
  • parser/API warnings

Validate the returned structure locally. A Materials Project structure is a computed relaxed representation, not necessarily the experimental setting, lattice parameters, disorder, temperature, or composition model.

This convenience method searches /materials/core/ for structure when final=True, or initial_structures when false. The former returns one Structure, the latter a list; unavailable data can return None.

Raw lines 213 to 242
243## Entries and phase diagrams
245```python
246from mp_api.client import MPRester
248with MPRester() as rester:
249 entries = rester.get_entries_in_chemsys(
250 "Li-Fe-O",
251 compatible_only=True,
252 conventional_unit_cell=False,
253 )
254```
256Version 0.46.5 changed this workflow: the default thermotype is the joint
257`GGA_GGA+U_R2SCAN` hull. An unfiltered full-system query with
258`compatible_only=True` normally returns entries from MP's precomputed phase
259diagram, keeping all subsystems on one energy scale. If that diagram is missing,
260or `property_data`/`conventional_unit_cell` require reshaping, the client runs
261`MaterialsProjectDFTMixingScheme` locally; it warns about possible hull changes
262and dropped entries. This can query/cache Delta-table data, unlike the bundled
263summary-only CLI.
265To explicitly select the earlier GGA/GGA+U correction convention:
267```python
268with MPRester() as rester:
269 entries = rester.get_entries_in_chemsys(
270 "Co-N",
271 additional_criteria={
272 "thermo_types": ["GGA_GGA+U"]
273 },
274 )
275```
277Extra filters on mixed thermotypes or `compatible_only=False` bypass the
278consistent full-system path; those entries are not immediately hull-ready.
279Retrieve the full consistent set before post-filtering for reporting, and keep
280all competitors for hull construction. Do not pool all three thermotypes into
281one hull. The non-mixed path uses `/materials/thermo/`; the prebuilt mixed path
282uses the `materialsproject-build` Delta table `objects/phase-diagrams`, selected
283by chemical system, thermotype and database version. These are SDK-managed data
284locations, not REST endpoints to invent. Record all arguments, correction data,
285origins and database release; cache and analyze the resulting entries offline.
287`use_gibbs` requests a GibbsComputedStructureEntry model estimate at 300–2000 K,
288not a measured free energy. `property_data` selects supported thermo fields.
289The convenience method has no summary-CLI result cap; bound the chemical system
290and expected dataset independently.

Entries and phase diagrams

from mp_api.client import MPRester

with MPRester() as rester:
    entries = rester.get_entries_in_chemsys(
        "Li-Fe-O",
        compatible_only=True,
        conventional_unit_cell=False,
    )

Version 0.46.5 changed this workflow: the default thermotype is the joint GGA_GGA+U_R2SCAN hull. An unfiltered full-system query with compatible_only=True normally returns entries from MP's precomputed phase diagram, keeping all subsystems on one energy scale. If that diagram is missing, or property_data/conventional_unit_cell require reshaping, the client runs MaterialsProjectDFTMixingScheme locally; it warns about possible hull changes and dropped entries. This can query/cache Delta-table data, unlike the bundled summary-only CLI.

To explicitly select the earlier GGA/GGA+U correction convention:

with MPRester() as rester:
    entries = rester.get_entries_in_chemsys(
        "Co-N",
        additional_criteria={
            "thermo_types": ["GGA_GGA+U"]
        },
    )

Extra filters on mixed thermotypes or compatible_only=False bypass the consistent full-system path; those entries are not immediately hull-ready. Retrieve the full consistent set before post-filtering for reporting, and keep all competitors for hull construction. Do not pool all three thermotypes into one hull. The non-mixed path uses /materials/thermo/; the prebuilt mixed path uses the materialsproject-build Delta table objects/phase-diagrams, selected by chemical system, thermotype and database version. These are SDK-managed data locations, not REST endpoints to invent. Record all arguments, correction data, origins and database release; cache and analyze the resulting entries offline.

use_gibbs requests a GibbsComputedStructureEntry model estimate at 300–2000 K, not a measured free energy. property_data selects supported thermo fields. The convenience method has no summary-CLI result cap; bound the chemical system and expected dataset independently.

Raw lines 243 to 291
292## Band structures and DOS
294Official convenience methods include:
296```python
297with MPRester() as rester:
298 bands = rester.get_bandstructure_by_material_id("mp-149", load_projections=False)
299 dos = rester.get_dos_by_material_id("mp-149", load_projections=False)
300```
302In 0.46.5 missing metadata or task data raises `MPRestError`; catch it without
303turning absence into a zero gap or DOS. The client first searches
304`/materials/electronic_structure/` for the task, then queries SDK-managed Delta
305tables under `materialsproject-parsed/core/electronic-structure/` for
306`bandstructures` or `total-dos`; projections use additional tables only when
307requested. Default DOS retrieval returns `Dos`, not necessarily `CompleteDos`.
308Preserve task origins, spin/SOC, path convention, functional and database release.
309These convenience calls have different network/cache costs from a summary
310property query.

Band structures and DOS

Official convenience methods include:

with MPRester() as rester:
    bands = rester.get_bandstructure_by_material_id("mp-149", load_projections=False)
    dos = rester.get_dos_by_material_id("mp-149", load_projections=False)

In 0.46.5 missing metadata or task data raises MPRestError; catch it without turning absence into a zero gap or DOS. The client first searches /materials/electronic_structure/ for the task, then queries SDK-managed Delta tables under materialsproject-parsed/core/electronic-structure/ for bandstructures or total-dos; projections use additional tables only when requested. Default DOS retrieval returns Dos, not necessarily CompleteDos. Preserve task origins, spin/SOC, path convention, functional and database release. These convenience calls have different network/cache costs from a summary property query.

Raw lines 292 to 311
312## Provenance with origins
314The official query guide recommends requesting `origins` to connect a summary
315property to a calculation task:
317```python
318with MPRester() as rester:
319 summaries = rester.materials.summary.search(
320 material_ids=["mp-149"],
321 fields=["material_id", "structure", "origins"],
322 all_fields=False,
323 num_chunks=1,
324 chunk_size=1,
325 )
326```
328An origin can identify the task used for a property. A corresponding thermo
329document's `run_type` distinguishes categories such as GGA, GGA+U, or r2SCAN.
330Do not assume all properties on one summary document came from one calculation
331or functional.

Provenance with origins

The official query guide recommends requesting origins to connect a summary property to a calculation task:

with MPRester() as rester:
    summaries = rester.materials.summary.search(
        material_ids=["mp-149"],
        fields=["material_id", "structure", "origins"],
        all_fields=False,
        num_chunks=1,
        chunk_size=1,
    )

An origin can identify the task used for a property. A corresponding thermo document's run_type distinguishes categories such as GGA, GGA+U, or r2SCAN. Do not assume all properties on one summary document came from one calculation or functional.

Raw lines 312 to 332
333## Other routes
335The client exposes endpoint-specific resters under `rester.materials`, with
336routes documented for thermo, electronic structure, elasticity, dielectric,
337magnetism, phonons, surfaces, XAS, synthesis-related data, and others.
338Signatures and document models vary. Inspect the current route documentation
339and request only supported fields.
341Do not copy old endpoint examples or invent filter names. Endpoint availability
342and schema can evolve independently of the Python wrapper.

Other routes

The client exposes endpoint-specific resters under rester.materials, with routes documented for thermo, electronic structure, elasticity, dielectric, magnetism, phonons, surfaces, XAS, synthesis-related data, and others. Signatures and document models vary. Inspect the current route documentation and request only supported fields.

Do not copy old endpoint examples or invent filter names. Endpoint availability and schema can evolve independently of the Python wrapper.

Raw lines 333 to 343
344## Errors, retries, and rate handling
346Use the current exception:
348```python
349from mp_api.client.core.exceptions import MPRestError
351try:
352 with MPRester() as rester:
353 docs = rester.materials.summary.search(
354 material_ids=["mp-149"],
355 fields=["material_id"],
356 all_fields=False,
357 num_chunks=1,
358 chunk_size=1,
359 )
360except MPRestError:
361 # Report a bounded, credential-redacted failure.
362 raise
363```
365Official 0.46.5 client source configures retries for HTTP 429, 502, and 504 and
366respects `Retry-After` for its API session (heartbeat is separate). It wraps request failures as `MPRestError` and advises
367smaller requests on connection timeout.
369Safety rules:
371- rely on the pinned client's bounded retry behavior
372- do not add an unbounded retry loop
373- do not claim a numeric service quota unless current official documentation
374 publishes one
375- reduce fields/chunk size on timeout or oversized responses
376- stop after a persistent authorization, schema, or validation error
377- redact `MP_API_KEY` from any exception text
379The current [large-download guide](https://docs.materialsproject.org/downloading-data/using-the-api/tips-for-large-downloads)
380says rate limiting starts at 25 requests/second. Treat HTTP 429 and
381`Retry-After` as authoritative, not that number as a guaranteed quota.

Errors, retries, and rate handling

Use the current exception:

from mp_api.client.core.exceptions import MPRestError

try:
    with MPRester() as rester:
        docs = rester.materials.summary.search(
            material_ids=["mp-149"],
            fields=["material_id"],
            all_fields=False,
            num_chunks=1,
            chunk_size=1,
        )
except MPRestError:
    # Report a bounded, credential-redacted failure.
    raise

Official 0.46.5 client source configures retries for HTTP 429, 502, and 504 and respects Retry-After for its API session (heartbeat is separate). It wraps request failures as MPRestError and advises smaller requests on connection timeout.

Safety rules:

  • rely on the pinned client's bounded retry behavior
  • do not add an unbounded retry loop
  • do not claim a numeric service quota unless current official documentation publishes one
  • reduce fields/chunk size on timeout or oversized responses
  • stop after a persistent authorization, schema, or validation error
  • redact MP_API_KEY from any exception text

The current large-download guide says rate limiting starts at 25 requests/second. Treat HTTP 429 and Retry-After as authoritative, not that number as a guaranteed quota.

Raw lines 344 to 382
383## Cache policy
385Caching can improve reproducibility but creates a data-governance obligation.
386Before using a cache, disclose:
388- exact path, schema, size limit, and retention
389- cache key: endpoint, filters, fields, client version, and database release
390- whether stale data is acceptable
391- license/citation metadata
392- whether structures or contributed data are stored
394Never cache credentials. Never treat a cache as current without checking its
395retrieval time and database version. `mp-api` exposes a local full-dataset cache
396path for bulk/delta-table workflows; the bundled summary-query CLI does not
397request those downloads and intentionally uses no hidden result cache.

Cache policy

Caching can improve reproducibility but creates a data-governance obligation. Before using a cache, disclose:

  • exact path, schema, size limit, and retention
  • cache key: endpoint, filters, fields, client version, and database release
  • whether stale data is acceptable
  • license/citation metadata
  • whether structures or contributed data are stored

Never cache credentials. Never treat a cache as current without checking its retrieval time and database version. mp-api exposes a local full-dataset cache path for bulk/delta-table workflows; the bundled summary-query CLI does not request those downloads and intentionally uses no hidden result cache.

Raw lines 383 to 398
399## License, attribution, and citation
401Materials Project states that its data is licensed under
402[CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) and that contributed
403data is owned by its respective contributors.
405The official FAQ says citations are appropriate wherever Materials Project
406data, methods, or output are used. Preserve:
408- canonical Materials Project citation
409- property/tool-specific citations from the material/citation page
410- database release citation
411- material IDs and task/property origins
412- retrieval date and query
414See [How to Cite](https://materialsproject.org/about/cite) and
415[Database Versions](https://docs.materialsproject.org/changes/database-versions).

License, attribution, and citation

Materials Project states that its data is licensed under CC BY 4.0 and that contributed data is owned by its respective contributors.

The official FAQ says citations are appropriate wherever Materials Project data, methods, or output are used. Preserve:

  • canonical Materials Project citation
  • property/tool-specific citations from the material/citation page
  • database release citation
  • material IDs and task/property origins
  • retrieval date and query

See How to Cite and Database Versions.

Raw lines 399 to 416
417## Computed-data limitations
419Materials Project documents that:
421- core properties are calculated in-house using simulation methods
422- typical/systematic errors must be assessed from property publications
423- PBE lattice parameters often show systematic overestimation, with larger
424 interlayer errors where van der Waals interactions are poorly described
425- PBE band gaps are systematically underestimated
426- summary/aggregated values can change as calculations and database releases
427 are updated
428- space groups depend on `symprec`; the MP pipeline commonly uses `0.1 Å`
430Therefore:
432- computed stability is not experimental stability or synthesizability
433- predicted structures are not proof of existence
434- missing data is not zero
435- a material ID does not guarantee one immutable property record
436- cite the database version and property methodology

Computed-data limitations

Materials Project documents that:

  • core properties are calculated in-house using simulation methods
  • typical/systematic errors must be assessed from property publications
  • PBE lattice parameters often show systematic overestimation, with larger interlayer errors where van der Waals interactions are poorly described
  • PBE band gaps are systematically underestimated
  • summary/aggregated values can change as calculations and database releases are updated
  • space groups depend on symprec; the MP pipeline commonly uses 0.1 Å

Therefore:

  • computed stability is not experimental stability or synthesizability
  • predicted structures are not proof of existence
  • missing data is not zero
  • a material ID does not guarantee one immutable property record
  • cite the database version and property methodology
Raw lines 417 to 437
438## Minimal provenance envelope
440```json
442 "retrieved_at_utc": "2026-09-30T00:00:00Z",
443 "endpoint": "https://api.materialsproject.org/materials/summary/",
444 "filters": {"material_ids": ["mp-149"]},
445 "fields": ["material_id", "formula_pretty", "origins", "last_updated"],
446 "limit": 1,
447 "client": {
448 "mp-api": "0.46.5",
449 "pymatgen": "2026.9.24",
450 "pymatgen-core": "2026.9.23"
451 },
452 "database_version": "record from current MP release metadata",
453 "license": "CC BY 4.0",
454 "citation": "https://materialsproject.org/about/cite"
456```
458Do not include the API key.

Minimal provenance envelope

{
  "retrieved_at_utc": "2026-09-30T00:00:00Z",
  "endpoint": "https://api.materialsproject.org/materials/summary/",
  "filters": {"material_ids": ["mp-149"]},
  "fields": ["material_id", "formula_pretty", "origins", "last_updated"],
  "limit": 1,
  "client": {
    "mp-api": "0.46.5",
    "pymatgen": "2026.9.24",
    "pymatgen-core": "2026.9.23"
  },
  "database_version": "record from current MP release metadata",
  "license": "CC BY 4.0",
  "citation": "https://materialsproject.org/about/cite"
}

Do not include the API key.

Raw lines 438 to 459
460## Sources (verified 2026-09-30)
462- [mp-api 0.46.5 on PyPI](https://pypi.org/project/mp-api/)
463- [Official mp-api repository](https://github.com/materialsproject/api)
464- [Current REST schema](https://api.materialsproject.org/openapi.json)
465- [mp-api 0.46.5 source](https://github.com/materialsproject/api/tree/v0.46.5/mp_api/client)
466- [Materials Project identifier conventions](https://docs.materialsproject.org/data-production/identifiers)
467- [Getting started](https://docs.materialsproject.org/downloading-data/using-the-api/getting-started)
468- [Querying data](https://docs.materialsproject.org/downloading-data/using-the-api/querying-data)
469- [mp-api route reference](https://materialsproject.github.io/api/)
470- [Materials Project FAQ](https://docs.materialsproject.org/frequently-asked-questions)
471- [Materials Project calculation details](https://docs.materialsproject.org/methodology/materials-methodology/calculation-details)
472- [How to Cite](https://materialsproject.org/about/cite)
473- [Database versions](https://docs.materialsproject.org/changes/database-versions)
474- [Materials Project home and CC BY statement](https://materialsproject.org/)