Skip to content
Need help with our api? Ask in Community
Experimental API

Experimental API

The Experimental API is a Beta-only GraphQL endpoint for customers who are testing new ShipHero API capabilities before they are added to the standard Public API.

Access is not enabled by default. If you want to use the Experimental API, request access through your Customer Success Manager (CSM). Your CSM will confirm whether your account is eligible and enable access for your account.

Once access is enabled, use the standard GraphQL endpoint:

https://public-api.shiphero.com/graphql/experimental

Because the Experimental API can change frequently, fetch or inspect the latest GraphQL schema from this endpoint before building or updating an integration.

The endpoint is called Experimental because the operations exposed here are still under testing and active development. Available queries, mutations, fields, inputs, and response shapes may change.

If you have access, please share feedback quickly with your ShipHero contact. Feedback from Beta testers helps shape the final API before it becomes generally available.

Currently Available

Today, the Experimental API can be used to:

  • Query available carriers and shipping methods with carriers and shipping_methods queries
  • Request label printing with the label_print mutation
  • Create an inbound shipment from an Advance Shipment Notice with the inbound_shipment_create_from_asn mutation

Connected Carriers Query

Use the carriers query to retrieve the carriers and shipping methods currently available to your account.

query {
  carriers {
    request_id
    complexity
    data {
      carrier
      carrier_name
      shipping_methods {
        carrier
        carrier_name
        method
        method_name
      }
    }
  }
}

Example response:

{
  "data": {
    "carriers": {
      "request_id": "...",
      "complexity": 2,
      "data": [
        {
          "carrier": "amazon",
          "carrier_name": "Amazon",
          "shipping_methods": [
            {
              "carrier": "amazon",
              "carrier_name": "Amazon",
              "method": "UPS_PTP_2ND_DAY_AIR",
              "method_name": "UPS 2nd Day Air"
            },
            {
              "carrier": "amazon",
              "carrier_name": "Amazon",
              "method": "UPS_PTP_GND",
              "method_name": "UPS Ground"
            }
          ]
        },
        {
          "carrier": "genericlabel",
          "carrier_name": "Generic",
          "shipping_methods": [
            {
              "carrier": "genericlabel",
              "carrier_name": "Generic",
              "method": "genericlabel",
              "method_name": "genericlabel"
            }
          ]
        },
        {
          "carrier": "ups",
          "carrier_name": "UPS",
          "shipping_methods": [
            {
              "carrier": "ups",
              "carrier_name": "UPS",
              "method": "UPS Ground",
              "method_name": "UPS Ground"
            },
            {
              "carrier": "ups",
              "carrier_name": "UPS",
              "method": "UPS Next Day Air",
              "method_name": "UPS Next Day Air"
            }
          ]
        }
      ]
    }
  },
  "extensions": {
    "throttling": {
      "estimated_complexity": 2,
      "cost": 1,
      "cost_detail": {
        "carriers": {
          "items_count": 0,
          "cost": 1,
          "total_cost": 1,
          "fields": {}
        }
      },
      "user_quota": {
        "credits_remaining": 4003,
        "max_available": 4004,
        "increment_rate": 60
      }
    }
  }
}

Note

The carriers and methods returned by this query can vary by account configuration and by the current Experimental API release.

Label Print Mutation

Use label_print to request label printing for an order. The payload identifies the order, carrier, method, whether an invoice should print, and the package contents.

The mutation returns labels directly under data.label_print.labels. It does not return a top-level shipment object, but each label can include shipment data such as shipment_id and shipment_line_items when those fields are selected.

Required OAuth Scope

The label_print mutation requires the granted OAuth scope:

change:shipments

If the issued token does not include this scope, the mutation returns a permission error:

{
  "errors": [
    {
      "message": "Missing required scope(s): change:shipments",
      "operation": "label_print",
      "field": "label_print",
      "request_id": "...",
      "code": 7
    }
  ],
  "data": {
    "label_print": null
  }
}

Note

Requesting change:shipments in the OAuth flow is not enough. The issued token must actually include the granted change:shipments scope. Some OAuth clients or accounts may not be allowed to receive write scopes.

Mutation

