Skip to content

Shipping Labels API

This guide covers buying domestic US shipping labels with your Gearment wallet. Start with the quickstart for the day-one flow.

Get started

  1. Create your API credentials. In the dashboard, open Developer Settings > API credentials. See Authentication for how to use them. Create the credentials for your account yourself, and keep the client secret on your server.
  2. Check that Shipping Labels is enabled. Gearment enables it on your account; you do not need to request it. Call GET /carriers-services with your credentials: it returns USPS in data when your account is ready. Only if data is empty, email integration@gearment.com with the email address of your Gearment account.
  3. Fund your G-Wallet. In the dashboard, open Payments > Payment method. In the G-Wallet card, select Top-up. In the Top-up dialog, choose a funding method offered to your account, follow the on-screen instructions, and select Next to submit the top-up. The G-Wallet card shows your current balance; use Top-up history or Payments > Transaction history to review activity. If the dashboard asks you to verify your email or complete legal information, do that before continuing. Labels are charged to your G-Wallet balance only, never to a credit line or card on file.
  4. Your wallet balance is your limit. A purchase is refused before anything is bought when your G-Wallet balance cannot cover it; check available with GET /api/v3/wallet before you buy. Gearment can also set a per-label maximum or a daily label limit on an account; a purchase over them returns HTTP 412 or HTTP 429.
  5. Try the flow. Quotes are free. Buy one low-cost USPS label, then void it if you do not need it; the wallet refund is issued after the carrier confirms it and can take up to 30 days. For contract testing without a real purchase, request a test-environment client.

1. Before you start

Production base URL https://apiv2.gearment.com/integration-handler
API prefix /api/v3/shipping
Coverage United States domestic shipments only
Test mode Production has no test mode: every purchase is a real label charged to your wallet. For contract testing without money, request a test-environment client. To try the full production flow, buy one low-cost label and void it; the refund reaches your wallet only after the carrier confirms it.

Credentials

Every request carries two headers:

X-Gearment-Client-Key: <your client key>
X-Gearment-Client-Secret: <your client secret>
Content-Type: application/json
  • Keep the secret on your server. Never ship it in browser code or a mobile app.
  • A missing, wrong, or expired credential returns HTTP 401.

2. Conventions

JSON

  • Field names are snake_case.
  • 64-bit integers are sent as strings, for example "units": "5" and "quantity": "1".
  • Timestamps are RFC 3339 in UTC, for example "2026-09-10T14:18:22Z".

Money - read this carefully

Every money amount has this shape:

{ "currency_code": "USD", "units": "4", "nanos": 80 }

In this API, nanos carries cents (0-99), not billionths of a dollar. The example above is $4.80 USD.

amount = units + nanos / 100

Send declared values the same way: $10.50 -> { "currency_code": "USD", "units": "10", "nanos": 50 }.

Weights and dimensions

"package": {
  "weight":     { "value": "8",  "unit": "oz" },
  "dimensions": {
    "length":   { "value": "10", "unit": "in" },
    "width":    { "value": "8",  "unit": "in" },
    "height":   { "value": "1",  "unit": "in" }
  }
}
  • Weight units: oz, lb, kg, or g.
  • Dimensions: in only.
  • value is a positive decimal string, such as "8" or "0.5".
  • An unsupported weight unit or dimension unit is rejected with HTTP 400. Units are not guessed or converted.

Addresses

ship_from and ship_to are US addresses:

Field Required Notes
street1 yes 1-255 chars
street2 no
city yes
state_code yes 1-10 chars; for example CA
zip_code yes 4-10 chars
country_code yes US or USA
first_name, last_name no
company no
phone_no no
email no Must be a valid email address if set

Response envelope

Success:

{
  "request_id": "0a1b2c3d...",
  "status": "success",
  "message": "Shipping label purchased",
  "data": { }
}

Error:

{
  "request_id": "0a1b2c3d...",
  "status": "error",
  "message": "seller label rate has expired",
  "error_code": "SELLER_LABEL_ERROR_REASON_RATE_EXPIRED",
  "error_metadata": { }
}

error_code and error_metadata are included only when the error provides them. Always log request_id; quote it, with any label_id, whenever you contact support. When error_code is present, branch on it rather than message.


3. The flow

GET  /carriers-services       what your account can use
POST /rates                   quote - valid for 15 minutes
POST /labels                  buy one rate - returns tracking and the label file
GET  /labels/{label_id}       read it again later
POST /labels/{label_id}/void  cancel an unused label
GET  /labels                  list your labels, newest first

Your G-Wallet balance is at GET /api/v3/wallet, outside the shipping prefix.

A rate can be used for one new label request. A retry of that same request with the same request_id is allowed and returns the original label; do not get a fresh quote merely to retry it.


