Skip to content
3PL Billing

3PL Billing

If you are a 3PL you might want to handle your client billing through the API, for example, if you want to integrate with your current accounting procedure.

There are 8 actions you can use to manipulate bills:

  1. Create a Bill
  2. Recalculate a Bill
  3. Update a Bill’s status
  4. Submit a Bill to your client
  5. Delete a Bill
  6. Add an Ad-Hoc Charge
  7. Update an Ad-Hoc Charge
  8. Read Ad-Hoc Charges

Create a Bill

This is the first action you want to take when billing a customer, in this case, you will need to call the bill_create mutation as follows:

mutation{
  bill_create(data:{
    customer_account_id:"7556"
    start_date:"2021-11-01"
    end_date:"2021-11-04"
    }
  )
  {
    request_id
    complexity
    bill{
      id
      legacy_id
      status
      customer_name
      profile_name
      created_at
      due_date
      amount
      totals(first: 5){
        edges{
          node{
            id
            legacy_id
            amount
            label
            category
            quantity
          }
        }
      }
      bill_exports(first: 5){
        edges{
          node{
            id
            legacy_id
            status
            file_url 
          }
        }
      }
      billing_period{
        start
        end
      }
      billing_frequency
    }
  }
}

And this is an example response you should be getting:

{
  "data": {
    "bill_create": {
      "request_id": "618410c9dac8be5f60d8098a",
      "complexity": 1,
      "bill": {
        "id": "QmlsbDo1ODkxNQ==",
        "legacy_id": 58915,
        "status": "queued",
        "customer_name": "Child Account Nr2",
        "profile_name": "Test",
        "created_at": "2021-11-04T16:56:41",
        "due_date": null,
        "amount": "0.00",
        "totals": {
          "edges": [
            {
              "node": {
                "id": "RmVlQ2F0ZWdvcnlUb3RhbDoxNzg2NzQ=",
                "legacy_id": 178674,
                "amount": "0.00",
                "label": null,
                "category": "recurring",
                "quantity": 0
              }
            },
            {
              "node": {
                "id": "RmVlQ2F0ZWdvcnlUb3RhbDoxNzg2NzU=",
                "legacy_id": 178675,
                "amount": "0.00",
                "label": null,
                "category": "order",
                "quantity": 0
              }
            }
          ]
        },
        "bill_exports": {
          "edges": []
        },
        "billing_period": {
          "start": "2021-11-01",
          "end": "2021-11-04"
        },
        "billing_frequency": "monthly"
      }
    }
  }
}

Note

This will only calculate the amount due in the provided time frame, billing profile and parameters must be previously set up in https://3pl.shiphero.com/threepl/

Recalculate a Bill

This can be used, for example, if there was an update to the profile assigned to the customer that affects the amount due. The mutation, in this case, is bill_recalculate:

mutation{
  bill_recalculate(data:{
    	customer_account_id:"7556"
    	id:"58915"
  	}
  )
  {
    request_id
    complexity
    bill{
      id
      legacy_id
      status
      customer_name
      profile_name
      created_at
      due_date
      amount
      totals(first: 5){
        edges{
          node{
            id
            legacy_id
            amount
            label
            category
            quantity
          }
        }
      }
      bill_exports(first: 5){
        edges{
          node{
            id
            legacy_id
            status
            file_url 
          }
        }
      }
      billing_period{
        start
        end
      }
      billing_frequency
    }
  }
}

You will receive a response similar to the following:

