Developer reference
The GainingDocx API
Parse freight documents into structured data, validate the reference numbers that carry check digits, and run the freight calculations your team already does by hand — from your own systems, on your own schedule.
REST and JSON
Predictable resources, one error envelope, standard status codes.
Bearer keys
Created and revoked in your workspace. Stored only as hashes.
OpenAPI 3.1
Generate a client or import the spec straight into Postman.
Quickstart
- 1Sign in and open Integrations in your workspace.
- 2Create an API key. It is shown once — store it in your secret manager immediately.
- 3Confirm it works by calling
GET /v1/me. - 4Parse your first document with
POST /v1/parse.
export GAININGDOCX_API_KEY="gdx_live_..."
curl https://gainingdocx.com/api/v1/me \
-H "Authorization: Bearer $GAININGDOCX_API_KEY"Authentication
Every request needs an Authorization: Bearer header carrying a key that starts with gdx_live_. Only a SHA-256 hash of the key is stored, so a database compromise does not hand over working credentials — and neither we nor you can recover a lost key. Create a new one and revoke the old.
Never put an API key in browser or mobile code. A key carries full access to your account and is trivially readable by anyone who opens developer tools. Call the API from your server and keep the key in a secret manager or environment variable.
Errors and rate limits
Every failure returns the same envelope, so you write one error handler rather than one per endpoint. Branch on code, which is stable; message is for humans and may be reworded.
{
"error": {
"type": "invalid_request_error",
"code": "invalid_request",
"message": "`cbm` must be a number.",
"param": "cbm",
"request_id": "req_8f2c1a94be7d40118c3e"
}
}| Status | type | What to do |
|---|---|---|
| 400 | invalid_request_error | Fix the input named in param. Retrying unchanged will fail again. |
| 401 | authentication_error | Check the key and the Bearer header. A revoked key cannot be restored. |
| 404 | not_found_error | The id does not exist in your account. Ids from other accounts also return 404. |
| 429 | rate_limit_error | Wait for Retry-After seconds, then retry. |
| 5xx | api_error | Retry with exponential backoff. Quote request_id if it persists. |
Rate limiting is 120 requests per 60 seconds per key, counted in the database rather than per worker — so the limit is the real limit no matter which edge location serves you. Every response carries X-RateLimit-Remaining and X-Request-Id.
Endpoints
Base URL https://gainingdocx.com/api/v1 · OpenAPI spec
Account
Confirm a key works and see how much quota is left before you build against it.
/v1/meRetrieve the authenticated account
The first call to make. Returns your plan, key metadata and remaining rate-limit quota. If this returns 200, your key and headers are correct.
curl https://gainingdocx.com/api/v1/me \
-H "Authorization: Bearer $GAININGDOCX_API_KEY"Response
{
"object": "account",
"plan": "pro",
"api_key": { "name": "Production", "prefix": "gdx_live_" },
"rate_limit": { "limit": 120, "remaining": 119 }
}Documents
Parse freight documents into structured fields, then retrieve, list and delete them. Parsing is synchronous and can take up to two minutes on a long document.
/v1/parseParse a document
Send page images as HTTPS URLs or base64 data URLs. Document type is detected automatically; the optional hint only biases detection. Returns extracted fields plus deterministic validation findings.
curl https://gainingdocx.com/api/v1/parse \
-H "Authorization: Bearer $GAININGDOCX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"pages": [{ "url": "https://example.com/bl-page-1.jpg" }],
"document_type": "bill_of_lading"
}'Response
{
"id": "b2c1…",
"object": "document",
"status": "parsed",
"document_type": "bill_of_lading",
"fields": { "bl_number": "MEDUX1234567", "containers": [ … ] },
"validation": [ { "field": "container_no", "severity": "error", … } ]
}/v1/documentsList documents
Paginated with `limit` and `offset`, filterable by `status`, `document_type` and `shipment_id`. Extracted fields are omitted here — retrieve a document to get them.
curl "https://gainingdocx.com/api/v1/documents?status=parsed&limit=10" \
-H "Authorization: Bearer $GAININGDOCX_API_KEY"/v1/documents/{id}Retrieve a document
Returns the full document including `fields` and `validation`.
/v1/documents/{id}Delete a document
Permanently deletes the document and its extracted data. This cannot be undone. An id belonging to another account returns 404, not 403.
Tools
Stateless calculations and reference checks. These run the same code as the free on-site calculators, so an API answer and a browser answer cannot drift apart.
/v1/tools/validate-referenceValidate container, AWB or port references
Batch-checks ISO 6346 container check digits, IATA modulus-7 AWB check digits, or resolves port names and UN/LOCODEs. On failure it returns the expected check digit, which is what separates a typo from a fabricated number.
curl https://gainingdocx.com/api/v1/tools/validate-reference \
-H "Authorization: Bearer $GAININGDOCX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "type": "container", "values": ["MSCU1234565", "TGHU7654321"] }'Response
{
"object": "reference_validation",
"valid_count": 1,
"results": [
{ "input": "MSCU1234565", "valid": true, "expected_check_digit": 5 },
{ "input": "TGHU7654321", "valid": false,
"expected_check_digit": 7, "suggested": "TGHU7654327" }
]
}/v1/tools/volumeCalculate CBM and chargeable weight
Totals volume across package groups and compares actual against volumetric weight, reporting which figure the carrier will rate on. Default divisor is 6000 cm³/kg (general air cargo); express is 5000.
curl https://gainingdocx.com/api/v1/tools/volume \
-H "Authorization: Bearer $GAININGDOCX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"unit": "cm",
"groups": [{ "length": 120, "width": 80, "height": 95, "quantity": 4, "gross_weight": 260 }]
}'Response
{
"totals": {
"volume_m3": 3.648,
"actual_weight": 260,
"volumetric_weight": 608,
"chargeable_weight": 608,
"rated_on": "volumetric"
}
}/v1/tools/freight-chargesCalculate LCL freight or demurrage and detention
Set `calculation` to `lcl_wm` for weight-or-measure ocean freight, or `free_time` for demurrage and detention against free days and rate tiers. Both return the working, not just a total, so you can show a carrier which figure controlled.
curl https://gainingdocx.com/api/v1/tools/freight-charges \
-H "Authorization: Bearer $GAININGDOCX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"calculation": "lcl_wm",
"cbm": 12.4, "gross_kg": 9800, "rate_per_revenue_ton": 48
}'Content
Embed GainingDocx reference material in your own help centre or internal tools.
/v1/content/searchSearch reference content
Searches guides, tools, templates and the answers inside them. Trade shorthand is understood — B/L, AWB, VGM and D&D all resolve. Question-shaped queries may return a direct `answer` suitable for rendering inline.
curl "https://gainingdocx.com/api/v1/content/search?q=how+is+chargeable+weight+calculated" \
-H "Authorization: Bearer $GAININGDOCX_API_KEY"Webhooks
Rather than polling for a parse to finish, register an HTTPS endpoint in Integrations and receive document.parsed, document.failed and hs.reviewed events. Each delivery is signed with your endpoint’s secret so you can verify it came from us — always verify before acting on a payload.
API questions
- How do I get an API key?
- Sign in, open Integrations in your workspace, and create a key. The plaintext key is shown once at creation and only its SHA-256 hash is stored, so it cannot be recovered later — save it to your secret manager immediately. Keys can be revoked at any time and revocation takes effect on the next request.
- What are the rate limits?
- 120 requests per 60 seconds per key. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset; a 429 additionally carries Retry-After. Counting happens in the database rather than per worker, so the limit is the real limit regardless of which edge location serves you.
- Is the API versioned?
- Yes. Every path is prefixed with /v1. Additive changes — new endpoints, new response fields — ship within v1. Anything that could break a working integration would ship as a new version, and error codes are treated as part of the contract even though messages are not.
- Can I call the API from a browser?
- No. API keys carry full account access and must never appear in browser or mobile code, where anyone can read them. Call the API from your server. CORS is permissive so server-side proxies and tools work, which is not an invitation to embed a key client-side.
- How should I handle errors?
- Every error returns the same envelope with a stable `code`, a human `message`, an optional `param` naming the offending input, and a `request_id`. Branch on `code`, show `message`, and quote `request_id` to support. Retry 429 after Retry-After and 5xx with exponential backoff; do not retry 400 or 401 without changing something.
- Is there an OpenAPI specification?
- Yes, at /api/v1/openapi.json. It is OpenAPI 3.1 and is maintained in the same commit as the routes, so you can generate a client, import it into Postman or Insomnia, and diff it between releases.
Ready to build?
Create a key in your workspace, or read how extraction and validation work before you integrate.