Glosario

Cómo initializeUpload de LinkedIn convierte un archivo en un URN de imagen

Taras Shynkarenko
Taras Shynkarenko
Actualizado: 9 min de lectura
Cómo initializeUpload de LinkedIn convierte un archivo en un URN de imagenCómo initializeUpload de LinkedIn convierte un archivo en un URN de imagen

TL;DR, Respuesta Rápida

9 min de lectura

Publicar una imagen en LinkedIn cuesta tres llamadas. POST /rest/images?action=initializeUpload registra la subida y devuelve un uploadUrl, una marca de tiempo uploadUrlExpiresAt y un URN de imagen con la forma urn:li:image:{id}. Luego envías el archivo a esa URL, algo que la página de Assets documenta como un PUT con un token OAuth, y referencias el URN como content.media.id en POST /rest/posts. Cada paso tiene su propia tabla de errores, y LinkedIn no documenta ninguna vía de reintento para una subida fallida más allá de empezar de nuevo.

¿Qué hace la llamada initializeUpload de LinkedIn?

Una llamada initializeUpload de LinkedIn registra la subida de una imagen antes de que se mueva un solo byte, y devuelve la URL a la que enviar el archivo más el URN al que apuntará el post. La descripción del propio LinkedIn son tres frases: "Use the initializeUpload action to register the upload. When you initialize, you declare the upcoming upload. Use the upload URL to upload the image."

La llamada es una acción de la Images API, pasada como parámetro de consulta:

POST https://api.linkedin.com/rest/images?action=initializeUpload
Authorization: Bearer {INSERT_TOKEN}
Linkedin-Version: 202608
X-Restli-Protocol-Version: 2.0.0

{
  "initializeUploadRequest": {
    "owner": "urn:li:organization:5583111"
  }
}

Un campo obligatorio, initializeUploadRequest.owner, descrito como el "URN of the entity that owns this asset. Can be a person(urn:li:person:123), or organization(urn:li:organization:123) URN." Merece la pena leerlo frente al propio esquema de imagen, donde el campo owner de primer nivel también acepta un URN sponsoredAccount. La petición de inicialización solo lista persona y organización.

El segundo campo opcional registra el recurso en la biblioteca de medios de una cuenta publicitaria al mismo tiempo:

{
  "initializeUploadRequest": {
    "owner": "urn:li:organization:2414183",
    "mediaLibraryMetadata": {
      "associatedAccount": "urn:li:sponsoredAccount:123456789",
      "assetName": "My media library asset"
    }
  }
}

mediaLibraryMetadata.mediaLibraryStatus "defaults to ACTIVE on creation," así que un recurso de biblioteca está activo en cuanto termina de procesarse.

Una nota que la documentación mete en un recuadro, porque rompe un patrón que la gente arrastra de la vieja Assets API: "SYNCHRONOUS_UPLOAD is not supported in Images API." No hay atajo de una sola llamada. Los tres pasos son toda la superficie.

¿Qué devuelve initializeUpload?

Un 200 con tres valores, envueltos en value:

{
   "value": {
       "uploadUrlExpiresAt": 1650567510704,
       "uploadUrl": "https://www.linkedin.com/dms-uploads/C4E10AQFoyyAjHPMQuQ/uploaded-image/0?ca=vector_ads&cn=uploads&sync=0&v=beta&ut=08zHQjMjAOLqc1",
       "image": "urn:li:image:C4E10AQFoyyAjHPMQuQ"
   }
}

El valor image es el URN, y es la pieza que hay que guardar. Todo lo que viene después se refiere a la imagen por esa cadena: el cuerpo del post, el GET que comprueba el estado de procesamiento, el listado de la biblioteca de medios. Fíjate en que el identificador dentro del URN es el mismo que hay dentro de la ruta de la URL de subida, lo que hace fácil correlacionar las dos en los logs.

uploadUrlExpiresAt son milisegundos desde el epoch. LinkedIn no publica cuánto dura la ventana, así que lo correcto es leer la marca de tiempo en lugar de suponer una duración. Una cola que inicializa un lote de subidas horas antes de enviar los archivos depende de un número que nadie ha documentado.