4. Endpoints

4.1 List carriers and services

GET /api/v3/shipping/carriers-services

curl https://apiv2.gearment.com/integration-handler/api/v3/shipping/carriers-services \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET"
{
  "request_id": "...",
  "status": "success",
  "message": "Shipping carrier services listed",
  "data": [
    {
      "carrier": "usps",
      "services": [],
      "enabled": true
    }
  ]
}
  • An empty services list means every service of that carrier is allowed.
  • An empty data list means shipping labels are not enabled for your account yet.
  • Only carriers and services enabled for your account can be quoted.

4.2 Quote rates

POST /api/v3/shipping/rates

curl -X POST https://apiv2.gearment.com/integration-handler/api/v3/shipping/rates \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "ship_from": {
      "first_name": "Warehouse", "last_name": "Team", "company": "Your Co",
      "street1": "2401 Polk St", "city": "Houston", "state_code": "TX",
      "zip_code": "77003", "country_code": "US", "phone_no": "7135550100"
    },
    "ship_to": {
      "first_name": "Jane", "last_name": "Buyer",
      "street1": "727 S Broadway", "city": "Los Angeles", "state_code": "CA",
      "zip_code": "90014", "country_code": "US", "phone_no": "2135550100"
    },
    "package": {
      "weight": { "value": "8", "unit": "oz" },
      "dimensions": {
        "length": { "value": "10", "unit": "in" },
        "width":  { "value": "8",  "unit": "in" },
        "height": { "value": "1",  "unit": "in" }
      },
      "value": { "currency_code": "USD", "units": "10", "nanos": 0 },
      "quantity": "1"
    }
  }'
{
  "request_id": "...",
  "status": "success",
  "message": "Shipping rates estimated",
  "data": {
    "rate_quote_id": "srq_...",
    "expires_at": "2026-09-10T14:18:22Z",
    "rates": [
      {
        "rate_id": "srate_...",
        "carrier": "USPS",
        "service": "GroundAdvantage",
        "seller_price": { "currency_code": "USD", "units": "5", "nanos": 97 },
        "delivery_days": 3
      }
    ]
  }
}
  • Keep the exact ship_from, ship_to, and package you quoted. The purchase must send the same values.
  • If a per-label maximum is set on your account, rates above it are not returned.

4.3 Buy a label

POST /api/v3/shipping/labels

curl -X POST https://apiv2.gearment.com/integration-handler/api/v3/shipping/labels \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "request_id": "order-10001-label-1",
    "rate_id": "srate_...",
    "label_format": "zpl",
    "ship_from": { ...same as the quote... },
    "ship_to":   { ...same as the quote... },
    "package":   { ...same as the quote... }
  }'
Field Required Notes
request_id yes Your idempotency key. One per label. See below.
rate_id yes From the quote, within 15 minutes.
ship_from, ship_to, package yes Must match the quote exactly.
label_format no Lowercase pdf or zpl. Empty means pdf.
{
  "request_id": "...",
  "status": "success",
  "message": "Shipping label purchased",
  "data": {
    "label_id": "slbl_...",
    "status": "SELLER_LABEL_STATUS_PURCHASED",
    "carrier": "USPS",
    "service": "GroundAdvantage",
    "tracking_no": "9400...",
    "tracking_url": "https://...",
    "label_url": "https://...",
    "label_format": "zpl",
    "seller_price": { "currency_code": "USD", "units": "5", "nanos": 97 },
    "rate_id": "srate_...",
    "request_id": "order-10001-label-1",
    "created_at": "2026-09-10T14:06:01Z"
  }
}

Always check data.status. Only SELLER_LABEL_STATUS_PURCHASED means you have a usable label. A failed label includes failure_reason with the recorded reason.

Idempotency - how request_id works

You send You get
A new request_id A new purchase.
The same request_id, rate_id, shipment data, and requested format The label from the first attempt, whatever its outcome - no second purchase.
The same request_id with a different rate_id, shipment data, or non-default format HTTP 409, SELLER_LABEL_ERROR_REASON_REQUEST_MISMATCH. Nothing is bought.
A purchase whose shipment data does not match the quote HTTP 400, SELLER_LABEL_ERROR_REASON_REQUEST_MISMATCH. Nothing is bought.

Blank optional fields and an omitted label_format count the same as their defaults. Build request_id from something stable on your side, such as your order ID plus a label sequence number. Never reuse a request_id for a different shipment.

If the purchase call fails or times out

