How to add ssh-keys via GitHub's v3 API? - github

I'm trying to add an ssh key via GitHub's v3 API, but it doesn't seem to be working.
What I'm doing is based on the instructions given here.
More specifically, I'm using the following:
KEY=$( cat ~/.ssh/id_rsa.pub )
TITLE=${KEY/* }
# the '/* ' above deletes every character in $KEY up to and including the last
# space.
JSON=$( printf '{"title": "%s", "key": "%s"}' "$TITLE" "$KEY" )
TOKEN=$( cat /path/to/tokenfile )
curl -s -d "$JSON" "https://api.github.com/user/keys?access_token=$TOKEN"
When I run the above, the response I get is:
{
"message": "Not Found"
}
...and, sure enough, when I check in my GitHub account, $KEY is not among the ssh-keys listed1.
What am I doing wrong?
Additional details
I get the same "message": "Not Found" response if I just run
curl -s "https://api.github.com/user/keys?access_token=$TOKEN"
If I replace the -s above with -i I see that, indeed, the returned status is 404 Not Found. And yet, the returned status for
curl -i "https://api.github.com/user/keys"
is 401 Unauthorized.
1 I know that the access token in $TOKEN is fine, and therefore it is not the reason for the "message": "Not Found" response, because
curl -s "https://api.github.com/user/repos?access_token=$TOKEN"
returns the correct information, and
curl -s "https://api.github.com/user/repos"
returns
{
"message": "Requires authentication"
}

Does your access token have "user" scope? A relevant excerpt from the docs:
Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the ‘user’ scope.
If your token does not have "user" scope, you will get a 404 response with a message of "Not Found".
To see the scopes associated with your tokens, use the "Authorizations" API:
curl -u <username> https://api.github.com/authorizations
In the example response below, the first authorization has "user" scope, but the second one does not.
enter code here
[
{
"id": 123,
"url": "https://api.github.com/authorizations/123",
"app": {
"name": "Foo",
"url": "https://foo.example.com/",
"client_id": "REDACTED-ID-1"
},
"token": "REDACTED-TOKEN-1",
"note": null,
"note_url": null,
"created_at": "2013-02-18T18:24:00Z",
"updated_at": "2013-05-06T14:17:00Z",
"scopes": [
"repo",
"user"
]
},
{
"id": 456,
"url": "https://api.github.com/authorizations/456",
"app": {
"name": "Bar",
"url": "https://bar.example.com/",
"client_id": "REDACTED-ID-2"
},
"token": "REDACTED-TOKEN-2",
"note": "for stuff",
"note_url": null,
"created_at": "2013-04-16T12:20:00Z",
"updated_at": "2013-05-13T21:28:00Z",
"scopes": [
"public_repo"
]
}
]
If you determine that this is the source of your problem, then you can resolve it in one of two ways:
Create a new token that has "user" scope, or
Update your existing token to add the "user" scope to it: "add_scopes": [ "user" ]

As of February 2014 the "user" scope no longer provides enough access to manage a user's SSH keys. The scope must be defined as:
read:public_key - provides read access to the user’s SSH keys
write:public_key - allows an app to read existing keys and create new ones
admin:public_key - enables an app to read, write, and delete keys

Related

Update IP status from Unused to Used Infoblox API

I am working on a script where I am creating VM and assigning available IP address to it given by concerned team. I need to integrate Infoblox API functionality with this
Once the IP is assigned,
I have to find the status of that particular IP address and
This part I got the request
https://url/wapi/v2.10.5/ipv4address?ip_address=10.1.0.0
Update the status of that IP from "Unused" to "Used".
Can you please help me with this. Need the API request to modify the status value against IP address
Sample API Response
[
{
"_ref": "ipv4address/Li5pcHY0X2FkZHJlc3MkMTAuMTI0LjExLjIvMA:10.1.1.2",
"ip_address": "10.1.1.2",
"is_conflict": false,
"mac_address": "",
"names": [],
"network": "10.1.1.0/7",
"network_view": "default",
"objects": [],
"status": "UNUSED",
"types": [],
"usage": []
}
]
I was trying a PUT request like below
``` https://url/wapi/v2.10.5/record:host/ZG5zLmhvc3QkLl9kZWZhdWx0LmNvbS5pbmZvLndhcGlhbGlhcw:10.124.11.2/default?_return_fields%2B=aliases&_return_as_object=1" -d '{"status": ["Used"]}'
```
but it is giving error
**{
"Error": "AdmConProtoError: Invalid value for _return_as_object: 1\" -d '{\"status\": [\"Used\"]}'",
"code": "Client.Ibap.Proto",
"text": "Invalid value for _return_as_object: 1\" -d '{\"status\": [\"Used\"]}'"
}**

Using REST API to create alerting rule in Kibana fails on 400 "Invalid action groups: default"

I have ELK cloud v. 7.13.2 and trying to create alert rule with slack action via REST API. This is my curl invocation:
curl -u ****** -s -H 'kbn-xsrf: true' -H 'Content-Type: application/json' https://***********.westeurope.azure.elastic-cloud.com:9243/api/alerting/rule -X POST -d #src/rules/cpu_utilization.json
I am expecting that new rule is created, but unfortunately I am getting following error:
{
"statusCode": 400,
"error": "Bad Request",
"message": "Invalid action groups: default"
}
The contents of src/rules/cpu_utilization.json are:
{
"params": {
"nodeType": "host",
"criteria": [
{
"comparator": ">",
"timeSize": 1,
"metric": "cpu",
"threshold": [
80
],
"timeUnit": "m"
}
],
"sourceId": "default"
},
"consumer": "alerts",
"schedule": {
"interval": "1m"
},
"tags": [],
"name": "CPU2",
"throttle": "1000d",
"enabled": true,
"rule_type_id": "metrics.alert.inventory.threshold",
"notify_when": "onThrottleInterval",
"actions": [
{
"group": "default",
"id": "fce4c27f-d22a-4209-858c-253a06511c1b",
"params": {
"message": "{{alertName}} - {{context.group}} is in a state of {{context.alertState}}\n\nReason:\n{{context.reason}}"
}
}
]
}
Documentation says clearly:
Properties of the action objects:
group
(Required, string) Grouping actions is recommended for escalations for different types of alerts. If you don’t need this, set this value to default.
Is this a bug in ELK or I am doing something wrong? I am able to use API for other purposes, like listing rules, deleting rules etc. I am also capable of creating a rule without an action, but this doen`t seem to be too useful...
OKAY, I got an answer from ELK support. Apparently, you can use another endpoint to list all rule types GET /api/alerting/rule_types. Then you need to find your type and lookup property default_action_group_id - it will hold the correct value. Eg. in the above example it was:
"default_action_group_id": "metrics.inventory_threshold.fired"

LinkedIn API :: how to obtain the bearer access token

It's not easy to use the official LinkedIn API and I cannot find a valid documentation.
Following the official documentation I created a new application in order to obtain the Client ID and Client Secret
When I now make a POST call through Postman to https://www.linkedin.com/oauth/v2/accessToken this is what I obtain:
{
"error": "invalid_grant_type",
"error_description": "The passed in grant_type is invalid"
}
Where am I wrong?
EDIT AFTER HELP FROM #Amit Singh
Thanks to #AmitSingh I was able to create 2 different applications, the test with the Client Credentials flow gave me as a result an error retrieving the token:
{
"error": "access_denied",
"error_description": "This application is not allowed to create application tokens"
}
When I try to use the LinkedIn 3-legged workflow I receive Unauthorized
EDIT 3: GETTING THERE THROUGH POSTMAN
I now see that I can ask Postman to do the job, however when I press on Get New Access Token it opens an error page. I believe the error might be in these 4 elements:
Token name: maybe I have to give a special token name?
Auth URL: I set https://www.getpostman.com/oauth2/callback as explained here but maybe I have to set something else?
Access Token URL: I left it blank, maybe I have to put something here?
State: I set a random string like Hello123Boy but maybe I have to put something else. Maybe is too long. Maybe is too short. Maybe it has to contain symbols, etc... ?
...Also, in the guide you linked it says that the applicatoin needs to have:
r_liteprofile
rw_company_admin
w_member_social
mine has nothing:
Being recently created is still under review. It says it can take up to 90 days. Is that true?
4th EDIT: I WANT TO BELIEVE!
Here we are, at least now I'm getting the error: Bummer, something went wrong. The redirect_uri does not match the registered value. This is amazing: finally an error that says where the problem is!
On the app the, on the Products tab, I choose Sign In with LinkedIn. As
Authorized redirect URLs for your app I set https://www.getpostman.com/oauth2/callback
In Postman I setup Auth URL and Access Token URL as you said:
LinkedIn Credential workflows
LinkedIn offers 2 different credential workflows.
LinkedIn 3-legged workflow - When you want to use an API that will access LinkedIn member's data. Authorization Code grant type needed.
LinkedIn Client Credentials flow - When you want to use an API that will access non-member resources. Client credentials grant needed.
What are grant types?
"Grant type" refers to how you have acquired an access token in an OAuth workflow.
Several grant types are supported. Some of them are:
Client Credentials - Used when you want to access your own resources and not any other users
Authorization Code - Used when an app wants to access a client's data
Refresh token - Exchange an expired access token for a valid access token, used to avoid repeated user involvement
Password - Used when there is high trust between the app and the user e.g. LinkedIn mobile app, you provide your username and password
Client Credentials flow
What you need to know
Grant type used here is Client credentials - client_credentials.
Remember to set your Content-Type to application/x-www-form-urlencoded for all POST requests in OAuth.
Steps
Create an App and get your Client ID and Client Secret. Steps are shown in the respective docs linked above. Let's say they have values - <client_id> and <client_secret>.
Send a POST required to https://www.linkedin.com/oauth/v2/accessToken with following information.
Parameters
grant_type : client_credentials
client_id : <client_id>
client_secret : <client_secret>
NOTE : client_credentials is the literal text to be entered for grant_type.
Response will return a JSON Object containing your access token and its expiry duration in seconds.
Response
{
"access_token" : <access_token>,
"expires_in" : "1800"
}
Use the <access_token> obtained in Step 2 make API requests.
Example
Request URL: https://www.linkedin.com/v2/jobs
Request type: GET
Parameters
Authorization: Bearer <access_token>
LinkedIn 3-legged workflow
What you need to know
Grant type will be Authorization code - code, since you want to access a user's data.
Your Content-Type should be application/x-www-form-urlencoded for all POST requests in OAuth.
Redirect URLs are URLs where you OAuth server will redirect the user after successful authorization.
These are verified against your provided redirect URLs to ensure that it's not fraudulent.
These should be absolute URLs.
URL arguments are ignored and cannot include a #.
Steps
Create app and provide the Redirect URLs, if not already provided. Check docs for information regarding how to do this.
Get your Client ID and Client Secret. Let's say the values are <client_id> and <client_secret>.
Generate a random, hard to guess string. Let's say it's <random-string>.
Choose one of the redirect URLs provided in Step 1, where you want user to be redirected after authorization. Let's say it is <redirect_uri>.
Let's suppose you want to:
r_emailaddress - Get his email address
w_member_social - Post, comment and like posts on behalf of the user.
These are referred as "permission scopes", as in what permissions is the user authenticating you for. When sending these scopes in your request, they should be URL-encoded and space-delimited. In this particular instance, our scope will be scope: r_emailaddress%20w_member_social. We have URL-encoded the scopes mentioned above.
Adding more information regarding scopes from the Microsoft docs:
The scopes available to your app depend on which Products or Partner Programs your app has access to. Your app's Auth tab will show current scopes available. You can apply for new Products under the Products tab. If approved, your app will have access to new scopes.
Send a POST request to https://www.linkedin.com/oauth/v2/authorization with following information.
Parameters
response_type : code
client_id : <client_id>
redirect_uri : <redirect_uri>
state : <random_string>
scope : r_emailaddress%20w_member_social
After the request, the user will be presented with LinkedIn's Auth screen and asked to approve the request.
After user approves the request and the <redirect_uri> has been verified, user will be redirected to provided <redirect_uri> along with the access code <access_code> and a value in state argument. Let's say in the state argument is <state_value>.
Verify that the <state_value> is equal to the <random_string> before working with the <access_code> to get access token, for security purposes. Also, use the <access_code> within 30 minutes of being issued, for security reasons.
Next, send a POST request to https://www.linkedin.com/oauth/v2/accessToken with following information to get the access token.
Parameters
grant_type : authorization_code
client_id : <client_id>
client_secret : <client_secret>
redirect_uri : <redirect_uri>
code : <access_code>
NOTE : authorization_code is the literal text to be passed in grant_type.
You should get a similar response as in the Client Credentials workflow containing your access token and expiry duration.
Response
{
"access_token" : <access_token>,
"expires_in" : "1800"
}
Use the <access_token> obtained in Step 9 make API requests.
Example
Request URL: `https://www.linkedin.com/v2/me`
Request type: GET
Parameters:
Authorization: Bearer <access_token>
How to do this in Postman?
Create a new Collection.
Right click, select edit collection and move to authorization tab.
In "Type", select "OAuth2.0", click on "Get New Access Token".
You will see a screen where all the familiar terms mentioned above are there. Fill those, check the "Authorize via Browser" checkbox for authorization.
Now you have the access token and can proceed to make your API calls.
Postman has been designed to make such operations easier, but you have to know how to do it. For more details, you can read their official docs.
Thanks to #timur and #AmitSingh I finally arrived to authenticate to LinkedIn API.
A brief step by step solution in pictures:
Authorized redirect URLs for your app = https://oauth.pstmn.io/v1/callback
OAuth 2.0 scopes = must have r_emailaddress and r_liteprofile
In the Products Tab set Sign In with LinkedIn
Now open Postman > Collections > New Collection > Authorization and set the parameters as in picture:
TYPE = OAUTH 2.0
Token Name = put whatever you want
Callback URL = https://oauth.pstmn.io/v1/callback (should be greyed out once you tick Authorize using browser)
Tick Authorize using browser
Auth URL = https://www.linkedin.com/oauth/v2/authorization
Access Token URL = https://www.linkedin.com/oauth/v2/accessToken
Client ID = The Client ID you find on your LinkedIn App
Client Secret = The Client Secret you find on your LinkedIn App
Scope = r_liteprofile r_emailaddress
State = put whatever you like
Now click on Get New Access Token, a page will open on your browser and you will be able to login using your LinkedIn account. Once done you are authenticated.
Now use the code provided by #timur and on Postman go to Import > Upload File and import that .JSON file. You will now have the 4 queries and you can drag and drop them in your collection.
Assuming you've created your app, added correct redirect URL and enabled "Sign In with LinkedIn" product for your app, the issue you are having is probably that the first call returns a login page where your users are supposed to authenticate.
submit the request to https://www.linkedin.com/oauth/v2/authorization (you seem to have done that)
parse response of step 1 and extract all form values, add username and password to simulate user login
make POST request and use values from previous step as x-www-form-urlencoded data
manually follow the redirect header from step 3
make note of second redirect header but do not follow it - instead extract the code
POST code from previous step to https://www.linkedin.com/oauth/v2/accessToken and get access_token in response
From here, I was able to successfully transition to the auth code by following the steps.
I am not sure if you use the online Postman, but here's my complete collection export file for reference:
{
"info": {
"_postman_id": "397761c9-4287-43f2-860a-3c34cb710d50",
"name": "Linkedin oAuth",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"item": [
{
"name": "01 request Login form",
"event": [
{
"listen": "test",
"script": {
"exec": [
"const $ = cheerio.load(pm.response.text());\r",
"var inputs = $('form').serializeArray();\r",
"var payload = '';\r",
"inputs.forEach(i => {\r",
" payload += encodeURIComponent(i.name)+ '=' + encodeURIComponent(i.value) + '&';\r",
"})\r",
"payload += 'session_key='+ encodeURIComponent(pm.collectionVariables.get('username')) + '&'\r",
"payload += 'session_password='+ encodeURIComponent(pm.collectionVariables.get('password'))\r",
"\r",
"pm.collectionVariables.set(\"form_data\", payload);"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "https://www.linkedin.com/oauth/v2/authorization?response_type=code&client_id={{client_id}}&redirect_uri={{redirect_uri}}&scope=r_liteprofile&state={{$guid}}",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"oauth",
"v2",
"authorization"
],
"query": [
{
"key": "response_type",
"value": "code"
},
{
"key": "client_id",
"value": "{{client_id}}"
},
{
"key": "redirect_uri",
"value": "{{redirect_uri}}"
},
{
"key": "scope",
"value": "r_liteprofile"
},
{
"key": "state",
"value": "{{$guid}}"
}
]
}
},
"response": []
},
{
"name": "02 Submit login form",
"event": [
{
"listen": "prerequest",
"script": {
"exec": [
""
],
"type": "text/javascript"
}
},
{
"listen": "test",
"script": {
"exec": [
"var url = 'https://www.linkedin.com'+ pm.response.headers.get(\"Location\");\r",
"pm.collectionVariables.set('first_redirect', url);\r",
"//console.log(pm.collectionVariables.get('first_redirect'));"
],
"type": "text/javascript"
}
}
],
"protocolProfileBehavior": {
"followRedirects": false
},
"request": {
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/x-www-form-urlencoded",
"type": "text"
}
],
"body": {
"mode": "raw",
"raw": "{{form_data}}",
"options": {
"raw": {
"language": "text"
}
}
},
"url": {
"raw": "https://www.linkedin.com/checkpoint/lg/login-submit",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"checkpoint",
"lg",
"login-submit"
]
}
},
"response": []
},
{
"name": "03 handle login-success redirect",
"event": [
{
"listen": "test",
"script": {
"exec": [
"var sdk = require('postman-collection');\r",
"var redirect = new sdk.Url(pm.response.headers.get(\"Location\"));\r",
"pm.collectionVariables.set('code', redirect.query.filter(q => q.key === 'code').map(k => k.value)[0]);\r",
"//console.log(pm.collectionVariables.get('code'));"
],
"type": "text/javascript"
}
},
{
"listen": "prerequest",
"script": {
"exec": [
"console.log(pm.variables.get('first_redirect'));\r",
"pm.request.url.update(pm.variables.get('first_redirect'));"
],
"type": "text/javascript"
}
}
],
"protocolProfileBehavior": {
"followRedirects": false
},
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{first_redirect}}",
"host": [
"{{first_redirect}}"
]
}
},
"response": []
},
{
"name": "04 Get Auth Code",
"request": {
"method": "POST",
"header": [],
"url": {
"raw": "https://www.linkedin.com/oauth/v2/accessToken?grant_type=authorization_code&code={{code}}&redirect_uri={{redirect_uri}}&client_id={{client_id}}&client_secret={{client_secret}}",
"protocol": "https",
"host": [
"www",
"linkedin",
"com"
],
"path": [
"oauth",
"v2",
"accessToken"
],
"query": [
{
"key": "grant_type",
"value": "authorization_code"
},
{
"key": "code",
"value": "{{code}}"
},
{
"key": "redirect_uri",
"value": "{{redirect_uri}}"
},
{
"key": "client_id",
"value": "{{client_id}}"
},
{
"key": "client_secret",
"value": "{{client_secret}}"
}
]
}
},
"response": []
}
],
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
""
]
}
}
],
"variable": [
{
"key": "client_id",
"value": "your app id"
},
{
"key": "client_secret",
"value": "your app secret"
},
{
"key": "redirect_uri",
"value": "your urlencoded redirect uri such as https%3A%2F%2Flocalhost%3A8080"
},
{
"key": "username",
"value": "user login"
},
{
"key": "password",
"value": "user password"
}
]
}

How can I use the BigQuery REST API from the command line?

Attempting to make a plain GET request to one of the BigQuery REST APIs gives an error that looks like this:
curl https://www.googleapis.com/bigquery/v2/projects/$PROJECT_ID/jobs/$JOBID
Output:
{
"error": {
"errors": [
{
"domain": "global",
"reason": "required",
"message": "Login Required",
"locationType": "header",
"location": "Authorization",
...
What is the correct way to invoke one of the REST APIs from the command-line, such as the query or insert APIs? The API reference has a "Try this API", but the examples don't translate directly to something you can run from the command-line.
As a disclaimer, when working from the command-line, using the bq tool will usually be sufficient, or for more complex use cases, the BigQuery client libraries enable programming with BigQuery from multiple languages. It can still be useful sometimes to make plain requests to the REST APIs to see how certain APIs work at a low level, however.
First, make sure that you have installed the Google Cloud SDK. This should include the gcloud and bq command-line tools. If you haven't already, authorize your account by running this command from your terminal:
gcloud auth login
This should prompt you to log in and then give you an access code that you can paste into your terminal. (The exact process may change over time).
Now let's try a query using the BigQuery REST API, calling the jobs.query method. Modify this script with your own project name, which you can find from the Google Cloud Console, then paste the script into your terminal:
PROJECT="YOUR_PROJECT_NAME"
QUERY="\"SELECT 1 AS x, 'foo' AS y;\""
REQUEST="{\"kind\":\"bigquery#queryRequest\",\"useLegacySql\":false,\"query\":$QUERY}"
echo $REQUEST | \
curl -X POST -d #- -H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://www.googleapis.com/bigquery/v2/projects/$PROJECT/queries
If it worked, you should see output that looks like this:
{
"kind": "bigquery#queryResponse",
"schema": {
"fields": [
{
"name": "x",
"type": "INTEGER",
"mode": "NULLABLE"
},
{
"name": "y",
"type": "STRING",
"mode": "NULLABLE"
}
]
},
"jobReference": {
"projectId": "<your project ID>",
"jobId": "<your job ID>"
},
"totalRows": "1",
"rows": [
{
"f": [
{
"v": "1"
},
{
"v": "foo"
}
]
}
],
"totalBytesProcessed": "0",
"jobComplete": true,
"cacheHit": false
}
If you haven't set up the bq command-line tool, you can use bq init from your terminal to do so. Once you have, you can try running the same query using it:
bq query --use_legacy_sql=False "SELECT 1 AS x, 'foo' AS y;"
You can also see the REST API requests that the bq tool makes by passing the --apilog= option:
bq --apilog= query --use_legacy_sql=False "SELECT [1, 2, 3] AS x;"
Now let's try an example using the jobs.insert method instead of the query API. Run this script, replacing YOUR_PROJECT_NAME with your project name:
PROJECT="YOUR_PROJECT_NAME"
QUERY="\"SELECT 1 AS x, 'foo' AS y;\""
REQUEST="{\"configuration\":{\"query\":{\"useLegacySql\":false,\"query\":${QUERY}}}}"
echo $REQUEST | \
curl -X POST -d #- -H "Content-Type: application/json" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://www.googleapis.com/bigquery/v2/projects/$PROJECT/jobs
Unlike the query API, which returned a response immediately, you will see a result that looks similar to this:
{
"kind": "bigquery#job",
"etag": "\"<etag string>\"",
"id": "<project name>:<job ID>",
"selfLink": "https://www.googleapis.com/bigquery/v2/projects/<project name>/jobs/<job ID>",
"jobReference": {
"projectId": "<project name>",
"jobId": "<job ID>"
},
"configuration": {
"query": {
"query": "SELECT 1 AS x, 'foo' AS y;",
"destinationTable": {
"projectId": "<project name>",
"datasetId": "<anonymous dataset>",
"tableId": "<anonymous table>"
},
"createDisposition": "CREATE_IF_NEEDED",
"writeDisposition": "WRITE_TRUNCATE",
"useLegacySql": false
}
},
"status": {
"state": "RUNNING"
},
"statistics": {
"creationTime": "<timestamp millis>",
"startTime": "<timestamp millis>"
},
"user_email": "<your email address>"
}
Notice the status:
"status": {
"state": "RUNNING"
},
If you want to check on the job now, you can use the jobs.get method. Similar to before, run this from your terminal, using the job ID from the output in the previous step:
PROJECT="YOUR_PROJECT_NAME"
JOB_ID="YOUR_JOB_ID"
curl -H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://www.googleapis.com/bigquery/v2/projects/$PROJECT/jobs/$JOB_ID
If the query is done, you'll get a response that indicates as much:
...
"status": {
"state": "DONE"
},
...
Finally, we can make a request to fetch the query results, also using the REST API.
curl -H "Authorization: Bearer $(gcloud auth print-access-token)" \
https://www.googleapis.com/bigquery/v2/projects/$PROJECT/queries/$JOB_ID
The output will look similar to when we used the jobs.query method above:
{
"kind": "bigquery#getQueryResultsResponse",
"etag": "\"<etag string>\"",
"schema": {
"fields": [
{
"name": "x",
"type": "INTEGER",
"mode": "NULLABLE"
},
{
"name": "y",
"type": "STRING",
"mode": "NULLABLE"
}
]
},
"jobReference": {
"projectId": "<project ID>",
"jobId": "<job ID>"
},
"totalRows": "1",
"rows": [
{
"f": [
{
"v": "1"
},
{
"v": "foo"
}
]
}
],
"totalBytesProcessed": "0",
"jobComplete": true,
"cacheHit": true
}

Zendesk API - Creating a ticket gives wrong ticket status

Zendesk API documentation states that when creating a ticket through the API, the status field can be set to "new" (https://developer.zendesk.com/rest_api/docs/core/tickets#create-ticket), yet if I call the API with the following command specifying a value for status, it creates a token yet still sets status to be the default value of open:
curl -u <username>/token:<api_token> https://<subdomain>.zendesk.com/api/v2/tickets.json -d '{"ticket": {"subject":"test subject", "comment": { "body": "test body" }, "status": "new" } }' -H "Content-Type: application/json" -v POST
The relevant part of the response body is:
"ticket": {
"url": "https://<subdomain>.zendesk.com/api/v2/tickets/60.json",
"id": 60,
"external_id": null,
"via": {
"channel": "api",
"source": {
"from": {},
"to": {},
"rel": null
}
},
"created_at": "2016-05-05T13:30:01Z",
"updated_at": "2016-05-05T13:30:01Z",
"type": null,
"subject": "test subject",
"raw_subject": "test subject",
"description": "test body",
"priority": null,
"status": "open",
"recipient": null,
"requester_id": 5917202647,
"submitter_id": 5917202647,
"assignee_id": 5917202647,
"organization_id": 3740197137,
"group_id": 28473587,
"collaborator_ids": [],
"forum_topic_id": null,
"problem_id": null,
"has_incidents": false,
"due_at": null,
"tags": [],
"custom_fields": [],
"satisfaction_rating": null,
"sharing_agreement_ids": [],
"fields": [],
"brand_id": 1090897,
"allow_channelback": false
}
Am I doing something wrong?
So it turns out that if you assign a ticket to a group with only one member/agent, the ticket automatically gets assigned to that lone agent. As such, any ticket that's already assigned to a specific agent, is automatically set to open instead of new.
Because I was using a test subdomain, I was the only agent and so it was auto-updating the status from "new" to "open".
Hmm, I made the same API call (with my creds/subdomain) and it worked, setting the "status" to any option I choose (new, pending, solved).
Have you confirmed that all your credentials and subdomain are correctly inputted? Also, check the API settings in your Zendesk account. Try creating a new token and Save the settings.
If the API token still doesn't work, maybe try authenticating with password or making the request by means other than curl.