mutation Label_print($data: PrintLabelInput!) {
  label_print(data: $data) {
    request_id
    complexity
    labels {
      id
      legacy_id
      account_id
      shipment_id
      order_id
      box_id
      box_name
      status
      tracking_number
      alternate_tracking_id
      order_number
      order_account_id
      carrier
      shipping_name
      shipping_method
      cost
      box_code
      device_id
      delivered
      picked_up
      refunded
      needs_refund
      profile
      partner_fulfillment_id
      full_size_to_print
      packing_slip
      warehouse
      warehouse_id
      insurance_amount
      carrier_account_id
      source
      created_date
      tracking_url
      package_number
      parcelview_url
      tracking_status
      in_shipping_container
      shipping_container_id
      label {
        pdf_location
        paper_pdf_location
        thermal_pdf_location
        image_location
      }
      shipment_line_items {
        edges {
          cursor
          node {
            id
            legacy_id
            line_item_id
            shipment_id
            shipping_label_id
            quantity
            line_item {
              id
              legacy_id
              sku
              partner_line_item_id
              product_id
              quantity
              price
              product_name
              option_title
              fulfillment_status
              quantity_pending_fulfillment
              quantity_shipped
              warehouse
              quantity_allocated
              backorder_quantity
              custom_options
              custom_barcode
              eligible_for_return
              customs_value
              warehouse_id
              locked_to_warehouse_id
              subtotal
              barcode
              created_at
              updated_at
              order_id
              promotion_discount
            }
          }
        }
      }
    }
  }
}

Variables

This example uses genericlabel and explicit package dimensions.

{
  "data": {
    "order_id": "{{order_id}}",
    "shipping_carrier": "genericlabel",
    "shipping_method": "genericlabel",
    "print_invoice": false,
    "packages": [
      {
        "dimensions": {
          "weight": 0.0625,
          "height": 1,
          "width": 1,
          "length": 1
        },
        "line_items": [
          {
            "line_item_id": "{{line_item_id}}",
            "quantity": 1
          }
        ]
      }
    ]
  }
}

Before calling label_print, use the carriers query to retrieve the carrier and method values available for the account. For genericlabel, the carrier result looks like this:

{
  "carrier": "genericlabel",
  "carrier_name": "Generic",
  "shipping_methods": [
    {
      "carrier": "genericlabel",
      "carrier_name": "Generic",
      "method": "genericlabel",
      "method_name": "genericlabel"
    }
  ]
}

Package Dimensions Input

PrintLabelPackageInput supports dimensions as an alternative to carrier_box_code or custom_box_id. You can also send custom_box_id instead of carrier_box_code when you want to print the label with a custom box.

The PrintLabelDimensionsInput fields are:

weight: Float!
height: Float!
width: Float!
length: Float!

Example:

{
  "dimensions": {
    "weight": 0.0625,
    "height": 1,
    "width": 1,
    "length": 1
  }
}

Response

Example response:

{
  "data": {
    "label_print": {
      "request_id": "...",
      "complexity": 15,
      "labels": [
        {
          "id": "...",
          "legacy_id": 12345,
          "shipment_id": "...",
          "order_id": "{{order_id}}",
          "status": "valid",
          "tracking_number": "",
          "order_number": "EXAMPLE-1001",
          "carrier": "genericlabel",
          "shipping_method": "genericlabel",
          "cost": "0.00",
          "warehouse": "Primary",
          "warehouse_id": "12345",
          "created_date": "2026-06-22T19:58:51",
          "tracking_url": "",
          "package_number": 1,
          "tracking_status": "UNKNOWN",
          "label": {
            "pdf_location": "https://example.com/shipping-labels/example-1001/label.pdf",
            "paper_pdf_location": "https://example.com/shipping-labels/example-1001/paper-label.pdf",
            "thermal_pdf_location": "https://example.com/shipping-labels/example-1001/thermal-label.pdf",
            "image_location": "[\"https://example.com/shipping-labels/example-1001/label.pdf\", \"https://example.com/shipping-labels/example-1001/label.png\"]"
          },
          "shipment_line_items": {
            "edges": [
              {
                "cursor": "...",
                "node": {
                  "id": "...",
                  "legacy_id": 12345,
                  "line_item_id": "{{line_item_id}}",
                  "shipment_id": "...",
                  "shipping_label_id": "...",
                  "quantity": 1,
                  "line_item": {
                    "id": "{{line_item_id}}",
                    "legacy_id": 12345,
                    "sku": "EXAMPLE-SKU",
                    "product_name": "Example Product",
                    "quantity": 1,
                    "quantity_shipped": 1,
                    "order_id": "{{order_id}}"
                  }
                }
              }
            ]
          }
        }
      ]
    }
  }
}

Note

For generic labels, tracking_number and tracking_url may be empty strings.

Note

The image_location field is returned as a JSON-encoded string containing label asset URLs.

