Aller au contenu

Pour les développeurs

API ouverte PODFY référence

Récupérez les enregistrements, mettez à jour leur statut et gérez votre registre de références depuis vos propres systèmes. Une API REST JSON, incluse dans PODFY Advanced.

Ce qu'est l'API

L'API ouverte PODFY permet à vos propres systèmes de lire les enregistrements (preuves de livraison et signalements QR), de mettre à jour leur statut de traitement et de gérer le registre de références (équipements). C'est une API REST JSON pour un usage de serveur à serveur. Il n'y a pas de CORS : appelez l'API depuis votre backend, jamais depuis un navigateur.

L'API ouverte est incluse dans PODFY Advanced. Si elle n'est pas active pour votre marque, chaque appel répond 403 feature_not_active. La spécification est au format OpenAPI 3.1 et la référence ci-dessous est générée à partir du même fichier.

Obtenir une clé API

Un administrateur de votre marque crée les clés dans le portail (en anglais), sous Settings → Integrations → API keys. Donnez un nom à la clé et choisissez ses scopes. La clé n'est affichée qu'une fois : conservez-la dans votre gestionnaire de secrets. Vous pouvez révoquer une clé à tout moment, et une clé révoquée cesse de fonctionner immédiatement.

  • records:read : lire les enregistrements
  • records:write : mettre à jour les enregistrements (autorise aussi la lecture)
  • references:read : lire le registre de références
  • references:write : créer et modifier des références (autorise aussi la lecture)

URL de base et authentification

L'URL de base est https://portal.podfy.net/api/v1. Envoyez votre clé comme jeton Bearer dans l'en-tête Authorization à chaque requête. Une clé ne fonctionne jamais comme paramètre de requête.

Une clé absente, mal formée, inconnue ou révoquée reçoit toujours la même réponse : 401 invalid_key. Une clé sans le scope requis reçoit 403 insufficient_scope.

curl -H "Authorization: Bearer $PODFY_API_KEY" \
  "https://portal.podfy.net/api/v1/records?limit=10"

Clés live et clés de test

Les clés qui commencent par pk_live_ ne voient que les enregistrements de production. Les clés qui commencent par pk_test_ (enregistrements QA uniquement) ne voient que les enregistrements de test de qa.podfy.app, dont les ID PODFY commencent par QA-. Les deux environnements ne se mélangent jamais.

Le registre de références est partagé avec la production : les clés de test ne peuvent donc ni créer ni modifier de références (403 insufficient_scope). Un enregistrement ou une référence d'une autre marque, ou un enregistrement de l'autre environnement, répond 404 not_found, jamais 403.

Limite de débit

Chaque clé peut effectuer 600 requêtes par minute, comptées par fenêtres fixes d'une minute. Chaque réponse contient X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset (secondes unix de la fin de la fenêtre).

Au-delà de la limite, vous recevez 429 rate_limited avec un en-tête Retry-After (secondes). Attendez ce délai, puis réessayez.

Erreurs

Chaque erreur est un JSON de même forme : {"error":{"code":"…","message":"…"}}. Traitez les erreurs selon le statut HTTP et le code, pas selon le texte du message. Les réponses ne sont jamais mises en cache (Cache-Control: no-store). La liste complète des codes figure dans la référence ci-dessous.

Pagination

Les points de terminaison de liste renvoient {"data": [...], "next_cursor": "…"}. Renvoyez next_cursor comme paramètre cursor pour obtenir la page suivante, jusqu'à ce qu'il soit null. Les curseurs sont opaques : ne les construisez pas et ne les modifiez pas. Les enregistrements sont listés du plus récent au plus ancien. La taille de page se règle avec limit (de 1 à 200, 50 par défaut).

Référence

Opérations

La référence ci-dessous est générée à partir du fichier OpenAPI et reste en anglais dans toutes les langues. Téléchargez la spécification : openapi.json

Codes d'erreur

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
409ref_existsThe reference already exists.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

GET /records

List records Required scope: records:read

Records of your brand, newest first. Deleted records are never listed.

Parameters