El URN de imagen también tiene una forma que conviene validar por tu lado, ya que la Images API rechaza los malformados con un error propio. urn:li:image: seguido del identificador, y nada más. La Images API acepta "Images with less than 36,152,320 pixels" en "JPG, GIF, and PNG formats," con "GIF format supports up to 250 frames."

Una pantalla de teléfono muestra una subida de archivo en curso, el paso en el que los bytes de la imagen se envían a la URL de initializeUpload.

¿Cómo subes los bytes de la imagen?

A la uploadUrl, con el archivo como cuerpo y el mismo token bearer adjunto. La página de Assets a la que la Images API remite para este paso es explícita sobre el método: "Use the uploadUrl from the previous step to upload the image. Use a PUT method to upload the image. The upload call requires a valid OAuth token in the 'Authorization' header. This is different than the upload video call which doesn't accept an OAuth token."

curl -i --upload-file ~/Desktop/Myimage.jpg \
  -H 'Authorization: Bearer Redacted' \
  "https://www.linkedin.com/dms-uploads/C5622AQHdBDflPp0pEg/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&sync=1&v=beta&ut=1lrKqjt4fYuqw1"

Una subida correcta responde HTTP/2 201 con content-length: 0. Sin cuerpo, sin JSON, nada que parsear. Lo único que averiguas es el código de estado.

LinkedIn se contradice en el verbo, y conviene saberlo antes de depurar un 405. La guía de consumo Share on LinkedIn, que cubre el flujo antiguo de /v2/assets, dice que envíes "a POST request to the uploadUrl with your image or video included as a binary file," y luego lo demuestra con curl -i --upload-file, que es un PUT. La página de Assets dice PUT en la prosa y enseña el mismo comando. El comando es la parte fiable de las dos páginas.

Después de la subida, GET https://api.linkedin.com/rest/images/urn:li:image:C4E10AQFn10iWtKexVA devuelve el recurso con un campo status. Los valores documentados son WAITING_UPLOAD ("Waiting for client to upload source file or uploading process to be completed"), PROCESSING, AVAILABLE ("All of the recipe's required artifacts are ready. The asset is available to be served") y PROCESSING_FAILED, que el esquema atribuye a "client error such as file size too large, unsupported file format, internal error."

AdaptlyPost
AdaptlyPost

Prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

Una trampa de permisos en ese GET: la Images API requiere rw_ads, w_member_social, w_organization_social o w_power_creators, y LinkedIn señala que "w_member_social permission are write-only and tokens with only w_member_social permissions would be unable to perform a GET call for rest/images." Una integración con alcance de miembro puede subir y no puede consultar.

¿Cómo referencias el URN de imagen en un post?

Como content.media.id en la Posts API, junto al texto alternativo:

POST https://api.linkedin.com/rest/posts

{
  "author": "urn:li:organization:5515715",
  "commentary": "test strings!",
  "visibility": "PUBLIC",
  "distribution": {
    "feedDistribution": "MAIN_FEED",
    "targetEntities": [],
    "thirdPartyDistributionChannels": []
  },
  "content": {
    "media": {
      "altText": "testing for alt tags",
      "id": "urn:li:image:C5610AQFj6TdYowm17w"
    }
  },
  "lifecycleState": "PUBLISHED",
  "isReshareDisabledByAuthor": false
}

"A successful response returns a 201 Created HTTP status code and the ID in the x-restli-id response header." El URN del post vuelve en una cabecera, no en el cuerpo, y tiene el aspecto de urn:li:share:6844785523593134080 o urn:li:ugcPost:68447855235931240. Las integraciones que solo leen cuerpos de respuesta pierden el ID del post por completo.

El altText de ese objeto de medios lleva su propio techo documentado, cubierto en el desglose de dónde escribe LinkedIn su límite de texto alternativo. Para un post de varias imágenes, los mismos URN van a un array images, con un mínimo de 2 y un máximo de 20.