A purchase can take several seconds, and a failed or timed-out call may still complete.

  1. Retry the same call - same request_id, same shipment data, and same format. It never buys a second label; it returns the first label with its current status. The API returns HTTP 504 after 10 seconds, but a purchase may still complete.
  2. If the purchase returns HTTP 503, SELLER_LABEL_ERROR_REASON_PURCHASE_OUTCOME_UNKNOWN, the label remains SELLER_LABEL_STATUS_PURCHASING while its outcome is confirmed. Retry with the same request_id or use GET /labels/{label_id}; never buy again with a new request_id while it is purchasing.
  3. A purchasing label older than 10 minutes is automatically rechecked every 5 minutes. A confirmed label changes to SELLER_LABEL_STATUS_PURCHASED and its wallet charge is captured once; a definitively rejected purchase changes to SELLER_LABEL_STATUS_FAILED, includes failure_reason, and releases the hold.
  4. If a label remains SELLER_LABEL_STATUS_PURCHASING for more than one day, contact support with its request_id and label_id.

Only after the label shows SELLER_LABEL_STATUS_FAILED should you get a new quote and buy with a new request_id.

4.4 Get a label

GET /api/v3/shipping/labels/{label_id}

Returns the current label data, including failure_reason when the label failed. Labels are visible only to the account that bought them.

4.5 Void a label

POST /api/v3/shipping/labels/{label_id}/void

curl -X POST https://apiv2.gearment.com/integration-handler/api/v3/shipping/labels/slbl_.../void \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET" \
  -H "Content-Type: application/json" -d '{}'
  • The first void request must target a SELLER_LABEL_STATUS_PURCHASED label.
  • If the void call itself fails, for example with HTTP 503, the label can stay in SELLER_LABEL_STATUS_CANCEL_REQUESTED. Call void again on the same label to resume. A void never refunds twice.
  • A void starts in SELLER_LABEL_STATUS_REFUND_PENDING. The wallet is credited automatically only after the carrier confirms the refund, with the full amount charged; a label may already return as SELLER_LABEL_STATUS_REFUNDED if confirmation is immediate.
  • USPS refunds usually take 2 to 4 weeks; allow up to 30 days.
  • If the refund is rejected or does not apply, the label ends in SELLER_LABEL_STATUS_CANCEL_REJECTED and the charge remains.
  • If an unusually high share of your recent labels has been voided, a new void can be refused with HTTP 429, SELLER_LABEL_ERROR_REASON_VOID_LIMIT_REACHED. The label stays purchased; contact support.

4.6 List labels

GET /api/v3/shipping/labels

curl "https://apiv2.gearment.com/integration-handler/api/v3/shipping/labels?filter.status=purchased&paging.limit=50" \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET"
Query parameter Notes
filter.status One status, for example purchased or SELLER_LABEL_STATUS_PURCHASED.
filter.created_from RFC 3339 time, inclusive.
filter.created_to RFC 3339 time, exclusive.
filter.request_id An exact request_id. Use it to find the label of a purchase whose response was lost.
paging.page Page number, starting at 1.
paging.limit Page size. Default 20, maximum 250.
{
  "status": "success",
  "message": "Shipping labels retrieved",
  "data": [
    { "label_id": "slbl_...", "status": "SELLER_LABEL_STATUS_PURCHASED", "request_id": "order-10001-label-1" }
  ],
  "paging": { "total": 42, "total_page": 3, "page": 1, "limit": 20 }
}

Each item has the same fields as GET /labels/{label_id}. Labels are listed newest first, and only your own account's labels are returned.

4.7 Check your wallet balance

GET /api/v3/wallet

curl https://apiv2.gearment.com/integration-handler/api/v3/wallet \
  -H "X-Gearment-Client-Key: $GEARMENT_KEY" \
  -H "X-Gearment-Client-Secret: $GEARMENT_SECRET"
{
  "status": "success",
  "message": "Wallet retrieved",
  "data": {
    "currency_code": "USD",
    "balance":   { "currency_code": "USD", "units": "50", "nanos": 0 },
    "held":      { "currency_code": "USD", "units": "6", "nanos": 57 },
    "available": { "currency_code": "USD", "units": "43", "nanos": 43 }
  }
}
  • balance is your G-Wallet balance. held is money reserved for purchases that are still in progress.
  • available is balance minus held: what a new purchase can use. A purchase above available is refused with label purchase funds insufficient.
  • The values are a snapshot. A purchase made at the same moment can change them.
  • Amounts follow the same money convention: nanos carries cents.

5. Errors

When available, branch on error_code. HTTP status is given for orientation.

