Supply Lens

File Drop Service

The complete reference for sending a file to Supply Lens through the File Drop Service, from getting an access token to the request forms, document type values, responses and error codes.

The File Drop Service lets you send a file to Supply Lens. Supply Lens keeps the file as source data for one of your Integrations, then converts it into a Document automatically, using that Integration's Configuration.

There's one endpoint with two request forms. Both use the same URL; the request's Content-Type header picks the form.

FormContent typeUse it when
JSON formapplication/jsonThe file is a JSON value.
Multipart formmultipart/form-dataThe file is another format (CSV, XML, EDI, text), or you need to keep the file name.

What you need

Your Supply Lens contact gives you these.

ItemWhat it is
Client IDThe identifier of your API client.
Client secretThe password of your API client. Keep it secret, and don't put it in source control.
Organisation IDThe GUID of your Supply Lens organisation, for example 3fa85f64-5717-4562-b3fc-2c963f66afa6.
Integration type IDThe identifier of a type of Integration (not of one Integration), in lowercase, for example despatch-cloud. Supply Lens uses it to find the Integration of that type in your organisation.
Document typeThe type of Document in the file, for example order. See the document type values below.

Supply Lens must also:

  1. Enable the File Drop Service for the Integration type.
  2. Install one Integration of that type in your organisation.
  3. Enable that Integration.
  4. Configure that Integration to convert each document type you send.

Only one enabled Integration of the type

If your organisation has two or more enabled Integrations of the type, the file is rejected. A disabled or uninstalled Integration doesn't count.

Conversion isn't checked up front

The File Drop Service doesn't check step 4. If the Integration can't convert the document type, the file is accepted but the conversion fails.

Addresses

All addresses are for production.

ServiceAddress
Authentication Servicehttps://id.supplylens.co.uk
File Drop Servicehttps://filedrop.supplylens.co.uk

The Authentication Service publishes its configuration at https://id.supplylens.co.uk/.well-known/openid-configuration.

Step 1: get an access token

The File Drop Service only accepts an access token from the Supply Lens Authentication Service. Get one with the OAuth 2.0 client credentials grant.

Request: POST https://id.supplylens.co.uk/connect/token with the header Content-Type: application/x-www-form-urlencoded.

Body valueRequiredValueEffect
grant_typeYesclient_credentialsSelects the client credentials grant.
client_idYesYour client ID.Identifies your API client.
client_secretYesYour client secret.Proves the request comes from your API client.
  • Don't send scope. The token automatically gets every scope Supply Lens gave your client, including file_drop:write.
  • URL-encode each value. A secret can contain +, /, = or &, and the request fails if these aren't encoded.
  • Read access_token from the response.
curl -s https://id.supplylens.co.uk/connect/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "grant_type=client_credentials" \
  --data-urlencode "client_id=<client_id>" \
  --data-urlencode "client_secret=<client_secret>"

You can send the client ID and secret with HTTP Basic authentication instead. If you do, leave client_id and client_secret out of the body.

curl -s https://id.supplylens.co.uk/connect/token \
  -u "<client_id>:<client_secret>" \
  --data-urlencode "grant_type=client_credentials"

The token response

A correct request returns 200 OK:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6...",
  "expires_in": 3600,
  "token_type": "Bearer",
  "scope": "file_drop:write organisations:read"
}
FieldWhat it is
access_tokenThe token. Send it in the Authorization header of each File Drop request.
expires_inSeconds until the token expires. Currently 3600 (one hour), but use the value in the response rather than assuming 3600.
token_typeAlways Bearer.
scopeThe scopes in the token.

Reuse the token until it expires; don't get a new one for each file. Get a new token when the File Drop Service returns 401 Unauthorized, or before expires_in runs out. A wrong client ID or secret returns 400 Bad Request with "error": "invalid_client".

What the token must contain

The token is a JSON Web Token (JWT). You don't need to read it, but if a request fails, check these claims.

ClaimMust contain
audintegrations
scopefile_drop:write
organisationIdYour organisation ID. There's one organisationId claim for each organisation your client can send files to.

Step 2: send a file

Endpoint: POST https://filedrop.supplylens.co.uk/{integrationTypeId}/{organisationId} with the header Authorization: Bearer <access_token>.

Path valueRequiredEffect
integrationTypeIdYesThe Integration type ID. Supply Lens finds the one enabled Integration of this type in the organisation, and that Integration receives and converts the file. Case-sensitive.
organisationIdYesThe organisation that receives the file. Must be a GUID, must match one of the organisationId claims in your token, and the organisation must have an active subscription.

JSON form

Send the file as the request body, with Content-Type: application/json, and the other values in the query string. The body can be any JSON value (an object, an array or a single value) and is required: an empty body causes a validation error.

Query valueRequiredEffect
typeYesThe document type of the file.
referenceYesThe reference users see for the file in Supply Lens. Also used to make the file name if you don't send fileName.
idNoYour identifier for the file. Kept as the file's external ID and used to find duplicates.
fileNameNoThe file's name in Supply Lens. Without it, the name is <reference>.json.

Supply Lens stores the JSON with indentation and the content type application/json. The formatting changes; the data doesn't. URL-encode each query value: a value containing &, #, + or a space otherwise changes the query string.

curl -si "https://filedrop.supplylens.co.uk/<integration_type_id>/<organisation_id>?type=order&reference=PO-10001&id=PO-10001" \
  -H "Authorization: Bearer <access_token>" \
  -H "Content-Type: application/json" \
  --data-binary @order.json

Multipart form

Send every value as a part of a multipart/form-data body. Let your HTTP client set the Content-Type header, because it must include the boundary.