NameInTypeRequiredDescription
sincequerystringoptionalOnly records created at or after this moment (ISO 8601 date or date-time; a time without zone is UTC).
updated_sincequerystringoptionalOnly records changed (or created) at or after this moment (ISO 8601).
statusquerystringoptionalWork status, one or more comma separated.
referencequerystring max 100 charactersoptionalExact reference (1-100 characters).
categoryquerystring max 40 charactersoptionalCategory code (letters, digits, _ and -; case-insensitive).
limitqueryinteger 1-200 default 50optionalPage size, 1-200 (default 50; larger values are capped at 200).
cursorquerystringoptionalThe next_cursor of the previous page (opaque).

Response 200

A page of records.

FieldTypeRequiredDescription
dataarray of objectrequired
data[].podfy_idstringrequired
data[].modestring one of delivery, reportrequired
data[].referencestringoptionalEmpty string when none.
data[].assetobjectoptionalRegister data at upload time.
data[].asset.namestring or nulloptional
data[].asset.locationstring or nulloptional
data[].asset.groupstring or nulloptional
data[].categorystring or nulloptionalCategory code (report mode) or delivery issue code.
data[].prioritystring one of low, normal, high, criticalrequired
data[].work_statusstring one of new, in_progress, resolved, rejectedrequired
data[].notestringoptional
data[].fieldsobjectoptionalCustom form fields.
data[].group_idstringrequiredRecords of one multi-file upload share it (the podfy_id without the -N suffix).
data[].filesarray of objectrequired
data[].files[].namestringoptional
data[].files[].urlstring urioptional
data[].locationobject or nulloptional
data[].location.latnumberoptional
data[].location.lngnumberoptional
data[].location.sourcestring or nulloptional
data[].duplicate_ofstring or nulloptionalpodfy_id of the first report this one duplicates.
data[].urlstring or null urioptionalPublic detail page of the record.
data[].assigneestring or nulloptionalE-mail of the assigned brand member.
data[].created_atstring date-timerequired
data[].updated_atstring or null date-timeoptional
data[].resolved_atstring or null date-timeoptional
data[].keep_informedbooleanoptionalTrue when the reporter asked to be kept informed (a confirmation or resolved message was or can be sent). Never the address.
next_cursorstring or nullrequired

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  "https://portal.podfy.net/api/v1/records?limit=50"

GET /records/{podfy_id}

Get a record Required scope: records:read

One record with its timeline (created, status, comment, assign, priority, duplicate). Mail recipients and reporter data never appear.

Parameters

NameInTypeRequiredDescription
podfy_idpathstring pattern ^[A-Za-z0-9_-]{1,64}$requiredThe record's PODFY ID, e.g. PFY-7Q4K2-1 (QA-… for test records).

Response 200

The record.

FieldTypeRequiredDescription
podfy_idstringrequired
modestring one of delivery, reportrequired
referencestringoptionalEmpty string when none.
assetobjectoptionalRegister data at upload time.
asset.namestring or nulloptional
asset.locationstring or nulloptional
asset.groupstring or nulloptional
categorystring or nulloptionalCategory code (report mode) or delivery issue code.
prioritystring one of low, normal, high, criticalrequired
work_statusstring one of new, in_progress, resolved, rejectedrequired
notestringoptional
fieldsobjectoptionalCustom form fields.
group_idstringrequiredRecords of one multi-file upload share it (the podfy_id without the -N suffix).
filesarray of objectrequired
files[].namestringoptional
files[].urlstring urioptional
locationobject or nulloptional
location.latnumberoptional
location.lngnumberoptional
location.sourcestring or nulloptional
duplicate_ofstring or nulloptionalpodfy_id of the first report this one duplicates.
urlstring or null urioptionalPublic detail page of the record.
assigneestring or nulloptionalE-mail of the assigned brand member.
created_atstring date-timerequired
updated_atstring or null date-timeoptional
resolved_atstring or null date-timeoptional
keep_informedbooleanoptionalTrue when the reporter asked to be kept informed (a confirmation or resolved message was or can be sent). Never the address.
eventsarray of objectrequired
events[].typestring one of created, status, comment, assign, priority, duplicaterequired
events[].fromstring or nulloptional
events[].tostring or nulloptional
events[].notestring or nulloptionalThe comment text (comment events only).
events[].actorstring or nulloptionalBrand member e-mail, app, or api:<key prefix>.
events[].created_atstring date-timerequired

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  "https://portal.podfy.net/api/v1/records/PFY-7Q4K2-1"