{
  "data": {
    "bill_recalculate": {
      "request_id": "618427a5f92531de6da4252d",
      "complexity": 1,
      "bill": {
        "id": "QmlsbDo1ODkxOA==",
        "legacy_id": 58918,
        "status": "queued",
        "customer_name": "Child Account Nr2",
        "profile_name": "Test",
        "created_at": "2021-11-04T18:34:13",
        "due_date": null,
        "amount": "0.00",
        "totals": {
          "edges": [
            {
              "node": {
                "id": "RmVlQ2F0ZWdvcnlUb3RhbDoxNzg2ODc=",
                "legacy_id": 178687,
                "amount": "0.00",
                "label": null,
                "category": "recurring",
                "quantity": 0
              }
            },
            {
              "node": {
                "id": "RmVlQ2F0ZWdvcnlUb3RhbDoxNzg2ODg=",
                "legacy_id": 178688,
                "amount": "0.00",
                "label": null,
                "category": "order",
                "quantity": 0
              }
            }
          ]
        },
        "bill_exports": {
          "edges": []
        },
        "billing_period": {
          "start": "2021-11-01",
          "end": "2021-11-04"
        },
        "billing_frequency": "monthly"
      }
    }
  }
}

Note

This mutation will delete the previously created bill and generate a new one using the same time frame, which will have a new ID. You can check this ID on the response.

Update a Bill’s status

This is used to change the bill’s status to draft, finalized, or paid. Draft is the default status, which allows you to audit and update as needed. Finalized sets the bill ready to be submitted to the client. Paid is used when the amount due was paid for by the client. Status is updated using the bill_update mutation:

mutation{
  bill_update(data:{
    	customer_account_id:"7556"
    	id:"58918"
    	status:"draft"
  	}
  )
  {
    request_id
    complexity
  }
}

As a response you will receive the request ID and the amount of credits expended.

Note

You can go back and forth between draft and finalized statuses in case you need to recalculate, but Paid can only be used on finalized bills, and once in this status, it can’t go back to draft or finalized.

Submit a Bill to your client

This mutation triggers an email to your client with the bill attached and adds the due date on your dashboard based on the payment terms you have configured for each customer. To do this use the bill_submit mutation:

mutation{
  bill_submit(data:{
    	customer_account_id:"7556"
    	id:"58918"    	
  	}
  )
  {
    request_id
    complexity
  }
}

As a response you will receive the request ID and the amount of credits expended.

Delete a Bill

This will delete the bill even if it was already submitted. The mutation for this action is bill_delete

mutation{
  bill_delete(data:{
    	customer_account_id:"7556"
    	id:"58918"
  	}
  )
  {
    request_id
    complexity
  }
}

As a response you will receive the request ID and the amount of credits expended.

Note

Once deleted, you can still see the bill on your dashboard, but you can’t undo this action.

Add an Ad-Hoc Charge

This can be used to add a one-off charge to a customer’s billing. You can optionally attach it to an existing bill using the bill_id field. The mutation for this action is bill_add_ad_hoc_charge:

mutation {
  bill_add_ad_hoc_charge(
    data: {
      customer_account_id: "7556"
      name: "Special Handling"
      description: "Custom packaging for fragile items"
      occurred_at: "2025-03-15"
      labor_unit_id: "TGFib3JVbml0OjEyMw=="
      unit_amount: "5"
      rate: "12.50"
    }
  ) {
    request_id
    complexity
    charge {
      id
      legacy_id
      name
      description
      occurred_at
      labor_unit_id
      unit_amount
      rate
    }
  }
}

Update an Ad-Hoc Charge

If you need to modify an existing ad-hoc charge, use the bill_update_ad_hoc_charge mutation:

mutation UpdateBillAdHocCharge($data: UpdateBillAdHocChargeInput!) {
  bill_update_ad_hoc_charge(data: $data) {
    request_id
    complexity
    charge {
      id
      legacy_id
      name
      description
      occurred_at
      labor_unit_id
      unit_amount
      rate
      bill_id
    }
  }
}

Read Ad-Hoc Charges

You can retrieve ad-hoc charges by their IDs using the ad_hoc_charges query:

query GetAdHocCharges($ids: [String]!) {
  ad_hoc_charges(ids: $ids) {
    request_id
    complexity
    data(first: 100) {
      edges {
        node {
          id
          legacy_id
          name
          description
          occurred_at
          labor_unit_id
          unit_amount
          rate
          bill_id
        }
      }
    }
  }
}