Create Inbound Shipment from ASN

Use inbound_shipment_create_from_asn to create an inbound shipment from an Advance Shipment Notice (ASN): the inbound counterpart to a shipping label. Where a supplier would otherwise send an EDI 856 or EDI 943 document, this mutation accepts a normalized JSON payload describing what is arriving, and creates the corresponding ShipHero records so the shipment can be received at the dock.

From a single submission the mutation:

  1. Creates a Purchase Order and its line items (one per SKU).
  2. Creates an Inbound Shipment linked to that Purchase Order, with status PENDING_ARRIVAL.
  3. Creates the expected inbound line items (quantity per SKU).
  4. Stores the full ASN payload so warehouse workers can look it up by scanning any container barcode (SSCC) when the truck arrives.

The mutation always returns a 997-style acknowledgment envelope describing whether the ASN was Accepted or Rejected, echoing the original document metadata back to the sender.

Required OAuth Scope

The inbound_shipment_create_from_asn mutation requires the granted OAuth scope:

change:inbound_shipments

If the issued token does not include this scope, the mutation returns a permission error:

{
  "errors": [
    {
      "message": "Missing required scope(s): change:inbound_shipments",
      "operation": "inbound_shipment_create_from_asn",
      "field": "inbound_shipment_create_from_asn",
      "request_id": "...",
      "code": 7
    }
  ],
  "data": {
    "inbound_shipment_create_from_asn": null
  }
}

Note

Requesting change:inbound_shipments in the OAuth flow is not enough. The issued token must actually include the granted scope. Some OAuth clients or accounts may not be allowed to receive write scopes.

Packing Structure

The payload describes packaging with a recursive packing_units tree, which lets a single input shape represent both flat (943-style) and hierarchical (856-style) shipments:

  • A packing unit with nested packing_units is treated as a pallet.
  • A packing unit without nested packing_units is treated as a box, and carries the line items directly.
Hierarchical (856-style):                 Flat (943-style):

packing_units:                            packing_units:
  - sscc: PALLET-AAA                        - sscc: BOX-BBB
    packing_units:                            line_items:
      - sscc: BOX-BBB                           - sku: WIDGET-A, qty: 50
        line_items:
          - sku: WIDGET-A, qty: 50

Each unit optionally carries an sscc (the shipper’s GS1 container barcode) and a po_number. Purchase Orders are grouped by the distinct po_number values found across the tree.

Mutation

mutation InboundShipmentCreateFromAsn($data: CreateInboundShipmentFromAsnInput!) {
  inbound_shipment_create_from_asn(data: $data) {
    request_id
    complexity
    document_type
    document_id
    created_at
    interchange {
      sender_id
      sender_qualifier
      receiver_id
      receiver_qualifier
      control_number
    }
    functional_group {
      functional_id_code
      version
      control_number
      original_transaction_set_id
    }
    acknowledgment {
      original_transaction_set_id
      original_external_shipment_id
      original_vendor_name
      original_ship_date
      accepted_count
      rejected_count
      status
      status_description
    }
    result {
      inbound_shipment {
        id
        legacy_id
        bol_reference
        warehouse_id
        status
        carrier
        pro_number
        container_number
        scheduled_at
        estimated_truck_arrival
        pallets_quantity
        number_carton
        booking_contact_name
        booking_contact_email
        booking_contact_number
      }
      purchase_orders {
        id
        legacy_id
        po_number
        line_items {
          edges {
            node {
              id
              sku
              quantity
            }
          }
        }
      }
      asn_document_id
    }
    errors {
      code
      segment
      element
      qualifier
      value
      message
    }
  }
}

Note

result.inbound_shipment and result.purchase_orders are the standard InboundShipment and PurchaseOrder types, so you can select any field those types expose (including the full line_items and purchase_orders connections). Object ids are the encoded global id; use legacy_id when you need the numeric id for legacy endpoints. The booking_contact_* fields require the view:pii scope.

Variables

This example is a single-box (943-style) shipment for one SKU.

{
  "data": {
    "external_shipment_id": "BOL-001",
    "warehouse_id": "{{warehouse_id}}",
    "vendor_name": "Acme Co",
    "edi_type": "943",
    "packing_units": [
      {
        "sscc": "00012345600000000018",
        "po_number": "PO-001",
        "line_items": [
          {
            "product_ids": [{ "qualifier": "SK", "value": "{{sku}}" }],
            "quantity": 10,
            "uom": "EA"
          }
        ]
      }
    ]
  }
}

Required Input Fields

