<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://wiki.pengtools.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=MishaT</id>
		<title>wiki.pengtools.com - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://wiki.pengtools.com/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=MishaT"/>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Special:Contributions/MishaT"/>
		<updated>2026-08-25T23:56:09Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.29.0-alpha</generator>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7949</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7949"/>
				<updated>2026-07-22T14:31:59Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Python Quick Start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|center|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
The notebook demonstrates how to call the pengtools PVT calculator over the HTTP API:&lt;br /&gt;
&lt;br /&gt;
* Configuration — PENGTOOLS_API_BASE and PENGTOOLS_API_KEY&lt;br /&gt;
* Helpers — requests session with Bearer token and parsing of {success, data} envelope&lt;br /&gt;
* Synchronous calculation — POST /pvt-calculator/calc&lt;br /&gt;
* Plots — render every curve from the plots block&lt;br /&gt;
* Error handling — 401 / 422&lt;br /&gt;
&lt;br /&gt;
Create a key in the accounts portal: [https://accounts.pengtools.com accounts.pengtools.com] → profile → API keys.&lt;br /&gt;
Contact us at support@pengtools.com to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
The notebook is self-contained. Download it here: [[Media:pvt_api.ipynb|pvt_api.ipynb]]&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=File:Pvt_api.ipynb&amp;diff=7948</id>
		<title>File:Pvt api.ipynb</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=File:Pvt_api.ipynb&amp;diff=7948"/>
				<updated>2026-07-22T14:30:29Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: PVT Calculator — API usage example
This notebook shows how to call the pengtools PVT calculator over the HTTP API.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;PVT Calculator — API usage example&lt;br /&gt;
This notebook shows how to call the pengtools PVT calculator over the HTTP API.&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7947</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7947"/>
				<updated>2026-07-22T13:35:09Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Python Quick Start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|center|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
The notebook demonstrates how to call the pengtools PVT calculator over the HTTP API:&lt;br /&gt;
&lt;br /&gt;
* Configuration — PENGTOOLS_API_BASE and PENGTOOLS_API_KEY&lt;br /&gt;
* Helpers — requests session with Bearer token and parsing of {success, data} envelope&lt;br /&gt;
* Synchronous calculation — POST /pvt-calculator/calc&lt;br /&gt;
* Plots — render every curve from the plots block&lt;br /&gt;
* Error handling — 401 / 422&lt;br /&gt;
&lt;br /&gt;
Create a key in the accounts portal: [https://accounts.pengtools.com accounts.pengtools.com] → profile → API keys.&lt;br /&gt;
Contact us at support@pengtools.com to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
The notebook is self-contained.&lt;br /&gt;
&lt;br /&gt;
[[File:pvt_api.ipynb]]&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7946</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7946"/>
				<updated>2026-07-22T13:34:54Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Python Quick Start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|center|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
The notebook demonstrates how to call the pengtools PVT calculator over the HTTP API:&lt;br /&gt;
&lt;br /&gt;
* Configuration — PENGTOOLS_API_BASE and PENGTOOLS_API_KEY&lt;br /&gt;
* Helpers — requests session with Bearer token and parsing of {success, data} envelope&lt;br /&gt;
* Synchronous calculation — POST /pvt-calculator/calc&lt;br /&gt;
* Plots — render every curve from the plots block&lt;br /&gt;
* Error handling — 401 / 422&lt;br /&gt;
&lt;br /&gt;
Create a key in the accounts portal: [https://accounts.pengtools.com accounts.pengtools.com] → profile → API keys.&lt;br /&gt;
Contact us at support@pengtools.com to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
The notebook is self-contained and covers PVT only.&lt;br /&gt;
&lt;br /&gt;
[[File:pvt_api.ipynb]]&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7945</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7945"/>
				<updated>2026-07-22T13:33:53Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Python Quick Start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|center|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
The notebook demonstrates how to call the pengtools PVT calculator over the HTTP API:&lt;br /&gt;
&lt;br /&gt;
* Configuration — PENGTOOLS_API_BASE and PENGTOOLS_API_KEY&lt;br /&gt;
* Helpers — requests session with Bearer token and parsing of {success, data} envelope&lt;br /&gt;
* Synchronous calculation — POST /pvt-calculator/calc&lt;br /&gt;
* Plots — render every curve from the plots block&lt;br /&gt;
* Error handling — 401 / 422&lt;br /&gt;
&lt;br /&gt;
Create a key in the accounts portal: [https://accounts.pengtools.com accounts.pengtools.com] → profile → API keys.&lt;br /&gt;
&lt;br /&gt;
The notebook is self-contained and covers PVT only.&lt;br /&gt;
&lt;br /&gt;
[[File:pvt_api.ipynb]]&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7944</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7944"/>
				<updated>2026-07-22T13:01:22Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Support */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. [[File:pengtools_REST_API.png|center|right|600px| pengtools REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
# Contact us at [mailto:support@pengtools.com support@pengtools.com] to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [mailto:support@pengtools.com support@pengtools.com].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7943</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7943"/>
				<updated>2026-07-22T13:00:15Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Getting a key */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. [[File:pengtools_REST_API.png|center|right|600px| pengtools REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
# Contact us at [mailto:support@pengtools.com support@pengtools.com] to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7942</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7942"/>
				<updated>2026-07-22T13:00:04Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Getting a key */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. [[File:pengtools_REST_API.png|center|right|600px| pengtools REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
# Contact us at [mailto:support@pengtools.com support@pengtools.com] to activate your API trial license.&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7941</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7941"/>
				<updated>2026-07-22T04:27:10Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. [[File:pengtools_REST_API.png|center|right|600px| pengtools REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7940</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7940"/>
				<updated>2026-07-22T04:26:43Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|center|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7939</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7939"/>
				<updated>2026-07-22T04:25:59Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]]. [[File:pengtools_PVT_API.png|thumb|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7938</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7938"/>
				<updated>2026-07-22T04:25:48Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].[[File:pengtools_PVT_API.png|thumb|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7937</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7937"/>
				<updated>2026-07-22T04:24:26Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
[[File:pengtools_PVT_API.png|thumb|600px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7936</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7936"/>
				<updated>2026-07-22T04:24:15Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
[[File:pengtools_PVT_API.png|thumb|right|300px| PVT REST API]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=File:Pengtools_PVT_API.png&amp;diff=7935</id>
		<title>File:Pengtools PVT API.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=File:Pengtools_PVT_API.png&amp;diff=7935"/>
				<updated>2026-07-22T04:23:02Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using industry-standard correlations. The API returns pressure-dependent property curves, reservoir-condition values, and complete calculation tables.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using industry-standard correlations. The API returns pressure-dependent property curves, reservoir-condition values, and complete calculation tables.&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7934</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7934"/>
				<updated>2026-07-22T04:21:38Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
[[File:pengtools_PVT_API.png|thumb|right|300px| PVT REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7933</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7933"/>
				<updated>2026-07-20T11:30:20Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:pengtools_REST_API.png|thumb|right|300px| pengtools REST API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=File:Pengtools_REST_API.png&amp;diff=7932</id>
		<title>File:Pengtools REST API.png</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=File:Pengtools_REST_API.png&amp;diff=7932"/>
				<updated>2026-07-20T11:29:07Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: REST APIs for Petroleum Engineering
Programmatic access to the pengtools engineering modules for calculations, automation and optimization.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;REST APIs for Petroleum Engineering&lt;br /&gt;
Programmatic access to the pengtools engineering modules for calculations, automation and optimization.&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7931</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7931"/>
				<updated>2026-07-16T10:54:49Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* REST APIs for Petroleum Engineering */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:pengtools_REST_API.png|thumb|right|300px| pengtools RESt API|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7930</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7930"/>
				<updated>2026-07-15T12:49:16Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Support */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues contact us at [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7929</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7929"/>
				<updated>2026-07-15T12:48:07Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Quickstart */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7928</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7928"/>
				<updated>2026-07-15T12:45:49Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Getting Started */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Quickstart==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7927</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7927"/>
				<updated>2026-07-15T12:44:59Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Response envelope */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429.&lt;br /&gt;
&lt;br /&gt;
==Getting Started==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7926</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7926"/>
				<updated>2026-07-15T12:43:59Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Getting a key */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429. See the error reference for details.&lt;br /&gt;
&lt;br /&gt;
==Getting Started==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7925</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7925"/>
				<updated>2026-07-15T12:43:45Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Getting a key */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at [https://accounts.pengtools.com accounts.pengtools.com].&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429. See the error reference for details.&lt;br /&gt;
&lt;br /&gt;
==Getting Started==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7924</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7924"/>
				<updated>2026-07-15T12:40:53Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Base URL==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;https://api.pengtools.com/&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Endpoints are addressed as &amp;lt;base&amp;gt;/&amp;lt;resource&amp;gt;/&amp;lt;action&amp;gt;, e.g. &amp;lt;pre&amp;gt;https://api.pengtools.com/pvt-calculator/calc&amp;lt;/pre&amp;gt;. All examples below use this base URL.&lt;br /&gt;
&lt;br /&gt;
==Authentication==&lt;br /&gt;
&lt;br /&gt;
Every request must include an API key as a Bearer token:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;Authorization: Bearer &amp;lt;api_key&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A key is a single opaque token. It is stored only as a salted hash on the server, so the plaintext is shown once, at creation time, and cannot be recovered afterwards.&lt;br /&gt;
&lt;br /&gt;
===Getting a key===&lt;br /&gt;
&lt;br /&gt;
Manage your keys in the accounts portal:&lt;br /&gt;
&lt;br /&gt;
# Sign in at accounts.pengtools.com.&lt;br /&gt;
# Open the API keys section of your profile.&lt;br /&gt;
# Click Create to issue a new key, optionally giving it a name.&lt;br /&gt;
&lt;br /&gt;
The new token is displayed once, right after creation. Copy it immediately and store it as a secret (environment variable, secrets manager). If you lose it, revoke the key on the same page and create a new one. The page also lists your existing keys (without the plaintext) and lets you revoke any of them.&lt;br /&gt;
&lt;br /&gt;
A request with no key, or an invalid/revoked key, returns HTTP 401.&lt;br /&gt;
&lt;br /&gt;
==Response envelope==&lt;br /&gt;
&lt;br /&gt;
Every JSON response is wrapped in a uniform envelope:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{ &amp;quot;success&amp;quot;: true,  &amp;quot;data&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } }&lt;br /&gt;
{ &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;...&amp;quot;: &amp;quot;...&amp;quot; } } }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
success mirrors the HTTP status (2xx → true). Validation problems return 422, rate-limit rejections return 429. See the error reference for details.&lt;br /&gt;
&lt;br /&gt;
==Getting Started==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7923</id>
		<title>Category:API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=Category:API&amp;diff=7923"/>
				<updated>2026-07-15T11:07:07Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Petroleum Engineering API */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==REST APIs for Petroleum Engineering==&lt;br /&gt;
&lt;br /&gt;
The pengtools [[:Category:pengtools | API]]  gives programmatic access to the engineering calculators that power [https://www.pengtools.com www.pengtools.com]. &lt;br /&gt;
&lt;br /&gt;
[[File:EPPortal.png|thumb|right|300px|link=https://ep.pengtools.com/| E&amp;amp;P Portal|right]]&lt;br /&gt;
&lt;br /&gt;
==Available APIs==&lt;br /&gt;
&lt;br /&gt;
* [[:PVT_API|PVT API]] - Fluid properties calculator&lt;br /&gt;
&lt;br /&gt;
==Getting Started==&lt;br /&gt;
&lt;br /&gt;
1. [[Authentication]] - API key setup&lt;br /&gt;
2. [[API Reference]] - Endpoint documentation&lt;br /&gt;
3. [[Rate Limits]] - Usage policies&lt;br /&gt;
&lt;br /&gt;
==Support==&lt;br /&gt;
&lt;br /&gt;
For questions or issues, contact [[Support]] or visit our [https://www.pengtools.com/contact contact page].&lt;br /&gt;
&lt;br /&gt;
[[Category:APT]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=Petroleum Engineering API Documentation&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=petroleum engineering API, PVT API, nodal analysis API, bottomhole pressure calculation API developer docs, pengtools API, REST API&lt;br /&gt;
|description=Programmatic access to pengtools petroleum engineering software: PVT, PQplot, sPipe, optiFrac, fracDesign, pumpDesign.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7922</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7922"/>
				<updated>2026-07-15T08:07:59Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Phyton Quick Start */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Python Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7921</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7921"/>
				<updated>2026-07-15T08:07:24Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Phyton Quick Start==&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7920</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7920"/>
				<updated>2026-07-15T08:04:33Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Synchronous request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* &amp;lt;code&amp;gt;plots&amp;lt;/code&amp;gt; — property curves&lt;br /&gt;
* &amp;lt;code&amp;gt;solution&amp;lt;/code&amp;gt; — single-point reservoir-condition values&lt;br /&gt;
* &amp;lt;code&amp;gt;results&amp;lt;/code&amp;gt; — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7919</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7919"/>
				<updated>2026-07-15T08:04:04Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Synchronous request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys (see Units):&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7918</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7918"/>
				<updated>2026-07-15T08:03:14Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Endpoints */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an &amp;lt;code&amp;gt;api_task&amp;lt;/code&amp;gt;  row that is picked up by the &amp;lt;code&amp;gt;CalcDaemon&amp;lt;/code&amp;gt;  worker; you then poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt;  and fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; . The async job runs the same &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;  code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7917</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7917"/>
				<updated>2026-07-15T08:02:23Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Endpoints */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc&amp;lt;/code&amp;gt; (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use &amp;lt;code&amp;gt;/calc-async&amp;lt;/code&amp;gt; only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7916</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7916"/>
				<updated>2026-07-15T08:01:22Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Example */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7915</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7915"/>
				<updated>2026-07-15T08:01:04Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Units */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7914</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7914"/>
				<updated>2026-07-15T08:00:48Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Units */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7913</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7913"/>
				<updated>2026-07-15T08:00:34Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Units */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;unit_system&amp;lt;/code&amp;gt; &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7912</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7912"/>
				<updated>2026-07-15T08:00:03Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Synchronous request */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
{&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7911</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7911"/>
				<updated>2026-07-15T07:59:30Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* HTTP status codes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7910</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7910"/>
				<updated>2026-07-15T07:58:49Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* HTTP status codes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===429 - rate limiting===&lt;br /&gt;
Limits are per API key over a 60‑second window, and the cap depends on the license tier that grants access to the &amp;lt;code&amp;gt;pvtCalculator&amp;lt;/code&amp;gt; module.&lt;br /&gt;
&lt;br /&gt;
==Asynchronous flow==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
POST /pvt-calculator/calc-async        →  { &amp;quot;token&amp;quot;: &amp;quot;&amp;lt;token&amp;gt;&amp;quot; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/status    →  { &amp;quot;status&amp;quot;: &amp;lt;code&amp;gt;, &amp;quot;progress&amp;quot;: &amp;lt;number&amp;gt; }&lt;br /&gt;
GET  /pvt-calculator/&amp;lt;token&amp;gt;/output-data →  { plots, solution, results }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; is returned as a numeric code (the raw api_task.status value), not a string:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Code !! Meaning&lt;br /&gt;
|-&lt;br /&gt;
| 1 || CREATED&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IN_PROGRESS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ERROR&lt;br /&gt;
|-&lt;br /&gt;
| 4 || STOPPED&lt;br /&gt;
|-&lt;br /&gt;
| 5 || SUCCESS&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
A job cycles 1 → 2 → 5 (or 3 / 4). Poll &amp;lt;code&amp;gt;status&amp;lt;/code&amp;gt; until it reaches a terminal code (3, 4, 5), then fetch &amp;lt;code&amp;gt;output-data&amp;lt;/code&amp;gt; when it is 5. The &amp;lt;code&amp;gt;CalcDaemon &amp;lt;/code&amp;gt;worker must be running for jobs to progress.&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7909</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7909"/>
				<updated>2026-07-15T07:54:42Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* HTTP status codes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===422 - validation and calculation errors===&lt;br /&gt;
Field validation errors are keyed by attribute:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: { &amp;quot;temperature&amp;quot;: [&amp;quot;Temperature must be no less than 529.47.&amp;quot;] } } }&lt;br /&gt;
Errors raised while loading the body or running the calculation (e.g. an unknown &amp;lt;code&amp;gt;defaultFluidType&amp;lt;/code&amp;gt;, or a physical guard inside &amp;lt;code&amp;gt;calculatePvt()&amp;lt;/code&amp;gt;) come back as a flat list:&lt;br /&gt;
 { &amp;quot;success&amp;quot;: false, &amp;quot;data&amp;quot;: { &amp;quot;errors&amp;quot;: [&amp;quot;Invalid input: Wrong default fluid type&amp;quot;] } } &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7908</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7908"/>
				<updated>2026-07-15T07:52:37Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==HTTP status codes==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Status !! Meaning !! Body (data)&lt;br /&gt;
|-&lt;br /&gt;
| 200 || Success || { plots, solution, results }&lt;br /&gt;
|-&lt;br /&gt;
| 401 || Missing or invalid API key || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 404 || Unknown async token || Yii error payload&lt;br /&gt;
|-&lt;br /&gt;
| 422 || Validation / calculation error || { &amp;quot;errors&amp;quot;: … }&lt;br /&gt;
|-&lt;br /&gt;
| 429 || Rate limit exceeded || error message&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7907</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7907"/>
				<updated>2026-07-15T07:49:41Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Response format */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Results - stepped table===&lt;br /&gt;
Each fluid maps to a list of rows. The first row is standard conditions; the next nine rows are stepped pressures between the bubble point (oil) or p/2 (gas/water) and the maximum pressure. Each row is a positional array with these columns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Columns (in order)&lt;br /&gt;
|-&lt;br /&gt;
| OIL || pressure, Rs, density, fvf, viscosity, temperature, compressibility, tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || pressure, ZFactor, densitygas, fvfgas, viscositygas, temperature, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || pressure, compressibilitywater, densitywater, fvfwater, viscositywater, temperature, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;results&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: [&lt;br /&gt;
    [1.0, 0.0, 845.0, 1.01, 2.1, 20.0, 0.00012, 30.5],&lt;br /&gt;
    [12.8, 22.0, 812.4, 1.08, 1.6, 90.0, 0.00018, 12.1],&lt;br /&gt;
    &amp;quot;… 8 more rows …&amp;quot;&lt;br /&gt;
  ]&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7906</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7906"/>
				<updated>2026-07-15T07:47:51Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Response format */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots - property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Solution - reservoir‑condition values===&lt;br /&gt;
Single scalar values evaluated at reservoir conditions.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Keys&lt;br /&gt;
|-&lt;br /&gt;
| OIL || solution_pBubble, solution_rsb, solution_Rs, solution_compressibility, solution_density, solution_fvf, solution_deadOilViscosity, solution_viscosity, solution_tension&lt;br /&gt;
|-&lt;br /&gt;
| GAS || solution_ZFactor, solution_compressibilitygas, solution_densitygas, solution_fvfgas, solution_viscositygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || solution_compressibilitywater, solution_densitywater, solution_fvfwater, solution_viscositywater, solution_tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;solution&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;solution_pBubble&amp;quot;: 115.0,&lt;br /&gt;
    &amp;quot;solution_rsb&amp;quot;: 60.0,&lt;br /&gt;
    &amp;quot;solution_density&amp;quot;: 756.0,&lt;br /&gt;
    &amp;quot;solution_fvf&amp;quot;: 1.197&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7905</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7905"/>
				<updated>2026-07-15T07:46:13Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===Plots property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7904</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7904"/>
				<updated>2026-07-15T07:45:00Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;code&amp;gt;Plots&amp;lt;/code&amp;gt; property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7903</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7903"/>
				<updated>2026-07-15T07:44:38Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;code&amp;gt;Plots&amp;lt;/code&amp;gt; property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;:      [[14.6, 0.0], [36.4, 5.1], &amp;quot;…&amp;quot;, [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;:     [[14.6, 1.02], &amp;quot;…&amp;quot;],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4], &amp;quot;…&amp;quot;]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7902</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7902"/>
				<updated>2026-07-15T07:43:52Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;code&amp;gt;Plots&amp;lt;/code&amp;gt; property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;: [[14.6, 0.0], [36.4, 5.1], [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;: [[14.6, 1.02]],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4]]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7901</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7901"/>
				<updated>2026-07-15T07:42:50Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;code&amp;gt;Plots&amp;lt;/code&amp;gt; property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;json&amp;quot;&amp;gt;&lt;br /&gt;
&amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;: [[14.6, 0.0], [36.4, 5.1], [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;: [[14.6, 1.02]],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4]]&lt;br /&gt;
  }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	<entry>
		<id>https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7900</id>
		<title>PVT API</title>
		<link rel="alternate" type="text/html" href="https://wiki.pengtools.com/index.php?title=PVT_API&amp;diff=7900"/>
				<updated>2026-07-15T07:42:05Z</updated>
		
		<summary type="html">&lt;p&gt;MishaT: /* Plots property curves */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__TOC__&lt;br /&gt;
&lt;br /&gt;
==PVT API==&lt;br /&gt;
The PVT calculator models reservoir fluid properties (oil, gas, water) over a pressure range using various correlations, and returns property curves (plots), single‑point reservoir‑condition values (solution), and a stepped property table (results) available in [[:Category:PVT|PVT calculator]] of the [[:Category: Pengtools | pengtools]].&lt;br /&gt;
&lt;br /&gt;
==Endpoints==&lt;br /&gt;
All endpoints require the Authorization: Bearer &amp;lt;api_key&amp;gt; header and are subject to rate limiting. The response envelope is always { &amp;quot;success&amp;quot;: &amp;lt;bool&amp;gt;, &amp;quot;data&amp;quot;: &amp;lt;payload&amp;gt; }&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method !! Path !! Purpose&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc || Synchronous — compute and return the result in the same request&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/calc-async || Asynchronous — enqueue a job, return a {token}&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/status || Job status and progress&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/output-data || Job result (same shape as the sync data)&lt;br /&gt;
|-&lt;br /&gt;
| GET || /pvt-calculator/{token}/input-data || The input the job was created with&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/start || Reset and re-run the job&lt;br /&gt;
|-&lt;br /&gt;
| POST || /pvt-calculator/{token}/stop || Stop a running job&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /pvt-calculator/{token} || Delete the job&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Use /calc (synchronous) for normal interactive requests — a single PVT model computes in well under a second and the result comes back in the HTTP response.&lt;br /&gt;
&lt;br /&gt;
Use /calc-async only for batch/heavy workloads where you would rather not hold an open HTTP connection. The async path enqueues an api_task row that is picked up by the CalcDaemon worker; you then poll status and fetch output-data. The async job runs the same calculatePvt() code as the sync endpoint, so the result is identical for identical input.&lt;br /&gt;
&lt;br /&gt;
==Synchronous request==&lt;br /&gt;
&lt;br /&gt;
 POST /pvt-calculator/calc&lt;br /&gt;
&lt;br /&gt;
The request body is a JSON object containing PVT calculator attributes plus two optional unit-control keys:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;RU&amp;quot;,&lt;br /&gt;
  &amp;quot;defaultFluidType&amp;quot;: &amp;quot;OIL&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;reservoirPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90,&lt;br /&gt;
  &amp;quot;pBubbleInitial&amp;quot;: 200,&lt;br /&gt;
  &amp;quot;rsbInitial&amp;quot;: 60,&lt;br /&gt;
  &amp;quot;isRsbUsedForPb&amp;quot;: true,&lt;br /&gt;
  &amp;quot;sgOil&amp;quot;: 0.85,&lt;br /&gt;
  &amp;quot;sgGas&amp;quot;: 0.75,&lt;br /&gt;
  &amp;quot;sgWater&amp;quot;: 1.0&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
On success the endpoint returns HTTP 200 with:&lt;br /&gt;
&lt;br /&gt;
 { &amp;quot;success&amp;quot;: true, &amp;quot;data&amp;quot;: { &amp;quot;plots&amp;quot;: {},&amp;quot;solution&amp;quot;: {}, &amp;quot;results&amp;quot;: {}  } }&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;code&amp;gt;data&amp;lt;/code&amp;gt; carries:&lt;br /&gt;
* plots — property curves&lt;br /&gt;
* solution — single-point reservoir-condition values&lt;br /&gt;
* results — stepped property table&lt;br /&gt;
&lt;br /&gt;
==Units==&lt;br /&gt;
&lt;br /&gt;
Input field names (e.g., maximumPressure, temperature) carry no unit. The unit system determines how values are interpreted.&lt;br /&gt;
&lt;br /&gt;
 unit_system &lt;br /&gt;
&lt;br /&gt;
a shortcut that applies a whole preset of units. Accepted values (case‑insensitive):&lt;br /&gt;
* METRIC - Metric system&lt;br /&gt;
* FIELD - Field system&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
 {&lt;br /&gt;
  &amp;quot;unit_system&amp;quot;: &amp;quot;METRIC&amp;quot;,&lt;br /&gt;
  &amp;quot;maximumPressure&amp;quot;: 300,&lt;br /&gt;
  &amp;quot;temperature&amp;quot;: 90&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
===Attribute units===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! METRIC !! FIELD&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || ATM || PSIA&lt;br /&gt;
|-&lt;br /&gt;
| temperature || CELSIUS || FAHRENHEIT&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || M3_PER_M3 || SCF_PER_BBL&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || SPECIFIC_GRAVITY || API&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || SPECIFIC_GRAVITY || SPECIFIC_GRAVITY&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Input parameter specification==&lt;br /&gt;
&lt;br /&gt;
Ranges below are expressed in internal units (the units the validator sees), with common METRIC/FIELD equivalents for convenience.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Field !! Required !! Internal unit !! Range (internal) !! METRIC !! FIELD !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| defaultFluidType || yes || — || OIL or GAS || — || — || Selects the primary fluid path. WATER is only valid inside forFluid.&lt;br /&gt;
|-&lt;br /&gt;
| maximumPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Upper bound of the pressure sweep.&lt;br /&gt;
|-&lt;br /&gt;
| minimumPressure || no (default 14.6) || PSIA || 14.6 … 10000 || ≈ 1.0 … 680 ATM || 14.6 … 10000 psi || Lower bound of the sweep; must be ≤ maximumPressure.&lt;br /&gt;
|-&lt;br /&gt;
| reservoirPressure || yes || PSIA || 25 … 10000 || ≈ 1.7 … 680 ATM || 25 … 10000 psi || Reservoir-condition pressure for solution.&lt;br /&gt;
|-&lt;br /&gt;
| temperature || yes || RANKIN || 529.47 … 851.67 || ≈ 21 … 200 °C || ≈ 70 … 392 °F || Reservoir-condition temperature for solution.&lt;br /&gt;
|-&lt;br /&gt;
| pBubbleInitial || yes || PSIA || 0 … 20000 || ≈ 0 … 1361 ATM || 0 … 20000 psi || Initial bubble point. See isRsbUsedForPb.&lt;br /&gt;
|-&lt;br /&gt;
| rsbInitial || yes (when OIL) || M3_PER_M3 || &amp;gt; 0 || m³·m⁻³ || scf/bbl || Solution GOR at bubble point.&lt;br /&gt;
|-&lt;br /&gt;
| sgOil || yes || SPECIFIC_GRAVITY || 0.75 … 0.99 || 0.75 … 0.99 SG || ≈ 11.4 … 57.2 °API || Oil specific gravity. US system accepts API.&lt;br /&gt;
|-&lt;br /&gt;
| sgGas || yes || SPECIFIC_GRAVITY || 0.55 … 1.8 || 0.55 … 1.8 SG || 0.55 … 1.8 SG || Gas specific gravity (air = 1).&lt;br /&gt;
|-&lt;br /&gt;
| sgWater || yes || SPECIFIC_GRAVITY || 0.9 … 1.2 || 0.9 … 1.2 SG || 0.9 … 1.2 SG || Water specific gravity.&lt;br /&gt;
|-&lt;br /&gt;
| isRsbUsedForPb || no (default false) || bool || true / false || — || — || true: derive bubble point from rsbInitial. false: derive GOR from pBubbleInitial.&lt;br /&gt;
|-&lt;br /&gt;
| forFluid || no (default all) || — || subset of OIL,GAS,WATER || — || — || Which fluids to compute.&lt;br /&gt;
|-&lt;br /&gt;
| needPlots || no (default true) || bool || true / false || — || — || Include the plots block.&lt;br /&gt;
|-&lt;br /&gt;
| needSolution || no (default true) || bool || true / false || — || — || Include the solution block.&lt;br /&gt;
|-&lt;br /&gt;
| needResults || no (default true) || bool || true / false || — || — || Include the results block.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Notes===&lt;br /&gt;
For an oil model, both &amp;lt;code&amp;gt;pBubbleInitial&amp;lt;/code&amp;gt; and &amp;lt;code&amp;gt;rsbInitial&amp;lt;/code&amp;gt;are required; &amp;lt;code&amp;gt;isRsbUsedForPb&amp;lt;/code&amp;gt; decides which one is the input and which is derived.&lt;br /&gt;
&lt;br /&gt;
==Response format==&lt;br /&gt;
On success, data contains up to three blocks, gated by &amp;lt;code&amp;gt;needPlots / needSolution / needResults&amp;lt;/code&amp;gt;. Each block is keyed by fluid (&amp;lt;code&amp;gt;OIL, GAS, WATER&amp;lt;/code&amp;gt;) — only the fluids in &amp;lt;code&amp;gt;forFluid&amp;lt;/code&amp;gt; (and, for oil curves, only when &amp;lt;code&amp;gt;defaultFluidType is OIL&amp;lt;/code&amp;gt;) are present.&lt;br /&gt;
&lt;br /&gt;
===&amp;lt;code&amp;gt;Plots&amp;lt;/code&amp;gt; property curves===&lt;br /&gt;
Each fluid maps curve names to an array of [pressure, value] pairs, one pair per pressure step (200 steps by default). The pressure axis is in the output pressure unit (see Units section).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Fluid !! Curves&lt;br /&gt;
|-&lt;br /&gt;
| OIL || Rs, density, fvf, viscosity, tension, compressibility&lt;br /&gt;
|-&lt;br /&gt;
| GAS || ZFactor, densitygas, fvfgas, viscositygas, compressibilitygas&lt;br /&gt;
|-&lt;br /&gt;
| WATER || densitywater, fvfwater, viscositywater, compressibilitywater, tensionwater&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
 &amp;quot;plots&amp;quot;: {&lt;br /&gt;
  &amp;quot;OIL&amp;quot;: {&lt;br /&gt;
    &amp;quot;Rs&amp;quot;: [[14.6, 0.0], [36.4, 5.1], [4351.13, 200.0]],&lt;br /&gt;
    &amp;quot;fvf&amp;quot;: [[14.6, 1.02]],&lt;br /&gt;
    &amp;quot;density&amp;quot;: [[14.6, 812.4]]&lt;br /&gt;
  }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
{{#seo:&lt;br /&gt;
|title=PVT API Documentation | Petroleum Engineering Software&lt;br /&gt;
|titlemode= replace&lt;br /&gt;
|keywords=PVT API, petroleum engineering API, fluid properties API, REST API, developer documentation, pengtools API&lt;br /&gt;
|description=REST API documentation for PVT fluid properties calculator. Endpoints, authentication, and data models for programmatic access to oil, gas, and water property calculations.&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>MishaT</name></author>	</entry>

	</feed>