Unable to add expense via API

Hi there, I was wondering if there is any documentation on how to add an expense via the API.

I’ve tried passing the following body through, which gives me a 200 response, but I just end up with an empty new expense.

{
    "data" : {
        "vendor_id": "Opnel5aKBz",
        "category_id": "4openRe7Az",
        "amount": 10,
        "date": "2021-10-01"
    }
}

I’ve used the API to pull the ID’s for both the vendor and expense category I need for this example.

Any help is appreciated! Thanks!!

Hi,

It may help to remove the ‘data’ index, ie.

{
    "vendor_id": "Opnel5aKBz",
    "category_id": "4openRe7Az",
    "amount": 10,
    "date": "2021-10-01"
}
1 Like

Hi, I’ve tried without the data index and I would get 500 server errors whenever I would try the requests

Are there any details about the error in storage/log?

You can use the browser console to inspect the API request made by the web app.

I’ve attached the response from the log in the screenshot below. For context, I’m using this within a flow I’ve been working on in NodeRed, so this is the response I’m getting when trying to make an HTTP request.

EDIT: The error response I get is in the “payload” index, all I get is the message “Server Error”

Are there any details about the error in storage/log?

Here’s the error message:

production.ERROR: array_merge(): Expected parameter 1 to be an array, null given {"userId":1,"exception":"[object] (ErrorException(code: 0): array_merge(): Expected parameter 1 to be an array, null given at /var/www/invoiceninja/app/Http/Requests/Request.php:42)

@david do you have any thoughts?

@bds, I wrote a test for this and I can confirm the API behaves correctly. Can you please show the FULL request you are sending up

public function testAddingExpense()
    {

        $data = [
            'name' => $this->faker->firstName,
        ];

        $response = $this->withHeaders([
                'X-API-SECRET' => config('ninja.api_secret'),
                'X-API-TOKEN' => $this->token,
            ])->post('/api/v1/expense_categories', $data);

        $response->assertStatus(200);

        $arr = $response->json();
        $category_id = $arr['data']['id'];

        $data = 
        [
            "vendor_id" => $this->vendor->hashed_id,
            "category_id" => $category_id,
            "amount" => 10,
            "date" => "2021-10-01"
        ];


        $response = $this->withHeaders([
                'X-API-SECRET' => config('ninja.api_secret'),
                'X-API-TOKEN' => $this->token,
            ])->post('/api/v1/expenses', $data);

        $arr = $response->json();
        $response->assertStatus(200);


    }

Thanks for getting back to me David. I’ve included my full request from NodeRed below:

var accessToken = global.get('invoiceNinjaToken');

msg.headers = {
    "Content-Type": "application/json",
    "X-API-TOKEN": accessToken,
    "X-Requested-With": "XMLHttpRequest",
}

msg.payload = {
    "vendor_id": "Opnel5aKBz",
    "category_id": "4openRe7Az",
    "amount": 10,
    "date": "2021-10-01"
}

return msg;

I am sending this POST request to an HTTP request node in NodeRed to the URL http://my-internal-ip/api/v1/expenses

Similar to the NodeRed documentation I’ve linked below, instead of passing the URL to the node like in the example, I am instead passing the headers for the request (i.e. msg.headers) and the body of the request (i.e. msg.payload) to the HTTP request note:
https://cookbook.nodered.org/http/set-request-url

@bds

I still can’t recreate this, I would suggest using this curl command to test:

curl -X POST 'http://ninja.test:8000/api/v1/expenses' \
-H "X-API-TOKEN:company-token-test" \
-H "Content-Type:application/json" \
-d '{"date":"2021-10-01","vendor_id":"ELe3lrQa69","category_id":"BDbDRJqel2","amount":10}' \
-H "X-Requested-With: XMLHttpRequest" \
-H "X-API-SECRET:password";

Can you also advise if this is the only route you are seeing this issue on?

Yes, this is the only route I’m seeing this issue on. I’ve been able to create and retrieve vendors no problem.

I tried the curl request and it gave me the error message:
{"message":"The given data was invalid.","errors":{"vendor_id":["The selected vendor id is invalid."]}}

When I switched to a different vendor id it worked! It’s weird I never got this error message anywhere else though. I tried in Postman as well and the error message was only "message":"Server Error"

Thanks for all your help guys! Very much appreciated :grinning:

One other thing I noticed, is the order of the keys/values in the object matter. Having the “date” field first helped (I went back to NodeRed with a different vendor id like in the curl request, but I kept getting the error). It was only after moving the “date” field to the first position that got my flow in NodeRed to work (like in the curl example).