Introduction
Welcome to the ScriptDrop Tracking API.
Tracking API v1 lets callers subscribe to shipment tracking updates for a
USPS or UPS tracking number. When a subscription is enabled, ScriptDrop posts
notification events to the caller's listener_url as tracking status changes.
Use the subscription endpoints to enable tracking, check subscription status, and receive webhook notifications at your listener URL.
Base URLs
| Environment | Base URL |
|---|---|
| Production | https://request.scriptdrop.co/tracking/v1/subscriptions |
| Sandbox | https://request.sandbox.scriptdrop.co/tracking/v1/subscriptions |
The examples below use the production base URL. Substitute the sandbox URL when testing against the sandbox environment.
Authentication
Authentication uses HTTP Basic authentication.
The API key is sent as the Basic auth username. The API secret is sent as the Basic auth password.
To authorize, use this code:
api_key = "pk_myapikey1234"
api_secret = "sk_myapisecret1234"
encoded_authorization = Base.encode64("#{api_key}:#{api_secret}")
authorization_header = "Basic #{encoded_authorization}"
export SCRIPTDROP_API_KEY="pk_myapikey1234"
export SCRIPTDROP_API_SECRET="sk_myapisecret1234"
ScriptDrop uses API keys to allow access to the API. Please contact our support team for API keys.
ScriptDrop expects API requests to include an Authorization header:
Authorization: Basic encoded_authorization
Authorization
Callers need active ScriptDrop API credentials that are explicitly enabled for Tracking API access.
Credentials issued for another ScriptDrop API surface are not automatically authorized for the Tracking API.
V1 Subscriptions
Tracking API v1 supports USPS and UPS tracking numbers. Subscription responses
and notification events include "carrier": "USPS" or "carrier": "UPS".
Get a Subscription
url = "https://request.scriptdrop.co/tracking/v1/subscriptions"
headers = [
{"Authorization", "Basic encoded_authorization"},
{"Content-Type", "application/json"}
]
params = %{
"tracking_number" => "9400111899223197428490"
}
HTTPoison.start()
HTTPoison.get!(url, headers, params: params)
curl --request GET \
"https://request.scriptdrop.co/tracking/v1/subscriptions?tracking_number=9400111899223197428490" \
--user "$SCRIPTDROP_API_KEY:$SCRIPTDROP_API_SECRET"
The above command returns JSON structured like this:
{
"reference_id": "order-12345",
"tracking_number": "9400111899223197428490",
"carrier": "USPS",
"subscription_status": "ENABLED",
"subscription_status_reason": null,
"subscribed_at": "2026-07-01T14:30:00Z",
"updated_at": "2026-07-02T09:15:00Z"
}
Endpoint
GET https://request.scriptdrop.co/tracking/v1/subscriptions
Request Shape
Send tracking_number as a query parameter. Subscriptions are looked up by
tracking number only.
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
tracking_number |
string | yes | USPS or UPS tracking number to look up. |
Response Fields
| Field | Type | Description |
|---|---|---|
reference_id |
string | Caller-supplied metadata stored with the subscription. Echoed in the response; not used to filter GET requests. |
tracking_number |
string | USPS or UPS tracking number. |
carrier |
string | USPS or UPS in v1. |
subscription_status |
string | Current subscription status. See Subscription Status. |
subscription_status_reason |
string | Additional detail about the current status, when available. |
subscribed_at |
string | ISO 8601 timestamp when the subscription was created. |
updated_at |
string | ISO 8601 timestamp when the subscription was last updated. |
Create or Update a Subscription
url = "https://request.scriptdrop.co/tracking/v1/subscriptions"
headers = [
{"Authorization", "Basic encoded_authorization"},
{"Content-Type", "application/json"}
]
subscription_params = %{
"reference_id" => "order-12345",
"tracking_number" => "9400111899223197428490",
"listener_url" => "https://example.com/tracking/notifications"
}
HTTPoison.start()
HTTPoison.post(url, Jason.encode!(subscription_params), headers)
curl --request POST "https://request.scriptdrop.co/tracking/v1/subscriptions" \
--user "$SCRIPTDROP_API_KEY:$SCRIPTDROP_API_SECRET" \
--header "Content-Type: application/json" \
--data '{
"reference_id": "order-12345",
"tracking_number": "9400111899223197428490",
"listener_url": "https://example.com/tracking/notifications"
}'
The above command returns JSON structured like this:
{
"reference_id": "order-12345",
"tracking_number": "9400111899223197428490",
"carrier": "USPS",
"subscription_status": "ENABLED",
"subscription_status_reason": null,
"subscribed_at": "2026-07-01T14:30:00Z",
"updated_at": "2026-07-02T09:15:00Z"
}
Endpoint
POST https://request.scriptdrop.co/tracking/v1/subscriptions
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
tracking_number |
string | yes | USPS or UPS tracking number to subscribe to. |
listener_url |
string | yes | HTTPS URL where ScriptDrop posts tracking notification events. |
reference_id |
string | no | Caller-supplied reference for the shipment. |
Response Fields
| Field | Type | Description |
|---|---|---|
reference_id |
string | Caller-supplied reference, if provided. |
tracking_number |
string | USPS or UPS tracking number. |
carrier |
string | USPS or UPS in v1. |
subscription_status |
string | Current subscription status. See Subscription Status. |
subscription_status_reason |
string | Additional detail about the current status, when available. |
subscribed_at |
string | ISO 8601 timestamp when the subscription was created. |
updated_at |
string | ISO 8601 timestamp when the subscription was last updated. |
Subscription Status
ScriptDrop posts notifications to the supplied listener_url when a
subscription is enabled. If the listener_url cannot be reached or is invalid,
ScriptDrop changes the subscription status to SUSPENDED.
| Status | Description |
|---|---|
ENABLED |
The subscription is active and notifications are sent to listener_url. |
DISABLED |
A previously enabled subscription has ended. |
SUSPENDED |
Notifications could not be delivered to listener_url. |
Notification Events
When tracking status changes for an enabled subscription, ScriptDrop sends an
HTTP POST request to the subscription's listener_url.
Notification Payload
{
"reference_id": "order-12345",
"tracking_number": "9400111899223197428490",
"timestamp": "2026-07-02T09:15:00Z",
"carrier": "USPS",
"status": "Moving Through Network",
"status_text": "Your package is moving through the carrier network.",
"status_occurred_at": "2026-07-02T08:45:00Z",
"tracking_events": [
{
"status": "Accepted",
"status_occurred_at": "2026-07-01T14:30:00Z"
},
{
"status": "Moving Through Network",
"status_occurred_at": "2026-07-02T08:45:00Z"
}
]
}
Notification Fields
| Field | Type | Required | Description |
|---|---|---|---|
reference_id |
string | no | Caller-supplied reference, if provided. |
tracking_number |
string | yes | USPS or UPS tracking number. |
timestamp |
string | yes | ISO 8601 timestamp when the notification was generated. |
carrier |
string | yes | USPS or UPS in v1. |
status |
string | yes | Status category for the current tracking state. |
status_text |
string | no | Customer-facing sentence summarizing the current status. |
status_occurred_at |
string | yes | ISO 8601 timestamp when the current status occurred. |
tracking_events |
array | no | Chronological tracking events for the shipment. |
tracking_events[].status |
string | no | Status category for the event. |
tracking_events[].status_occurred_at |
string | no | ISO 8601 timestamp when the event occurred. |
Status Categories
Tracking status values use carrier-agnostic status categories such as:
Pre-ShipmentAcceptedMoving Through NetworkOut for DeliveryDelivered
Error Responses
Error responses return a JSON object with an error field containing a machine-readable
code and a human-readable message.
Response Shape
{
"error": {
"code": "invalid_request",
"message": "tracking_number is required"
}
}
| Field | Type | Description |
|---|---|---|
error |
object | Error details. |
error.code |
string | Machine-readable error code. |
error.message |
string | Human-readable description of the error. |
The ScriptDrop Tracking API uses the following HTTP status codes:
| Error Code | Meaning |
|---|---|
| 400 | Bad Request -- Your request is invalid. |
| 401 | Unauthorized -- Your API key is missing or invalid. |
| 403 | Forbidden -- Your API key is valid, but it is not enabled for Tracking API access. |
| 404 | Not Found -- The specified resource could not be found. |
| 405 | Method Not Allowed -- You tried to access a route that's not allowed. |
| 406 | Not Acceptable -- You requested a format that isn't supported. |
| 429 | Too Many Requests -- You've hit your request limit. Retry in a few moments. |
| 500 | Internal Server Error -- We had a problem with our server. Try again later. |
| 502 | Bad Gateway -- ScriptDrop could not retrieve a reliable status from an upstream provider. |
| 503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |
400 Bad Request
Your request is invalid.
Examples:
- malformed JSON
- missing required field
- invalid field type
- unsupported
Content-Type
{
"error": {
"code": "invalid_request",
"message": "tracking_number is required"
}
}
{
"error": {
"code": "invalid_request",
"message": "Request body must be valid JSON"
}
}
{
"error": {
"code": "invalid_request",
"message": "tracking_number must be a string"
}
}
{
"error": {
"code": "invalid_request",
"message": "Content-Type must be application/json"
}
}
401 Unauthorized
Your API key is missing or invalid.
Examples:
- missing
Authorizationheader - non-Basic authorization scheme
- malformed Basic credentials
- unknown API key
- secret mismatch
- disabled credentials
{
"error": {
"code": "unauthorized",
"message": "Authorization header is required"
}
}
{
"error": {
"code": "unauthorized",
"message": "Authorization scheme must be Basic"
}
}
{
"error": {
"code": "unauthorized",
"message": "Invalid authorization credentials"
}
}
{
"error": {
"code": "unauthorized",
"message": "API key is invalid"
}
}
{
"error": {
"code": "unauthorized",
"message": "API secret is invalid"
}
}
{
"error": {
"code": "unauthorized",
"message": "API credentials are disabled"
}
}
403 Forbidden
Your API key is valid, but it is not enabled for Tracking API access.
{
"error": {
"code": "forbidden",
"message": "API credentials are not enabled for Tracking API access"
}
}
404 Not Found
The specified resource could not be found.
{
"error": {
"code": "not_found",
"message": "Subscription not found"
}
}
405 Method Not Allowed
You tried to access a route that's not allowed.
{
"error": {
"code": "method_not_allowed",
"message": "PATCH is not allowed on /tracking/v1/subscriptions"
}
}
406 Not Acceptable
You requested a format that isn't supported.
{
"error": {
"code": "not_acceptable",
"message": "Accept header must be application/json"
}
}
429 Too Many Requests
You've hit your request limit. Retry in a few moments.
When available, the response includes a Retry-After header.
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Retry after 60 seconds."
}
}
500 Internal Server Error
We had a problem with our server. Try again later.
{
"error": {
"code": "internal_error",
"message": "An unexpected error occurred"
}
}
502 Bad Gateway
ScriptDrop could not retrieve a reliable status from an upstream provider.
{
"error": {
"code": "bad_gateway",
"message": "Unable to subscribe to tracking number via upstream provider"
}
}
503 Service Unavailable
We're temporarily offline for maintenance. Please try again later.
{
"error": {
"code": "service_unavailable",
"message": "Service is temporarily unavailable. Please try again later."
}
}