Una persona lee un mensaje de error en la pantalla de un portátil, reflejo de la depuración que sigue a una llamada de subida o publicación fallida.

¿Qué errores aparecen en cada paso?

Tres pasos, tres tablas de errores separadas, y no se solapan.

PasoEstadoCódigoQué significa
initializeUpload400INVALID_URN_TYPE"{field} value {value} must be a {urnType} URN"
initializeUpload400INVALID_URN_ID"This URN ID is invalid"
initializeUpload403ninguno publicado"Accessing this image resource is forbidden. Please check your permissions for this resource"
initializeUpload400VERSION_MISSINGSe omitió la cabecera de versión en la petición
PUT de subida401UNAUTHORIZED"The OAuth token is missing, invalid, or expired"
PUT de subida413REQUEST_ENTITY_TOO_LARGE"The uploaded file exceeds the allowed size limit"
PUT de subida415UNSUPPORTED_MEDIA_TYPE"The uploaded file format is not supported"
PUT de subida422UNPROCESSABLE_ENTITY"The server understands the request but can't process it"
POST /rest/posts400INVALID_URN_TYPE"Verify the URN type used for fields such as author or content.media.id"
POST /rest/posts400MISSING_FIELDFalta author, visibility, distribution o lifecycleState
POST /rest/posts403ACCESS_DENIEDScope concedido pero el miembro no tiene el rol en la página de empresa
POST /rest/posts429TOO_MANY_REQUESTS"The API rate limit has been exceeded"

El 403 de la inicialización es el que hay que leer con cuidado, porque LinkedIn lo publica como cuerpo en bruto y no como código, y porque su causa suele ser un rol de página más que un scope. Las comprobaciones de permisos documentadas son por rol: "For images with company URN owners, the caller must have ADMIN or DSC permissions for the company page," y "For images with member URN owners, the caller must match the image owner."

Una cabecera de versión ausente hace fallar la llamada de inicialización antes de evaluar nada de eso, con 400 VERSION_MISSING y el mensaje "A version must be present. Please specify a version by adding the Linkedin-Version header." Las reglas de esa cabecera, incluido qué devuelve un valor retirado, conviene leerlas junto a este flujo en la pieza sobre la cabecera de versión que necesita cada llamada /rest/.

¿Qué deja LinkedIn sin documentar aquí?

Tres cosas, y cada una es una decisión que tienes que tomar sin cita que la respalde.

Cuánto dura la URL de subida. Recibes uploadUrlExpiresAt en la respuesta y ninguna duración declarada en toda la página, así que un programador que agrupe subidas tiene que tratar la marca de tiempo como el contrato.

Si hay que esperar a AVAILABLE antes de crear el post. Los valores de estado están documentados, el GET que los devuelve está documentado, y la relación entre ambos y la llamada POST /rest/posts no lo está. El patrón seguro es consultar hasta AVAILABLE, y es un patrón, no una regla.

Qué hacer con PROCESSING_FAILED. El esquema nombra las causas y ahí se para. No hay endpoint de reintento documentado, lo que en la práctica significa inicializar una subida nueva y conseguir un URN nuevo. Los equipos que hacen esto a volumen con un programador de publicaciones de LinkedIn acaban construyendo ese reintento por su cuenta, igual que hacen con otras APIs de publicación con flujos de medios en tres pasos.

Tres decisiones sin documentar
1
Duración de la URL de subida. No se publica ninguna duración, así que uploadUrlExpiresAt es la única garantía.
2
Esperar a AVAILABLE. Consultar el estado hasta que cambie es una práctica, no una regla documentada.
3
PROCESSING_FAILED. No existe un endpoint de reintento, así que la solución es una nueva llamada a initializeUpload y una URN nueva.
Cada una de estas tres decisiones se toma sin una cita de la documentación de LinkedIn.

Preguntas frecuentes

¿Qué es el endpoint initializeUpload de LinkedIn?