Form partRequiredEffect
fileYesThe file. The part must have a file name (filename in its Content-Disposition). Supply Lens keeps the file name and this part's content type.
typeYesThe document type of the file.
referenceNoThe reference users see. Without it, the file name is used.
idNoYour identifier for the file. Kept as the file's external ID and used to find duplicates.

Send one file per request. Values in the query string are ignored: the multipart form only reads form parts. Set the file part's content type correctly, because Supply Lens keeps it with the file.

curl -si "https://filedrop.supplylens.co.uk/<integration_type_id>/<organisation_id>" \
  -H "Authorization: Bearer <access_token>" \
  -F "type=order" \
  -F "reference=PO-10001" \
  -F "id=PO-10001" \
  -F "file=@PO-10001.csv;type=text/csv"

How id, reference and the file name are used

ValueIf you send itIf you don't
idKept as the file's external ID and used to find duplicates.No duplicate check. The external ID is the file name.
referenceUsers see it in Supply Lens.Users see the file name. (The JSON form always requires reference.)
File nameThe file's name in Supply Lens. In the JSON form it comes from fileName, or else from reference; in the multipart form, from the file part.Not applicable: the file name is always set.

Duplicate rules:

  1. If you send id, it's compared with the external IDs of files the same Integration received before, for the same document type.
  2. The comparison covers all the Integration's files, including those received another way and those sent without id (whose external ID is their file name).
  3. If the same external ID is found, the file is rejected with 400 Bad Request and isn't kept.
  4. If you don't send id, there's no duplicate check: the file is kept and converted every time you send it.

Always send a stable id

Send a unique, stable id for each file, such as your order number. Then if you resend after a timeout or network error, you won't get a second Document.

Size limit

A request can be at most 1 MB (1,048,576 bytes). The limit covers the whole request body; for the multipart form that includes the boundaries and every part. Larger requests get 413 Request Entity Too Large.

Document type values

Send one of these in type, and only a type Supply Lens has configured your Integration for. Supply Lens tells you which types your Integration accepts. Values are case-sensitive and lowercase.

ValueDocument
orderSales order
order-changeChange to a sales order
order-acknowledgementOrder acknowledgement
purchase-orderPurchase order
warehouse-orderWarehouse order
shipmentShipment or despatch advice
warehouse-shipmentWarehouse shipment
goods-inboundAdvice of goods that will arrive
goods-inbound-receiptReceipt of goods that arrived
proof-of-deliveryProof of delivery
invoiceSales invoice
creditSales credit note
debit-noteDebit note
purchase-invoicePurchase invoice
purchase-creditPurchase credit note
payment-requestPayment request
payment-confirmationPayment confirmation
remittanceRemittance advice
statementStatement
bank-transactionBank transaction
journalJournal
quoteQuote
inventoryInventory levels
inventory-reportInventory report
stock-adjustmentStock adjustment
warehouse-transferWarehouse transfer
pickPick
work-orderWork order
product-updateProduct update
customer-updateCustomer update
sales-reportSales report
functional-acknowledgementFunctional acknowledgement
customCustom file

Responses

Success

An accepted file returns 201 Created, with a Location header giving the file's address in the Supply Lens app (https://app.supplylens.co.uk/org/<organisation_id>/data/source/<id>) and this body:

{
  "id": "6710c2f4a1b2c3d4e5f60789"
}

id is the Supply Lens identifier of the source data. Keep it, and give it to Supply Lens support if there's a problem with the file.

201 Created means Supply Lens has kept the file. It doesn't mean the conversion is complete or correct: users see the result of the conversion in the Supply Lens app.

Errors

A rejected request returns a problem body (application/problem+json), with the cause in detail:

{
  "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
  "title": "Bad Request",
  "status": 400,
  "detail": "The integration type does not support file drop"
}
StatusDetail or causeWhat to do
400Incorrect integration type "<integrationTypeId>"The organisation has no enabled, installed Integration of this type, or the value is wrong (it's case-sensitive). Check integrationTypeId, then speak to Supply Lens.
400The integration type does not support file dropThe File Drop Service isn't enabled for this Integration type. Speak to Supply Lens.
400Too many integrations of type "<integrationTypeId>", please contact supportThe organisation has two or more enabled Integrations of this type. Speak to Supply Lens.
400The file <id> is a duplicateThe Integration has already received a file with this external ID. Don't send it again.
400There was a problem saving the file, if this continues please contact supportSupply Lens didn't keep the file. Send it again; if the error repeats, speak to Supply Lens.
400A validation problem with an errors objectA required value is missing or invalid. The errors object names it.
401No bodyThe token is missing, expired or invalid. Get a new token.
403No bodyThe token lacks the file_drop:write scope, wasn't issued for organisationId, or the organisation has no active subscription. Check the token claims.
404No bodyThe URL is wrong. Check it has both path values and that organisationId is a GUID.
413An HTML pageThe request is over the 1 MB size limit.
415NoneThe Content-Type header isn't application/json or multipart/form-data.
500Invalid document type <type>The type value isn't a known document type. It's case-sensitive; use a value from the list above.

An unknown type returns 500

At the moment an unknown type causes 500, not 400. Don't resend the request unchanged: correct the type first.

Checklist for a failed request

  1. You're using the production addresses.
  2. The Authorization header is Bearer <access_token>, with one space.
  3. The token hasn't expired (it's valid for expires_in seconds).
  4. The token has the file_drop:write scope and your organisationId claim.
  5. The organisationId in the URL matches the claim in the token.
  6. integrationTypeId is the value Supply Lens gave you, in lowercase.
  7. type is a lowercase value from the document type list.
  8. JSON form: type and reference are in the query string, and the body is JSON.
  9. Multipart form: type and file are form parts, and the file part has a file name.
  10. The request is no larger than 1 MB.
  11. You haven't sent the same id before.