Fulfillment Service Integration Guide

    This guide explains how to use TradeGecko API to integrate with a fulfillment service - a third party warehouse that prepares and ships orders on behalf of a merchant on TradeGecko. You can use these resources to receive and create fulfillments.

    In this guide:

    Fulfillment Resources

    Before you start working on a fulfillment integration with TradeGecko, it's helpful to understand some of the different fulfillment-related resources.

    • Sales Order: Contains information about a sales order, its associated order line items and fulfillments. Order line items contain information such as variants and tax types.
      • An order in TradeGecko can have 1 of 6 statuses: draft, active, finalized, fulfilled, void or deleted.
      • When an order is fully shipped, the order status will be changed to fulfilled.
    • Fulfillment: Represents a shipment of one or more items in a sales order. It contains information about the shipment, such as the ship to address (shipping_address), ship from address (stock_location_id), tracking information and an array of fulfillment line items.
      • A fulfillment in TradeGecko can have 1 of 4 statuses: packed, fulfilled, void or deleted.
      • A fulfillment is created with a status of packed by default. After the fulfillment is shipped, its status should be updated to fulfilled.
    • Fulfillment Line Item: Contains information about the order line item and quantity of the order line item’s variant which is being fulfilled.
    • Address: Represents a physical address of a merchant's supplier or customer created and stored in the TradeGecko Relationships section.
    • Location: Represents a geographical location where a merchant can receive, store and transfer goods.

    Fulfillment Behaviour

    Each order includes an array of order line items that needs to be fulfilled. Each order line item can be packed and fulfilled separately, depending on how the inventory is packed and managed.

    • Scenario 1: If packing is handled by a merchant while shipping is handled by the fulfillment service, the fulfillment service should subscribe to the fulfillment.create webhook to be notified of any new fulfillments to be shipped.
    • Scenario 2: If both packing and shipping are handled by the fulfillment service, the fulfillment service should subscribe to the order.create webhook to be notified when a new order is created.
      • The fulfillment service can pack all order line items through an API call to: POST /orders/[:order_id]/actions/pack. This will create a fulfillment for all order line items with status packed.
      • Once the fulfillment has been shipped, the status can be updated to fulfilled through an API call to: POST /orders/[:order_id]/actions/fulfill.

    Completing a Fulfillment

    Scenario 1: Merchant is in charge of packing. Fulfillment service completes the shipment after items are packed.

    • Step 1: Receive a fulfillment alert from fulfillment.create webhook.
    • Step 2: Query the fulfillment to see the fulfillment line items.
    • Step 3: Update fulfillment status to fulfilled.

    Step 1: Receive a fulfillment alert from fulfillment.create webhook.

    To get started, subscribe to the fulfillment.create webhook to be notified when a fulfillment is created for an order.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    webhook = gecko.Webhook.build({:address=>"https://mywebsite.com/webhooks", :event=>"fulfillment.create"})
    webhook.save
    
    {
      "webhook": {
        "id": 1,
        "created_at": "2018-09-24T11:12:49.244Z",
        "updated_at": "2018-09-24T11:12:49.244Z",
        "event": "fulfillment.create",
        "address": "https://mywebsite.com/webhooks",
        "oauth_application_id": 1
      }
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/webhooks/ -d '{"webhook":{"address":"https://mywebsite.com/webhooks","event":"fulfillment.create"}'}
    
    {
      "webhook": {
        "id": 1,
        "created_at": "2018-09-24T11:12:49.244Z",
        "updated_at": "2018-09-24T11:12:49.244Z",
        "event": "fulfillment.create",
        "address": "https://mywebsite.com/webhooks",
        "oauth_application_id": 1
      }
    }
    

    Step 2: Query the fulfillment to see the fulfillment line items.

    If your fulfillment service only handles fulfillment in certain stock locations, you can check the stock_location_id of the fulfillment to determine if you should ship any variants. You can also refer to the quantity and variant_id or variant_sku fields on the fulfillment line items to determine which and how many items to ship.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    gecko.Fulfillment.find(1)
    
    {
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-12-02T01:11:25.524Z",
        "stock_location_id": 1,
        "fulfillment_line_item_ids": [1, 2, 3]
        // more fields
      }
    }
    
    curl -X GET -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/fulfillments/1?include=fulfillment_line_items
    
    {
      "fulfillment_line_items": [
        {
          "id": 1,
          "created_at": "2015-11-02T01:22:25.524Z",
          "updated_at": "2015-12-02T01:11:25.524Z",
          "variant_id": 1,
          "variant_sku": "SKU123",
          "quantity": 1
          // more fields
        },
      ],
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-12-02T01:11:25.524Z",
        "stock_location_id": 1,
        "fulfillment_line_item_ids": [1],
        // more fields
      }
    }
    

    Step 3: Update fulfillment status to fulfilled.

    After shipping a fulfillment, you can update the status of the fulfillment to fulfilled and include information like tracking_company, tracking_number and tracking_url.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    fulfillment = gecko.Fulfillment.find(1)
    fulfillment.attributes = {
      status: "fulfilled",
      tracking_company: "GeckoShip",
      tracking_number: "123TrackMe",
    }
    fulfillment.save
    
    {
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-12-02T01:11:25.524Z",
        "status": "fulfilled",
        "tracking_company": "GeckoShip",
        "tracking_number": "123TrackMe",
        // more fields
      }
    }
    
    curl -X PUT -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/fulfillments/1 -d '{"fulfillment":{"status":"fulfilled","tracking_company":"GeckoShip","tracking_number":"123TrackMe"}}'
    
    {
      "fulfillment_line_items": [
        {
          "id": 1,
          "created_at": "2015-11-02T01:22:25.524Z",
          "updated_at": "2015-12-02T01:11:25.524Z",
          // more fields
        },
      ],
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-12-02T01:11:25.524Z",
        "tracking_company": "GeckoShip",
        "tracking_number": "123TrackMe",
        "status": "fulfilled",
        "stock_location_id": 1,
        "fulfillment_line_item_ids": [1],
        // more fields
      }
    }
    

    Notes:

    • Query the order to see its order line items: In TradeGecko, merchants have the option to partially pack order line items. For example, a merchant may choose to pack only 5 out of 10 items from an order line item.

    As a result, a fulfillment service may need to query for order line items and determine the outstanding items to be shipped in upcoming fulfillments.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    gecko.Order.find(1)
    
    {
      "order": {
        "id": 1,
        "created_at": "2015-11-12T08:06:01.561Z",
        "updated_at": "2015-11-12T08:06:01.561Z",
        "order_line_item_ids": [
          1,
          2
        ]
      // more fields
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/orders/1?include=order_line_items
    
    {
      "order_line_items": [
        // order line item attributes
      ],
      "order": {
        "id": 1,
        "created_at": "2015-11-12T08:06:01.561Z",
        "updated_at": "2015-11-12T08:06:01.561Z",
        "order_line_item_ids": [
          1,
          2
        ]
      // more fields
    }
    

    Scenario 2: Fulfillment service is in charge of packing and fulfilling an order.

    • Step 1: Receive an order alert from order.create webhook.
    • Step 2: Query the order to see the order line items.
    • Step 3: Create a new fulfillment.

    Step 1: Receive an order alert from order.create webhook.

    To get started, subscribe to the order.create webhook to be notified when a new order comes in.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    webhook = gecko.Webhook.build({:address=>"https://mywebsite.com/webhooks", :event=>"order.create"})
    webhook.save
    
    {
      "webhook": {
        "id": 1,
        "created_at": "2018-09-24T11:12:49.244Z",
        "updated_at": "2018-09-24T11:12:49.244Z",
        "event": "order.create",
        "address": "https://mywebsite.com/webhooks",
        "oauth_application_id": 1
      }
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/webhooks/ -d '{"webhook":{"address":"https://mywebsite.com/webhooks","event":"order.create"}'}
    
    {
      "webhook": {
        "id": 1,
        "created_at": "2018-09-24T11:12:49.244Z",
        "updated_at": "2018-09-24T11:12:49.244Z",
        "event": "order.create",
        "address": "https://mywebsite.com/webhooks",
        "oauth_application_id": 1
      }
    }
    

    Step 2: Query the order to see the order line items.

    Note: If your fulfillment service only handles fulfillments in certain stock locations, you can check the order's stock_location_id to determine if you should fulfill it.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    gecko.Order.find(1)
    
    {
      "order": {
        "id": 1,
        "created_at": "2015-11-12T08:06:01.561Z",
        "updated_at": "2015-11-12T08:06:01.561Z",
        "stock_location_id": 1,
        "order_line_item_ids": [
          1,
          2
        ]
      // more fields
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/orders/1?include=order_line_items
    
    {
      "order_line_items": [
        {
          "id": 1,
          "created_at": "2015-11-12T08:06:01.561Z",
          "updated_at": "2015-11-12T08:06:01.561Z",
          // more fields
        }
      ],
      "order": {
        "id": 1,
        "created_at": "2015-11-12T08:06:01.561Z",
        "updated_at": "2015-11-12T08:06:01.561Z",
        "stock_location_id": 1,
        "order_line_item_ids": [
          1
        ]
        // more fields
    }
    

    Step 3: Create a new fulfillment.

    A fulfillment service can either partially or completely fulfill an order.

    To completely fulfill an order, create a fulfillment using POST /orders/[:order_id]/actions/fulfil. Do note that this will create a fulfillment with status fulfilled for all unpacked order line items and also update the status of all existing packed fulfillments to fulfilled.

    To partially fulfill an order, pass in the order_line_item_ids and quantities to be fulfilled. Do note that this will create a fulfillment with status packed. After shipping the fulfillment, you can update the status to fulfilled as seen in Scenario 1 - Step 3.

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    fulfillment = gecko.Fulfillment.build({:order_id=>1, :packed_at=>"Time.now", :billing_address_id=>1, :shipping_address_id=>1, :fulfillment_line_items=>[{:order_line_item_id=>1}, {:order_line_item_id=>2}]})
    fulfillment.save
    
    {
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-11-02T01:22:25.524Z",
        "order_id": 2,
        "shipping_address_id": 1,
        "billing_address_id": 1,
        "stock_location_id": 1,
        "fulfillment_line_item_ids": [
          1,
          2
        ]
        // more fields
      }
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/fulfillments/ -d '{"fulfillment":{"order_id":1,"packed_at":"Time.now","billing_address_id":1,"shipping_address_id":1,"fulfillment_line_items":[{"order_line_item_id":1},{"order_line_item_id":2}]}'}
    {
      "fulfillment": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.524Z",
        "updated_at": "2015-11-02T01:22:25.524Z",
        "order_id": 2,
        "shipping_address_id": 1,
        "billing_address_id": 1,
        "stock_location_id": 1,
        "fulfillment_line_item_ids": [
          1,
          2
        ]
        // more fields
      }
    }
    

    Notes:

    • The fulfillment stock_location_id will default to the order stock_location id unless a stock_location_id is specified on fulfillment creation.
    • As merchants may have already created fulfillments, you may need to check if there are existing fulfillments before creating new ones.

    Handling Returns

    Depending on a merchant's return policy, there may be a need to create a fulfillment return or void an order. You can return an entire order or part of an order.

    In the event that your company is handling the return through TradeGecko API, you can create a fulfillment_return as shown below: 

    require 'gecko-ruby'
    gecko = Gecko::Client.new(<OAUTH_ID>, <OAUTH_SECRET>)
    access_token = OAuth2::AccessToken.new(gecko.oauth_client, <ACCESS_TOKEN>)
    gecko.access_token = access_token
    fulfillment_return = gecko.FulfillmentReturn.build({:order_id=>1, :fulfillment_return_line_items=>[{:order_line_item_id=>1, :quantity=>1}, {:order_line_item_id=>2, :quantity=>1}]})
    fulfillment_return.save
    
    {
      "fulfillment_return": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.535Z",
        "updated_at": "2015-11-02T01:22:25.535Z",
        "order_id": 1,
        "location_id": 1,
        "delivery_type": null,
        "exchange_rate": "1.0",
        "notes": null,
        "received_at": null,
        "tracking_company": null,
        "tracking_number": null,
        "tracking_url": null,
        "status": "returning",
        "credit_note_number": "CN0001",
        "order_number": "SO0001",
        "company_id": 1
      }
    }
    
    curl -X POST -H "Content-type: application/json" -H "Authorization: Bearer <ACCESS_TOKEN>"
    https://api.tradegecko.com/fulfillment_returns/ -d '{"fulfillment_return":{"order_id":1,"fulfillment_return_line_items":[{"order_line_item_id":1,"quantity":1},{"order_line_item_id":2,"quantity":1}]}'}
    
    {
      "fulfillment_return": {
        "id": 1,
        "created_at": "2015-11-02T01:22:25.535Z",
        "updated_at": "2015-11-02T01:22:25.535Z",
        "order_id": 1,
        "location_id": 1,
        "delivery_type": null,
        "exchange_rate": "1.0",
        "notes": null,
        "received_at": null,
        "tracking_company": null,
        "tracking_number": null,
        "tracking_url": null,
        "status": "returning",
        "credit_note_number": "CN0001",
        "order_number": "SO0001",
        "company_id": 1
      }
    }
    

    Tips:

    • If fulfillment return creation is handled by the merchant, you can subscribe to the fulfillment_return.create webhook to receive notifications.

    Notes:

    • You cannot delete a fulfillment if there are any associated fulfillment returns.
    • If a merchant is integrated with an accounting platform on TradeGecko, creating a fulfillment return would create a credit note on the accounting platform.
    • Refunds are currently not supported. If you need an endpoint for the refund process, let us know here.
    • You can void an order via the order's void endpoint.

    Additional Resources

    See these additional resources for more information about authorization, webhooks and order actions.

    Support

    For API feature requests, bug reports and other questions related to API guides, contact support@tradegecko.com.

    Got Feedback? We want to hear from you!

    Give Feedback