Quickstart
Send one delivery to Norra and read the receipt. It takes about two minutes.
Before you start
You need a company in Norra, and the sources.manage and connections.manage permissions on it. You also need BankID, because you sign the new connection with it.
To try a call first, use Test Request in the API reference. It sends real requests to the demo deployment with the demo connection. It also sends them to your own sandbox with a sandbox connection's credential that you paste in.
1. Add a source
A source is one system that sends numbers to Norra. Open the company in the app, go to Sources, and fill in Add a source:
- Give it a name, for example
Billing system. - Say what kind of system it is, for example
app. - Choose Push as the way it delivers.
- List the fields it sends:
periodas a Timestamp, andrevenueandactive_usersas a Number. - Choose
periodas the Event time. A metric over the source reads each row's day from it. - Keep Events as what each delivery is. Each delivery then adds to the last. The connectors guide says when to choose Statements instead.
Save it with Add the source. The fields are the source's shape. Each save is a new shape version, and the first is version 1.
2. Make a connection that may write
Go to the company's Developer page. Under Make a connection:
- Pick the source.
- Choose Write as what the connection may do.
- Leave Client id and secret chosen as how it signs in.
- Tick Sandbox while you try things out. What a sandbox connection sends is marked test and reaches no report.
Select Make the connection. The new connection waits in To sign until you sign it with BankID. Sign it now from the sheet that opens, or later in To sign.
When you sign, Norra makes the secret. To sign shows the secret once, in the sign result. The Developer page shows the client id and the token URL. Copy all three into your secret store now.
3. Get a token
export NORRA_CLIENT_ID="paste the client id here"
export NORRA_CLIENT_SECRET="paste the secret here"
curl https://app.norra-co.com/oauth/token \
--request POST \
--user "$NORRA_CLIENT_ID:$NORRA_CLIENT_SECRET" \
--data grant_type=client_credentialsThe answer's access_token lasts an hour. Copy it:
export NORRA_TOKEN="paste the access_token here"4. Send one delivery
curl https://app.norra-co.com/v1/ingest \
--request POST \
--header "Authorization: Bearer $NORRA_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"idempotency_key": "2026-09",
"shape_version": 1,
"payload": {
"period": "2026-09-01T00:00:00+02:00",
"revenue": "4201000",
"active_users": "1200"
}
}'The idempotency key is your own name for the delivery. Sending the same one again with the same body returns the same receipt and stores nothing twice, so a retry is safe. The same key with a different body is refused with 409 and the code key_reused. A key that starts with norra: is Norra's own and is refused with 400.
Values are strings. An amount is an exact decimal, and a string keeps a JSON parser from reading it as a float.
A timestamp is a date, a time and an offset from UTC, as in RFC 3339. Norra reads a date alone, such as 2026-09-01, as midnight on that day in the company's timezone. This suits a source that sends one total per day:
curl https://app.norra-co.com/v1/ingest \
--request POST \
--header "Authorization: Bearer $NORRA_TOKEN" \
--header "Content-Type: application/json" \
--data '{
"idempotency_key": "2026-09-02",
"shape_version": 1,
"payload": {
"period": "2026-09-02",
"revenue": "3900000",
"active_users": "1180"
}
}'The Developer page then says how many rows gave a date alone and which timezone they were read in. A time with no offset, such as 2026-09-02T10:00:00, names no moment and the row is refused.
5. Read the receipt
202 Accepted means the delivery is stored:
{
"artifact_id": "0199c1f4-6b3a-7c21-9f10-2a5b4c6d8e90",
"delivers": "events",
"dropped_keys": [],
"sandbox": true,
"shape_version": 1,
"status": "queued"
}artifact_idnames what was stored. Keep it. It is what you cite when you ask why a number in a report is what it is.statusisqueued. The delivery is parsed after it is stored.sandboxistruefor a sandbox connection.dropped_keyslists the keys you sent that the source does not declare. They were not stored. Add them to the source's fields if you want them kept.deliversiseventsorstatements, as the source was declared. An events delivery adds to what came before. A statement replaces what earlier deliveries said about the periods it has rows in.
The Developer page shows when the source last received a delivery, when it last parsed one, and the last error if there was one. A row that does not fit the source's fields is refused when the delivery is parsed, after the 202. The page then says how many rows of the last delivery were refused, and what to send instead.
Next
- Connections and permissions for renewing tokens, static keys for devices, reading, expiry and rotation.
- Errors and retries for what each status means and when to send again.
- The API reference for every field.