Solved

Orders.json => Transactions.json

Daniel76
Shopify Partner
9 0 1

Please note: This is a two-part question:

PART I

According to the Order API documentation payment_details has been deprecated and we're told to use "Transaction resource" instead.

So, I added "transactions" to my "order" like so...

{
    "order": {
        "transaction": {
            "currency": "USD",
            "amount": 219.8,
            "kind": "sale",
            "authorization": "",
            "status": "success",
            "gateway": "Authorize.net"
        },

I am able to POST the order without error, however, I cannot retrieve any transactions, nor do I see a transaction comment on the order itself.

I have tried omitting financial_status, changing the various values passed within the transaction, and numerous other changes--all to no avail. Also, no matter what I do, the order shows as "Paid.

PART 2

Our client would like to have both approved and declined transactions saved to their storefront. Assuming I get the transaction working, is posting a declined order as simple as setting transaction.status = "failure"?

Can you please help?

 

Accepted Solution (1)

KarlOffenberger
Shopify Partner
1873 184 901

This is an accepted solution.

Hi Daniel,

This topic keeps popping up on the forums and there seems to be a lot of confusion around creating orders via API, but not being able to collect payment information or transactions.

Let's begin with documentation straight from the Order API

Orders can be created through the API, but no payment information will be collected, and no transaction performed. You can mark the order with any payment status.

You can also allow merchants to create orders manually by using the DraftOrder resource.

So there we have it. Which makes sense. If you create an order via the Shopify Admin UI, notice you really are creating a draft order first. Which is what you need to do with the API as well. Looking at the Draft Order API

You can use the DraftOrder resource to allow merchants to create orders on behalf of customers. This is useful for Shopify merchants who receive orders through outside channels

Your app IS an outside channel. Anyway, let us create a draft order

1. Create Draft Order

POST /admin/draft_orders.json

{
  "draft_order": {
    "line_items": [
      {
        "variant_id": <SOME_PRODUCT_VARIANT_ID>,
        "quantity": 1
      }
    ]
  }
}

The response will provide you with the draft order id for the next request

2. Complete Draft Order

PUT /admin/draft_orders/<DRAFT_ORDER_ID>/complete.json?payment_pending=true

The response will provide you with the order_id for the next step

3. Mark Order as paid

Now what's important to understand is that with completing your draft order and transfering it to an order, you have also implicitly created a transaction. Since we didn't specify otherwise on our draft order, the default (in my dev store) is a manual transaction. Let's check it, we will need the transaction ID anyway.

GET /admin/orders/<ORDER_ID>/transactions.json

// Query Response
{
  "transactions": [
    {
      "id": <TRANSACTION_ID>,
      "order_id": <ORDER_ID>,
      "kind": "sale",
      "gateway": "manual",
      "status": "pending",
      "message": "Pending the manual payment from the buyer",
      "created_at": "2019-01-02T11:57:43-12:00",
      "test": false,
      "authorization": null,
      "location_id": null,
      "user_id": null,
      "parent_id": null,
      "processed_at": "2019-01-02T11:57:43-12:00",
      "device_id": null,
      "receipt": {},
      "error_code": null,
      "source_name": "2632381",
      "amount": "6.00",
      "currency": "CZK",
      "admin_graphql_api_id": "gid:\/\/shopify\/OrderTransaction\/1041253236851"
    }
  ]
}

See gateway is manual since that's my default and status is pending as when I completed the draft order in step 2, I passed along the querystring argument payment_pending=true. To mark it as paid, I need to create a new transaction referencing the parent transaction I am referring to.

POST /admin/orders/<ORDER_ID>/transactions.json

{
  "transaction": {
	"parent_id": <TRANSACTION_ID>,
    "currency": "CZK",
    "amount": "6.00",
	"kind": "capture"
  }
}

Hang on, why capture? Well the entire authorization, capture etc. lingo is just a common denominator from card processing, but applies just as well to any other kind. When we created the draft order, we basically said the customer authorized us to take their 6.00 CZK and when completing that draft and marking its payment as pending, we just noted that we are waiting to receive that issued amount - which once we do, we capture - thus kind is capture even for manual payments.

And that's that. I'll leave other payment methods for you to explore , but generally advise to reading the documentation TOP to bottom and not jumping straight to examples and making assumptions though I can't blame you, we all do sometime 😉

Hope this helps!

View solution in original post

Replies 8 (8)

Daniel76
Shopify Partner
9 0 1

Attempting to submit the transaction on its own via admin/orders/#order/transactions.json results in:

{
    "errors": {
        "kind": [
            "sale is not a valid transaction"
        ],
        "currency": []
    }
}

KarlOffenberger
Shopify Partner
1873 184 901

This is an accepted solution.

Hi Daniel,

This topic keeps popping up on the forums and there seems to be a lot of confusion around creating orders via API, but not being able to collect payment information or transactions.

Let's begin with documentation straight from the Order API

Orders can be created through the API, but no payment information will be collected, and no transaction performed. You can mark the order with any payment status.

You can also allow merchants to create orders manually by using the DraftOrder resource.

So there we have it. Which makes sense. If you create an order via the Shopify Admin UI, notice you really are creating a draft order first. Which is what you need to do with the API as well. Looking at the Draft Order API

You can use the DraftOrder resource to allow merchants to create orders on behalf of customers. This is useful for Shopify merchants who receive orders through outside channels

Your app IS an outside channel. Anyway, let us create a draft order

1. Create Draft Order

POST /admin/draft_orders.json

{
  "draft_order": {
    "line_items": [
      {
        "variant_id": <SOME_PRODUCT_VARIANT_ID>,
        "quantity": 1
      }
    ]
  }
}

The response will provide you with the draft order id for the next request

2. Complete Draft Order

PUT /admin/draft_orders/<DRAFT_ORDER_ID>/complete.json?payment_pending=true

The response will provide you with the order_id for the next step

3. Mark Order as paid

Now what's important to understand is that with completing your draft order and transfering it to an order, you have also implicitly created a transaction. Since we didn't specify otherwise on our draft order, the default (in my dev store) is a manual transaction. Let's check it, we will need the transaction ID anyway.

GET /admin/orders/<ORDER_ID>/transactions.json

// Query Response
{
  "transactions": [
    {
      "id": <TRANSACTION_ID>,
      "order_id": <ORDER_ID>,
      "kind": "sale",
      "gateway": "manual",
      "status": "pending",
      "message": "Pending the manual payment from the buyer",
      "created_at": "2019-01-02T11:57:43-12:00",
      "test": false,
      "authorization": null,
      "location_id": null,
      "user_id": null,
      "parent_id": null,
      "processed_at": "2019-01-02T11:57:43-12:00",
      "device_id": null,
      "receipt": {},
      "error_code": null,
      "source_name": "2632381",
      "amount": "6.00",
      "currency": "CZK",
      "admin_graphql_api_id": "gid:\/\/shopify\/OrderTransaction\/1041253236851"
    }
  ]
}

See gateway is manual since that's my default and status is pending as when I completed the draft order in step 2, I passed along the querystring argument payment_pending=true. To mark it as paid, I need to create a new transaction referencing the parent transaction I am referring to.

POST /admin/orders/<ORDER_ID>/transactions.json

{
  "transaction": {
	"parent_id": <TRANSACTION_ID>,
    "currency": "CZK",
    "amount": "6.00",
	"kind": "capture"
  }
}

Hang on, why capture? Well the entire authorization, capture etc. lingo is just a common denominator from card processing, but applies just as well to any other kind. When we created the draft order, we basically said the customer authorized us to take their 6.00 CZK and when completing that draft and marking its payment as pending, we just noted that we are waiting to receive that issued amount - which once we do, we capture - thus kind is capture even for manual payments.

And that's that. I'll leave other payment methods for you to explore , but generally advise to reading the documentation TOP to bottom and not jumping straight to examples and making assumptions though I can't blame you, we all do sometime 😉

Hope this helps!

Daniel76
Shopify Partner
9 0 1

Perfect and thank you, Karl. I'll give this a go.

Your response here should be part of the documentation. I had read the term "draft order" in the documents. However, I was fixated in adding an Order--not a Draft Order (I don't speak Shopify, yet.) The Draft Order needs to be to be clarified in Shopify's documentation, at the very least much easier to pick out--especially given that you mention the topic "keeps popping up on the forums."

KarlOffenberger
Shopify Partner
1873 184 901

Don't take my word for it 😉 I may be wrong or there may be better ways to achieve the same - I am pretty new to Shopify myself. A lot of reading and a lot of reverse *cough* engineering or to be more accurate, network activity monitoring, of what the admin UI does (though A LOT of those APIs are not accessible outside of the admin UI... at least not officially) have helped me understand a few things and might help you too.

Ravipatel
Shopify Partner
35 0 2

i have same error apper

 

$transactions=array(
    "transaction"=>array(
         "kind"=> "sale",
         "amount" => "585.60",
         "currency"=> "AUD",
        "status"=>"success",
        "gateway"=>"manual"
    )
);

 

POST /admin/orders/#{order_id}/transaction.json

Array
(
    [errors] => Array
        (
            [kind] => Array
                (
                    [0] => sale is not a valid transaction
                )

            [currency] => Array
                (
                )

        )

)

 Any one can solve this issue

KarlOffenberger
Shopify Partner
1873 184 901

Hi @Ravipatel the answer as to why you're getting that error is in this thread 🙄

Ravipatel
Shopify Partner
35 0 2

create order using api

POST /admin/orders.json/

 

Then POST /admin/orders/#order_id/transactions.json

 

$transactions=array(
    "transaction"=>array(
         "kind"=> "sale",
         "amount" => "585.60",
         "currency"=> "AUD",
        "status"=>"success",
        "gateway"=>"manual"
    )
);
 $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_VERBOSE, 0);
    curl_setopt($curl, CURLOPT_HEADER, 0);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($transactions));
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    $response = curl_exec ($curl);
    curl_close ($curl);
    $resp = json_decode($response,true);

but still given error

Array
(
    [errors] => Array
        (
            [kind] => Array
                (
                    [0] => sale is not a valid transaction
                )

            [currency] => Array
                (
                )

        )

)
KarlOffenberger
Shopify Partner
1873 184 901

Sorry @Ravipatel but

 

  1. The answer is really in this thread so please read it again
  2. I don't (want to) read PHP