DeveloperRegister an app
Menu

Connect

Six steps from a new app to a verified webhook. See Authentication for the OAuth2 details.

1. Register an app

Register an app in the developer portal. A sandbox app works at once, against sandbox companies only.

A production app is available after the partner review. You note the client ID, and for a confidential client the secret, which is shown once.

Register an app

You should see: A client ID, and the redirect URIs and scopes you registered.

2. Send a company to Connect

Put a Connect Sparro button in your app. It opens the Connect URL below with your client ID in the path. The person signs in or creates an account, picks a company and approves the scopes you ask for. Only an owner of the company can approve.

Public clients must send a PKCE code_challenge with code_challenge_method=S256. Any other query parameter is ignored.

The browser comes back to your redirect_uri with a code and your state. Check the state before you use the code.

url
https://app.sparro.dk/connect/<client_id>
  ?redirect_uri=https://app.example.com/sparro/callback
  &scope=shifts:read shifts:write
  &state=<random>
  &code_challenge=<pkce>
  &code_challenge_method=S256

You should see: Your redirect_uri receives ?code=…&state=… after the owner approves.

3. Exchange the code for tokens

Post the code to the token endpoint from your server. For a public client, send the code_verifier that matches your code_challenge instead of a secret.

curl
curl -X POST "https://app.sparro.dk/api/v2/oauth/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET&code=$CODE&redirect_uri=$REDIRECT_URI"

You should see: An access_token, a refresh_token and the scope that was granted. The access token lasts one hour.

4. Read with the access token

Call a read endpoint with the token as a bearer credential. The shifts list also gives you employee_ref values: an employee is only ever an opaque reference, and it is different for every app.

An employee with no shift or mileage record yet has no reference to read.

curl
curl -X GET "https://app.sparro.dk/api/v2/shifts?limit=100" \
  -H "Authorization: Bearer $SPARRO_ACCESS_TOKEN"

You should see: A shifts array and a next_cursor. Each shift has an employee_ref.

5. Write with an Idempotency-Key

Every write needs an Idempotency-Key header. Send a new random UUID for each logical operation and reuse it only to retry that operation.

Send the same request again with the same key and you get the first response back with Idempotent-Replayed: true, and no second record.

curl
curl -X POST "https://app.sparro.dk/api/v2/shifts" \
  -H "Authorization: Bearer $SPARRO_ACCESS_TOKEN" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{"employee_ref":"emp_Qm9hcmRFeGFtcGxlUmVmZXJlbmNlS2V5Rm9yRG9jc09","start_time":"2026-11-02T08:00:00+01:00","end_time":"2026-11-02T16:00:00+01:00","break_minutes":30}'

You should see: 201 with the new shift. The repeat answers 201 with the same body and Idempotent-Replayed: true.

6. Verify a webhook signature

Create an endpoint in the developer portal and keep its signing secret on your server. Every delivery carries a Sparro-Signature header. Check it against the test vector on the Webhooks page before you go live.

pseudocode
t, v1  = parse(request.headers["Sparro-Signature"])
signed = t + "." + request.raw_body
expect = hex(HMAC_SHA256(signing_secret, signed))
valid  = constant_time_equal(expect, v1)
         and abs(now() - t) <= 300

You should see: Your verifier accepts the test vector and rejects the same body with one character changed.

Next: Scopes, Webhooks and Errors.