{
  "info": {
    "_postman_id": "5d0c1f3e-6c8a-4a64-9f1e-5a0b8b2f7a11",
    "name": "SafetyDataSheetAPI",
    "description": "Official Postman collection for SafetyDataSheetAPI, published by SafetyDataSheetAPI (Dscvry).\n\nExtract Safety Data Sheet PDFs into normalized JSON, XML, and CSV.\n\nSetup: set the collection variable `apiKey` to your API key (request one at https://safetydatasheetapi.com/#self-serve-signup). `baseUrl` defaults to production.\n\nDocs: https://safetydatasheetapi.com/api-docs/ | OpenAPI: https://safetydatasheetapi.com/openapi.yaml | Changelog: https://safetydatasheetapi.com/changelog/\n\nSource of truth: published at https://safetydatasheetapi.com/postman/safetydatasheetapi.postman_collection.json (method: published).",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{apiKey}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://safetydatasheetapi.com",
      "type": "string"
    },
    {
      "key": "apiKey",
      "value": "",
      "type": "secret"
    },
    {
      "key": "jobId",
      "value": "",
      "type": "string"
    }
  ],
  "item": [
    {
      "name": "Extract one SDS",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "formdata",
          "formdata": [
            {
              "key": "file",
              "type": "file",
              "src": [],
              "description": "The SDS/MSDS PDF to extract."
            },
            {
              "key": "language_hint",
              "value": "en",
              "type": "text",
              "description": "Optional language hint, for example en, de, fr.",
              "disabled": true
            },
            {
              "key": "schema_version",
              "value": "1.0",
              "type": "text",
              "description": "Optional output schema version.",
              "disabled": true
            }
          ]
        },
        "url": {
          "raw": "{{baseUrl}}/extract-sds",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "extract-sds"
          ]
        },
        "description": "Upload one SDS/MSDS PDF and receive the normalized record as JSON, XML, and CSV inside one JSON response. Choose a PDF in the \"file\" field of the Body tab. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('status is 200', () => pm.response.to.have.status(200));",
              "const body = pm.response.json();",
              "pm.test('ok is true', () => pm.expect(body.ok).to.eql(true));",
              "pm.test('has the 16-section record', () => pm.expect(body.outputs.json).to.have.property('product_identification'));",
              "pm.test('has a request_id', () => pm.expect(body.request_id).to.be.a('string'));"
            ]
          }
        }
      ],
      "response": [
        {
          "name": "200 Extraction succeeded",
          "originalRequest": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "The SDS/MSDS PDF to extract."
                },
                {
                  "key": "language_hint",
                  "value": "en",
                  "type": "text",
                  "description": "Optional language hint, for example en, de, fr.",
                  "disabled": true
                },
                {
                  "key": "schema_version",
                  "value": "1.0",
                  "type": "text",
                  "description": "Optional output schema version.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds"
              ]
            },
            "description": "Upload one SDS/MSDS PDF and receive the normalized record as JSON, XML, and CSV inside one JSON response. Choose a PDF in the \"file\" field of the Body tab. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "OK",
          "code": 200,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            },
            {
              "key": "X-RateLimit-Remaining",
              "value": "99"
            }
          ],
          "body": "{\n  \"ok\": true,\n  \"request_id\": \"2f6c1a54-7b0e-4d0a-9d52-6a1f0f3c9b11\",\n  \"output_formats\": [\n    \"JSON\",\n    \"XML\",\n    \"CSV\"\n  ],\n  \"confidence_score\": 0.94,\n  \"document_language\": \"en\",\n  \"warnings\": [],\n  \"outputs\": {\n    \"json\": {\n      \"product_identification\": {\n        \"product_name\": \"Acetone\",\n        \"supplier_name\": \"Example Chemicals\"\n      },\n      \"transport_information\": {\n        \"un_number\": \"UN1090\",\n        \"proper_shipping_name\": \"Acetone\",\n        \"hazard_class\": \"3\",\n        \"packing_group\": \"II\"\n      }\n    },\n    \"xml\": \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\\n<sds_extraction><product_identification><product_name>Acetone</product_name></product_identification></sds_extraction>\",\n    \"csv\": \"field,value\\nproduct_identification.product_name,Acetone\\ntransport_information.un_number,UN1090\"\n  },\n  \"metadata\": {\n    \"file_name\": \"acetone-sds.pdf\",\n    \"file_size_bytes\": 184220,\n    \"language_hint\": \"en\",\n    \"schema_version\": null\n  },\n  \"processing_ms\": 8412\n}"
        },
        {
          "name": "401 Invalid or missing API key",
          "originalRequest": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "The SDS/MSDS PDF to extract."
                },
                {
                  "key": "language_hint",
                  "value": "en",
                  "type": "text",
                  "description": "Optional language hint, for example en, de, fr.",
                  "disabled": true
                },
                {
                  "key": "schema_version",
                  "value": "1.0",
                  "type": "text",
                  "description": "Optional output schema version.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds"
              ]
            },
            "description": "Upload one SDS/MSDS PDF and receive the normalized record as JSON, XML, and CSV inside one JSON response. Choose a PDF in the \"file\" field of the Body tab. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Unauthorized",
          "code": 401,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"unauthorized\",\n    \"message\": \"Invalid or missing API key.\"\n  }\n}"
        },
        {
          "name": "429 Rate limited",
          "originalRequest": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "The SDS/MSDS PDF to extract."
                },
                {
                  "key": "language_hint",
                  "value": "en",
                  "type": "text",
                  "description": "Optional language hint, for example en, de, fr.",
                  "disabled": true
                },
                {
                  "key": "schema_version",
                  "value": "1.0",
                  "type": "text",
                  "description": "Optional output schema version.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds"
              ]
            },
            "description": "Upload one SDS/MSDS PDF and receive the normalized record as JSON, XML, and CSV inside one JSON response. Choose a PDF in the \"file\" field of the Body tab. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Too Many Requests",
          "code": 429,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            },
            {
              "key": "Retry-After",
              "value": "3600"
            }
          ],
          "body": "{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"rate_limited\",\n    \"message\": \"Upload limit reached for this time window.\"\n  },\n  \"retry_after_epoch_seconds\": 1792800000\n}"
        },
        {
          "name": "502 Provider error",
          "originalRequest": {
            "method": "POST",
            "header": [],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "The SDS/MSDS PDF to extract."
                },
                {
                  "key": "language_hint",
                  "value": "en",
                  "type": "text",
                  "description": "Optional language hint, for example en, de, fr.",
                  "disabled": true
                },
                {
                  "key": "schema_version",
                  "value": "1.0",
                  "type": "text",
                  "description": "Optional output schema version.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds"
              ]
            },
            "description": "Upload one SDS/MSDS PDF and receive the normalized record as JSON, XML, and CSV inside one JSON response. Choose a PDF in the \"file\" field of the Body tab. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Bad Gateway",
          "code": 502,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"provider_error\",\n    \"message\": \"The extraction provider failed to process this document. Please retry.\"\n  },\n  \"request_id\": \"7ce6ebcf-dc15-410a-9e27-5ce5f3d074c9\"\n}"
        }
      ]
    },
    {
      "name": "Submit bulk job",
      "request": {
        "method": "POST",
        "header": [
          {
            "key": "Idempotency-Key",
            "value": "{{$guid}}",
            "description": "Repeat the same key to get the existing job back instead of creating a duplicate."
          }
        ],
        "body": {
          "mode": "formdata",
          "formdata": [
            {
              "key": "file",
              "type": "file",
              "src": [],
              "description": "Repeat this field for up to 10 PDFs."
            },
            {
              "key": "callback_url",
              "value": "https://example.com/hooks/sds",
              "type": "text",
              "description": "Optional https URL that receives a signed webhook (X-Webhook-Signature) when the job finishes.",
              "disabled": true
            }
          ]
        },
        "url": {
          "raw": "{{baseUrl}}/extract-sds/bulk",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "extract-sds",
            "bulk"
          ]
        },
        "description": "Submit up to 10 PDFs as an asynchronous job. Returns 202 with a job_id, which the test script saves to {{jobId}}. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('status is 202 (new job) or 200 (idempotent replay)', () => pm.expect(pm.response.code).to.be.oneOf([200, 202]));",
              "const body = pm.response.json();",
              "pm.test('has a job_id', () => pm.expect(body.job_id).to.be.a('string'));",
              "if (body.job_id) { pm.collectionVariables.set('jobId', body.job_id); }"
            ]
          }
        }
      ],
      "response": [
        {
          "name": "202 Job queued",
          "originalRequest": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Repeat the same key to get the existing job back instead of creating a duplicate."
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "Repeat this field for up to 10 PDFs."
                },
                {
                  "key": "callback_url",
                  "value": "https://example.com/hooks/sds",
                  "type": "text",
                  "description": "Optional https URL that receives a signed webhook (X-Webhook-Signature) when the job finishes.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds",
                "bulk"
              ]
            },
            "description": "Submit up to 10 PDFs as an asynchronous job. Returns 202 with a job_id, which the test script saves to {{jobId}}. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Accepted",
          "code": 202,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": true,\n  \"job_id\": \"9b1e3c0a-5d4f-4a7e-8f21-0c6d2e7a4b88\",\n  \"status\": \"queued\",\n  \"total_items\": 3,\n  \"status_url\": \"https://safetydatasheetapi.com/extract-sds/bulk/9b1e3c0a-5d4f-4a7e-8f21-0c6d2e7a4b88\"\n}"
        },
        {
          "name": "413 File too large",
          "originalRequest": {
            "method": "POST",
            "header": [
              {
                "key": "Idempotency-Key",
                "value": "{{$guid}}",
                "description": "Repeat the same key to get the existing job back instead of creating a duplicate."
              }
            ],
            "body": {
              "mode": "formdata",
              "formdata": [
                {
                  "key": "file",
                  "type": "file",
                  "src": [],
                  "description": "Repeat this field for up to 10 PDFs."
                },
                {
                  "key": "callback_url",
                  "value": "https://example.com/hooks/sds",
                  "type": "text",
                  "description": "Optional https URL that receives a signed webhook (X-Webhook-Signature) when the job finishes.",
                  "disabled": true
                }
              ]
            },
            "url": {
              "raw": "{{baseUrl}}/extract-sds/bulk",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds",
                "bulk"
              ]
            },
            "description": "Submit up to 10 PDFs as an asynchronous job. Returns 202 with a job_id, which the test script saves to {{jobId}}. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Payload Too Large",
          "code": 413,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"file_too_large\",\n    \"message\": \"File 'big.pdf' exceeds the 10 MB per-file limit.\"\n  }\n}"
        }
      ]
    },
    {
      "name": "Get bulk job status",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "{{baseUrl}}/extract-sds/bulk/{{jobId}}",
          "host": [
            "{{baseUrl}}"
          ],
          "path": [
            "extract-sds",
            "bulk",
            "{{jobId}}"
          ]
        },
        "description": "Poll job status and per-file results. Run \"Submit bulk job\" first so {{jobId}} is set. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
      },
      "event": [
        {
          "listen": "test",
          "script": {
            "type": "text/javascript",
            "exec": [
              "pm.test('status is 200', () => pm.response.to.have.status(200));",
              "const body = pm.response.json();",
              "pm.test('status is a known state', () => pm.expect(body.status).to.be.oneOf(['queued', 'processing', 'completed', 'failed']));"
            ]
          }
        }
      ],
      "response": [
        {
          "name": "200 Completed",
          "originalRequest": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/extract-sds/bulk/{{jobId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds",
                "bulk",
                "{{jobId}}"
              ]
            },
            "description": "Poll job status and per-file results. Run \"Submit bulk job\" first so {{jobId}} is set. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "OK",
          "code": 200,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": true,\n  \"job_id\": \"9b1e3c0a-5d4f-4a7e-8f21-0c6d2e7a4b88\",\n  \"status\": \"completed\",\n  \"total_items\": 1,\n  \"completed_items\": 1,\n  \"failed_items\": 0,\n  \"webhook_status\": \"delivered\",\n  \"webhook_attempts\": 1,\n  \"items\": [\n    {\n      \"file_name\": \"acetone-sds.pdf\",\n      \"status\": \"success\",\n      \"confidence_score\": 0.94,\n      \"warnings\": [],\n      \"data\": {\n        \"product_identification\": {\n          \"product_name\": \"Acetone\",\n          \"supplier_name\": \"Example Chemicals\"\n        },\n        \"transport_information\": {\n          \"un_number\": \"UN1090\",\n          \"proper_shipping_name\": \"Acetone\",\n          \"hazard_class\": \"3\",\n          \"packing_group\": \"II\"\n        }\n      }\n    }\n  ]\n}"
        },
        {
          "name": "404 Unknown job",
          "originalRequest": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/extract-sds/bulk/{{jobId}}",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "extract-sds",
                "bulk",
                "{{jobId}}"
              ]
            },
            "description": "Poll job status and per-file results. Run \"Submit bulk job\" first so {{jobId}} is set. Auth is inherited from the collection (Bearer {{apiKey}}). The X-API-Key header also works."
          },
          "status": "Not Found",
          "code": 404,
          "_postman_previewlanguage": "json",
          "header": [
            {
              "key": "Content-Type",
              "value": "application/json; charset=utf-8"
            }
          ],
          "body": "{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"job_not_found\",\n    \"message\": \"No bulk job found for this id.\"\n  }\n}"
        }
      ]
    }
  ]
}
