Validating barcode scans in real-time

What is a Validation URL?

A Validation URL allows your system to inspect data entered from the Orca Scan mobile app before it is saved to your sheet. This not only allows you to reject invalid data, but also modify the data or provide meaningful feedback to the user about how to resolve an issue.

Quick example

Suppose a user scans a QR Code containing an email address and enters some data. Orca Scan will HTTP POST the following JSON payload to your Validation URL:

{
    "___orca_sheet_name": "Vehicle Checks",
    "___orca_user_email": "hidden@requires.https",
    "barcode": "hello@orcascan.com",
    "notes": "Something important!"
}

If your system responds with a JSON object containing a title and message in the following format:

{
    "title": "Try again",
    "message": "Please provide more information"
}

That message will be present to the user within the app, preventing them from saving until the issue(s) are resolved.

We'll present this message to your users within the app
We'll present this message to your users within the app

Issues are considered resolved when your Validation URL returns an HTTP 200 response with no body. At that point, changes are applied to your sheet and the user is able to progress to the next task.

HTTP Headers

The following HTTP headers are sent with every request:

Parameter Description
orca-request-type validation
orca-secret Sheet assigned secret (check this to verify request)
orca-sheet-id Unique ID of the Orca Scan sheet
orca-sheet-name The name of the sheet making the request
orca-timestamp UNIX epoch time of the request
orca-user-email Email of user who triggered the request (requires HTTPS)

How do I create a Validation URL?

You need to create an endpoint in your systems that accepts POST request. Once configured you will be able to control accept or reject data depending on your code. Check out the following example snippets.

Node.js C# Go Python PHP Java
const app = express(); app.use(express.json()); app.post('/', function(request, response){ data = request.body; // dubug purpose: show in console raw data received console.log("Request received: \n"+JSON.stringify(data, null, 2)); // orca system fields start with ___ // access the value of fields using field name // example: data.Name, data.Barcode, data.Location const name = data.Name // validation example if (name.length > 20) { // return error message to show user response.json({ "title": "Invalid Name", "message": "Name cannot contain more than 20 characters", }).send(); return; } // return HTTP Status 204 (no content) response.status(204).send(); }); app.listen(3000, () => console.log('Example app is listening on port 3000.'));
[ApiController] [Route("/")] public class OrcaValidationDotNet : ControllerBase { [HttpPost] [Consumes("application/json")] public async Task<ActionResult> validationReceiver() { using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8)) { // get the raw JSON string string json = await reader.ReadToEndAsync(); // convert into .net object dynamic data = JObject.Parse(json); // orca system fields start with ___ // access the value of fields using field name // example: data.Name, data.Barcode, data.Location string name = (data.Name != null) ? (string) data.Name : ""; // validation example if (name.Length > 20) { // return error message to show user return Ok(new { title = "Name is too long", message = "Name cannot contain more than 20 characters" }); } } // return HTTP Status 204 (no content) return NoContent(); } }
func validationHandler(w http.ResponseWriter, r *http.Request) { // Read body body, err := ioutil.ReadAll(r.Body) defer r.Body.Close() if err != nil { fmt.Println(err) http.Error(w, err.Error(), 500) return } // Parse JSON data var barcode OrcaBarcode jsonErr := json.Unmarshal([]byte(body), &barcode) if jsonErr != nil { fmt.Println(jsonErr) http.Error(w, jsonErr.Error(), 500) return } // dubug purpose: show in console raw data received fmt.Println(barcode) // orca system fields start with ___ // access the value of fields using field name // example: data.Name, data.Barcode, data.Location name := barcode.Name // validation example if (len(name) > 20) { // return error message to show user w.Write([]byte(`{ "title": "Invalid Name", "message": "Name must be less than 20 characters"} `)) return } // return HTTP Status 204 (no content) w.WriteHeader(204) }
@app.route('/', methods=['POST']) def orca_validation(): if request.method == 'POST': data = request.get_json() # dubug purpose: show in console raw data received print("Request received: \n"+json.dumps(data, sort_keys=True, indent=4)) # orca system fields start with ___ # access the value of fields using field name # example: data["Barcode"], data["Location"] name = data["Name"] # validation example if(len(name) > 20): # return error message to show user return json.dumps({ "title": "Invalid Name", "message": "Name cannot contain more than 20 characters", }) # return HTTP Status 204 (no content) return '', 204
if (preg_match('/$/', $_SERVER["REQUEST_URI"])) { if ($_SERVER['REQUEST_METHOD'] === 'POST') { $data = json_decode(file_get_contents('php://input'), true); // orca system fields start with ___ // access the value of fields using field name // example: data.Name, data.Barcode, data.Location $name = $data["Name"]; // validation example if (strlen($name) < 20) { // return error message to show user echo json_encode(array( "title" => "Invalid Name", "message" => "Name cannot contain more than 20 characters" )); exit; } // return HTTP Status 204 (No Content) http_response_code(204); exit; } }
@RequestMapping( value = "/", method = RequestMethod.POST) String index(@RequestBody Map<String, Object> data) throws Exception { // dubug purpose: show in console raw data received System.out.println(data); // orca system fields start with ___ // access the value of fields using field name // example: data.get("Barcode"), data.get("Location") String name = data.get("Name").toString(); // validation example if (name.length() > 20) { // return error message to show user JSONObject json = new JSONObject(); json.put("title", "Invalid Name"); json.put("message", "Name cannot contain more than 20 characters"); return json.toJSONString(); } // return HTTP Status 204 (no content) return ""; }

A fully working version for all programming languages can be found on GitHub.


How do I add a Validation URL to my sheet?

1. Edit Sheet Integrations

Click on the 'integrations' button at the top of the sheet
Click on the 'integrations' button at the top of the sheet

A Validation URL can only be set on sheets created at cloud.orcascan.com. To add a Validation URL, select the sheet you would like to validate, then open the Integration Settings.


2. Add your Validation URL

Enter the Validation URL you'd like Orca Scan to integrate with
Enter the Validation URL you'd like Orca Scan to integrate with

Now enter the Validation URL you would like Orca Scan to call as items are updated. Please note: this URL must be publicly accessible.

Security

You can provide a secret that will be sent to your server as an HTTP header with every request, allowing you to determine if the incoming request is from Orca Scan.


3. Test your Validation URL

Test your validation, if it works then you'll receive a 'passed' message
Test your validation, if it works then you'll receive a 'passed' message

You can now test the Validation URL by clicking the Test button. This will HTTP POST a JSON object to your server containing randomly generated data and display the result.

To test an error, simply have your endpoint return a JSON object containing a title and message and hit test again.

To test an error, have your endpoint return a JSON object containing a title and message and test again
To test an error, have your endpoint return a JSON object containing a title and message and test again

4. Save the changes

Finally, save the changes and you’re done. You can now select that sheet in the Orca Scan mobile app and test it.


Validation URL questions?

We’re happy to help you get up and running, chat with us live or drop us an email.


Ready to start scanning?