POST https://api.linkedin.com/rest/images?action=initializeUpload. Es una acción de la Images API que registra una subida y devuelve un uploadUrl, una marca de tiempo uploadUrlExpiresAt y un URN image, antes de enviar ningún dato del archivo.

¿Qué aspecto tiene el URN de imagen de initializeUpload?

urn:li:image:{id}, por ejemplo urn:li:image:C4E10AQFoyyAjHPMQuQ. El mismo identificador aparece dentro de la ruta de la URL de subida devuelta, y el URN es lo que pasas como content.media.id al crear el post.

¿Qué método HTTP sube la imagen a LinkedIn?

PUT. La página de Assets afirma "Use a PUT method to upload the image" y exige "a valid OAuth token in the 'Authorization' header," y una subida correcta devuelve 201 con el cuerpo vacío. La prosa de la guía de consumo dice POST, pero su propio ejemplo de curl usa --upload-file, que envía un PUT.

AdaptlyPost
AdaptlyPost

Prueba gratis de 7 días

Analíticas multiplataforma

Bandeja Social

Asistente con IA

¿Hay que esperar a que la imagen termine de procesarse antes de publicar?

LinkedIn no documenta ninguna espera obligatoria. Documenta un campo status en la imagen con los valores WAITING_UPLOAD, PROCESSING, AVAILABLE y PROCESSING_FAILED, y consultar GET /rest/images/{urn} hasta AVAILABLE es la lectura segura de eso.

¿Por qué initializeUpload devuelve 403?

El cuerpo documentado es "Accessing this image resource is forbidden. Please check your permissions for this resource" con "status": 403. Las comprobaciones de permisos son por rol: un propietario con URN de empresa requiere permisos ADMIN o DSC en la página, y un propietario con URN de miembro tiene que coincidir con quien llama.

¿Puede un token con solo w_member_social usar la Images API?

Para escrituras, sí. LinkedIn afirma que "w_member_social permission are write-only and tokens with only w_member_social permissions would be unable to perform a GET call for rest/images," así que ese token puede inicializar y subir pero no puede consultar el estado de la imagen en el endpoint versionado.

¿Qué formatos y tamaños de imagen acepta la Images API de LinkedIn?

La Images API acepta archivos JPG, GIF y PNG con un límite de 36.152.320 píxeles. Los GIF pueden llegar hasta 250 fotogramas. Estos límites se aplican a cualquier imagen del flujo de tres pasos, no a un paso en concreto.

¿La Images API de LinkedIn admite subida síncrona?

No la admite. LinkedIn lo deja en un aviso: "SYNCHRONOUS_UPLOAD is not supported in Images API." Las tres llamadas, initializeUpload, el PUT y POST /rest/posts, son todo el flujo, sin el atajo de un solo paso que algunos arrastran de la antigua Assets API.

¿Qué scopes de OAuth permiten usar la Images API de LinkedIn?

rw_ads, w_member_social, w_organization_social o w_power_creators. Cualquiera de los cuatro cubre initializeUpload y el PUT de subida, pero w_member_social por sí solo no puede leer el estado de la imagen con un GET, porque LinkedIn documenta ese scope como solo de escritura.

¿Cuántas imágenes puede llevar un post de LinkedIn?

Un post de una sola imagen referencia una URN mediante content.media.id. Un post de varias imágenes usa en su lugar un array images, que LinkedIn exige con un mínimo de 2 y un máximo de 20 URNs.

¿Te resultó útil este artículo?

¡Cuéntanos qué te parece!

Vernos más en Google

Un clic marca AdaptlyPost como fuente preferida y nuestros artículos aparecen más arriba en tus Noticias destacadas, el modo IA y los resúmenes con IA.

Antes de irte...

AdaptlyPost

AdaptlyPost

Programa tu contenido en todas las plataformas

Gestiona todas tus cuentas de redes sociales en un solo lugar con AdaptlyPost.

Analíticas multiplataforma

Bandeja Social

Asistente con IA

Términos relacionados del glosario

Artículos Relacionados