PATCH /records/{podfy_id}

Update a record Required scope: records:write

Change the work status, assignee or priority, or add a comment. Same rules as the portal: one timeline event per change, webhooks record.status_changed / record.updated are sent, the actor is api:<key prefix>. Needs status tracking (report mode or the status tracking add-on), else 403 feature_not_active. Only the fields below are accepted.

Parameters

NameInTypeRequiredDescription
podfy_idpathstring pattern ^[A-Za-z0-9_-]{1,64}$requiredThe record's PODFY ID, e.g. PFY-7Q4K2-1 (QA-… for test records).

Request body (JSON)

FieldTypeRequiredDescription
work_statusstring one of new, in_progress, resolved, rejectedoptional
assigneestring or null emailoptionalAn active member of the brand, or null to unassign.
prioritystring one of low, normal, high, criticaloptional
commentstring or null max 2000 charactersoptionalAdded to the timeline.

Response 200

The record after the update. changed is false when nothing differed.

FieldTypeRequiredDescription
changedbooleanrequired
recordobjectrequiredThe same record object as in webhook payloads, plus timestamps and the assignee.
record.podfy_idstringrequired
record.modestring one of delivery, reportrequired
record.referencestringoptionalEmpty string when none.
record.assetobjectoptionalRegister data at upload time.
record.asset.namestring or nulloptional
record.asset.locationstring or nulloptional
record.asset.groupstring or nulloptional
record.categorystring or nulloptionalCategory code (report mode) or delivery issue code.
record.prioritystring one of low, normal, high, criticalrequired
record.work_statusstring one of new, in_progress, resolved, rejectedrequired
record.notestringoptional
record.fieldsobjectoptionalCustom form fields.
record.group_idstringrequiredRecords of one multi-file upload share it (the podfy_id without the -N suffix).
record.filesarray of objectrequired
record.files[].namestringoptional
record.files[].urlstring urioptional
record.locationobject or nulloptional
record.location.latnumberoptional
record.location.lngnumberoptional
record.location.sourcestring or nulloptional
record.duplicate_ofstring or nulloptionalpodfy_id of the first report this one duplicates.
record.urlstring or null urioptionalPublic detail page of the record.
record.assigneestring or nulloptionalE-mail of the assigned brand member.
record.created_atstring date-timerequired
record.updated_atstring or null date-timeoptional
record.resolved_atstring or null date-timeoptional
record.keep_informedbooleanoptionalTrue when the reporter asked to be kept informed (a confirmation or resolved message was or can be sent). Never the address.

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl -X PATCH \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"work_status": "in_progress", "assignee": "[email protected]"}' \
  "https://portal.podfy.net/api/v1/records/PFY-7Q4K2-1"

GET /references

List references Required scope: references:read

Your reference register, ordered by ref.

Parameters

NameInTypeRequiredDescription
statusquerystring one of active, retiredoptional
groupquerystring max 40 charactersoptionalExact group code.
qquerystring max 100 charactersoptionalText contained in ref, name or location (1-100 characters).
limitqueryinteger 1-200 default 50optionalPage size, 1-200 (default 50; larger values are capped at 200).
cursorquerystringoptionalThe next_cursor of the previous page (opaque).

Response 200

A page of references.

FieldTypeRequiredDescription
dataarray of objectrequired
data[].refstringrequired
data[].kindstring or null one of asset, shipmentoptional
data[].namestring or nulloptional
data[].locationstring or nulloptional
data[].group_codestring or nulloptional
data[].sticker_textstring or nulloptional
data[].statusstring one of active, retiredrequired
data[].active_fromstring or nulloptional
data[].retired_atstring or null date-timeoptional
data[].created_atstring or null date-timeoptional
data[].updated_atstring or null date-timeoptional
data[].qr_urlstring urirequiredhttps://podfy.app/{brand}/{ref}
next_cursorstring or nullrequired

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  "https://portal.podfy.net/api/v1/references?limit=50"

POST /references

Create a reference Required scope: references:write

Adds one reference. 409 ref_exists when the ref is already in the register.

QA keys (pk_test_) cannot change references: the register is shared with production records (403 insufficient_scope).

Request body (JSON)

