Receive in real time the creations, modifications and deletions of media and References, instead of polling the API.
A webhook is a URL of your system that Grand Shooting calls when something changes in the account: a media uploaded, approved, retagged, a Reference imported… Your integration reacts within seconds, without spending its API quota checking for news.
A subscription links a URL to a topic:
| Topic | Triggered when |
|---|---|
pictures/create | a media is created (upload, export…) |
pictures/update | a media is modified (status, tags, new version, Reference, View code…) |
pictures/delete | a media is deleted |
references/create | a Reference is created |
references/update | a Reference is modified |
references/delete | a Reference is deleted |
Events are generic: there is no "media approved" topic. To process only approved media, subscribe to pictures/update and filter on picturestatus in the message.
From the account administration, Team > API menu, WebHooks section (account administrators), or with the API:
curl -X POST -H "Authorization: Bearer $GS_TOKEN" -H "Content-Type: application/json" \
-d '{"address":"https://myapp.example/gs/webhook-7f3a9c","topic":"pictures/update"}' \
https://api.grand-shooting.com/v3/webhook
One subscription = one URL + one topic: to follow several topics, create one subscription per topic (the same URL can be used for all of them). GET /webhook lists the subscriptions of the account, PUT /webhook/{webhook_id} modifies one, DELETE /webhook/{webhook_id} deletes it.
The address is stored in lower case. If your URL contains a token or a case-sensitive path, choose it in lower case.
A new subscription receives its first events within a minute.
Grand Shooting sends a JSON POST. Events are grouped: a message holds up to 100 objects of the same account and the same topic, and directly contains their full state (the same as GET /picture/{id} or GET /reference/{id}):
{
"account_id": 10229487,
"topic": "pictures/update",
"type": "picture",
"ids": [175, 176],
"data": {
"175": { "picture_id": 175, "bench_root_id": 19, "picturestatus": 50, "ref": "SS26-DRESS-110", "…": "…" },
"176": { "picture_id": 176, "bench_root_id": 19, "picturestatus": 40, "ref": "SS26-DRESS-110", "…": "…" }
}
}
type is picture or reference; ids lists the objects concerned.data gives the state of each object when the message is sent (so it can be more recent than the event itself). For a deleted or unreadable object, the value is null.picture_id (or reference_id) field, a copy of ids, is deprecated and will be removed: use ids.update can arrive without any visible change. Handle each message as the current state of the object, not as a difference.account_id is an expected account, and for sensitive actions read the object again through the authenticated API from ids rather than trusting data.GET /picture?date_mod=gte:…) fills any gaps.Example of a receiver (Node.js / Express):
app.post('/gs/webhook-7f3a9c', express.json({ limit: '20mb' }), (req, res) => {
const { account_id, topic, ids } = req.body;
if (!EXPECTED_ACCOUNTS.has(account_id)) return res.sendStatus(403);
res.sendStatus(200); // answer before processing
queue.push({ account_id, topic, ids });
});
There is no test event. To try your receiver, modify a media or a Reference of the account (a tag is enough): the message arrives within seconds.