FieldDescription
external_shipment_idBOL, shipment ID, or any shipper reference. Must be unique per account.
warehouse_idThe receiving warehouse (encoded Public API id).
vendor_nameThe shipping vendor / trading partner name.
edi_typeThe source document type: "856" or "943".
packing_unitsRecursive list of pallets and boxes carrying the line items.

Each line item requires product_ids, quantity, and uom. Supported uom codes are EA, CA, PL, CT, and BX.

Optional shipment fields include edi_version, trading_partner_id, carrier, pro_number, container_number, ship_date, estimated_arrival, the vendor_* address fields, and the booking_contact_* fields.

Note

In the current release, products can only be identified by ShipHero SKU. Send qualifier: "SK" and set value to the exact SKU. Other identifiers (UPC, GTIN, vendor part number) are not yet resolved.

Response

When the ASN is accepted, acknowledgment.status is "A" and result contains the created records.

{
  "data": {
    "inbound_shipment_create_from_asn": {
      "request_id": "...",
      "complexity": 15,
      "document_type": "997",
      "document_id": "997-20260715-1a2b3c4d",
      "created_at": "2026-07-15T12:00:00",
      "interchange": {
        "sender_id": "SHIPHERO",
        "sender_qualifier": "ZZ",
        "receiver_id": "ACME-EDI",
        "receiver_qualifier": "ZZ",
        "control_number": "a1b2c3d4e"
      },
      "functional_group": {
        "functional_id_code": "FA",
        "version": "004010",
        "control_number": "f5e6d7c8b",
        "original_transaction_set_id": "943"
      },
      "acknowledgment": {
        "original_transaction_set_id": "943",
        "original_external_shipment_id": "BOL-001",
        "original_vendor_name": "Acme Co",
        "original_ship_date": null,
        "accepted_count": 1,
        "rejected_count": 0,
        "status": "A",
        "status_description": "Accepted"
      },
      "result": {
        "inbound_shipment": {
          "id": "SW5ib3VuZFNoaXBtZW50Ojc4OQ==",
          "legacy_id": 789,
          "bol_reference": "BOL-001",
          "warehouse_id": "V2FyZWhvdXNlOjQ1Ng==",
          "status": "PENDING_ARRIVAL",
          "carrier": null,
          "pro_number": null,
          "container_number": null,
          "scheduled_at": null,
          "estimated_truck_arrival": null,
          "pallets_quantity": 0,
          "number_carton": 1,
          "booking_contact_name": null,
          "booking_contact_email": null,
          "booking_contact_number": null
        },
        "purchase_orders": [
          {
            "id": "UHVyY2hhc2VPcmRlcjoxMDE=",
            "legacy_id": 101,
            "po_number": "PO-001",
            "line_items": {
              "edges": [
                { "node": { "id": "...", "sku": "WIDGET-A", "quantity": 10 } }
              ]
            }
          }
        ],
        "asn_document_id": "..."
      },
      "errors": []
    }
  }
}

Rejection Envelope

Validation failures do not raise a GraphQL error. Instead the mutation returns a rejection envelope: acknowledgment.status is "R", result is null, and errors lists what went wrong. Each error maps back to the originating EDI segment where applicable.

{
  "data": {
    "inbound_shipment_create_from_asn": {
      "document_type": "997",
      "acknowledgment": {
        "status": "R",
        "status_description": "Rejected",
        "accepted_count": 0,
        "rejected_count": 1
      },
      "result": null,
      "errors": [
        {
          "code": "PRODUCT_NOT_FOUND",
          "segment": "W04",
          "element": "W0406",
          "qualifier": "SK",
          "value": "SKU-DOES-NOT-EXIST",
          "message": "Could not resolve product identifiers: SKU:SKU-DOES-NOT-EXIST"
        }
      ]
    }
  }
}

The error code values are:

CodeMeaning
WAREHOUSE_NOT_FOUNDwarehouse_id does not belong to the account.
DUPLICATE_SHIPMENTAn inbound shipment already exists for this external_shipment_id.
NO_LINE_ITEMSThe shipment contains no line items.
PRODUCT_NOT_FOUNDA SKU could not be resolved for the account.
INVALID_SSCC_LENGTHAn SSCC exceeds the 22-character limit.
AMBIGUOUS_LOT_NOT_SUPPORTEDAn item references multiple lots without a per-lot quantity.

Note

external_shipment_id must be unique per account. Re-submitting the same value returns a DUPLICATE_SHIPMENT rejection rather than overwriting the existing shipment.