FieldTypeRequiredDescription
refstring pattern ^[A-Za-z0-9._-]{1,64}$required
namestring or null max 120 charactersoptional
locationstring or null max 120 charactersoptional
group_codestring or null max 40 charactersoptional
sticker_textstring or null max 120 charactersoptional

Response 201

The new reference.

FieldTypeRequiredDescription
refstringrequired
kindstring or null one of asset, shipmentoptional
namestring or nulloptional
locationstring or nulloptional
group_codestring or nulloptional
sticker_textstring or nulloptional
statusstring one of active, retiredrequired
active_fromstring or nulloptional
retired_atstring or null date-timeoptional
created_atstring or null date-timeoptional
updated_atstring or null date-timeoptional
qr_urlstring urirequiredhttps://podfy.app/{brand}/{ref}

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
409ref_existsThe reference already exists.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl -X POST \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ref": "example", "name": "example"}' \
  "https://portal.podfy.net/api/v1/references"

GET /references/{ref}

Get a reference Required scope: references:read

One reference.

Parameters

NameInTypeRequiredDescription
refpathstring pattern ^[A-Za-z0-9._-]{1,64}$requiredThe reference (1-64 characters: letters, digits, dot, underscore, hyphen).

Response 200

The reference.

FieldTypeRequiredDescription
refstringrequired
kindstring or null one of asset, shipmentoptional
namestring or nulloptional
locationstring or nulloptional
group_codestring or nulloptional
sticker_textstring or nulloptional
statusstring one of active, retiredrequired
active_fromstring or nulloptional
retired_atstring or null date-timeoptional
created_atstring or null date-timeoptional
updated_atstring or null date-timeoptional
qr_urlstring urirequiredhttps://podfy.app/{brand}/{ref}

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  "https://portal.podfy.net/api/v1/references/YOUR_REF"

PATCH /references/{ref}

Update a reference Required scope: references:write

Edit, move, retire (status: retired) or reactivate a reference. Only the fields below are accepted; an empty string clears a text field.

QA keys (pk_test_) cannot change references: the register is shared with production records (403 insufficient_scope).

Parameters

NameInTypeRequiredDescription
refpathstring pattern ^[A-Za-z0-9._-]{1,64}$requiredThe reference (1-64 characters: letters, digits, dot, underscore, hyphen).

Request body (JSON)

FieldTypeRequiredDescription
namestring or null max 120 charactersoptional
locationstring or null max 120 charactersoptional
group_codestring or null max 40 charactersoptional
sticker_textstring or null max 120 charactersoptional
statusstring one of active, retiredoptional

Response 200

The reference after the update.

FieldTypeRequiredDescription
changedbooleanrequired
referenceobjectrequired
reference.refstringrequired
reference.kindstring or null one of asset, shipmentoptional
reference.namestring or nulloptional
reference.locationstring or nulloptional
reference.group_codestring or nulloptional
reference.sticker_textstring or nulloptional
reference.statusstring one of active, retiredrequired
reference.active_fromstring or nulloptional
reference.retired_atstring or null date-timeoptional
reference.created_atstring or null date-timeoptional
reference.updated_atstring or null date-timeoptional
reference.qr_urlstring urirequiredhttps://podfy.app/{brand}/{ref}

Errors

StatusCodesMeaning
400invalid_parameter invalid_cursor invalid_body invalid_status invalid_priority invalid_assignee invalid_comment comment_too_long nothing_to_update invalid_ref name_too_long location_too_long group_code_too_long sticker_text_too_long no_valid_fieldsInvalid query parameter or body.
401invalid_keyThe API key is missing, malformed, unknown or revoked (always the same body).
403feature_not_active insufficient_scopeThe Open API (or, for references, the reference register; for record updates, status tracking) is not active for the brand, or the key lacks the scope.
404not_foundNo such endpoint, or no such record / reference for this key's brand and environment.
405method_not_allowedThe endpoint exists but not with this method; Allow lists the methods.
429rate_limitedMore than 600 requests in this minute for this key.
500server_errorUnexpected error; try again later.

Example

curl -X PATCH \
  -H "Authorization: Bearer $PODFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "example", "location": "example"}' \
  "https://portal.podfy.net/api/v1/references/YOUR_REF"