Getting started
Send shipments to your shipping company straight from your store, ERP or website, and know the moment their status changes.
# What you need
Ask your shipping company for:
Example
API address
https://your-company.com:8443/graphql
Username and password of your customer account
store@example.com
# How requests work
Every request is a POST to that one address, with a JSON body. The body says what you want to do (query) and the values you send (variables). The API uses GraphQL , but you don't need to know it: copy the examples in this guide.
curl https://your-company.com:8443 /graphql \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_TOKEN" \
-d '{
"query": "query ($code: String) { shipment(code: $code) { code status { name } } }",
"variables": { "code": "A12345" }
}' {
"data" : {
"shipment" : { "code" : "A12345" , "status" : { "name" : "Out To Deliver" } }
}
}
The answer is always JSON. You get back exactly the fields you asked for.
Header
Value
Content-Type
application/json
Required
Authorization
Bearer YOUR_TOKEN
Required, except to log in
Content-Language
en or ar, the language of status and zone names
Optional
Postman and Insomnia make testing easy: choose GraphQL as the body type, then paste the query and the variables from this guide.
Authentication
Log in once with your username and password to get a token , then send that token with every request.
# Log in
Query Variables Response cURL JavaScript PHP
Copy mutation Login($input : LoginInput!) {
login(input: $input ) {
token
}
}{
"input" : {
"username" : "store@example.com" ,
"password" : "your-password"
}
}{
"data" : {
"login" : { "token" : "3|kD8f2...x91" }
}
}curl https://your-company.com:8443 /graphql \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ($input: LoginInput!) { login(input: $input) { token } }",
"variables": { "input": { "username": "store@example.com", "password": "your-password" } }
}' const response = await fetch("https://your-company.com:8443/graphql" , {
method: "POST" ,
headers: { "Content-Type" : "application/json" },
body: JSON.stringify({
query: "mutation ($input: LoginInput!) { login(input: $input) { token } }" ,
variables: { input: { username: "store@example.com" , password: "your-password" } },
}),
});
const { data } = await response.json();
const token = data.login.token;$response = Http::post('https://your-company.com:8443/graphql' , [
'query' => 'mutation ($input: LoginInput!) { login(input: $input) { token } }' ,
'variables' => ['input' => ['username' => 'store@example.com' , 'password' => 'your-password' ]],
]);
$token = $response ->json('data.login.token' );
# Use the token
Send it in the Authorization header of every request, after Bearer :
Text Copy
Authorization: Bearer 3 |kD8f2...x91
Keep the token on your server , like a password. Reuse it: log in again only when a request answers Unauthenticated.
Create a shipment
A shipment needs three ids : the shipping service, the recipient's zone (city) and subzone (area). Look them up once and save them in your system; they rarely change. Then creating a shipment is a single request.
# 1. Get the shipping services
query Services {
listShippingServicesDropdown(input: { active: true }) {
id
name
}
}{
"data" : {
"listShippingServicesDropdown" : [
{ "id" : 1 , "name" : "Standard" },
{ "id" : 4 , "name" : "Same day" }
]
}
}
# 2. Get the zones and subzones
The zones the service delivers to:
query Zones($serviceId : Int!) {
listZonesDropdown(input: { active: true , service: { serviceId: $serviceId } }) {
id
name
}
}
Then the subzones inside a zone:
query Subzones($zoneId : Int!) {
listZonesDropdown(input: { active: true , parentId: $zoneId }) {
id
name
}
}
# 3. Create the shipment
Query Variables Response JavaScript PHP
Copy mutation CreateShipment($input : ShipmentInput!) {
saveShipment(input: $input ) {
id
code
trackingUrl
status { code name }
}
}{
"input" : {
"serviceId" : 1 ,
"refNumber" : "ORDER-1001" ,
"recipientName" : "Ahmed Ali" ,
"recipientMobile" : "01012345678" ,
"recipientZoneId" : 12 ,
"recipientSubzoneId" : 140 ,
"recipientAddress" : "12 Nile St, building 4, floor 2" ,
"description" : "2 T-shirts" ,
"weight" : 1.5 ,
"piecesCount" : 1 ,
"price" : 250 ,
"priceTypeCode" : "INCLD" ,
"paymentTypeCode" : "COLC" ,
"openableCode" : "Y" ,
"notes" : "Call before delivery"
}
}{
"data" : {
"saveShipment" : {
"id" : 10832354 ,
"code" : "A12345" ,
"trackingUrl" : "https://your-company.com/track/A12345" ,
"status" : { "code" : "PKR" , "name" : "Shipping Request" }
}
}
}const response = await fetch("https://your-company.com:8443/graphql" , {
method: "POST" ,
headers: {
"Content-Type" : "application/json" ,
Authorization: `Bearer ${token}` ,
},
body: JSON.stringify({
query: `mutation ($input: ShipmentInput!) {
saveShipment(input: $input) { id code trackingUrl }
}` ,
variables: {
input: {
serviceId: 1 ,
refNumber: "ORDER-1001" ,
recipientName: "Ahmed Ali" ,
recipientMobile: "01012345678" ,
recipientZoneId: 12 ,
recipientSubzoneId: 140 ,
recipientAddress: "12 Nile St, building 4, floor 2" ,
price: 250 ,
},
},
}),
});
const { data, errors } = await response.json();$response = Http::withToken($token )->post('https://your-company.com:8443/graphql' , [
'query' => 'mutation ($input: ShipmentInput!) { saveShipment(input: $input) { id code trackingUrl } }' ,
'variables' => ['input' => [
'serviceId' => 1 ,
'refNumber' => 'ORDER-1001' ,
'recipientName' => 'Ahmed Ali' ,
'recipientMobile' => '01012345678' ,
'recipientZoneId' => 12 ,
'recipientSubzoneId' => 140 ,
'recipientAddress' => '12 Nile St, building 4, floor 2' ,
'price' => 250 ,
]],
]);
$shipment = $response ->json('data.saveShipment' );
Save the id and code: you'll need them to track the shipment, and every webhook includes them.
# Fields
Required
Field
serviceId
Shipping service, from step 1
recipientZoneId, recipientSubzoneId
Zone and subzone, from step 2
recipientMobile
Recipient's mobile number
recipientAddress
Full delivery address
Optional, most used
Field
refNumber
Your order number. Recommended: you can search by it
recipientName, recipientPhone
Name and a second number
price
What the courier collects from the recipient (0 if prepaid)
priceTypeCode
INCLD: price includes shipping fees · EXCLD: fees are added
paymentTypeCode
COLC collect on delivery · PAID prepaid · more
typeCode
FDP deliver (default) · PDP partial · PTP exchange · RTS pick up a return
openableCode
Y / N: may the recipient open it before paying?
description, notes
What's inside, and notes for the courier
weight, piecesCount, size
Kilograms, pieces, { length, width, height } in cm
deliveryDate
Requested date, YYYY-MM-DD
senderName, senderMobile, senderAddress, senderZoneId, senderSubzoneId
Pickup details, if not your account's
Every field is in the reference .
To change a shipment , send saveShipment again with its id and the fields to change. That works until the shipping company starts handling it: the shipment's editable field tells you.
Track shipments
Prefer webhooks : we tell you as soon as a status changes, so you don't have to ask.
# One shipment
query Track($code : String) {
shipment(code: $code ) {
code
refNumber
status { code name }
deliveredOrReturnedDate
deliveredAmount
trackingUrl
}
}
status.code is one of the status codes ; status.name is its name in the Content-Language you asked for.
# Many shipments
query MyShipments($input : ListShipmentsFilterInput, $page : Int) {
listShipments(input: $input , first: 50 , page: $page ) {
paginatorInfo { currentPage lastPage total hasMorePages }
data {
code
refNumber
status { code name }
}
}
}{
"input" : {
"date" : { "fromDate" : "2026-10-01" , "toDate" : "2026-10-13" },
"statusCode" : ["OTD" , "DEX" , "HTR" ]
},
"page" : 1
}
Up to 100 per page (first). Ask for the next page while hasMorePages is true.
# Filters
Filter
Example
Finds
code
["A12345"]
These shipment codes
refNumber
["ORDER-1001"]
Your order numbers
search
"01012345678"
Part of the code, or a recipient's or sender's name or phone
statusCode
["DTR"]
In these statuses
date
{ "fromDate": "2026-10-01" }
Created in this period
deliveredOrReturnedDate
{ "fromDays": 7 }
Delivered or returned in the last 7 days
delivered, notDelivered
true
Delivered, or not yet
All filters are in the reference .
Webhooks
Every time one of your shipments changes status, we send a POST to an address on your server. No need to keep asking.
Make an address on your server that accepts a JSON POST, like https://your-store.com/accurate/webhook.
Send it to your shipping company : they save it on your account.
Answer 200 as soon as a request arrives, then update the shipment in your system.
# What you receive
Body Headers Example handler
Copy {
"shipmentId" : 10832354 ,
"shipmentCode" : "A12345" ,
"typeCode" : "SHP_STATUS_UPDATE" ,
"shipmentStatusCode" : "DTR" ,
"deliveryTypeCode" : "FD" ,
"returnTypeCode" : null,
"deliveredAmount" : 250 ,
"collectedFees" : 0 ,
"deliveryDate" : "2026-10-13" ,
"cancellationReasonId" : null,
"notes" : "Delivered to the security guard"
}POST /accurate/webhook
Content-Type: application/json
X-Client-Id: telegraph
app.post("/accurate/webhook" , express.json(), async (req, res) => {
res.sendStatus(200 );
const { shipmentCode, shipmentStatusCode } = req.body;
await orders.updateByShipmentCode(shipmentCode, { status: shipmentStatusCode });
});
Field
shipmentId, shipmentCode
The shipment, as saveShipment returned it
shipmentStatusCode
The new status : see codes
deliveryTypeCode
When delivered: FD fully, PD partially
returnTypeCode
When returned: how the fees were settled, see codes
deliveredAmount
Collected from the recipient
collectedFees
Shipping fees collected from the recipient
deliveryDate
Delivery date
cancellationReasonId
Why it couldn't be delivered, if given
notes
The courier's notes
typeCode
Always SHP_STATUS_UPDATE
X-Client-Id header
Your shipping company's name, if you work with several
Fields that don't apply to the status are null.
The same update can arrive twice. Saving the same status again should do no harm.
Codes
# Shipment status
In the order a shipment usually goes through them.
Code
Status
Meaning
PKR
Shipping request
Created, waiting for pickup
PKM
Picking up
A courier is on the way to pick it up
PKH
Pickup rescheduled
Pickup will be tried again
PKD
Picked up
Picked up from you
RJCT
Rejected
Refused by the shipping company
RITS
In the warehouse
At the shipping company's warehouse
PRP
Being prepared
Being packed
PRPD
Prepared
Ready to go out
BMT
Sent to another branch
Moving between branches
BMR
Arrived at the branch
At the branch that delivers it
STD
Handing to courier
Being given to the delivery courier
OTD
Out for delivery
On the way to the recipient
DTR
Delivered
See deliveryTypeCode
DEX
Delivery failed
Not delivered this time, see cancellationReasonId
HTR
Waiting to redeliver
Will be delivered again later
RTS
Returning
Will come back to you
RCV
Return in the warehouse
Back at the warehouse
OTR
Out for return
On the way back to you
RTRN
Returned
Back with you, see returnTypeCode
# Delivery type
Code
FD
Fully delivered
PD
Partially delivered: the rest comes back
# Return type
Code
WODF
Returned, you pay no fees
WFDF
Returned, you pay the full shipping fees
WPDF
Returned, you pay part of the shipping fees
FFC
Returned, the recipient paid the full shipping fees
FPC
Returned, the recipient paid part of the shipping fees
PRTS
Partially returned
# Shipment type
Code
FDP
Deliver the whole package (default)
PDP
The recipient may keep only part of it
PTP
Exchange: deliver one package, bring another back
RTS
Pick up a package from the recipient for you
# Payment type
Code
COLC
Collect from the recipient on delivery
PAID
Prepaid
CASH
Paid in cash
CRDT
Postpaid, settled with you later
VISA
Paid by card
# Price type and open package
Code
INCLD
price includes the shipping fees
EXCLD
Shipping fees are added to price
Y
The recipient may open the package before paying
N
The recipient may not open it
Errors
A failed request has an errors list. The HTTP status is usually still 200, so always check for errors .
Response Copy
{
"errors" : [
{
"message" : "Validation failed for the field [saveShipment]." ,
"extensions" : {
"validation" : {
"input.recipientMobile" : ["The recipient mobile field is required." ]
}
}
}
],
"data" : { "saveShipment" : null }
}
Message
What to do
Unauthenticated.
Log in again and retry
Validation failed…
extensions.validation lists each wrong field and why
Variable "$input" got invalid value…
A value has the wrong type, or a required field is missing
Value "X" does not exist in "…" enum
Use one of the codes
Cannot query field "x"…
Check the field's name in the reference
This action is unauthorized.
Your account isn't allowed to: ask your shipping company
Send Content-Language: ar to get messages in Arabic. Log the whole errors list when a request fails: it makes support much faster.
What changed
If your integration follows an older version of these docs:
Change
What to do
serviceId is required in saveShipment
Send a service id from listShippingServicesDropdown
recipientPhone is optional
Nothing: recipientMobile is still required
customerId in listShipments is a list
Send [123] instead of 123
ImageInput.file is a required file upload
Upload the file itself
ttl removed from login
Stop asking for it
state, city, area removed from Branch
Stop asking for them
Shipment type CLC removed
Use another shipment type
ShipmentFees.post, tax and Shipment.createdBy may be null
Handle an empty value
Webhooks also send shipmentCode
Find the shipment by its code
API reference
Every operation and type available to your account. Click a type to jump to it.
# Operations
Query calculateShipmentFees
Arguments
Returns ShipmentFees!
Query listCountriesDropdown
Returns [DropdownEntry]!
Query listLookupEntriesDropdown
Arguments
Returns [DropdownEntry]
Query listPaymentTypesDropdown
Arguments
Returns [DropdownEntry]
Query listShipments
Arguments Name Type input ListShipmentsFilterInputfirst required Int!Limits number of fetched items. Maximum allowed value: 100. page IntThe offset from which items are returned.
Returns ShipmentPaginator!
Query listShipmentTypesDropdown
Arguments Name Type serviceId IntmobileActive Boolean
Returns [DropdownEntry]
Query listShippingServicesDropdown
Arguments
Returns [DropdownEntry]!
Query listZonesDropdown
Arguments
Returns [DropdownEntry]
Mutation login
Arguments
Returns UserWithToken!
Mutation saveShipment
Arguments
Returns Shipment
Query shipment
Arguments Name Type id Intcode String
Returns Shipment
# Types
Input BoxSizeInput
Name Type length required Float!width required Float!height required Float!
Type Branch
Name Type idInt!codeString!nameString!activeBoolean!mainBoolean!addressStringphoneStringfaxStringcountryCountrywarehouseSections[WarehouseSection]
Input CalculateShipmentFeesInput
Type Country
Name Type idInt!codeString!nameString!
Enum CustomerTypeCode
Customer type code
MERCHANT INDIVIDUAL CONCIERGE
Input DateFilterInput
Name Type fromDays IntfromDate DatetoDate Date
Input DeliveryAgentCustodyInput
Name Type deliveryAgentId Int
Type DropdownEntry
Name Type idIntcodeStringnameString
Input FilterZonesByServiceInput
Name Type serviceId required Int!customerId IntcustomerTypeCode CustomerTypeCodefromZoneId IntfromSubzoneId Int
Type Image
Name Type pathString!subjectCodeString
Input ImageInput
Name Type file required Upload!subjectCode String
Input ListLookupEntriesFilterInput
Name Type code required String!
Input ListPaymentTypesDropdownInput
Input ListShipmentsFilterInput
Input ListShippingServicesFilterInput
Input ListZonesFilterInput
Input LoginInput
Name Type username required String!password required String!rememberMe required Boolean!fcmToken String
Type Lookup
Type LookupEntry
Name Type idInt!codeString!nameString!activeBooleanweightInt!lookupLookup!mobileActiveBoolean
Type PaginatorInfo
Information about pagination using a fully featured paginator.
Name Type countInt!Number of items in the current page. currentPageInt!Index of the current page. firstItemIntIndex of the first item in the current page. hasMorePagesBoolean!Are there more pages after this one? lastItemIntIndex of the last item in the current page. lastPageInt!Index of the last available page. perPageInt!Number of items per page. totalInt!Number of total available items.
Type Permission
Name Type idInt!nameString!slugString!
Type Role
Name Type idInt!codeString!nameString!usersCountInt!permissions[Permission]!
Type Sequence
Name Type idInt!codeStringnameString!
Type Shipment
Name Type idInt!codeString!typeLookupEntry!openableLookupEntry!dateDateTime!createdAtDateTime!updatedAtDateTimedeliveryDateDatedeliveredOrReturnedDateDateTimedescriptionStringweightFloat!piecesCountInt!collectedBoolean!paidToCustomerBoolean!paidToDeliveryAgentBoolean!editableBoolean!trackingUrlString!deletableBoolean!hasProductsBoolean!inWarehouseBoolean!unpackedBoolean!refNumberStringnotesStringadminNotesStringreturnPiecesCountIntpaymentTypeLookupEntry!priceTypeLookupEntry!deliveryTypeLookupEntryreturnTypeLookupEntrytransactionTypeTransactionType!branchBranch!originBranchBranch!statusLookupEntry!returnStatusLookupEntryserviceShippingService!history[Shipment!]!createdByUserupdatedByUserwarehouseSectionWarehouseSectioncustomerTypeLookupEntry!attemptsIntcancellableBoolean!cancelledBoolean!priceFloat!amountFloat!deliveryFeesFloat!extraWeightFeesFloat!collectionFeesFloat!totalAmountFloat!deliveredAmountFloat!returningDueFeesFloat!returnedValueFloat!allDueFeesFloat!collectedFeesFloat!customerDueFloat!collectedAmountFloat!pendingCollectionAmountFloat!returnFeesFloat!postFeesFloat!taxFloat!deliveryCommissionFloatrecipientNameStringrecipientPhoneStringrecipientMobileString!recipientZoneZone!recipientSubzoneZone!recipientAddressString!recipientPostalCodeStringrecipientLatitudeFloatrecipientLongitudeFloatsenderNameStringsenderPhoneStringsenderMobileStringsenderZoneZonesenderSubzoneZonesenderAddressStringsenderPostalCodeStringsenderLatitudeFloatsenderLongitudeFloatdeliveryOtpStringhasDeliveryOtpBoolean!images[Image]
Enum ShipmentDeliveryTypeCode
Shipment delivery type code
FD PD
Type ShipmentFees
Name Type amountFloat!deliveryFloat!weightFloat!collectionFloat!postFloattaxFloatreturnFloat!totalFloat!
Input ShipmentInput
Name Type id Intcode Stringdate DateTimedeliveryDate DateserviceId required Int!description StringrefNumber Stringweight Floatsize BoxSizeInputpiecesCount IntreturnPiecesCount Intprice Floatnotes StringtypeCode ShipmentTypeCodepriceTypeCode ShipmentPriceTypeCodepaymentTypeCode ShipmentPaymentTypeCodeopenableCode ShipmentOpenableCodeshipmentProducts [ShipmentProductInput]senderName StringsenderZoneId IntsenderSubzoneId IntsenderPhone StringsenderMobile StringsenderAddress StringsenderPostalCode StringsenderLatitude FloatsenderLongitude FloatrecipientName StringrecipientZoneId required Int!recipientSubzoneId required Int!recipientPhone StringrecipientMobile required String!recipientAddress required String!recipientLatitude FloatrecipientLongitude Float
Enum ShipmentOpenableCode
Shipment openable code
Y N
Type ShipmentPaginator
A paginated list of Shipment items.
Enum ShipmentPaymentTypeCode
Shipment payment type code
COLC PAID CASH CRDT VISA
Enum ShipmentPriceTypeCode
Shipment price type code
EXCLD INCLD
Input ShipmentProductInput
Enum ShipmentProductTypeCode
Shipment product type code
IN OUT
Enum ShipmentReturnTypeCode
Shipment return type code
FFC FPC WFDF WODF WPDF PRTS
Enum ShipmentStatusCode
Shipment status code
PKR PKM PKH PKD RJCT BMR BMT PRP PRPD RITS STD OTD DTR DEX HTR RTS RCV OTR RTRN
Enum ShipmentTypeCode
Shipment type code
FDP PDP PTP RTS
Type ShippingService
Name Type idInt!codeString!nameString!daysInt!egsCodeStringactiveBoolean!branchBranchshipmentTypes[LookupEntry]
Type TransactionType
Type User
Type UserBranch
Type UserWithToken
Name Type userUser!tokenString!
Type WarehouseSection
Type Zone
Name Type idInt!codeString!nameString!parentZoneactiveBooleanbranchBranchchildren[Zone]