error_code Meaning What to do
(none), HTTP 400 Request failed validation. message names the field. Fix the request. Do not retry unchanged.
(none), HTTP 401 Missing, wrong, or expired credentials. Check both headers.
SELLER_LABEL_ERROR_REASON_FEATURE_DISABLED Shipping labels are switched off. Contact support.
SELLER_LABEL_ERROR_REASON_TEAM_DISABLED Shipping labels are not enabled for your account. Contact support.
SELLER_LABEL_ERROR_REASON_NO_CARRIER_CONFIGURED No carrier enabled for your account. Check /carriers-services or contact support.
SELLER_LABEL_ERROR_REASON_RATE_EXPIRED The quote is older than 15 minutes. Quote again.
SELLER_LABEL_ERROR_REASON_RATE_CONSUMED This rate was already used for a different label request. Quote again.
SELLER_LABEL_ERROR_REASON_RATE_NOT_FOUND Unknown rate_id, or it belongs to another account. Use a rate_id from your own quote.
SELLER_LABEL_ERROR_REASON_REQUEST_MISMATCH, HTTP 400 The purchase does not match its quote. Send the quoted values unchanged.
SELLER_LABEL_ERROR_REASON_REQUEST_MISMATCH, HTTP 409 A reused request_id has different purchase data. Reuse the original data, or use a new ID for a new shipment.
SELLER_LABEL_ERROR_REASON_LABEL_FORMAT_UNSUPPORTED, HTTP 400 The carrier cannot produce the requested format. No wallet funds are held. Use a supported lowercase format.
SELLER_LABEL_ERROR_REASON_PRICE_EXCEEDS_TEAM_MAX, HTTP 412 Above the per-label maximum set on your account. Choose a cheaper rate or contact support.
SELLER_LABEL_ERROR_REASON_DAILY_LIMIT_REACHED, HTTP 429 The daily label limit set on your account is used up. Wait until the next day or contact support.
SELLER_LABEL_ERROR_REASON_VOID_LIMIT_REACHED, HTTP 429 Voids are temporarily limited on your account. The label is unchanged. Contact support.
SELLER_LABEL_ERROR_REASON_RATE_PRICE_INVALID The returned rate cannot be sold. Quote again. Contact support if it repeats.
SELLER_LABEL_ERROR_REASON_NOT_IMPLEMENTED, SELLER_LABEL_ERROR_REASON_NOT_CONFIGURED, or SELLER_LABEL_ERROR_REASON_PURCHASE_PROVIDER_UNSUPPORTED, HTTP 501 This purchase capability is not available. Contact support.
SELLER_LABEL_ERROR_REASON_LABEL_NOT_FOUND Unknown label_id, or it belongs to another account. Check the ID.
SELLER_LABEL_ERROR_REASON_CANCEL_NOT_SUPPORTED This label cannot be voided through the API. Contact support.
SELLER_LABEL_ERROR_REASON_CANCEL_INVALID_STATE The label is not in a voidable state. Check status with GET /labels/{label_id}.
SELLER_LABEL_ERROR_REASON_PURCHASE_OUTCOME_UNKNOWN, HTTP 503 The purchase outcome is not yet known. The label may still be issued. Retry with the same request_id; do not buy with a new ID.
(none), HTTP 503, message contains label purchase funds insufficient The wallet does not have enough available funds. Nothing is bought, and that label ends as SELLER_LABEL_STATUS_FAILED. Fund the wallet, then get a new quote and buy with a new request_id.

6. Limits

Limit Value
Quote validity 15 minutes
Spending Your G-Wallet balance: a purchase it cannot cover is refused before anything is bought
Labels per day No limit unless Gearment sets one on your account (DAILY_LIMIT_REACHED, HTTP 429)
Price per label No limit unless Gearment sets one on your account (PRICE_EXCEEDS_TEAM_MAX, HTTP 412)
Destinations US domestic

When a per-label maximum is set, rates above it are not quoted and a purchase above it is rejected with HTTP 412. When a daily label limit is set, a purchase over it is rejected with HTTP 429.


7. Pricing

seller_price is the price charged to your wallet. Quotes, purchases and label reads always return this price. The purchase first holds those funds, then captures the charge after the label is confirmed. If the wallet balance is too low, the purchase is refused before anything is bought.

Known limitations

  • Test mode. Wallet-billed labels have no test mode. For contract testing without money, request a test-environment client. To try the full production flow, buy one low-cost real label and void it; the refund reaches your wallet only after the carrier confirms it.
  • Slow requests. The API returns HTTP 504 after 10 seconds. A purchase may still complete, so retry with the same request_id and check the label rather than buying again.
  • Label file format. Request lowercase pdf or zpl. USPS supports both. A format that the carrier cannot produce is rejected before funds are held; the returned label uses the format you requested.
  • Carriers. Wallet-billed label purchases currently support USPS only. DHL eCommerce and GOFO wallet billing are planned, without a published date. A carrier or service that is not enabled for your account is not quoted.

Support

Email integration@gearment.com for Shipping Labels API support. Include the request_id from the response and any label_id in every request.